1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: lock_method.c,v 12.25 2008/05/07 12:27:35 bschmeck Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/lock.h" 13 14/* 15 * __lock_env_create -- 16 * Lock specific creation of the DB_ENV structure. 17 * 18 * PUBLIC: int __lock_env_create __P((DB_ENV *)); 19 */ 20int 21__lock_env_create(dbenv) 22 DB_ENV *dbenv; 23{ 24 u_int32_t cpu; 25 /* 26 * !!! 27 * Our caller has not yet had the opportunity to reset the panic 28 * state or turn off mutex locking, and so we can neither check 29 * the panic state or acquire a mutex in the DB_ENV create path. 30 */ 31 dbenv->lk_max = DB_LOCK_DEFAULT_N; 32 dbenv->lk_max_lockers = DB_LOCK_DEFAULT_N; 33 dbenv->lk_max_objects = DB_LOCK_DEFAULT_N; 34 35 /* 36 * Default to 10 partitions per cpu. This seems to be near 37 * the point of diminishing returns on Xeon type processors. 38 * Cpu count often returns the number of hyper threads and if 39 * there is only one CPU you probably do not want to run partitions. 40 */ 41 cpu = __os_cpu_count(); 42 dbenv->lk_partitions = cpu > 1 ? 10 * cpu : 1; 43 44 return (0); 45} 46 47/* 48 * __lock_env_destroy -- 49 * Lock specific destruction of the DB_ENV structure. 50 * 51 * PUBLIC: void __lock_env_destroy __P((DB_ENV *)); 52 */ 53void 54__lock_env_destroy(dbenv) 55 DB_ENV *dbenv; 56{ 57 ENV *env; 58 59 env = dbenv->env; 60 61 if (dbenv->lk_conflicts != NULL) { 62 __os_free(env, dbenv->lk_conflicts); 63 dbenv->lk_conflicts = NULL; 64 } 65} 66 67/* 68 * __lock_get_lk_conflicts 69 * Get the conflicts matrix. 70 * 71 * PUBLIC: int __lock_get_lk_conflicts 72 * PUBLIC: __P((DB_ENV *, const u_int8_t **, int *)); 73 */ 74int 75__lock_get_lk_conflicts(dbenv, lk_conflictsp, lk_modesp) 76 DB_ENV *dbenv; 77 const u_int8_t **lk_conflictsp; 78 int *lk_modesp; 79{ 80 DB_LOCKTAB *lt; 81 ENV *env; 82 83 env = dbenv->env; 84 lt = env->lk_handle; 85 86 ENV_NOT_CONFIGURED(env, 87 env->lk_handle, "DB_ENV->get_lk_conflicts", DB_INIT_LOCK); 88 89 if (LOCKING_ON(env)) { 90 /* Cannot be set after open, no lock required to read. */ 91 if (lk_conflictsp != NULL) 92 *lk_conflictsp = lt->conflicts; 93 if (lk_modesp != NULL) 94 *lk_modesp = ((DB_LOCKREGION *) 95 (lt->reginfo.primary))->stat.st_nmodes; 96 } else { 97 if (lk_conflictsp != NULL) 98 *lk_conflictsp = dbenv->lk_conflicts; 99 if (lk_modesp != NULL) 100 *lk_modesp = dbenv->lk_modes; 101 } 102 return (0); 103} 104 105/* 106 * __lock_set_lk_conflicts 107 * Set the conflicts matrix. 108 * 109 * PUBLIC: int __lock_set_lk_conflicts __P((DB_ENV *, u_int8_t *, int)); 110 */ 111int 112__lock_set_lk_conflicts(dbenv, lk_conflicts, lk_modes) 113 DB_ENV *dbenv; 114 u_int8_t *lk_conflicts; 115 int lk_modes; 116{ 117 ENV *env; 118 int ret; 119 120 env = dbenv->env; 121 122 ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_lk_conflicts"); 123 124 if (dbenv->lk_conflicts != NULL) { 125 __os_free(env, dbenv->lk_conflicts); 126 dbenv->lk_conflicts = NULL; 127 } 128 if ((ret = __os_malloc(env, 129 (size_t)(lk_modes * lk_modes), &dbenv->lk_conflicts)) != 0) 130 return (ret); 131 memcpy( 132 dbenv->lk_conflicts, lk_conflicts, (size_t)(lk_modes * lk_modes)); 133 dbenv->lk_modes = lk_modes; 134 135 return (0); 136} 137 138/* 139 * PUBLIC: int __lock_get_lk_detect __P((DB_ENV *, u_int32_t *)); 140 */ 141int 142__lock_get_lk_detect(dbenv, lk_detectp) 143 DB_ENV *dbenv; 144 u_int32_t *lk_detectp; 145{ 146 DB_LOCKTAB *lt; 147 DB_THREAD_INFO *ip; 148 ENV *env; 149 150 env = dbenv->env; 151 152 ENV_NOT_CONFIGURED(env, 153 env->lk_handle, "DB_ENV->get_lk_detect", DB_INIT_LOCK); 154 155 if (LOCKING_ON(env)) { 156 lt = env->lk_handle; 157 ENV_ENTER(env, ip); 158 LOCK_REGION_LOCK(env); 159 *lk_detectp = ((DB_LOCKREGION *)lt->reginfo.primary)->detect; 160 LOCK_REGION_UNLOCK(env); 161 ENV_LEAVE(env, ip); 162 } else 163 *lk_detectp = dbenv->lk_detect; 164 return (0); 165} 166 167/* 168 * __lock_set_lk_detect 169 * DB_ENV->set_lk_detect. 170 * 171 * PUBLIC: int __lock_set_lk_detect __P((DB_ENV *, u_int32_t)); 172 */ 173int 174__lock_set_lk_detect(dbenv, lk_detect) 175 DB_ENV *dbenv; 176 u_int32_t lk_detect; 177{ 178 DB_LOCKREGION *region; 179 DB_LOCKTAB *lt; 180 DB_THREAD_INFO *ip; 181 ENV *env; 182 int ret; 183 184 env = dbenv->env; 185 186 ENV_NOT_CONFIGURED(env, 187 env->lk_handle, "DB_ENV->set_lk_detect", DB_INIT_LOCK); 188 189 switch (lk_detect) { 190 case DB_LOCK_DEFAULT: 191 case DB_LOCK_EXPIRE: 192 case DB_LOCK_MAXLOCKS: 193 case DB_LOCK_MAXWRITE: 194 case DB_LOCK_MINLOCKS: 195 case DB_LOCK_MINWRITE: 196 case DB_LOCK_OLDEST: 197 case DB_LOCK_RANDOM: 198 case DB_LOCK_YOUNGEST: 199 break; 200 default: 201 __db_errx(env, 202 "DB_ENV->set_lk_detect: unknown deadlock detection mode specified"); 203 return (EINVAL); 204 } 205 206 ret = 0; 207 if (LOCKING_ON(env)) { 208 ENV_ENTER(env, ip); 209 210 lt = env->lk_handle; 211 region = lt->reginfo.primary; 212 LOCK_REGION_LOCK(env); 213 /* 214 * Check for incompatible automatic deadlock detection requests. 215 * There are scenarios where changing the detector configuration 216 * is reasonable, but we disallow them guessing it is likely to 217 * be an application error. 218 * 219 * We allow applications to turn on the lock detector, and we 220 * ignore attempts to set it to the default or current value. 221 */ 222 if (region->detect != DB_LOCK_NORUN && 223 lk_detect != DB_LOCK_DEFAULT && 224 region->detect != lk_detect) { 225 __db_errx(env, 226 "DB_ENV->set_lk_detect: incompatible deadlock detector mode"); 227 ret = EINVAL; 228 } else 229 if (region->detect == DB_LOCK_NORUN) 230 region->detect = lk_detect; 231 LOCK_REGION_UNLOCK(env); 232 ENV_LEAVE(env, ip); 233 } else 234 dbenv->lk_detect = lk_detect; 235 236 return (ret); 237} 238 239/* 240 * PUBLIC: int __lock_get_lk_max_locks __P((DB_ENV *, u_int32_t *)); 241 */ 242int 243__lock_get_lk_max_locks(dbenv, lk_maxp) 244 DB_ENV *dbenv; 245 u_int32_t *lk_maxp; 246{ 247 ENV *env; 248 249 env = dbenv->env; 250 251 ENV_NOT_CONFIGURED(env, 252 env->lk_handle, "DB_ENV->get_lk_maxlocks", DB_INIT_LOCK); 253 254 if (LOCKING_ON(env)) { 255 /* Cannot be set after open, no lock required to read. */ 256 *lk_maxp = ((DB_LOCKREGION *) 257 env->lk_handle->reginfo.primary)->stat.st_maxlocks; 258 } else 259 *lk_maxp = dbenv->lk_max; 260 return (0); 261} 262 263/* 264 * __lock_set_lk_max_locks 265 * DB_ENV->set_lk_max_locks. 266 * 267 * PUBLIC: int __lock_set_lk_max_locks __P((DB_ENV *, u_int32_t)); 268 */ 269int 270__lock_set_lk_max_locks(dbenv, lk_max) 271 DB_ENV *dbenv; 272 u_int32_t lk_max; 273{ 274 ENV *env; 275 276 env = dbenv->env; 277 278 ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_lk_max_locks"); 279 280 dbenv->lk_max = lk_max; 281 return (0); 282} 283 284/* 285 * PUBLIC: int __lock_get_lk_max_lockers __P((DB_ENV *, u_int32_t *)); 286 */ 287int 288__lock_get_lk_max_lockers(dbenv, lk_maxp) 289 DB_ENV *dbenv; 290 u_int32_t *lk_maxp; 291{ 292 ENV *env; 293 294 env = dbenv->env; 295 296 ENV_NOT_CONFIGURED(env, 297 env->lk_handle, "DB_ENV->get_lk_max_lockers", DB_INIT_LOCK); 298 299 if (LOCKING_ON(env)) { 300 /* Cannot be set after open, no lock required to read. */ 301 *lk_maxp = ((DB_LOCKREGION *) 302 env->lk_handle->reginfo.primary)->stat.st_maxlockers; 303 } else 304 *lk_maxp = dbenv->lk_max_lockers; 305 return (0); 306} 307 308/* 309 * __lock_set_lk_max_lockers 310 * DB_ENV->set_lk_max_lockers. 311 * 312 * PUBLIC: int __lock_set_lk_max_lockers __P((DB_ENV *, u_int32_t)); 313 */ 314int 315__lock_set_lk_max_lockers(dbenv, lk_max) 316 DB_ENV *dbenv; 317 u_int32_t lk_max; 318{ 319 ENV *env; 320 321 env = dbenv->env; 322 323 ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_lk_max_lockers"); 324 325 dbenv->lk_max_lockers = lk_max; 326 return (0); 327} 328 329/* 330 * PUBLIC: int __lock_get_lk_max_objects __P((DB_ENV *, u_int32_t *)); 331 */ 332int 333__lock_get_lk_max_objects(dbenv, lk_maxp) 334 DB_ENV *dbenv; 335 u_int32_t *lk_maxp; 336{ 337 ENV *env; 338 339 env = dbenv->env; 340 341 ENV_NOT_CONFIGURED(env, 342 env->lk_handle, "DB_ENV->get_lk_max_objects", DB_INIT_LOCK); 343 344 if (LOCKING_ON(env)) { 345 /* Cannot be set after open, no lock required to read. */ 346 *lk_maxp = ((DB_LOCKREGION *) 347 env->lk_handle->reginfo.primary)->stat.st_maxobjects; 348 } else 349 *lk_maxp = dbenv->lk_max_objects; 350 return (0); 351} 352 353/* 354 * __lock_set_lk_max_objects 355 * DB_ENV->set_lk_max_objects. 356 * 357 * PUBLIC: int __lock_set_lk_max_objects __P((DB_ENV *, u_int32_t)); 358 */ 359int 360__lock_set_lk_max_objects(dbenv, lk_max) 361 DB_ENV *dbenv; 362 u_int32_t lk_max; 363{ 364 ENV *env; 365 366 env = dbenv->env; 367 368 ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_lk_max_objects"); 369 370 dbenv->lk_max_objects = lk_max; 371 return (0); 372} 373/* 374 * PUBLIC: int __lock_get_lk_partitions __P((DB_ENV *, u_int32_t *)); 375 */ 376int 377__lock_get_lk_partitions(dbenv, lk_partitionp) 378 DB_ENV *dbenv; 379 u_int32_t *lk_partitionp; 380{ 381 ENV *env; 382 383 env = dbenv->env; 384 385 ENV_NOT_CONFIGURED(env, 386 env->lk_handle, "DB_ENV->get_lk_partitions", DB_INIT_LOCK); 387 388 if (LOCKING_ON(env)) { 389 /* Cannot be set after open, no lock required to read. */ 390 *lk_partitionp = ((DB_LOCKREGION *) 391 env->lk_handle->reginfo.primary)->stat.st_partitions; 392 } else 393 *lk_partitionp = dbenv->lk_partitions; 394 return (0); 395} 396 397/* 398 * __lock_set_lk_partitions 399 * DB_ENV->set_lk_partitions. 400 * 401 * PUBLIC: int __lock_set_lk_partitions __P((DB_ENV *, u_int32_t)); 402 */ 403int 404__lock_set_lk_partitions(dbenv, lk_partitions) 405 DB_ENV *dbenv; 406 u_int32_t lk_partitions; 407{ 408 ENV *env; 409 410 env = dbenv->env; 411 412 ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_lk_partitions"); 413 414 dbenv->lk_partitions = lk_partitions; 415 return (0); 416} 417 418/* 419 * PUBLIC: int __lock_get_env_timeout 420 * PUBLIC: __P((DB_ENV *, db_timeout_t *, u_int32_t)); 421 */ 422int 423__lock_get_env_timeout(dbenv, timeoutp, flag) 424 DB_ENV *dbenv; 425 db_timeout_t *timeoutp; 426 u_int32_t flag; 427{ 428 DB_LOCKREGION *region; 429 DB_LOCKTAB *lt; 430 DB_THREAD_INFO *ip; 431 ENV *env; 432 int ret; 433 434 env = dbenv->env; 435 436 ENV_NOT_CONFIGURED(env, 437 env->lk_handle, "DB_ENV->get_env_timeout", DB_INIT_LOCK); 438 439 ret = 0; 440 if (LOCKING_ON(env)) { 441 lt = env->lk_handle; 442 region = lt->reginfo.primary; 443 ENV_ENTER(env, ip); 444 LOCK_REGION_LOCK(env); 445 switch (flag) { 446 case DB_SET_LOCK_TIMEOUT: 447 *timeoutp = region->lk_timeout; 448 break; 449 case DB_SET_TXN_TIMEOUT: 450 *timeoutp = region->tx_timeout; 451 break; 452 default: 453 ret = 1; 454 break; 455 } 456 LOCK_REGION_UNLOCK(env); 457 ENV_LEAVE(env, ip); 458 } else 459 switch (flag) { 460 case DB_SET_LOCK_TIMEOUT: 461 *timeoutp = dbenv->lk_timeout; 462 break; 463 case DB_SET_TXN_TIMEOUT: 464 *timeoutp = dbenv->tx_timeout; 465 break; 466 default: 467 ret = 1; 468 break; 469 } 470 471 if (ret) 472 ret = __db_ferr(env, "DB_ENV->get_timeout", 0); 473 474 return (ret); 475} 476 477/* 478 * __lock_set_env_timeout 479 * DB_ENV->set_lock_timeout. 480 * 481 * PUBLIC: int __lock_set_env_timeout __P((DB_ENV *, db_timeout_t, u_int32_t)); 482 */ 483int 484__lock_set_env_timeout(dbenv, timeout, flags) 485 DB_ENV *dbenv; 486 db_timeout_t timeout; 487 u_int32_t flags; 488{ 489 DB_LOCKREGION *region; 490 DB_LOCKTAB *lt; 491 DB_THREAD_INFO *ip; 492 ENV *env; 493 int ret; 494 495 env = dbenv->env; 496 497 ENV_NOT_CONFIGURED(env, 498 env->lk_handle, "DB_ENV->set_env_timeout", DB_INIT_LOCK); 499 500 ret = 0; 501 if (LOCKING_ON(env)) { 502 lt = env->lk_handle; 503 region = lt->reginfo.primary; 504 ENV_ENTER(env, ip); 505 LOCK_REGION_LOCK(env); 506 switch (flags) { 507 case DB_SET_LOCK_TIMEOUT: 508 region->lk_timeout = timeout; 509 break; 510 case DB_SET_TXN_TIMEOUT: 511 region->tx_timeout = timeout; 512 break; 513 default: 514 ret = 1; 515 break; 516 } 517 LOCK_REGION_UNLOCK(env); 518 ENV_LEAVE(env, ip); 519 } else 520 switch (flags) { 521 case DB_SET_LOCK_TIMEOUT: 522 dbenv->lk_timeout = timeout; 523 break; 524 case DB_SET_TXN_TIMEOUT: 525 dbenv->tx_timeout = timeout; 526 break; 527 default: 528 ret = 1; 529 break; 530 } 531 532 if (ret) 533 ret = __db_ferr(env, "DB_ENV->set_timeout", 0); 534 535 return (ret); 536} 537