comparison src/lock.c @ 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 3c71e28c8eef
children 7ba337dafb2c
comparison
equal deleted inserted replaced
164:94f2e5607772 165:8ea6b5ddc5a5
1 /* 1 /*
2 lock.c 2 lock.c
3 3
4 $Id: lock.c 183 2000-07-25 12:14:54Z bears $ 4 $Id: lock.c 249 2001-01-25 13:38:31Z bears $
5 */ 5 */
6 6
7 #if HAVE_CONFIG_H 7 #if HAVE_CONFIG_H
8 #include <config.h> 8 #include <config.h>
9 #endif 9 #endif
13 #include <errno.h> 13 #include <errno.h>
14 #include <ctype.h> 14 #include <ctype.h>
15 #include <sys/types.h> 15 #include <sys/types.h>
16 #include <sys/stat.h> 16 #include <sys/stat.h>
17 #include <fcntl.h> 17 #include <fcntl.h>
18 #include <signal.h>
18 19
19 #if TIME_WITH_SYS_TIME 20 #if TIME_WITH_SYS_TIME
20 #include <sys/time.h> 21 #include <sys/time.h>
21 #include <time.h> 22 #include <time.h>
22 #else 23 #else
32 #include "log.h" 33 #include "log.h"
33 #include "database.h" 34 #include "database.h"
34 #include "group.h" 35 #include "group.h"
35 #include "request.h" 36 #include "request.h"
36 #include "portable.h" 37 #include "portable.h"
38 #include "util.h"
37 39
38 struct Lock 40 struct Lock
39 { 41 {
40 const char *name; 42 const char *name;
41 int lockFd; 43 int lockFd;
42 Str lockFile; 44 Str lockFile;
45 Bool doLazyLocking;
46 volatile Bool lazyClose;
47 volatile Bool lazyLockBusy;
43 }; 48 };
44 49
45 struct Lock globalLock = { "global", -1, "" }; 50 static struct Lock globalLock = { "global", -1, "", TRUE };
46 struct Lock fetchLock = { "fetch", -1, "" }; 51 static struct Lock fetchLock = { "fetch", -1, "", FALSE };
52
53 static sig_t oldHandler = NULL;
54
55 /* Block/unblock SIGUSR1. */
56 static Bool
57 blockSignal( Bool block )
58 {
59 sigset_t sigs;
60
61 sigemptyset(&sigs);
62 sigaddset(&sigs, SIGUSR1);
63
64 for(;;)
65 {
66 if ( sigprocmask( block ? SIG_BLOCK : SIG_UNBLOCK, &sigs, NULL ) != 0 )
67 {
68 if ( errno != EINTR )
69 {
70 Log_err( "Can't block/unblock signal" );
71 return FALSE;
72 }
73 }
74 else
75 return TRUE;
76 }
77 /* NOTREACHED */
78 }
47 79
48 /* Check the global lock held. */ 80 /* Check the global lock held. */
49 static Bool 81 static Bool
50 gotLock( struct Lock *lock ) 82 gotLock( struct Lock *lock )
51 { 83 {
52 return ( lock->lockFd != -1 ); 84 return ( lock->lockFd != -1 );
85 }
86
87 static void
88 lockWaitAlarm( int sig )
89 {
90 UNUSED( sig );
91
92 return;
53 } 93 }
54 94
55 static Bool 95 static Bool
56 waitLock( struct Lock *lock, enum LockRequestWait wait ) 96 waitLock( struct Lock *lock, enum LockRequestWait wait )
57 { 97 {
72 l.l_start = 0; 112 l.l_start = 0;
73 l.l_whence = SEEK_SET; 113 l.l_whence = SEEK_SET;
74 l.l_len = 0; 114 l.l_len = 0;
75 if ( wait == LOCK_WAIT ) 115 if ( wait == LOCK_WAIT )
76 { 116 {
77 if ( fcntl( fd, F_SETLKW, &l ) < 0 ) 117 sig_t oldAlarmHandler;
118 unsigned oldAlarm;
119
120 oldAlarmHandler = Utl_installSignalHandler( SIGALRM, lockWaitAlarm );
121 oldAlarm = alarm( 1 );
122 for(;;)
78 { 123 {
79 Log_err( "Cannot lock %s: %s", lock->lockFile, strerror( errno ) ); 124 alarm( 1 );
80 close( lock->lockFd ); 125 if ( fcntl( fd, F_SETLKW, &l ) < 0 )
81 return FALSE; 126 if ( errno != EINTR )
127 {
128 Utl_installSignalHandler( SIGALRM, oldAlarmHandler );
129 alarm( oldAlarm );
130 Log_err( "Cannot lock %s: %s", lock->lockFile,
131 strerror( errno ) );
132 close( lock->lockFd );
133 return FALSE;
134 }
135 else
136 {
137 /* Send SIGUSR1 to the process holding the lock. */
138 if ( fcntl( fd, F_GETLK, &l) == 0 && l.l_type != F_UNLCK )
139 if ( kill( l.l_pid, SIGUSR1 ) < 0 )
140 Log_err( "Can't signal process %d: %s", l.l_pid,
141 strerror( errno ) );
142 }
143 else
144 break;
82 } 145 }
146 Utl_installSignalHandler( SIGALRM, oldAlarmHandler );
147 alarm( oldAlarm );
83 } 148 }
84 else 149 else
85 { 150 {
86 if ( fcntl( fd, F_SETLK, &l ) < 0 ) 151 if ( fcntl( fd, F_SETLK, &l ) < 0 )
87 { 152 {
111 close( lock->lockFd ); 176 close( lock->lockFd );
112 lock->lockFd = -1; 177 lock->lockFd = -1;
113 Log_dbg( "Releasing lock" ); 178 Log_dbg( "Releasing lock" );
114 } 179 }
115 180
116 181 static Bool
117 /* Open all databases and set global lock. */ 182 openDatabases( void )
118 Bool 183 {
119 Lock_openDatabases( void ) 184 globalLock.lazyClose = FALSE;
120 {
121 if ( ! waitLock( &globalLock, LOCK_WAIT ) ) 185 if ( ! waitLock( &globalLock, LOCK_WAIT ) )
122 { 186 {
123 Log_err( "Could not get write lock" ); 187 Log_err( "Could not get write lock" );
124 return FALSE; 188 return FALSE;
125 } 189 }
143 Db_close(); 207 Db_close();
144 releaseLock( &globalLock ); 208 releaseLock( &globalLock );
145 return FALSE; 209 return FALSE;
146 } 210 }
147 211
212 globalLock.lazyClose = globalLock.doLazyLocking;
213 globalLock.lazyLockBusy = TRUE;
148 return TRUE; 214 return TRUE;
149 } 215 }
150 216
151 217 static void
152 /* Close all databases and release global lock. */ 218 closeDatabases( void )
153 void
154 Lock_closeDatabases( void )
155 { 219 {
156 Grp_close(); 220 Grp_close();
157 Db_close(); 221 Db_close();
158 Req_close(); 222 Req_close();
159 releaseLock( &globalLock ); 223 releaseLock( &globalLock );
224 globalLock.lazyLockBusy = FALSE;
225 globalLock.lazyClose = FALSE;
226 }
227
228 static void
229 lockSignal( int sig )
230 {
231 UNUSED( sig );
232
233 if ( globalLock.lazyLockBusy )
234 globalLock.lazyClose = FALSE;
235 else
236 closeDatabases();
237 return;
238 }
239
240 /* Open all databases and set global lock. */
241 Bool
242 Lock_openDatabases( void )
243 {
244 Bool res;
245
246 /* First time - need to initialise signal handler? */
247 if ( oldHandler == NULL )
248 oldHandler = Utl_installSignalHandler( SIGUSR1, lockSignal );
249
250 if ( ! blockSignal( TRUE ) )
251 return FALSE;
252
253 if ( ! globalLock.lazyClose )
254 res = openDatabases();
255 else
256 res = TRUE;
257
258 globalLock.lazyLockBusy = res;
259
260 if ( ! blockSignal( FALSE ) )
261 return FALSE;
262
263 return res;
264 }
265
266 /* Close all databases and release global lock. */
267 void
268 Lock_closeDatabases( void )
269 {
270 blockSignal( TRUE );
271
272 if ( ! globalLock.lazyClose )
273 closeDatabases();
274 else
275 globalLock.lazyLockBusy = FALSE;
276
277 blockSignal( FALSE );
278 }
279
280 /* Sync al databases to disc. Maintain global lock status. */
281 void
282 Lock_syncDatabases( void )
283 {
284 Bool wasOpen;
285
286 if ( gotLock( &globalLock ) )
287 {
288 blockSignal( TRUE );
289
290 wasOpen = globalLock.lazyLockBusy;
291 closeDatabases();
292 if ( wasOpen )
293 openDatabases();
294
295 blockSignal( FALSE );
296 }
160 } 297 }
161 298
162 /* Check the global lock held. */ 299 /* Check the global lock held. */
163 Bool 300 Bool
164 Lock_gotLock( void ) 301 Lock_gotLock( void )
165 { 302 {
166 return gotLock( &globalLock ); 303 return globalLock.lazyLockBusy;
167 } 304 }
168 305
169 /* Get fetch lock. */ 306 /* Get fetch lock. */
170 Bool 307 Bool
171 Lock_getFetchLock( enum LockRequestWait wait ) 308 Lock_getFetchLock( enum LockRequestWait wait )