00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifndef lint 00011 static const char revid[] = "$Id: lock_8c-source.html,v 1.1 2008年06月08日 10:19:51 sebdiaz Exp $"; 00012 #endif /* not lint */ 00013 00014 #ifndef NO_SYSTEM_INCLUDES 00015 #include <sys/types.h> 00016 00017 #include <errno.h> 00018 #include <string.h> 00019 #endif 00020 00021 #ifdef HAVE_RPC 00022 #include "db_server.h" 00023 #endif 00024 00025 #include "db_int.h" 00026 #include "db_page.h" 00027 #include "db_shash.h" 00028 #include "lock.h" 00029 #include "log.h" 00030 #include "db_am.h" 00031 #include "txn.h" 00032 00033 #ifdef HAVE_RPC 00034 #include "gen_client_ext.h" 00035 #include "rpc_client_ext.h" 00036 #endif 00037 00038 static int __lock_checklocker __P((DB_LOCKTAB *, 00039 struct __db_lock *, u_int32_t, u_int32_t, int *)); 00040 static int __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, 00041 u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); 00042 static int __lock_is_parent __P((DB_LOCKTAB *, u_int32_t, DB_LOCKER *)); 00043 static int __lock_put_internal __P((DB_LOCKTAB *, 00044 struct __db_lock *, u_int32_t, u_int32_t)); 00045 static int __lock_put_nolock __P((DB_ENV *, DB_LOCK *, int *)); 00046 static void __lock_remove_waiter __P((DB_LOCKOBJ *, 00047 struct __db_lock *, db_status_t)); 00048 00049 static const char __db_lock_err[] = "Lock table is out of available %s"; 00050 static const char __db_lock_invalid[] = "%s: Lock is no longer valid"; 00051 static const char __db_locker_invalid[] = "Locker is not valid"; 00052 00053 /* 00054 * CDB_lock_id -- 00055 * Generate a unique locker id. 00056 */ 00057 int 00058 CDB_lock_id(dbenv, idp) 00059 DB_ENV *dbenv; 00060 u_int32_t *idp; 00061 { 00062 DB_LOCKTAB *lt; 00063 DB_LOCKREGION *region; 00064 00065 #ifdef HAVE_RPC 00066 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) 00067 return (__dbcl_lock_id(dbenv, idp)); 00068 #endif 00069 00070 PANIC_CHECK(dbenv); 00071 ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); 00072 00073 lt = dbenv->lk_handle; 00074 region = lt->reginfo.primary; 00075 00076 /* 00077 * Note that we are letting locker IDs wrap. 00078 * 00079 * This is potentially dangerous in that it's conceivable that you 00080 * could be allocating a new locker id and still have someone using 00081 * it. However, the alternatives are that we keep a bitmap of 00082 * locker ids or we forbid wrapping. Both are probably bad. The 00083 * bitmap of locker ids will take up 64 MB of space. Forbidding 00084 * wrapping means that we'll run out of locker IDs after 2 billion. 00085 * In order for the wrap bug to fire, we'd need to have something 00086 * that stayed open while 2 billion locker ids were used up. Since 00087 * we cache cursors it means that something would have to stay open 00088 * sufficiently long that we open and close a lot of files and a 00089 * lot of cursors within them. Betting that this won't happen seems 00090 * to the lesser of the evils. 00091 */ 00092 LOCKREGION(dbenv, lt); 00093 if (region->id >= DB_LOCK_MAXID) 00094 region->id = 0; 00095 *idp = ++region->id; 00096 UNLOCKREGION(dbenv, lt); 00097 00098 return (0); 00099 } 00100 00101 /* 00102 * Vector lock routine. This function takes a set of operations 00103 * and performs them all at once. In addition, CDB_lock_vec provides 00104 * functionality for lock inheritance, releasing all locks for a 00105 * given locker (used during transaction commit/abort), releasing 00106 * all locks on a given object, and generating debugging information. 00107 */ 00108 int 00109 CDB_lock_vec(dbenv, locker, flags, list, nlist, elistp) 00110 DB_ENV *dbenv; 00111 u_int32_t locker, flags; 00112 int nlist; 00113 DB_LOCKREQ *list, **elistp; 00114 { 00115 struct __db_lock *lp, *next_lock; 00116 DB_LOCKER *sh_locker, *sh_parent; 00117 DB_LOCKOBJ *sh_obj; 00118 DB_LOCKREGION *region; 00119 DB_LOCKTAB *lt; 00120 u_int32_t lndx, ndx; 00121 int did_abort, i, ret, run_dd; 00122 00123 #ifdef HAVE_RPC 00124 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) 00125 return (__dbcl_lock_vec(dbenv, locker, 00126 flags, list, nlist, elistp)); 00127 #endif 00128 PANIC_CHECK(dbenv); 00129 ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); 00130 00131 /* Validate arguments. */ 00132 if ((ret = CDB___db_fchk(dbenv, "CDB_lock_vec", flags, DB_LOCK_NOWAIT)) != 0) 00133 return (ret); 00134 00135 lt = dbenv->lk_handle; 00136 region = lt->reginfo.primary; 00137 00138 run_dd = 0; 00139 LOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); 00140 for (i = 0, ret = 0; i < nlist && ret == 0; i++) 00141 switch (list[i].op) { 00142 case DB_LOCK_GET: 00143 ret = __lock_get_internal(dbenv->lk_handle, 00144 locker, flags, 00145 list[i].obj, list[i].mode, &list[i].lock); 00146 break; 00147 case DB_LOCK_INHERIT: 00148 00149 /* 00150 * Get the committing locker and mark it as deleted. 00151 * This allows us to traverse the locker links without 00152 * worrying that someone else is deleting locks out 00153 * from under us. However, if the locker doesn't 00154 * exist, that just means that the child holds no 00155 * locks, so inheritance is easy! 00156 */ 00157 ndx = CDB___lock_locker_hash(locker) % region->table_size; 00158 if ((ret = CDB___lock_getlocker(lt, 00159 locker, ndx, 0, &sh_locker)) != 0 || 00160 sh_locker == NULL || 00161 F_ISSET(sh_locker, DB_LOCKER_DELETED)) { 00162 if (ret == 0 && sh_locker != NULL) 00163 ret = EACCES; 00164 CDB___db_err(dbenv, __db_locker_invalid); 00165 break; 00166 } 00167 00168 /* Make sure we are a child transaction. */ 00169 if (sh_locker->parent_locker == INVALID_ROFF) { 00170 CDB___db_err(dbenv, "Not a child transaction"); 00171 ret = EINVAL; 00172 break; 00173 } 00174 sh_parent = (DB_LOCKER *) 00175 R_ADDR(<->reginfo, sh_locker->parent_locker); 00176 F_SET(sh_locker, DB_LOCKER_DELETED); 00177 00178 /* 00179 * Now, lock the parent locker; move locks from 00180 * the committing list to the parent's list. 00181 */ 00182 ndx = CDB___lock_locker_hash(locker) % region->table_size; 00183 if (F_ISSET(sh_parent, DB_LOCKER_DELETED)) { 00184 if (ret == 0) { 00185 CDB___db_err(dbenv, 00186 "Parent locker is not valid"); 00187 ret = EACCES; 00188 } 00189 break; 00190 } 00191 00192 for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock); 00193 lp != NULL; 00194 lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) { 00195 SH_LIST_REMOVE(lp, locker_links, __db_lock); 00196 SH_LIST_INSERT_HEAD(&sh_parent->heldby, lp, 00197 locker_links, __db_lock); 00198 lp->holder = sh_parent->id; 00199 } 00200 00201 /* Now free the original locker. */ 00202 ret = __lock_checklocker(lt, 00203 NULL, locker, DB_LOCK_IGNOREDEL, NULL); 00204 break; 00205 case DB_LOCK_PUT: 00206 ret = __lock_put_nolock(dbenv, &list[i].lock, &run_dd); 00207 break; 00208 case DB_LOCK_PUT_ALL: 00209 /* 00210 * Get the locker and mark it as deleted. This 00211 * allows us to traverse the locker links without 00212 * worrying that someone else is deleting locks out 00213 * from under us. Since the locker may hold no 00214 * locks (i.e., you could call abort before you've 00215 * done any work), it's perfectly reasonable for there 00216 * to be no locker; this is not an error. 00217 */ 00218 ndx = CDB___lock_locker_hash(locker) % region->table_size; 00219 if ((ret = CDB___lock_getlocker(lt, 00220 locker, ndx, 0, &sh_locker)) != 0 || 00221 sh_locker == NULL || 00222 F_ISSET(sh_locker, DB_LOCKER_DELETED)) 00223 /* 00224 * If ret is set, then we'll generate an 00225 * error. If it's not set, we have nothing 00226 * to do. 00227 */ 00228 break; 00229 F_SET(sh_locker, DB_LOCKER_DELETED); 00230 00231 /* Now traverse the locks, releasing each one. */ 00232 for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock); 00233 lp != NULL; 00234 lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) { 00235 SH_LIST_REMOVE(lp, locker_links, __db_lock); 00236 sh_obj = 00237 (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj); 00238 SHOBJECT_LOCK(lt, region, sh_obj, lndx); 00239 ret = __lock_put_internal(lt, 00240 lp, lndx, DB_LOCK_FREE | DB_LOCK_DOALL); 00241 if (ret != 0) 00242 break; 00243 } 00244 ret = __lock_checklocker(lt, 00245 NULL, locker, DB_LOCK_IGNOREDEL, NULL); 00246 break; 00247 case DB_LOCK_PUT_OBJ: 00248 /* Remove all the locks associated with an object. */ 00249 OBJECT_LOCK(lt, region, list[i].obj, ndx); 00250 if ((ret = CDB___lock_getobj(lt, list[i].obj, 00251 ndx, 0, &sh_obj)) != 0 || sh_obj == NULL) { 00252 if (ret == 0) 00253 ret = EINVAL; 00254 break; 00255 } 00256 00257 /* 00258 * Go through both waiters and holders. Don't bother 00259 * to run promotion, because everyone is getting 00260 * released. The processes waiting will still get 00261 * awakened as their waiters are released. 00262 */ 00263 for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock); 00264 ret == 0 && lp != NULL; 00265 lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock)) 00266 ret = __lock_put_internal(lt, 00267 lp, ndx, DB_LOCK_NOPROMOTE | DB_LOCK_DOALL); 00268 00269 /* 00270 * On the last time around, the object will get 00271 * reclaimed by __lock_put_internal, structure the 00272 * loop carefully so we do not get bitten. 00273 */ 00274 for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock); 00275 ret == 0 && lp != NULL; 00276 lp = next_lock) { 00277 next_lock = SH_TAILQ_NEXT(lp, links, __db_lock); 00278 ret = __lock_put_internal(lt, 00279 lp, ndx, DB_LOCK_NOPROMOTE | DB_LOCK_DOALL); 00280 } 00281 break; 00282 #ifdef DEBUG 00283 case DB_LOCK_DUMP: 00284 /* Find the locker. */ 00285 ndx = CDB___lock_locker_hash(locker) % region->table_size; 00286 if ((ret = CDB___lock_getlocker(lt, 00287 locker, ndx, 0, &sh_locker)) != 0 00288 || sh_locker == NULL 00289 || F_ISSET(sh_locker, DB_LOCKER_DELETED)) 00290 break; 00291 00292 for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock); 00293 lp != NULL; 00294 lp = SH_LIST_NEXT(lp, locker_links, __db_lock)) { 00295 CDB___lock_printlock(lt, lp, 1); 00296 } 00297 break; 00298 #endif 00299 default: 00300 CDB___db_err(dbenv, 00301 "Invalid lock operation: %d", list[i].op); 00302 ret = EINVAL; 00303 break; 00304 } 00305 00306 if (ret == 0 && region->need_dd && region->detect != DB_LOCK_NORUN) { 00307 run_dd = 1; 00308 region->need_dd = 0; 00309 } 00310 UNLOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); 00311 00312 if (run_dd) 00313 (void)CDB_lock_detect(dbenv, 0, region->detect, &did_abort); 00314 00315 if (ret != 0 && elistp != NULL) 00316 *elistp = &list[i - 1]; 00317 00318 return (ret); 00319 } 00320 00321 /* 00322 * Lock acquisition routines. There are two library interfaces: 00323 * 00324 * CDB_lock_get -- 00325 * original lock get interface that takes a locker id. 00326 * 00327 * All the work for CDB_lock_get (and for the GET option of CDB_lock_vec) is done 00328 * inside of lock_get_internal. 00329 */ 00330 int 00331 CDB_lock_get(dbenv, locker, flags, obj, lock_mode, lock) 00332 DB_ENV *dbenv; 00333 u_int32_t locker, flags; 00334 const DBT *obj; 00335 db_lockmode_t lock_mode; 00336 DB_LOCK *lock; 00337 { 00338 int ret; 00339 00340 #ifdef HAVE_RPC 00341 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) 00342 return (__dbcl_lock_get(dbenv, locker, 00343 flags, obj, lock_mode, lock)); 00344 #endif 00345 PANIC_CHECK(dbenv); 00346 ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); 00347 00348 if (IS_RECOVERING(dbenv)) 00349 return (0); 00350 00351 /* Validate arguments. */ 00352 if ((ret = CDB___db_fchk(dbenv, 00353 "CDB_lock_get", flags, DB_LOCK_NOWAIT | DB_LOCK_UPGRADE)) != 0) 00354 return (ret); 00355 00356 if (lock == NULL) 00357 return (EINVAL); 00358 00359 LOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); 00360 ret = __lock_get_internal(dbenv->lk_handle, 00361 locker, flags, obj, lock_mode, lock); 00362 UNLOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); 00363 return (ret); 00364 } 00365 00366 static int 00367 __lock_get_internal(lt, locker, flags, obj, lock_mode, lock) 00368 DB_LOCKTAB *lt; 00369 u_int32_t locker, flags; 00370 const DBT *obj; 00371 db_lockmode_t lock_mode; 00372 DB_LOCK *lock; 00373 { 00374 struct __db_lock *newl, *lp; 00375 DB_ENV *dbenv; 00376 DB_LOCKER *sh_locker; 00377 DB_LOCKOBJ *sh_obj; 00378 DB_LOCKREGION *region; 00379 u_int32_t locker_ndx; 00380 int did_abort, freed, ihold, on_locker_list, no_dd, ret; 00381 00382 no_dd = ret = 0; 00383 on_locker_list = 0; 00384 region = lt->reginfo.primary; 00385 dbenv = lt->dbenv; 00386 00387 /* 00388 * Check that the lock mode is valid. 00389 */ 00390 if ((u_int32_t)lock_mode >= region->nmodes) { 00391 CDB___db_err(dbenv, 00392 "CDB_lock_get: invalid lock mode %lu\n", (u_long)lock_mode); 00393 return (EINVAL); 00394 } 00395 00396 /* Allocate a new lock. Optimize for the common case of a grant. */ 00397 region->nrequests++; 00398 if ((newl = SH_TAILQ_FIRST(®ion->free_locks, __db_lock)) != NULL) 00399 SH_TAILQ_REMOVE(®ion->free_locks, newl, links, __db_lock); 00400 if (newl == NULL) { 00401 CDB___db_err(dbenv, __db_lock_err, "locks"); 00402 return (ENOMEM); 00403 } 00404 00405 /* Allocate a new object. */ 00406 OBJECT_LOCK(lt, region, obj, lock->ndx); 00407 if ((ret = CDB___lock_getobj(lt, obj, lock->ndx, 1, &sh_obj)) != 0) 00408 goto err; 00409 00410 /* Get the locker, we may need it to find our parent. */ 00411 locker_ndx = CDB___lock_locker_hash(locker) % region->table_size; 00412 if ((ret = 00413 CDB___lock_getlocker(lt, locker, locker_ndx, 1, &sh_locker)) != 0) { 00414 /* 00415 * XXX: Margo 00416 * CLEANUP the object and the lock. 00417 */ 00418 return (ret); 00419 } 00420 00421 /* 00422 * Now we have a lock and an object and we need to see if we should 00423 * grant the lock. We use a FIFO ordering so we can only grant a 00424 * new lock if it does not conflict with anyone on the holders list 00425 * OR anyone on the waiters list. The reason that we don't grant if 00426 * there's a conflict is that this can lead to starvation (a writer 00427 * waiting on a popularly read item will never be granted). The 00428 * downside of this is that a waiting reader can prevent an upgrade 00429 * from reader to writer, which is not uncommon. 00430 * 00431 * There is one exception to the no-conflict rule. If a lock is held 00432 * by the requesting locker AND the new lock does not conflict with 00433 * any other holders, then we grant the lock. The most common place 00434 * this happens is when the holder has a WRITE lock and a READ lock 00435 * request comes in for the same locker. If we do not grant the read 00436 * lock, then we guarantee deadlock. 00437 * 00438 * In case of conflict, we put the new lock on the end of the waiters 00439 * list, unless we are upgrading in which case the locker goes on the 00440 * front of the list. 00441 */ 00442 ihold = 0; 00443 for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock); 00444 lp != NULL; 00445 lp = SH_TAILQ_NEXT(lp, links, __db_lock)) { 00446 if (locker == lp->holder || 00447 __lock_is_parent(lt, lp->holder, sh_locker)) { 00448 if (lp->mode == lock_mode && 00449 lp->status == DB_LSTAT_HELD) { 00450 if (LF_ISSET(DB_LOCK_UPGRADE)) 00451 goto upgrade; 00452 00453 /* 00454 * Lock is held, so we can increment the 00455 * reference count and return this lock. 00456 */ 00457 lp->refcount++; 00458 lock->off = R_OFFSET(<->reginfo, lp); 00459 lock->gen = lp->gen; 00460 00461 ret = 0; 00462 goto done; 00463 } else 00464 ihold = 1; 00465 } else if (CONFLICTS(lt, region, lp->mode, lock_mode)) 00466 break; 00467 } 00468 00469 /* 00470 * Make the new lock point to the new object, initialize fields. 00471 * 00472 * This lock is not linked in anywhere, so we can muck with it 00473 * without holding any mutexes. 00474 */ 00475 newl->holder = locker; 00476 newl->refcount = 1; 00477 newl->mode = lock_mode; 00478 newl->obj = SH_PTR_TO_OFF(newl, sh_obj); 00479 newl->status = DB_LSTAT_HELD; 00480 00481 /* 00482 * If we are upgrading, then there are two scenarios. Either 00483 * we had no conflicts, so we can do the upgrade. Or, there 00484 * is a conflict and we should wait at the HEAD of the waiters 00485 * list. 00486 */ 00487 if (LF_ISSET(DB_LOCK_UPGRADE)) { 00488 if (lp == NULL) 00489 goto upgrade; 00490 00491 /* 00492 * There was a conflict, wait. If this is the first waiter, 00493 * add the object to the deadlock detector's list. 00494 */ 00495 if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL) 00496 SH_TAILQ_INSERT_HEAD(®ion->dd_objs, 00497 sh_obj, dd_links, __db_lockobj); 00498 00499 SH_TAILQ_INSERT_HEAD(&sh_obj->waiters, newl, links, __db_lock); 00500 goto llist; 00501 } 00502 00503 if (lp == NULL && !ihold) 00504 for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock); 00505 lp != NULL; 00506 lp = SH_TAILQ_NEXT(lp, links, __db_lock)) { 00507 if (CONFLICTS(lt, region, lp->mode, lock_mode) && 00508 locker != lp->holder) 00509 break; 00510 } 00511 if (lp == NULL) 00512 SH_TAILQ_INSERT_TAIL(&sh_obj->holders, newl, links); 00513 else if (!(flags & DB_LOCK_NOWAIT)) { 00514 /* 00515 * If this is the first waiter, add the object to the 00516 * deadlock detector's list. 00517 */ 00518 if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL) 00519 SH_TAILQ_INSERT_HEAD(®ion->dd_objs, 00520 sh_obj, dd_links, __db_lockobj); 00521 SH_TAILQ_INSERT_TAIL(&sh_obj->waiters, newl, links); 00522 } else { 00523 ret = DB_LOCK_NOTGRANTED; 00524 if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL 00525 && LOCKER_FREEABLE(sh_locker)) 00526 CDB___lock_freelocker( lt, region, sh_locker, locker_ndx); 00527 region->nnowaits++; 00528 goto err; 00529 } 00530 00531 llist: 00532 /* 00533 * Now, insert the lock onto its locker's list. If the locker does 00534 * not currently hold any locks, there's no reason to run a deadlock 00535 * detector, save that information. 00536 */ 00537 on_locker_list = 1; 00538 no_dd = sh_locker->master_locker == INVALID_ROFF 00539 && SH_LIST_FIRST(&sh_locker->child_locker, __db_locker) == NULL 00540 && SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL; 00541 00542 SH_LIST_INSERT_HEAD(&sh_locker->heldby, newl, locker_links, __db_lock); 00543 00544 if (lp != NULL) { 00545 /* 00546 * This is really a blocker for the thread. It should be 00547 * initized locked, so that when we try to acquire it, we 00548 * block. 00549 */ 00550 newl->status = DB_LSTAT_WAITING; 00551 region->nconflicts++; 00552 if (region->detect == DB_LOCK_NORUN) 00553 region->need_dd = 1; 00554 UNLOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); 00555 00556 /* 00557 * We are about to wait; before waiting, see if the deadlock 00558 * detector should be run. 00559 */ 00560 if (region->detect != DB_LOCK_NORUN && !no_dd) 00561 (void)CDB_lock_detect(dbenv, 0, region->detect, &did_abort); 00562 00563 MUTEX_LOCK(&newl->mutex, dbenv->lockfhp); 00564 LOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); 00565 00566 if (newl->status != DB_LSTAT_PENDING) { 00567 (void)__lock_checklocker(lt, 00568 newl, newl->holder, 0, &freed); 00569 switch (newl->status) { 00570 case DB_LSTAT_ABORTED: 00571 on_locker_list = 0; 00572 ret = DB_LOCK_DEADLOCK; 00573 break; 00574 case DB_LSTAT_NOGRANT: 00575 ret = DB_LOCK_NOTGRANTED; 00576 break; 00577 default: 00578 ret = EINVAL; 00579 break; 00580 } 00581 goto err; 00582 } else if (LF_ISSET(DB_LOCK_UPGRADE)) { 00583 /* 00584 * The lock that was just granted got put on the 00585 * holders list. Since we're upgrading some other 00586 * lock, we've got to remove it here. 00587 */ 00588 SH_TAILQ_REMOVE( 00589 &sh_obj->holders, newl, links, __db_lock); 00590 /* 00591 * Ensure that the object is not believed to be on 00592 * the object's lists, if we're traversing by locker. 00593 */ 00594 newl->links.stqe_prev = -1; 00595 goto upgrade; 00596 } else 00597 newl->status = DB_LSTAT_HELD; 00598 } 00599 00600 lock->off = R_OFFSET(<->reginfo, newl); 00601 lock->gen = newl->gen; 00602 00603 return (0); 00604 00605 upgrade:/* 00606 * This was an upgrade, so return the new lock to the free list and 00607 * upgrade the mode of the original lock. 00608 */ 00609 ((struct __db_lock *)R_ADDR(<->reginfo, lock->off))->mode = lock_mode; 00610 00611 ret = 0; 00612 /* FALLTHROUGH */ 00613 00614 done: 00615 err: newl->status = DB_LSTAT_FREE; 00616 if (on_locker_list) { 00617 SH_LIST_REMOVE(newl, locker_links, __db_lock); 00618 } 00619 SH_TAILQ_INSERT_HEAD(®ion->free_locks, newl, links, __db_lock); 00620 return (ret); 00621 } 00622 00623 /* 00624 * Lock release routines. 00625 * 00626 * The user callable one is CDB_lock_put and the three we use internally are 00627 * __lock_put_nolock, __lock_put_internal and CDB___lock_downgrade. 00628 */ 00629 int 00630 CDB_lock_put(dbenv, lock) 00631 DB_ENV *dbenv; 00632 DB_LOCK *lock; 00633 { 00634 DB_LOCKTAB *lt; 00635 int ret, run_dd; 00636 00637 #ifdef HAVE_RPC 00638 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) 00639 return (__dbcl_lock_put(dbenv, lock)); 00640 #endif 00641 PANIC_CHECK(dbenv); 00642 ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); 00643 00644 if (IS_RECOVERING(dbenv)) 00645 return (0); 00646 00647 lt = dbenv->lk_handle; 00648 00649 LOCKREGION(dbenv, lt); 00650 ret = __lock_put_nolock(dbenv, lock, &run_dd); 00651 UNLOCKREGION(dbenv, lt); 00652 00653 lock->off = LOCK_INVALID; 00654 00655 if (ret == 0 && run_dd) 00656 (void)CDB_lock_detect(dbenv, 0, 00657 ((DB_LOCKREGION *)lt->reginfo.primary)->detect, NULL); 00658 return (ret); 00659 } 00660 00661 static int 00662 __lock_put_nolock(dbenv, lock, runp) 00663 DB_ENV *dbenv; 00664 DB_LOCK *lock; 00665 int *runp; 00666 { 00667 struct __db_lock *lockp; 00668 DB_LOCKREGION *region; 00669 DB_LOCKTAB *lt; 00670 u_int32_t locker; 00671 int ret; 00672 00673 lt = dbenv->lk_handle; 00674 region = lt->reginfo.primary; 00675 00676 lockp = (struct __db_lock *)R_ADDR(<->reginfo, lock->off); 00677 if (lock->gen != lockp->gen) { 00678 CDB___db_err(dbenv, __db_lock_invalid, "CDB_lock_put"); 00679 return(EACCES); 00680 } 00681 00682 locker = lockp->holder; 00683 ret = __lock_put_internal(lt, 00684 lockp, lock->ndx, DB_LOCK_UNLINK | DB_LOCK_FREE); 00685 00686 *runp = 0; 00687 if (ret == 0 && region->need_dd && region->detect != DB_LOCK_NORUN) { 00688 *runp = 1; 00689 region->need_dd = 0; 00690 } 00691 00692 return (ret); 00693 } 00694 00695 /* 00696 * CDB___lock_downgrade -- 00697 * Used by the concurrent access product to downgrade write locks 00698 * back to iwrite locks. 00699 * 00700 * PUBLIC: int CDB___lock_downgrade __P((DB_ENV *, 00701 * PUBLIC: DB_LOCK *, db_lockmode_t, u_int32_t)); 00702 */ 00703 int 00704 CDB___lock_downgrade(dbenv, lock, new_mode, flags) 00705 DB_ENV *dbenv; 00706 DB_LOCK *lock; 00707 db_lockmode_t new_mode; 00708 u_int32_t flags; 00709 { 00710 struct __db_lock *lockp; 00711 DB_LOCKOBJ *obj; 00712 DB_LOCKREGION *region; 00713 DB_LOCKTAB *lt; 00714 int ret; 00715 00716 COMPQUIET(flags, 0); 00717 00718 PANIC_CHECK(dbenv); 00719 00720 lt = dbenv->lk_handle; 00721 region = lt->reginfo.primary; 00722 00723 LOCKREGION(dbenv, lt); 00724 00725 lockp = (struct __db_lock *)R_ADDR(<->reginfo, lock->off); 00726 if (lock->gen != lockp->gen) { 00727 CDB___db_err(dbenv, __db_lock_invalid, "lock_downgrade"); 00728 ret = EACCES; 00729 goto out; 00730 } 00731 00732 lockp->mode = new_mode; 00733 00734 /* Get the object associated with this lock. */ 00735 obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj); 00736 (void)CDB___lock_promote(lt, obj); 00737 00738 ++region->nreleases; 00739 out: UNLOCKREGION(dbenv, lt); 00740 00741 return (0); 00742 } 00743 00744 static int 00745 __lock_put_internal(lt, lockp, obj_ndx, flags) 00746 DB_LOCKTAB *lt; 00747 struct __db_lock *lockp; 00748 u_int32_t obj_ndx; 00749 u_int32_t flags; 00750 { 00751 DB_LOCKOBJ *sh_obj; 00752 DB_LOCKREGION *region; 00753 int no_reclaim, ret, state_changed; 00754 00755 region = lt->reginfo.primary; 00756 no_reclaim = ret = state_changed = 0; 00757 00758 if (!OBJ_LINKS_VALID(lockp)) { 00759 /* 00760 * Someone removed this lock while we were doing a release 00761 * by locker id. We are trying to free this lock, but it's 00762 * already been done; all we need to do is return it to the 00763 * free list. 00764 */ 00765 lockp->status = DB_LSTAT_FREE; 00766 SH_TAILQ_INSERT_HEAD( 00767 ®ion->free_locks, lockp, links, __db_lock); 00768 return (0); 00769 } 00770 00771 if (LF_ISSET(DB_LOCK_DOALL)) 00772 region->nreleases += lockp->refcount; 00773 else 00774 region->nreleases++; 00775 00776 if (!LF_ISSET(DB_LOCK_DOALL) && lockp->refcount > 1) { 00777 lockp->refcount--; 00778 return (0); 00779 } 00780 00781 /* Increment generation number. */ 00782 lockp->gen++; 00783 00784 /* Get the object associated with this lock. */ 00785 sh_obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj); 00786 00787 /* Remove this lock from its holders/waitlist. */ 00788 if (lockp->status != DB_LSTAT_HELD) 00789 __lock_remove_waiter(sh_obj, lockp, DB_LSTAT_FREE); 00790 else { 00791 SH_TAILQ_REMOVE(&sh_obj->holders, lockp, links, __db_lock); 00792 lockp->links.stqe_prev = -1; 00793 } 00794 00795 if (LF_ISSET(DB_LOCK_NOPROMOTE)) 00796 state_changed = 0; 00797 else 00798 state_changed = CDB___lock_promote(lt, sh_obj); 00799 00800 if (LF_ISSET(DB_LOCK_UNLINK)) 00801 ret = __lock_checklocker(lt, lockp, lockp->holder, flags, NULL); 00802 00803 /* Check if object should be reclaimed. */ 00804 if (SH_TAILQ_FIRST(&sh_obj->holders, __db_lock) == NULL) { 00805 HASHREMOVE_EL(lt->obj_tab, 00806 obj_ndx, __db_lockobj, links, sh_obj); 00807 if (sh_obj->lockobj.size > sizeof(sh_obj->objdata)) 00808 CDB___db_shalloc_free(lt->reginfo.addr, 00809 SH_DBT_PTR(&sh_obj->lockobj)); 00810 SH_TAILQ_INSERT_HEAD( 00811 ®ion->free_objs, sh_obj, links, __db_lockobj); 00812 state_changed = 1; 00813 } 00814 00815 /* Free lock. */ 00816 if (!LF_ISSET(DB_LOCK_UNLINK) && LF_ISSET(DB_LOCK_FREE)) { 00817 lockp->status = DB_LSTAT_FREE; 00818 SH_TAILQ_INSERT_HEAD( 00819 ®ion->free_locks, lockp, links, __db_lock); 00820 } 00821 00822 /* 00823 * If we did not promote anyone; we need to run the deadlock 00824 * detector again. 00825 */ 00826 if (state_changed == 0) 00827 region->need_dd = 1; 00828 00829 return (ret); 00830 } 00831 00832 /* 00833 * Utility functions; listed alphabetically. 00834 */ 00835 00836 /* 00837 * __lock_checklocker -- 00838 * If a locker has no more locks, then we can free the object. 00839 * Return a boolean indicating whether we freed the object or not. 00840 * 00841 * Must be called without the locker's lock set. 00842 */ 00843 static int 00844 __lock_checklocker(lt, lockp, locker, flags, freed) 00845 DB_LOCKTAB *lt; 00846 struct __db_lock *lockp; 00847 u_int32_t locker, flags; 00848 int *freed; 00849 { 00850 DB_ENV *dbenv; 00851 DB_LOCKER *sh_locker; 00852 DB_LOCKREGION *region; 00853 u_int32_t indx; 00854 int ret; 00855 00856 dbenv = lt->dbenv; 00857 region = lt->reginfo.primary; 00858 ret = 0; 00859 00860 if (freed != NULL) 00861 *freed = 0; 00862 00863 indx = CDB___lock_locker_hash(locker) % region->table_size; 00864 00865 /* If the locker's list is NULL, free up the locker. */ 00866 if ((ret = CDB___lock_getlocker(lt, 00867 locker, indx, 0, &sh_locker)) != 0 || sh_locker == NULL) { 00868 if (ret == 0) 00869 ret = EACCES; 00870 CDB___db_err(lt->dbenv, __db_locker_invalid); 00871 goto freelock; 00872 } 00873 00874 if (F_ISSET(sh_locker, DB_LOCKER_DELETED)) { 00875 LF_CLR(DB_LOCK_FREE); 00876 if (!LF_ISSET(DB_LOCK_IGNOREDEL)) 00877 goto freelock; 00878 } 00879 00880 if (LF_ISSET(DB_LOCK_UNLINK)) 00881 SH_LIST_REMOVE(lockp, locker_links, __db_lock); 00882 00883 if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL 00884 && LOCKER_FREEABLE(sh_locker)) { 00885 CDB___lock_freelocker( lt, region, sh_locker, indx); 00886 if (freed != NULL) 00887 *freed = 1; 00888 } 00889 00890 freelock: 00891 if (LF_ISSET(DB_LOCK_FREE)) { 00892 lockp->status = DB_LSTAT_FREE; 00893 SH_TAILQ_INSERT_HEAD( 00894 ®ion->free_locks, lockp, links, __db_lock); 00895 } 00896 00897 return (ret); 00898 } 00899 00900 /* 00901 * CDB___lock_addfamilylocker 00902 * Put a locker entry in for a child transaction. 00903 * 00904 * PUBLIC: int CDB___lock_addfamilylocker __P((DB_ENV *, u_int32_t, u_int32_t)); 00905 */ 00906 int 00907 CDB___lock_addfamilylocker(dbenv, pid, id) 00908 DB_ENV *dbenv; 00909 u_int32_t pid, id; 00910 { 00911 DB_LOCKER *lockerp, *mlockerp; 00912 DB_LOCKREGION *region; 00913 DB_LOCKTAB *lt; 00914 u_int32_t ndx; 00915 int ret; 00916 00917 lt = dbenv->lk_handle; 00918 region = lt->reginfo.primary; 00919 LOCKREGION(dbenv, lt); 00920 00921 /* get/create the parent locker info */ 00922 ndx = CDB___lock_locker_hash(pid) % region->table_size; 00923 if ((ret = CDB___lock_getlocker(dbenv->lk_handle, 00924 pid, ndx, 1, &mlockerp)) != 0) 00925 goto err; 00926 00927 /* 00928 * We assume that only one thread can manipulate 00929 * a single transaction family. 00930 * Therefore the master locker cannot go away while 00931 * we manipulate it, nor can another child in the 00932 * family be created at the same time. 00933 */ 00934 ndx = CDB___lock_locker_hash(id) % region->table_size; 00935 if ((ret = CDB___lock_getlocker(dbenv->lk_handle, 00936 id, ndx, 1, &lockerp)) != 0) 00937 goto err; 00938 00939 /* Point to our parent. */ 00940 lockerp->parent_locker = R_OFFSET(<->reginfo, mlockerp); 00941 00942 /* See if this locker is the family master. */ 00943 if (mlockerp->master_locker == INVALID_ROFF) 00944 lockerp->master_locker = R_OFFSET(<->reginfo, mlockerp); 00945 else { 00946 lockerp->master_locker = mlockerp->master_locker; 00947 mlockerp = R_ADDR(<->reginfo, mlockerp->master_locker); 00948 } 00949 00950 /* 00951 * Link the child at the head of the master's list. 00952 * The guess is when looking for deadlock that 00953 * the most recent child is the one thats blocked. 00954 */ 00955 SH_LIST_INSERT_HEAD( 00956 &mlockerp->child_locker, lockerp, child_link, __db_locker); 00957 00958 err: 00959 UNLOCKREGION(dbenv, lt); 00960 00961 return (ret); 00962 } 00963 00964 /* 00965 * CDB___lock_freefamilylocker 00966 * Remove a locker from the hash table and its family. 00967 * 00968 * This must be called without the locker bucket locked. 00969 * 00970 * PUBLIC: int CDB___lock_freefamilylocker __P((DB_LOCKTAB *, u_int32_t)); 00971 */ 00972 int 00973 CDB___lock_freefamilylocker(lt, locker) 00974 DB_LOCKTAB *lt; 00975 u_int32_t locker; 00976 { 00977 DB_ENV *dbenv; 00978 DB_LOCKER *sh_locker; 00979 DB_LOCKREGION *region; 00980 u_int32_t indx; 00981 int ret; 00982 00983 dbenv = lt->dbenv; 00984 region = lt->reginfo.primary; 00985 00986 LOCKREGION(dbenv, lt); 00987 indx = CDB___lock_locker_hash(locker) % region->table_size; 00988 00989 if ((ret = CDB___lock_getlocker(lt, 00990 locker, indx, 0, &sh_locker)) != 0 || sh_locker == NULL) { 00991 if (ret == 0) 00992 ret = EACCES; 00993 goto freelock; 00994 } 00995 if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) != NULL) { 00996 ret = EINVAL; 00997 CDB___db_err(dbenv, "Freeing locker with locks"); 00998 goto freelock; 00999 } 01000 01001 /* If this is part of a family, we must fix up its links. */ 01002 if (sh_locker->master_locker != INVALID_ROFF) 01003 SH_LIST_REMOVE(sh_locker, child_link, __db_locker); 01004 01005 CDB___lock_freelocker(lt, region, sh_locker, indx); 01006 01007 freelock: 01008 UNLOCKREGION(dbenv, lt); 01009 return (ret); 01010 } 01011 01012 /* 01013 * CDB___lock_freelocker 01014 * common code for deleting a locker. 01015 * 01016 * This must be called with the locker bucket locked. 01017 * 01018 * PUBLIC: void CDB___lock_freelocker __P((DB_LOCKTAB *, 01019 * PUBLIC: DB_LOCKREGION *, DB_LOCKER *, u_int32_t)); 01020 */ 01021 void 01022 CDB___lock_freelocker(lt, region, sh_locker, indx) 01023 DB_LOCKTAB *lt; 01024 DB_LOCKREGION *region; 01025 DB_LOCKER *sh_locker; 01026 u_int32_t indx; 01027 01028 { 01029 HASHREMOVE_EL( 01030 lt->locker_tab, indx, __db_locker, links, sh_locker); 01031 SH_TAILQ_INSERT_HEAD( 01032 ®ion->free_lockers, sh_locker, links, __db_locker); 01033 region->nlockers--; 01034 } 01035 /* 01036 * CDB___lock_getlocker -- 01037 * Get a locker in the locker hash table. The create parameter 01038 * indicates if the locker should be created if it doesn't exist in 01039 * the table. 01040 * 01041 * This must be called with the locker bucket locked. 01042 * 01043 * PUBLIC: int CDB___lock_getlocker __P((DB_LOCKTAB *, 01044 * PUBLIC: u_int32_t, u_int32_t, int, DB_LOCKER **)); 01045 */ 01046 int 01047 CDB___lock_getlocker(lt, locker, indx, create, retp) 01048 DB_LOCKTAB *lt; 01049 u_int32_t locker, indx; 01050 int create; 01051 DB_LOCKER **retp; 01052 { 01053 DB_ENV *dbenv; 01054 DB_LOCKER *sh_locker; 01055 DB_LOCKREGION *region; 01056 01057 dbenv = lt->dbenv; 01058 region = lt->reginfo.primary; 01059 01060 HASHLOOKUP(lt->locker_tab, 01061 indx, __db_locker, links, locker, sh_locker, CDB___lock_locker_cmp); 01062 01063 /* 01064 * If we found the locker, then we can just return it. If 01065 * we didn't find the locker, then we need to create it. 01066 */ 01067 if (sh_locker == NULL && create) { 01068 /* Create new locker and then insert it into hash table. */ 01069 if ((sh_locker = SH_TAILQ_FIRST( 01070 ®ion->free_lockers, __db_locker)) == NULL) { 01071 CDB___db_err(lt->dbenv, __db_lock_err, "locker entries"); 01072 return (ENOMEM); 01073 } 01074 SH_TAILQ_REMOVE( 01075 ®ion->free_lockers, sh_locker, links, __db_locker); 01076 if (++region->nlockers > region->maxnlockers) 01077 region->maxnlockers = region->nlockers; 01078 01079 sh_locker->id = locker; 01080 sh_locker->dd_id = 0; 01081 sh_locker->master_locker = INVALID_ROFF; 01082 sh_locker->parent_locker = INVALID_ROFF; 01083 SH_LIST_INIT(&sh_locker->child_locker); 01084 sh_locker->flags = 0; 01085 SH_LIST_INIT(&sh_locker->heldby); 01086 01087 HASHINSERT(lt->locker_tab, indx, __db_locker, links, sh_locker); 01088 } 01089 01090 *retp = sh_locker; 01091 return (0); 01092 } 01093 01094 /* 01095 * CDB___lock_getobj -- 01096 * Get an object in the object hash table. The create parameter 01097 * indicates if the object should be created if it doesn't exist in 01098 * the table. 01099 * 01100 * This must be called with the object bucket locked. 01101 * 01102 * PUBLIC: int CDB___lock_getobj __P((DB_LOCKTAB *, 01103 * PUBLIC: const DBT *, u_int32_t, int, DB_LOCKOBJ **)); 01104 */ 01105 int 01106 CDB___lock_getobj(lt, obj, ndx, create, retp) 01107 DB_LOCKTAB *lt; 01108 const DBT *obj; 01109 u_int32_t ndx; 01110 int create; 01111 DB_LOCKOBJ **retp; 01112 { 01113 DB_ENV *dbenv; 01114 DB_LOCKOBJ *sh_obj; 01115 DB_LOCKREGION *region; 01116 int ret; 01117 void *p; 01118 01119 dbenv = lt->dbenv; 01120 region = lt->reginfo.primary; 01121 01122 /* Look up the object in the hash table. */ 01123 HASHLOOKUP(lt->obj_tab, 01124 ndx, __db_lockobj, links, obj, sh_obj, CDB___lock_cmp); 01125 01126 /* 01127 * If we found the object, then we can just return it. If 01128 * we didn't find the object, then we need to create it. 01129 */ 01130 if (sh_obj == NULL && create) { 01131 /* Create new object and then insert it into hash table. */ 01132 if ((sh_obj = 01133 SH_TAILQ_FIRST(®ion->free_objs, __db_lockobj)) == NULL) { 01134 CDB___db_err(lt->dbenv, __db_lock_err, "object entries"); 01135 ret = ENOMEM; 01136 goto err; 01137 } 01138 01139 /* 01140 * If we can fit this object in the structure, do so instead 01141 * of shalloc-ing space for it. 01142 */ 01143 if (obj->size <= sizeof(sh_obj->objdata)) 01144 p = sh_obj->objdata; 01145 else if ((ret = CDB___db_shalloc( 01146 lt->reginfo.addr, obj->size, 0, &p)) != 0) { 01147 CDB___db_err(dbenv, "No space for lock object storage"); 01148 goto err; 01149 } 01150 01151 memcpy(p, obj->data, obj->size); 01152 01153 SH_TAILQ_REMOVE( 01154 ®ion->free_objs, sh_obj, links, __db_lockobj); 01155 01156 SH_TAILQ_INIT(&sh_obj->waiters); 01157 SH_TAILQ_INIT(&sh_obj->holders); 01158 sh_obj->lockobj.size = obj->size; 01159 sh_obj->lockobj.off = SH_PTR_TO_OFF(&sh_obj->lockobj, p); 01160 01161 HASHINSERT(lt->obj_tab, ndx, __db_lockobj, links, sh_obj); 01162 } 01163 01164 *retp = sh_obj; 01165 return (0); 01166 01167 err: return (ret); 01168 } 01169 01170 /* 01171 * __lock_is_parent -- 01172 * Given a locker and a transaction, return 1 if the locker is 01173 * an ancestor of the designcated transaction. This is used to determine 01174 * if we should grant locks that appear to conflict, but don't because 01175 * the lock is already held by an ancestor. 01176 */ 01177 static int 01178 __lock_is_parent(lt, locker, sh_locker) 01179 DB_LOCKTAB *lt; 01180 u_int32_t locker; 01181 DB_LOCKER *sh_locker; 01182 { 01183 DB_LOCKER *parent; 01184 01185 parent = sh_locker; 01186 while (parent->parent_locker != INVALID_ROFF) { 01187 parent = (DB_LOCKER *) 01188 R_ADDR(<->reginfo, parent->parent_locker); 01189 if (parent->id == locker) 01190 return (1); 01191 } 01192 01193 return (0); 01194 } 01195 01196 /* 01197 * CDB___lock_promote -- 01198 * 01199 * Look through the waiters and holders lists and decide which (if any) 01200 * locks can be promoted. Promote any that are eligible. 01201 * 01202 * PUBLIC: int CDB___lock_promote __P((DB_LOCKTAB *, DB_LOCKOBJ *)); 01203 */ 01204 int 01205 CDB___lock_promote(lt, obj) 01206 DB_LOCKTAB *lt; 01207 DB_LOCKOBJ *obj; 01208 { 01209 struct __db_lock *lp_w, *lp_h, *next_waiter; 01210 DB_LOCKER *sh_locker; 01211 DB_LOCKREGION *region; 01212 u_int32_t locker_ndx; 01213 int had_waiters, state_changed; 01214 01215 region = lt->reginfo.primary; 01216 had_waiters = 0; 01217 01218 /* 01219 * We need to do lock promotion. We also need to determine if we're 01220 * going to need to run the deadlock detector again. If we release 01221 * locks, and there are waiters, but no one gets promoted, then we 01222 * haven't fundamentally changed the lockmgr state, so we may still 01223 * have a deadlock and we have to run again. However, if there were 01224 * no waiters, or we actually promoted someone, then we are OK and we 01225 * don't have to run it immediately. 01226 * 01227 * During promotion, we look for state changes so we can return this 01228 * information to the caller. 01229 */ 01230 01231 for (lp_w = SH_TAILQ_FIRST(&obj->waiters, __db_lock), 01232 state_changed = lp_w == NULL; 01233 lp_w != NULL; 01234 lp_w = next_waiter) { 01235 had_waiters = 1; 01236 next_waiter = SH_TAILQ_NEXT(lp_w, links, __db_lock); 01237 for (lp_h = SH_TAILQ_FIRST(&obj->holders, __db_lock); 01238 lp_h != NULL; 01239 lp_h = SH_TAILQ_NEXT(lp_h, links, __db_lock)) { 01240 if (lp_h->holder != lp_w->holder && 01241 CONFLICTS(lt, region, lp_h->mode, lp_w->mode)) { 01242 01243 locker_ndx = CDB___lock_locker_hash(lp_w->holder) 01244 % region->table_size; 01245 if ((CDB___lock_getlocker(lt, lp_w->holder, 01246 locker_ndx, 0, &sh_locker)) != 0) { 01247 DB_ASSERT(0); 01248 break; 01249 } 01250 if (!__lock_is_parent(lt, lp_h->holder, sh_locker)) 01251 break; 01252 } 01253 } 01254 if (lp_h != NULL) /* Found a conflict. */ 01255 break; 01256 01257 /* No conflict, promote the waiting lock. */ 01258 SH_TAILQ_REMOVE(&obj->waiters, lp_w, links, __db_lock); 01259 lp_w->status = DB_LSTAT_PENDING; 01260 SH_TAILQ_INSERT_TAIL(&obj->holders, lp_w, links); 01261 01262 /* Wake up waiter. */ 01263 MUTEX_UNLOCK(&lp_w->mutex); 01264 state_changed = 1; 01265 } 01266 01267 /* 01268 * If this object had waiters and doesn't any more, then we need 01269 * to remove it from the dd_obj list. 01270 */ 01271 if (had_waiters && SH_TAILQ_FIRST(&obj->waiters, __db_lock) == NULL) 01272 SH_TAILQ_REMOVE(®ion->dd_objs, obj, dd_links, __db_lockobj); 01273 return (state_changed); 01274 } 01275 01276 /* 01277 * __lock_remove_waiter -- 01278 * Any lock on the waitlist has a process waiting for it. Therefore, 01279 * we can't return the lock to the freelist immediately. Instead, we can 01280 * remove the lock from the list of waiters, set the status field of the 01281 * lock, and then let the process waking up return the lock to the 01282 * free list. 01283 * 01284 * This must be called with the Object bucket locked. 01285 */ 01286 static void 01287 __lock_remove_waiter(sh_obj, lockp, status) 01288 DB_LOCKOBJ *sh_obj; 01289 struct __db_lock *lockp; 01290 db_status_t status; 01291 { 01292 int do_wakeup; 01293 01294 do_wakeup = lockp->status == DB_LSTAT_WAITING; 01295 01296 SH_TAILQ_REMOVE(&sh_obj->waiters, lockp, links, __db_lock); 01297 lockp->links.stqe_prev = -1; 01298 lockp->status = status; 01299 01300 /* 01301 * Wake whoever is waiting on this lock. 01302 * 01303 * The MUTEX_UNLOCK macro normally resolves to a single argument, 01304 * keep the compiler quiet. 01305 */ 01306 if (do_wakeup) 01307 MUTEX_UNLOCK(&lockp->mutex); 01308 } 01309 01310 /* 01311 * CDB___lock_printlock -- 01312 * 01313 * PUBLIC: void CDB___lock_printlock __P((DB_LOCKTAB *, struct __db_lock *, int)); 01314 */ 01315 void 01316 CDB___lock_printlock(lt, lp, ispgno) 01317 DB_LOCKTAB *lt; 01318 struct __db_lock *lp; 01319 int ispgno; 01320 { 01321 DB_LOCKOBJ *lockobj; 01322 db_pgno_t pgno; 01323 u_int32_t *fidp; 01324 u_int8_t *ptr, type; 01325 const char *mode, *status; 01326 01327 switch (lp->mode) { 01328 case DB_LOCK_IREAD: 01329 mode = "IREAD"; 01330 break; 01331 case DB_LOCK_IWR: 01332 mode = "IWR"; 01333 break; 01334 case DB_LOCK_IWRITE: 01335 mode = "IWRITE"; 01336 break; 01337 case DB_LOCK_NG: 01338 mode = "NG"; 01339 break; 01340 case DB_LOCK_READ: 01341 mode = "READ"; 01342 break; 01343 case DB_LOCK_WRITE: 01344 mode = "WRITE"; 01345 break; 01346 default: 01347 mode = "UNKNOWN"; 01348 break; 01349 } 01350 switch (lp->status) { 01351 case DB_LSTAT_ABORTED: 01352 status = "ABORT"; 01353 break; 01354 case DB_LSTAT_ERR: 01355 status = "ERROR"; 01356 break; 01357 case DB_LSTAT_FREE: 01358 status = "FREE"; 01359 break; 01360 case DB_LSTAT_HELD: 01361 status = "HELD"; 01362 break; 01363 case DB_LSTAT_NOGRANT: 01364 status = "NONE"; 01365 break; 01366 case DB_LSTAT_WAITING: 01367 status = "WAIT"; 01368 break; 01369 case DB_LSTAT_PENDING: 01370 status = "PENDING"; 01371 break; 01372 default: 01373 status = "UNKNOWN"; 01374 break; 01375 } 01376 printf("\t%lx\t%s\t%lu\t%s\t", 01377 (u_long)lp->holder, mode, (u_long)lp->refcount, status); 01378 01379 lockobj = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj); 01380 ptr = SH_DBT_PTR(&lockobj->lockobj); 01381 if (ispgno && lockobj->lockobj.size == sizeof(struct __db_ilock)) { 01382 /* Assume this is a DBT lock. */ 01383 memcpy(&pgno, ptr, sizeof(db_pgno_t)); 01384 fidp = (u_int32_t *)(ptr + sizeof(db_pgno_t)); 01385 type = *(u_int8_t *)(ptr + sizeof(db_pgno_t) + DB_FILE_ID_LEN); 01386 printf("%s %lu (%lu %lu %lu %lu %lu)\n", 01387 type == DB_PAGE_LOCK ? "page" : "record", 01388 (u_long)pgno, 01389 (u_long)fidp[0], (u_long)fidp[1], (u_long)fidp[2], 01390 (u_long)fidp[3], (u_long)fidp[4]); 01391 } else { 01392 printf("0x%lx ", (u_long)R_OFFSET(<->reginfo, lockobj)); 01393 CDB___db_pr(ptr, lockobj->lockobj.size); 01394 printf("\n"); 01395 } 01396 }