1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2005-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 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 * If the locker is transactional, we can ignore it if 49 * it has no read locks or has no locks at all. Check 50 * the heldby list rather then nlocks since a lock may 51 * be PENDING. __txn_failchk aborts any transactional 52 * lockers. Non-transactional lockers progress to 53 * is_alive test. 54 */ 55 if ((lip->id >= TXN_MINIMUM) && 56 (SH_LIST_EMPTY(&lip->heldby) || 57 lip->nlocks == lip->nwrites)) 58 continue; 59 60 /* If the locker is still alive, it's not a problem. */ 61 if (dbenv->is_alive(dbenv, lip->pid, lip->tid, 0)) 62 continue; 63 64 /* 65 * We can only deal with read locks. If a 66 * non-transactional locker holds write locks we 67 * have to assume a Berkeley DB operation was 68 * interrupted with only 1-of-N pages modified. 69 */ 70 if (lip->id < TXN_MINIMUM && lip->nwrites != 0) { 71 ret = __db_failed(env, 72 "locker has write locks", 73 lip->pid, lip->tid); 74 break; 75 } 76 77 /* 78 * Discard the locker and its read locks. 79 */ 80 if (!SH_LIST_EMPTY(&lip->heldby)) { 81 __db_msg(env, 82 "Freeing read locks for locker %#lx: %s", 83 (u_long)lip->id, dbenv->thread_id_string( 84 dbenv, lip->pid, lip->tid, buf)); 85 UNLOCK_LOCKERS(env, lrp); 86 memset(&request, 0, sizeof(request)); 87 request.op = DB_LOCK_PUT_READ; 88 if ((ret = __lock_vec(env, 89 lip, 0, &request, 1, NULL)) != 0) 90 return (ret); 91 } 92 else 93 UNLOCK_LOCKERS(env, lrp); 94 95 /* 96 * This locker is most likely referenced by a cursor 97 * which is owned by a dead thread. Normally the 98 * cursor would be available for other threads 99 * but we assume the dead thread will never release 100 * it. 101 */ 102 if (lip->id < TXN_MINIMUM && 103 (ret = __lock_freefamilylocker(lt, lip)) != 0) 104 return (ret); 105 goto retry; 106 } 107 108 UNLOCK_LOCKERS(env, lrp); 109 110 return (ret); 111} 112