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