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