00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #include <string.h>
00016 #endif
00017
00018 #include "db_int.h"
00019 #include "dbinc/db_shash.h"
00020 #include "dbinc/lock.h"
00021
00022 static int __lock_region_init __P((DB_ENV *, DB_LOCKTAB *));
00023 static size_t
00024 __lock_region_size __P((DB_ENV *));
00025
00026
00027
00028
00029
00030 #define DB_LOCK_RIW_N 9
00031 static const u_int8_t db_riw_conflicts[] = {
00032
00033 0, 0, 0, 0, 0, 0, 0, 0, 0,
00034 0, 0, 1, 0, 1, 0, 1, 0, 1,
00035 0, 1, 1, 1, 1, 1, 1, 1, 1,
00036 0, 0, 0, 0, 0, 0, 0, 0, 0,
00037 0, 1, 1, 0, 0, 0, 0, 1, 1,
00038 0, 0, 1, 0, 0, 0, 0, 0, 1,
00039 0, 1, 1, 0, 0, 0, 0, 1, 1,
00040 0, 0, 1, 0, 1, 0, 1, 0, 0,
00041 0, 1, 1, 0, 1, 1, 1, 0, 1
00042 };
00043
00044
00045
00046
00047
00048
00049 #define DB_LOCK_CDB_N 5
00050 static const u_int8_t db_cdb_conflicts[] = {
00051
00052 0, 0, 0, 0, 0,
00053 0, 0, 1, 0, 0,
00054 0, 1, 1, 1, 1,
00055 0, 0, 0, 0, 0,
00056 0, 0, 1, 0, 1
00057 };
00058
00059
00060
00061
00062
00063
00064
00065 int
00066 __lock_open(dbenv)
00067 DB_ENV *dbenv;
00068 {
00069 DB_LOCKREGION *region;
00070 DB_LOCKTAB *lt;
00071 size_t size;
00072 int region_locked, ret;
00073
00074 region_locked = 0;
00075
00076
00077 if ((ret = __os_calloc(dbenv, 1, sizeof(DB_LOCKTAB), <)) != 0)
00078 return (ret);
00079 lt->dbenv = dbenv;
00080
00081
00082 lt->reginfo.dbenv = dbenv;
00083 lt->reginfo.type = REGION_TYPE_LOCK;
00084 lt->reginfo.id = INVALID_REGION_ID;
00085 lt->reginfo.flags = REGION_JOIN_OK;
00086 if (F_ISSET(dbenv, DB_ENV_CREATE))
00087 F_SET(<->reginfo, REGION_CREATE_OK);
00088 size = __lock_region_size(dbenv);
00089 if ((ret = __db_r_attach(dbenv, <->reginfo, size)) != 0)
00090 goto err;
00091
00092
00093 if (F_ISSET(<->reginfo, REGION_CREATE))
00094 if ((ret = __lock_region_init(dbenv, lt)) != 0)
00095 goto err;
00096
00097
00098 region = lt->reginfo.primary =
00099 R_ADDR(<->reginfo, lt->reginfo.rp->primary);
00100
00101
00102 lt->conflicts = R_ADDR(<->reginfo, region->conf_off);
00103 lt->obj_tab = R_ADDR(<->reginfo, region->obj_off);
00104 lt->locker_tab = R_ADDR(<->reginfo, region->locker_off);
00105
00106 dbenv->lk_handle = lt;
00107
00108 LOCK_SYSTEM_LOCK(dbenv);
00109 region_locked = 1;
00110
00111 if (dbenv->lk_detect != DB_LOCK_NORUN) {
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 if (region->detect != DB_LOCK_NORUN &&
00122 dbenv->lk_detect != DB_LOCK_DEFAULT &&
00123 region->detect != dbenv->lk_detect) {
00124 __db_err(dbenv,
00125 "lock_open: incompatible deadlock detector mode");
00126 ret = EINVAL;
00127 goto err;
00128 }
00129 if (region->detect == DB_LOCK_NORUN)
00130 region->detect = dbenv->lk_detect;
00131 }
00132
00133
00134
00135
00136
00137 if (dbenv->lk_timeout != 0)
00138 region->lk_timeout = dbenv->lk_timeout;
00139 if (dbenv->tx_timeout != 0)
00140 region->tx_timeout = dbenv->tx_timeout;
00141
00142 LOCK_SYSTEM_UNLOCK(dbenv);
00143 region_locked = 0;
00144
00145 return (0);
00146
00147 err: dbenv->lk_handle = NULL;
00148 if (lt->reginfo.addr != NULL) {
00149 if (region_locked)
00150 LOCK_SYSTEM_UNLOCK(dbenv);
00151 (void)__db_r_detach(dbenv, <->reginfo, 0);
00152 }
00153
00154 __os_free(dbenv, lt);
00155 return (ret);
00156 }
00157
00158
00159
00160
00161
00162 static int
00163 __lock_region_init(dbenv, lt)
00164 DB_ENV *dbenv;
00165 DB_LOCKTAB *lt;
00166 {
00167 const u_int8_t *lk_conflicts;
00168 struct __db_lock *lp;
00169 DB_LOCKER *lidp;
00170 DB_LOCKOBJ *op;
00171 DB_LOCKREGION *region;
00172 u_int32_t i;
00173 u_int8_t *addr;
00174 int lk_modes, ret;
00175
00176 if ((ret = __db_shalloc(<->reginfo,
00177 sizeof(DB_LOCKREGION), 0, <->reginfo.primary)) != 0)
00178 goto mem_err;
00179 lt->reginfo.rp->primary = R_OFFSET(<->reginfo, lt->reginfo.primary);
00180 region = lt->reginfo.primary;
00181 memset(region, 0, sizeof(*region));
00182
00183 if ((ret = __mutex_alloc(
00184 dbenv, MTX_LOCK_REGION, 0, ®ion->mtx_region)) != 0)
00185 return (ret);
00186
00187
00188 if (dbenv->lk_modes == 0)
00189 if (CDB_LOCKING(dbenv)) {
00190 lk_modes = DB_LOCK_CDB_N;
00191 lk_conflicts = db_cdb_conflicts;
00192 } else {
00193 lk_modes = DB_LOCK_RIW_N;
00194 lk_conflicts = db_riw_conflicts;
00195 }
00196 else {
00197 lk_modes = dbenv->lk_modes;
00198 lk_conflicts = dbenv->lk_conflicts;
00199 }
00200
00201 region->need_dd = 0;
00202 LOCK_SET_TIME_INVALID(®ion->next_timeout);
00203 region->detect = DB_LOCK_NORUN;
00204 region->lk_timeout = dbenv->lk_timeout;
00205 region->tx_timeout = dbenv->tx_timeout;
00206 region->locker_t_size = __db_tablesize(dbenv->lk_max_lockers);
00207 region->object_t_size = __db_tablesize(dbenv->lk_max_objects);
00208 memset(®ion->stat, 0, sizeof(region->stat));
00209 region->stat.st_id = 0;
00210 region->stat.st_cur_maxid = DB_LOCK_MAXID;
00211 region->stat.st_maxlocks = dbenv->lk_max;
00212 region->stat.st_maxlockers = dbenv->lk_max_lockers;
00213 region->stat.st_maxobjects = dbenv->lk_max_objects;
00214 region->stat.st_nmodes = lk_modes;
00215
00216
00217 if ((ret = __db_shalloc(
00218 <->reginfo, (size_t)(lk_modes * lk_modes), 0, &addr)) != 0)
00219 goto mem_err;
00220 memcpy(addr, lk_conflicts, (size_t)(lk_modes * lk_modes));
00221 region->conf_off = R_OFFSET(<->reginfo, addr);
00222
00223
00224 if ((ret = __db_shalloc(<->reginfo,
00225 region->object_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0)
00226 goto mem_err;
00227 __db_hashinit(addr, region->object_t_size);
00228 region->obj_off = R_OFFSET(<->reginfo, addr);
00229
00230
00231 if ((ret = __db_shalloc(<->reginfo,
00232 region->locker_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0)
00233 goto mem_err;
00234 __db_hashinit(addr, region->locker_t_size);
00235 region->locker_off = R_OFFSET(<->reginfo, addr);
00236
00237
00238 SH_TAILQ_INIT(®ion->free_locks);
00239 for (i = 0; i < region->stat.st_maxlocks; ++i) {
00240 if ((ret = __db_shalloc(<->reginfo,
00241 sizeof(struct __db_lock), 0, &lp)) != 0)
00242 goto mem_err;
00243 lp->mtx_lock = MUTEX_INVALID;
00244 lp->gen = 0;
00245 lp->status = DB_LSTAT_FREE;
00246 SH_TAILQ_INSERT_HEAD(®ion->free_locks, lp, links, __db_lock);
00247 }
00248
00249
00250 SH_TAILQ_INIT(®ion->dd_objs);
00251 SH_TAILQ_INIT(®ion->free_objs);
00252 for (i = 0; i < region->stat.st_maxobjects; ++i) {
00253 if ((ret = __db_shalloc(<->reginfo,
00254 sizeof(DB_LOCKOBJ), 0, &op)) != 0)
00255 goto mem_err;
00256 SH_TAILQ_INSERT_HEAD(
00257 ®ion->free_objs, op, links, __db_lockobj);
00258 }
00259
00260
00261 SH_TAILQ_INIT(®ion->lockers);
00262 SH_TAILQ_INIT(®ion->free_lockers);
00263 for (i = 0; i < region->stat.st_maxlockers; ++i) {
00264 if ((ret = __db_shalloc(<->reginfo,
00265 sizeof(DB_LOCKER), 0, &lidp)) != 0) {
00266 mem_err: __db_err(dbenv,
00267 "Unable to allocate memory for the lock table");
00268 return (ret);
00269 }
00270 SH_TAILQ_INSERT_HEAD(
00271 ®ion->free_lockers, lidp, links, __db_locker);
00272 }
00273
00274 return (0);
00275 }
00276
00277
00278
00279
00280
00281
00282
00283 int
00284 __lock_dbenv_refresh(dbenv)
00285 DB_ENV *dbenv;
00286 {
00287 struct __db_lock *lp;
00288 DB_LOCKER *locker;
00289 DB_LOCKOBJ *lockobj;
00290 DB_LOCKREGION *lr;
00291 DB_LOCKTAB *lt;
00292 REGINFO *reginfo;
00293 int ret;
00294
00295 lt = dbenv->lk_handle;
00296 reginfo = <->reginfo;
00297 lr = reginfo->primary;
00298
00299
00300
00301
00302
00303
00304 if (F_ISSET(dbenv, DB_ENV_PRIVATE)) {
00305
00306 __db_shalloc_free(reginfo, R_ADDR(reginfo, lr->conf_off));
00307
00308
00309 __db_shalloc_free(reginfo, R_ADDR(reginfo, lr->obj_off));
00310
00311
00312 __db_shalloc_free(reginfo, R_ADDR(reginfo, lr->locker_off));
00313
00314
00315 while ((lp =
00316 SH_TAILQ_FIRST(&lr->free_locks, __db_lock)) != NULL) {
00317 SH_TAILQ_REMOVE(&lr->free_locks, lp, links, __db_lock);
00318 __db_shalloc_free(reginfo, lp);
00319 }
00320
00321
00322 while ((lockobj =
00323 SH_TAILQ_FIRST(&lr->free_objs, __db_lockobj)) != NULL) {
00324 SH_TAILQ_REMOVE(
00325 &lr->free_objs, lockobj, links, __db_lockobj);
00326 __db_shalloc_free(reginfo, lockobj);
00327 }
00328
00329
00330 while ((locker =
00331 SH_TAILQ_FIRST(&lr->free_lockers, __db_locker)) != NULL) {
00332 SH_TAILQ_REMOVE(
00333 &lr->free_lockers, locker, links, __db_locker);
00334 __db_shalloc_free(reginfo, locker);
00335 }
00336 }
00337
00338
00339 ret = __db_r_detach(dbenv, reginfo, 0);
00340
00341
00342 __os_free(dbenv, lt);
00343 dbenv->lk_handle = NULL;
00344
00345 return (ret);
00346 }
00347
00348
00349
00350
00351
00352
00353
00354 u_int32_t
00355 __lock_region_mutex_count(dbenv)
00356 DB_ENV *dbenv;
00357 {
00358 return (dbenv->lk_max);
00359 }
00360
00361
00362
00363
00364
00365 static size_t
00366 __lock_region_size(dbenv)
00367 DB_ENV *dbenv;
00368 {
00369 size_t retval;
00370
00371
00372
00373
00374
00375 retval = 0;
00376 retval += __db_shalloc_size(sizeof(DB_LOCKREGION), 0);
00377 retval += __db_shalloc_size(
00378 (size_t)(dbenv->lk_modes * dbenv->lk_modes), 0);
00379 retval += __db_shalloc_size(
00380 __db_tablesize(dbenv->lk_max_objects) * (sizeof(DB_HASHTAB)), 0);
00381 retval += __db_shalloc_size(
00382 __db_tablesize(dbenv->lk_max_lockers) * (sizeof(DB_HASHTAB)), 0);
00383 retval +=
00384 __db_shalloc_size(sizeof(struct __db_lock), 0) * dbenv->lk_max;
00385 retval +=
00386 __db_shalloc_size(sizeof(DB_LOCKOBJ), 0) * dbenv->lk_max_objects;
00387 retval +=
00388 __db_shalloc_size(sizeof(DB_LOCKER), 0) * dbenv->lk_max_lockers;
00389
00390
00391
00392
00393
00394 retval += __db_shalloc_size(dbenv->lk_max * 16, sizeof(size_t));
00395
00396
00397 retval += retval / 4;
00398
00399 return (retval);
00400 }