Mercurial > noffle
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 ) |