1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2005,2008 Oracle. All rights reserved. 5 * 6 * $Id: lock_failchk.c,v 12.18 2008/01/08 20:58:40 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/lock.h" 13#include "dbinc/txn.h" 14 15/* 16 * __lock_failchk -- 17 * Check for locks held by dead threads of control and release 18 * read locks. If any write locks were held by dead non-trasnactional 19 * lockers then we must abort and run recovery. Otherwise we release 20 * read locks for lockers owned by dead threads. Write locks for 21 * dead transactional lockers will be freed when we abort the transaction. 22 * 23 * PUBLIC: int __lock_failchk __P((ENV *)); 24 */ 25int 26__lock_failchk(env) 27 ENV *env; 28{ 29 DB_ENV *dbenv; 30 DB_LOCKER *lip; 31 DB_LOCKREGION *lrp; 32 DB_LOCKREQ request; 33 DB_LOCKTAB *lt; 34 u_int32_t i; 35 int ret; 36 char buf[DB_THREADID_STRLEN]; 37 38 dbenv = env->dbenv; 39 lt = env->lk_handle; 40 lrp = lt->reginfo.primary; 41 42retry: LOCK_LOCKERS(env, lrp); 43 44 ret = 0; 45 for (i = 0; i < lrp->locker_t_size; i++) 46 SH_TAILQ_FOREACH(lip, <->locker_tab[i], links, __db_locker) { 47 /* 48 * Skip lockers that have no locks. Check the heldby 49 * list rather then nlocks since a lock may be PENDING. 50 * If the locker is transactional, we can ignore it if 51 * it has no read lock or has no locks at all; 52 * __txn_failchk aborts any transactional lockers. 53 */ 54 if (SH_LIST_EMPTY(&lip->heldby) || 55 (lip->id >= TXN_MINIMUM && 56 lip->nlocks == lip->nwrites)) 57 continue; 58 59 /* If the locker is still alive, it's not a problem. */ 60 if (dbenv->is_alive(dbenv, lip->pid, lip->tid, 0)) 61 continue; 62 63 /* 64 * We can only deal with read locks. If a 65 * non-transactional locker holds write locks we 66 * have to assume a Berkeley DB operation was 67 * interrupted with only 1-of-N pages modified. 68 */ 69 if (lip->id < TXN_MINIMUM && lip->nwrites != 0) { 70 ret = __db_failed(env, 71 "locker has write locks", 72 lip->pid, lip->tid); 73 break; 74 } 75 76 /* 77 * Discard the locker and its read locks. 78 */ 79 __db_msg(env, "Freeing read locks for locker %#lx: %s", 80 (u_long)lip->id, dbenv->thread_id_string( 81 dbenv, lip->pid, lip->tid, buf)); 82 UNLOCK_LOCKERS(env, lrp); 83 memset(&request, 0, sizeof(request)); 84 request.op = DB_LOCK_PUT_READ; 85 if ((ret = __lock_vec(env, 86 lip, 0, &request, 1, NULL)) != 0) 87 return (ret); 88 89 /* 90 * This locker is most likely referenced by a cursor 91 * which is owned by a dead thread. Normally the 92 * cursor would be available for other threads 93 * but we assume the dead thread will never release 94 * it. 95 */ 96 if (lip->id < TXN_MINIMUM && 97 (ret = __lock_freefamilylocker(lt, lip)) != 0) 98 return (ret); 99 goto retry; 100 } 101 102 UNLOCK_LOCKERS(env, lrp); 103 104 return (ret); 105} 106