changeset 165:8ea6b5ddc5a5 noffle

[svn] * src/lock.h,src/lock.c,src/noffle.c: Add lazy lock release. Only release the lock and close the databases if (a) another process signals us SIGUSR1 indicating it wants the lock, or (b) it is explicitly requested by a call to new function Lock_syncDatabases(). When waiting for the lock, SIGUSR1 the holding process every second. This is all an attempt to minimise the number of times we need to close and open the database. When (ha!) the database is replaced by something that can handle multiple simultaneous writers (with appropriate locking) this won't be necessary.
author bears
date Thu, 25 Jan 2001 13:38:31 +0000
parents 94f2e5607772
children 1d92abe57427
files ChangeLog src/lock.c src/lock.h src/noffle.c
diffstat 4 files changed, 185 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Jan 25 11:00:03 2001 +0000
+++ b/ChangeLog	Thu Jan 25 13:38:31 2001 +0000
@@ -1,3 +1,19 @@
+Thu Jan 25 2001 Jim Hague <jim.hague@acm.org>
+
+ * src/client.c,src/protocol.c,src/util.h,src/util.c: Common up
+   repeated signal handler setting code into Utl_installSignalHandler.
+ * src/client.c: Ensure Client_retrieveArt always exits with the global
+   lock held. Previously it would be held on error, not held if OK.
+ * src/lock.h,src/lock.c,src/noffle.c: Add lazy lock release. Only release
+   the lock and close the databases if (a) another process signals us
+   SIGUSR1 indicating it wants the lock, or (b) it is explicitly requested by
+   a call to new function Lock_syncDatabases(). When waiting for the lock,
+   SIGUSR1 the holding process every second. This is all an attempt to
+   minimise the number of times we need to close and open the database.
+   When (ha!) the database is replaced by something that can handle
+   multiple simultaneous writers (with appropriate locking) this won't
+   be necessary.
+
 Fri Dec 29 2000 Markus Enzenberger <markus.enzenberger@t-online.de>
 
  * src/server.c: apply bug-fix for lazy group loading by Matija Nalis 
@@ -30,7 +46,7 @@
    packages/redhat/noffle.spec,src/configfile.h,src/configfile.c,
    src/noffle.c,src/post.h,src/post.c: Removed use of getopt_long,
    and added inews mode - the Noffle executable behaves
-   as inews is invoked as inews. This includes adding From: and
+   as inews if invoked as inews. This includes adding From: and
    Organization: headers if necessary - add configs to override
    defaults for the From: domain and specify the organization.
    For all my fellow trn-heads out there, and users of any other
--- a/src/lock.c	Thu Jan 25 11:00:03 2001 +0000
+++ b/src/lock.c	Thu Jan 25 13:38:31 2001 +0000
@@ -1,7 +1,7 @@
 /*
   lock.c
 
-  $Id: lock.c 183 2000-07-25 12:14:54Z bears $
+  $Id: lock.c 249 2001-01-25 13:38:31Z bears $
 */
 
 #if HAVE_CONFIG_H
@@ -15,6 +15,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <signal.h>
 
 #if TIME_WITH_SYS_TIME
 #include <sys/time.h>
@@ -34,16 +35,47 @@
 #include "group.h"
 #include "request.h"
 #include "portable.h"
+#include "util.h"
 
 struct Lock
 {
     const char *name;
     int lockFd;
     Str lockFile;
+    Bool doLazyLocking;
+    volatile Bool lazyClose;
+    volatile Bool lazyLockBusy;
 };
 
-struct Lock globalLock = { "global", -1, "" };
-struct Lock fetchLock = { "fetch", -1, "" };
+static struct Lock globalLock = { "global", -1, "", TRUE };
+static struct Lock fetchLock = { "fetch", -1, "", FALSE };
+
+static sig_t oldHandler = NULL;
+
+/* Block/unblock SIGUSR1. */
+static Bool
+blockSignal( Bool block )
+{
+    sigset_t sigs;
+
+    sigemptyset(&sigs);
+    sigaddset(&sigs, SIGUSR1);
+    
+    for(;;)
+    {
+	if ( sigprocmask( block ? SIG_BLOCK : SIG_UNBLOCK, &sigs, NULL ) != 0 )
+	{
+	    if ( errno != EINTR )
+	    {
+		Log_err( "Can't block/unblock signal" );
+		return FALSE;
+	    }
+	}
+	else
+	    return TRUE;
+    }
+    /* NOTREACHED */
+}
 
 /* Check the global lock held. */
 static Bool
@@ -52,6 +84,14 @@
     return ( lock->lockFd != -1 );    
 }
 
+static void
+lockWaitAlarm( int sig )
+{
+    UNUSED( sig );
+    
+    return;
+}
+
 static Bool
 waitLock( struct Lock *lock, enum LockRequestWait wait )
 {
@@ -74,12 +114,37 @@
     l.l_len = 0;
     if ( wait == LOCK_WAIT )
     {
-	if ( fcntl( fd, F_SETLKW, &l ) < 0 )
+	sig_t oldAlarmHandler;
+	unsigned oldAlarm;
+
+	oldAlarmHandler = Utl_installSignalHandler( SIGALRM, lockWaitAlarm );
+	oldAlarm = alarm( 1 );
+	for(;;)
 	{
-	    Log_err( "Cannot lock %s: %s", lock->lockFile, strerror( errno ) );
-	    close( lock->lockFd );
-	    return FALSE;
+	    alarm( 1 );
+	    if ( fcntl( fd, F_SETLKW, &l ) < 0 )
+		if ( errno != EINTR )
+		{
+		    Utl_installSignalHandler( SIGALRM, oldAlarmHandler );
+		    alarm( oldAlarm );
+		    Log_err( "Cannot lock %s: %s", lock->lockFile,
+			     strerror( errno ) );
+		    close( lock->lockFd );
+		    return FALSE;
+		}
+		else
+		{
+		    /* Send SIGUSR1 to the process holding the lock. */
+		    if ( fcntl( fd, F_GETLK, &l) == 0 && l.l_type != F_UNLCK )
+			if ( kill( l.l_pid, SIGUSR1 ) < 0 )
+			    Log_err( "Can't signal process %d: %s", l.l_pid,
+				     strerror( errno ) );
+		}
+	    else
+		break;
 	}
+	Utl_installSignalHandler( SIGALRM, oldAlarmHandler );
+	alarm( oldAlarm );
     }
     else
     {
@@ -113,11 +178,10 @@
     Log_dbg( "Releasing lock" );
 }
 
-
-/* Open all databases and set global lock. */
-Bool
-Lock_openDatabases( void )
+static Bool
+openDatabases( void )
 {
+    globalLock.lazyClose = FALSE;
     if ( ! waitLock( &globalLock, LOCK_WAIT ) )
     {
 	Log_err( "Could not get write lock" );
@@ -145,25 +209,98 @@
 	return FALSE;
     }
 
+    globalLock.lazyClose = globalLock.doLazyLocking;
+    globalLock.lazyLockBusy = TRUE;
     return TRUE;
 }
 
+static void
+closeDatabases( void )
+{
+    Grp_close();
+    Db_close();
+    Req_close();
+    releaseLock( &globalLock );
+    globalLock.lazyLockBusy = FALSE;
+    globalLock.lazyClose = FALSE;
+}
+
+static void
+lockSignal( int sig )
+{
+    UNUSED( sig );
+
+    if ( globalLock.lazyLockBusy )
+	globalLock.lazyClose = FALSE;
+    else
+	closeDatabases();
+    return;
+}
+
+/* Open all databases and set global lock. */
+Bool
+Lock_openDatabases( void )
+{
+    Bool res;
+
+    /* First time - need to initialise signal handler? */
+    if ( oldHandler == NULL )
+	oldHandler = Utl_installSignalHandler( SIGUSR1, lockSignal );
+
+    if ( ! blockSignal( TRUE ) )
+	return FALSE;
+    
+    if ( ! globalLock.lazyClose )
+	res = openDatabases();
+    else
+	res = TRUE;
+    
+    globalLock.lazyLockBusy = res;
+
+    if ( ! blockSignal( FALSE ) )
+	return FALSE;
+
+    return res;
+}
 
 /* Close all databases and release global lock. */
 void
 Lock_closeDatabases( void )
 {
-    Grp_close();
-    Db_close();
-    Req_close();
-    releaseLock( &globalLock );
+    blockSignal( TRUE );
+    
+    if ( ! globalLock.lazyClose )
+	closeDatabases();
+    else
+	globalLock.lazyLockBusy = FALSE;
+    
+    blockSignal( FALSE );
+}
+
+/* Sync al databases to disc. Maintain global lock status. */
+void
+Lock_syncDatabases( void )
+{
+    Bool wasOpen;
+    
+    if ( gotLock( &globalLock ) )
+    {
+	blockSignal( TRUE );
+    
+	wasOpen = globalLock.lazyLockBusy;
+	closeDatabases();
+	if ( wasOpen )
+	    openDatabases();
+	
+	blockSignal( FALSE );
+    }
 }
 
 /* Check the global lock held. */
 Bool
 Lock_gotLock( void )
 {
-    return gotLock( &globalLock );
+    return globalLock.lazyLockBusy;
 }
 
 /* Get fetch lock. */
--- a/src/lock.h	Thu Jan 25 11:00:03 2001 +0000
+++ b/src/lock.h	Thu Jan 25 13:38:31 2001 +0000
@@ -5,7 +5,7 @@
   articla database, groups database, outgoing articles database, requests
   database. Handles global lock.
 
-  $Id: lock.h 183 2000-07-25 12:14:54Z bears $
+  $Id: lock.h 249 2001-01-25 13:38:31Z bears $
 */
 
 #ifndef LOCK_H
@@ -27,6 +27,10 @@
 void
 Lock_closeDatabases( void );
 
+/* Ensure all databases synced to disc. */
+void
+Lock_syncDatabases( void );
+
 /* Check the global lock held. */
 Bool
 Lock_gotLock( void );
--- a/src/noffle.c	Thu Jan 25 11:00:03 2001 +0000
+++ b/src/noffle.c	Thu Jan 25 13:38:31 2001 +0000
@@ -10,7 +10,7 @@
   received for some seconds (to allow multiple clients connect at the same
   time).
 
-  $Id: noffle.c 227 2000-10-26 21:21:13Z bears $
+  $Id: noffle.c 249 2001-01-25 13:38:31Z bears $
 */
 
 #if HAVE_CONFIG_H
@@ -598,6 +598,7 @@
 {
     if ( noffle.lockAtStartup )
       Lock_closeDatabases();
+    Lock_syncDatabases();
 }
 
 static RETSIGTYPE
@@ -605,6 +606,10 @@
 {
     Log_err( "Received SIGSEGV. Please submit a bug report" );
     signal( SIGSEGV, SIG_DFL );
+
+    /* Attempt to save database state before passing on sig. */
+    Lock_syncDatabases();
+    
     raise( sig );
 }
 
@@ -636,6 +641,10 @@
     else
         Log_inf( "Received signal %i (%s). Aborting.", sig, name );
     signal( sig, SIG_DFL );
+
+    /* Attempt to save database state before passing on sig. */
+    Lock_syncDatabases();
+    
     raise( sig );
 }