1*7c478bd9Sstevel@tonic-gate /*- 2*7c478bd9Sstevel@tonic-gate * See the file LICENSE for redistribution information. 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1996, 1997, 1998 5*7c478bd9Sstevel@tonic-gate * Sleepycat Software. All rights reserved. 6*7c478bd9Sstevel@tonic-gate * 7*7c478bd9Sstevel@tonic-gate * @(#)lock.h 10.17 (Sleepycat) 1/3/99 8*7c478bd9Sstevel@tonic-gate */ 9*7c478bd9Sstevel@tonic-gate 10*7c478bd9Sstevel@tonic-gate typedef struct __db_lockobj DB_LOCKOBJ; 11*7c478bd9Sstevel@tonic-gate 12*7c478bd9Sstevel@tonic-gate #define DB_DEFAULT_LOCK_FILE "__db_lock.share" 13*7c478bd9Sstevel@tonic-gate 14*7c478bd9Sstevel@tonic-gate #ifndef DB_LOCK_DEFAULT_N 15*7c478bd9Sstevel@tonic-gate #define DB_LOCK_DEFAULT_N 5000 /* Default # of locks in region. */ 16*7c478bd9Sstevel@tonic-gate #endif 17*7c478bd9Sstevel@tonic-gate 18*7c478bd9Sstevel@tonic-gate /* 19*7c478bd9Sstevel@tonic-gate * The locker id space is divided between the transaction manager and the lock 20*7c478bd9Sstevel@tonic-gate * manager. Lockid's start at 0 and go to DB_LOCK_MAXID. Txn Id's start at 21*7c478bd9Sstevel@tonic-gate * DB_LOCK_MAXID + 1 and go up to TXN_INVALID. 22*7c478bd9Sstevel@tonic-gate */ 23*7c478bd9Sstevel@tonic-gate #define DB_LOCK_MAXID 0x7fffffff 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate /* Check for region catastrophic shutdown. */ 26*7c478bd9Sstevel@tonic-gate #define LOCK_PANIC_CHECK(lt) { \ 27*7c478bd9Sstevel@tonic-gate if ((lt)->region->hdr.panic) \ 28*7c478bd9Sstevel@tonic-gate return (DB_RUNRECOVERY); \ 29*7c478bd9Sstevel@tonic-gate } 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate /* 32*7c478bd9Sstevel@tonic-gate * The lock region consists of: 33*7c478bd9Sstevel@tonic-gate * The DB_LOCKREGION structure (sizeof(DB_LOCKREGION)). 34*7c478bd9Sstevel@tonic-gate * The conflict matrix of nmodes * nmodes bytes (nmodes * nmodes). 35*7c478bd9Sstevel@tonic-gate * The hash table for object lookup (hashsize * sizeof(DB_OBJ *)). 36*7c478bd9Sstevel@tonic-gate * The locks themselves (maxlocks * sizeof(struct __db_lock). 37*7c478bd9Sstevel@tonic-gate * The objects being locked (maxlocks * sizeof(DB_OBJ)). 38*7c478bd9Sstevel@tonic-gate * String space to represent the DBTs that are the objects being locked. 39*7c478bd9Sstevel@tonic-gate */ 40*7c478bd9Sstevel@tonic-gate struct __db_lockregion { 41*7c478bd9Sstevel@tonic-gate RLAYOUT hdr; /* Shared region header. */ 42*7c478bd9Sstevel@tonic-gate u_int32_t magic; /* lock magic number */ 43*7c478bd9Sstevel@tonic-gate u_int32_t version; /* version number */ 44*7c478bd9Sstevel@tonic-gate u_int32_t id; /* unique id generator */ 45*7c478bd9Sstevel@tonic-gate u_int32_t need_dd; /* flag for deadlock detector */ 46*7c478bd9Sstevel@tonic-gate u_int32_t detect; /* run dd on every conflict */ 47*7c478bd9Sstevel@tonic-gate SH_TAILQ_HEAD(lock_header) free_locks; /* free lock header */ 48*7c478bd9Sstevel@tonic-gate SH_TAILQ_HEAD(obj_header) free_objs; /* free obj header */ 49*7c478bd9Sstevel@tonic-gate u_int32_t maxlocks; /* maximum number of locks in table */ 50*7c478bd9Sstevel@tonic-gate u_int32_t table_size; /* size of hash table */ 51*7c478bd9Sstevel@tonic-gate u_int32_t nmodes; /* number of lock modes */ 52*7c478bd9Sstevel@tonic-gate u_int32_t numobjs; /* number of objects */ 53*7c478bd9Sstevel@tonic-gate u_int32_t nlockers; /* number of lockers */ 54*7c478bd9Sstevel@tonic-gate size_t increment; /* how much to grow region */ 55*7c478bd9Sstevel@tonic-gate size_t hash_off; /* offset of hash table */ 56*7c478bd9Sstevel@tonic-gate size_t mem_off; /* offset of memory region */ 57*7c478bd9Sstevel@tonic-gate size_t mem_bytes; /* number of bytes in memory region */ 58*7c478bd9Sstevel@tonic-gate u_int32_t nconflicts; /* number of lock conflicts */ 59*7c478bd9Sstevel@tonic-gate u_int32_t nrequests; /* number of lock gets */ 60*7c478bd9Sstevel@tonic-gate u_int32_t nreleases; /* number of lock puts */ 61*7c478bd9Sstevel@tonic-gate u_int32_t ndeadlocks; /* number of deadlocks */ 62*7c478bd9Sstevel@tonic-gate }; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* Macros to lock/unlock the region. */ 65*7c478bd9Sstevel@tonic-gate #define LOCK_LOCKREGION(lt) \ 66*7c478bd9Sstevel@tonic-gate (void)__db_mutex_lock(&(lt)->region->hdr.lock, (lt)->reginfo.fd) 67*7c478bd9Sstevel@tonic-gate #define UNLOCK_LOCKREGION(lt) \ 68*7c478bd9Sstevel@tonic-gate (void)__db_mutex_unlock(&(lt)->region->hdr.lock, (lt)->reginfo.fd) 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate /* 71*7c478bd9Sstevel@tonic-gate * Since we will be keeping DBTs in shared memory, we need the equivalent 72*7c478bd9Sstevel@tonic-gate * of a DBT that will work in shared memory. 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate typedef struct __sh_dbt { 75*7c478bd9Sstevel@tonic-gate u_int32_t size; 76*7c478bd9Sstevel@tonic-gate ssize_t off; 77*7c478bd9Sstevel@tonic-gate } SH_DBT; 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate #define SH_DBT_PTR(p) ((void *)(((u_int8_t *)(p)) + (p)->off)) 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate struct __db_lockobj { 82*7c478bd9Sstevel@tonic-gate SH_DBT lockobj; /* Identifies object locked. */ 83*7c478bd9Sstevel@tonic-gate SH_TAILQ_ENTRY links; /* Links for free list. */ 84*7c478bd9Sstevel@tonic-gate union { 85*7c478bd9Sstevel@tonic-gate SH_TAILQ_HEAD(_wait) _waiters; /* List of waiting locks. */ 86*7c478bd9Sstevel@tonic-gate u_int32_t _dd_id; /* Deadlock detector id. */ 87*7c478bd9Sstevel@tonic-gate } wlinks; 88*7c478bd9Sstevel@tonic-gate union { 89*7c478bd9Sstevel@tonic-gate SH_LIST_HEAD(_held) _heldby; /* Locks held by this locker. */ 90*7c478bd9Sstevel@tonic-gate SH_TAILQ_HEAD(_hold) _holders; /* List of held locks. */ 91*7c478bd9Sstevel@tonic-gate } dlinks; 92*7c478bd9Sstevel@tonic-gate #define DB_LOCK_OBJTYPE 1 93*7c478bd9Sstevel@tonic-gate #define DB_LOCK_LOCKER 2 94*7c478bd9Sstevel@tonic-gate /* Allocate room in the object to 95*7c478bd9Sstevel@tonic-gate * hold typical DB lock structures 96*7c478bd9Sstevel@tonic-gate * so that we do not have to 97*7c478bd9Sstevel@tonic-gate * allocate them from shalloc. */ 98*7c478bd9Sstevel@tonic-gate u_int8_t objdata[sizeof(struct __db_ilock)]; 99*7c478bd9Sstevel@tonic-gate u_int8_t type; /* Real object or locker id. */ 100*7c478bd9Sstevel@tonic-gate }; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate #define dd_id wlinks._dd_id 103*7c478bd9Sstevel@tonic-gate #define waiters wlinks._waiters 104*7c478bd9Sstevel@tonic-gate #define holders dlinks._holders 105*7c478bd9Sstevel@tonic-gate #define heldby dlinks._heldby 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * The lock table is the per-process cookie returned from a lock_open call. 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate struct __db_locktab { 111*7c478bd9Sstevel@tonic-gate DB_ENV *dbenv; /* Environment. */ 112*7c478bd9Sstevel@tonic-gate REGINFO reginfo; /* Region information. */ 113*7c478bd9Sstevel@tonic-gate DB_LOCKREGION *region; /* Address of shared memory region. */ 114*7c478bd9Sstevel@tonic-gate DB_HASHTAB *hashtab; /* Beginning of hash table. */ 115*7c478bd9Sstevel@tonic-gate void *mem; /* Beginning of string space. */ 116*7c478bd9Sstevel@tonic-gate u_int8_t *conflicts; /* Pointer to conflict matrix. */ 117*7c478bd9Sstevel@tonic-gate }; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* Test for conflicts. */ 120*7c478bd9Sstevel@tonic-gate #define CONFLICTS(T, HELD, WANTED) \ 121*7c478bd9Sstevel@tonic-gate T->conflicts[HELD * T->region->nmodes + WANTED] 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* 124*7c478bd9Sstevel@tonic-gate * Resources in the lock region. Used to indicate which resource 125*7c478bd9Sstevel@tonic-gate * is running low when we need to grow the region. 126*7c478bd9Sstevel@tonic-gate */ 127*7c478bd9Sstevel@tonic-gate typedef enum { 128*7c478bd9Sstevel@tonic-gate DB_LOCK_MEM, DB_LOCK_OBJ, DB_LOCK_LOCK 129*7c478bd9Sstevel@tonic-gate } db_resource_t; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate struct __db_lock { 132*7c478bd9Sstevel@tonic-gate /* 133*7c478bd9Sstevel@tonic-gate * Wait on mutex to wait on lock. You reference your own mutex with 134*7c478bd9Sstevel@tonic-gate * ID 0 and others reference your mutex with ID 1. 135*7c478bd9Sstevel@tonic-gate */ 136*7c478bd9Sstevel@tonic-gate db_mutex_t mutex; 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate u_int32_t holder; /* Who holds this lock. */ 139*7c478bd9Sstevel@tonic-gate SH_TAILQ_ENTRY links; /* Free or holder/waiter list. */ 140*7c478bd9Sstevel@tonic-gate SH_LIST_ENTRY locker_links; /* List of locks held by a locker. */ 141*7c478bd9Sstevel@tonic-gate u_int32_t refcount; /* Reference count the lock. */ 142*7c478bd9Sstevel@tonic-gate db_lockmode_t mode; /* What sort of lock. */ 143*7c478bd9Sstevel@tonic-gate ssize_t obj; /* Relative offset of object struct. */ 144*7c478bd9Sstevel@tonic-gate size_t txnoff; /* Offset of holding transaction. */ 145*7c478bd9Sstevel@tonic-gate db_status_t status; /* Status of this lock. */ 146*7c478bd9Sstevel@tonic-gate }; 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * This is a serious layering violation. To support nested transactions, we 150*7c478bd9Sstevel@tonic-gate * need to be able to tell that a lock is held by a transaction (as opposed to 151*7c478bd9Sstevel@tonic-gate * some other locker) and to be able to traverse the parent/descendent chain. 152*7c478bd9Sstevel@tonic-gate * In order to do this, each lock held by a transaction maintains a reference 153*7c478bd9Sstevel@tonic-gate * to the shared memory transaction structure so it can be accessed during lock 154*7c478bd9Sstevel@tonic-gate * promotion. As the structure is in shared memory, we cannot store a pointer 155*7c478bd9Sstevel@tonic-gate * to it, so we use the offset within the region. As nothing lives at region 156*7c478bd9Sstevel@tonic-gate * offset 0, we use that to indicate that there is no transaction associated 157*7c478bd9Sstevel@tonic-gate * with the current lock. 158*7c478bd9Sstevel@tonic-gate */ 159*7c478bd9Sstevel@tonic-gate #define TXN_IS_HOLDING(L) ((L)->txnoff != 0 /* INVALID_REG_OFFSET */) 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate /* 162*7c478bd9Sstevel@tonic-gate * We cannot return pointers to the user (else we cannot easily grow regions), 163*7c478bd9Sstevel@tonic-gate * so we return offsets in the region. These must be converted to and from 164*7c478bd9Sstevel@tonic-gate * regular pointers. Always use the macros below. 165*7c478bd9Sstevel@tonic-gate */ 166*7c478bd9Sstevel@tonic-gate #define OFFSET_TO_LOCK(lt, off) \ 167*7c478bd9Sstevel@tonic-gate ((struct __db_lock *)((u_int8_t *)((lt)->region) + (off))) 168*7c478bd9Sstevel@tonic-gate #define LOCK_TO_OFFSET(lt, lock) \ 169*7c478bd9Sstevel@tonic-gate ((size_t)((u_int8_t *)(lock) - (u_int8_t *)lt->region)) 170*7c478bd9Sstevel@tonic-gate #define OFFSET_TO_OBJ(lt, off) \ 171*7c478bd9Sstevel@tonic-gate ((DB_LOCKOBJ *)((u_int8_t *)((lt)->region) + (off))) 172*7c478bd9Sstevel@tonic-gate #define OBJ_TO_OFFSET(lt, obj) \ 173*7c478bd9Sstevel@tonic-gate ((size_t)((u_int8_t *)(obj) - (u_int8_t *)lt->region)) 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate /* 176*7c478bd9Sstevel@tonic-gate * The lock header contains the region structure and the conflict matrix. 177*7c478bd9Sstevel@tonic-gate * Aligned to a large boundary because we don't know what the underlying 178*7c478bd9Sstevel@tonic-gate * type of the hash table elements are. 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate #define LOCK_HASH_ALIGN 8 181*7c478bd9Sstevel@tonic-gate #define LOCK_HEADER_SIZE(M) \ 182*7c478bd9Sstevel@tonic-gate ((size_t)(sizeof(DB_LOCKREGION) + ALIGN((M * M), LOCK_HASH_ALIGN))) 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate /* 185*7c478bd9Sstevel@tonic-gate * For the full region, we need to add the locks, the objects, the hash table 186*7c478bd9Sstevel@tonic-gate * and the string space (which is 16 bytes per lock). 187*7c478bd9Sstevel@tonic-gate */ 188*7c478bd9Sstevel@tonic-gate #define STRING_SIZE(N) (16 * N) 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate #define LOCK_REGION_SIZE(M, N, H) \ 191*7c478bd9Sstevel@tonic-gate (ALIGN(LOCK_HEADER_SIZE(M) + \ 192*7c478bd9Sstevel@tonic-gate (H) * sizeof(DB_HASHTAB), MUTEX_ALIGNMENT) + \ 193*7c478bd9Sstevel@tonic-gate (N) * ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT) + \ 194*7c478bd9Sstevel@tonic-gate ALIGN((N) * sizeof(DB_LOCKOBJ), sizeof(size_t)) + \ 195*7c478bd9Sstevel@tonic-gate ALIGN(STRING_SIZE(N), sizeof(size_t))) 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate #include "lock_ext.h" 198