1<?xml version="1.0" encoding="UTF-8" standalone="no"?> 2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3<html xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 6 <title>The Locking Subsystem</title> 7 <link rel="stylesheet" href="gettingStarted.css" type="text/css" /> 8 <meta name="generator" content="DocBook XSL Stylesheets V1.62.4" /> 9 <link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" /> 10 <link rel="up" href="txnconcurrency.html" title="Chapter 4. Concurrency" /> 11 <link rel="previous" href="blocking_deadlocks.html" title="Locks, Blocks, and Deadlocks" /> 12 <link rel="next" href="isolation.html" title="Isolation" /> 13 </head> 14 <body> 15 <div class="navheader"> 16 <table width="100%" summary="Navigation header"> 17 <tr> 18 <th colspan="3" align="center">The Locking Subsystem</th> 19 </tr> 20 <tr> 21 <td width="20%" align="left"><a accesskey="p" href="blocking_deadlocks.html">Prev</a> </td> 22 <th width="60%" align="center">Chapter 4. Concurrency</th> 23 <td width="20%" align="right"> <a accesskey="n" href="isolation.html">Next</a></td> 24 </tr> 25 </table> 26 <hr /> 27 </div> 28 <div class="sect1" lang="en" xml:lang="en"> 29 <div class="titlepage"> 30 <div> 31 <div> 32 <h2 class="title" style="clear: both"><a id="lockingsubsystem"></a>The Locking Subsystem</h2> 33 </div> 34 </div> 35 <div></div> 36 </div> 37 <p> 38 In order to allow concurrent operations, DB provides the locking 39 subsystem. This subsystem provides inter- and intra- process 40 concurrency mechanisms. It is extensively used by DB concurrent 41 applications, but it can also be generally used for non-DB 42 resources. 43 </p> 44 <p> 45 This section describes the locking subsystem as it is used to 46 protect DB resources. In particular, issues on configuration are 47 examined here. For information on using the locking subsystem to 48 manage non-DB resources, see the 49 <i class="citetitle">Berkeley DB Programmer's Reference Guide</i>. 50 </p> 51 <div class="sect2" lang="en" xml:lang="en"> 52 <div class="titlepage"> 53 <div> 54 <div> 55 <h3 class="title"><a id="configuringlock"></a>Configuring the Locking Subsystem</h3> 56 </div> 57 </div> 58 <div></div> 59 </div> 60 <p> 61 You initialize the locking subsystem by specifying 62 <span> 63 <tt class="literal">DB_INIT_LOCK</tt> to the 64 <tt class="methodname">DB_ENV->open()</tt> 65 66 method. 67 </span> 68 69 </p> 70 <p> 71 Before opening your environment, you can configure various 72 maximum values for your locking subsystem. Note that these 73 limits can only be configured before the environment is 74 opened. Also, these methods configure the entire environment, 75 not just a specific environment handle. 76 </p> 77 <p> 78 Finally, each bullet below identifies the 79 <tt class="filename">DB_CONFIG</tt> file parameter that can be used 80 to specify the specific locking limit. If used, these 81 <tt class="filename">DB_CONFIG</tt> file parameters override any 82 value that you might specify using the environment handle. 83 </p> 84 <p> 85 The limits that you can configure are as follows: 86 </p> 87 <div class="itemizedlist"> 88 <ul type="disc"> 89 <li> 90 <p> 91 The maximum number of lockers 92 supported by the environment. This value is used by 93 the environment when it is opened to estimate the amount 94 of space that it should allocate for various internal 95 data structures. By default, 1,000 lockers are 96 supported. 97 </p> 98 <p> 99 To configure this value, use the 100 <span> 101 <tt class="methodname">DB_ENV->set_lk_max_lockers()</tt> 102 103 method. 104 </span> 105 106 </p> 107 <p> 108 As an alternative to this method, you can configure this 109 value using the <tt class="filename">DB_CONFIG</tt> file's 110 <tt class="literal">set_lk_max_lockers</tt> parameter. 111 </p> 112 </li> 113 <li> 114 <p> 115 The maximum number of locks supported by the environment. 116 By default, 1,000 locks are supported. 117 </p> 118 <p> 119 To configure this value, use the 120 <span> 121 <tt class="methodname">DB_ENV->set_lk_max_locks()</tt> 122 123 method. 124 </span> 125 126 </p> 127 <p> 128 As an alternative to this method, you can configure this 129 value using the <tt class="filename">DB_CONFIG</tt> file's 130 <tt class="literal">set_lk_max_locks</tt> parameter. 131 </p> 132 </li> 133 <li> 134 <p> 135 The maximum number of locked objects supported by the environment. 136 By default, 1,000 objects can be locked. 137 </p> 138 <p> 139 To configure this value, use the 140 <span> 141 <tt class="methodname">DB_ENV->set_lk_max_objects()</tt> 142 143 method. 144 </span> 145 146 </p> 147 <p> 148 As an alternative to this method, you can configure this 149 value using the <tt class="filename">DB_CONFIG</tt> file's 150 <tt class="literal">set_lk_max_objects</tt> parameter. 151 </p> 152 </li> 153 </ul> 154 </div> 155 <p> 156 For a definition of lockers, locks, and locked objects, see 157 <a href="blocking_deadlocks.html#lockresources">Lock Resources</a>. 158 </p> 159 <p> 160 For example, to configure the maximum number of locks that your 161 environment can use: 162 </p> 163 <pre class="programlisting">#include <stdio.h> 164#include <stdlib.h> 165 166#include "db.h" 167 168int 169main(void) 170{ 171 int ret, ret_c; 172 u_int32_t env_flags; 173 DB_ENV *envp; 174 const char *db_home_dir = "/tmp/myEnvironment"; 175 176 envp = NULL; 177 178 /* Open the environment */ 179 ret = db_env_create(&envp, 0); 180 if (ret != 0) { 181 fprintf(stderr, "Error creating environment handle: %s\n", 182 db_strerror(ret)); 183 return (EXIT_FAILURE); 184 } 185 186 env_flags = DB_CREATE | /* If the environment does not 187 * exist, create it. */ 188 DB_INIT_LOCK | /* Initialize locking */ 189 DB_INIT_LOG | /* Initialize logging */ 190 DB_INIT_MPOOL | /* Initialize the cache */ 191 DB_THREAD | /* Free-thread the env handle. */ 192 DB_INIT_TXN; /* Initialize transactions */ 193 194 /* Configure max locks */ 195 ret = envp->set_lk_max_locks(envp, 5000); 196 if (ret != 0) { 197 fprintf(stderr, "Error configuring locks: %s\n", 198 db_strerror(ret)); 199 goto err; 200 } 201 202 /* Open the environment. */ 203 ret = envp->open(envp, db_home_dir, env_flags, 0); 204 if (ret != 0) { 205 fprintf(stderr, "Error opening environment: %s\n", 206 db_strerror(ret)); 207 goto err; 208 } 209 210err: 211 /* Close the environment */ 212 if (envp != NULL) { 213 ret_c = envp->close(envp, 0); 214 if (ret_c != 0) { 215 fprintf(stderr, "environment close failed: %s\n", 216 db_strerror(ret_c)); 217 ret = ret_c; 218 } 219 } 220 221 return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 222} </pre> 223 </div> 224 <div class="sect2" lang="en" xml:lang="en"> 225 <div class="titlepage"> 226 <div> 227 <div> 228 <h3 class="title"><a id="configdeadlkdetect"></a>Configuring Deadlock Detection</h3> 229 </div> 230 </div> 231 <div></div> 232 </div> 233 <p> 234 In order for DB to know that a deadlock has occurred, 235 some mechanism must be used to perform deadlock 236 detection. There are three ways that deadlock detection can 237 occur: 238 </p> 239 <div class="orderedlist"> 240 <ol type="1"> 241 <li> 242 <p> 243 Allow DB to internally detect deadlocks as they 244 occur. 245 </p> 246 <p> 247 To do this, you use 248 <span><tt class="methodname">DB_ENV->set_lk_detect()</tt>.</span> 249 250 251 This method causes DB to walk its internal lock table 252 looking for a deadlock whenever a lock request 253 is blocked. This method also identifies how DB decides which lock 254 requests are rejected when deadlocks are detected. For example, 255 DB can decide to reject the lock request for the transaction 256 that has the most number of locks, the least number of locks, 257 holds the oldest lock, holds the most number of write locks, and 258 so forth (see the API reference documentation for a complete 259 list of the lock detection policies). 260 </p> 261 <p> 262 You can call this method at any time during your application's 263 lifetime, but typically it is used before you open your environment. 264 </p> 265 <p> 266 Note that how you want DB to decide which thread of control should break a deadlock is 267 extremely dependent on the nature of your application. It is not unusual for some performance 268 testing to be required in order to make this determination. That said, a transaction that is 269 holding the maximum number of locks is usually indicative of the transaction that has performed 270 the most amount of work. Frequently you will not want a transaction that has performed a lot of 271 work to abandon its efforts and start all over again. It is not therefore uncommon for 272 application developers to initially select the transaction with the <span class="emphasis"><em>minimum</em></span> 273 number of write locks to break the deadlock. 274 </p> 275 <p> 276 Using this mechanism for deadlock detection means 277 that your application will never have to wait on a 278 lock before discovering that a deadlock has 279 occurred. However, walking the lock table every 280 time a lock request is blocked can be expensive 281 from a performance perspective. 282 </p> 283 </li> 284 <li> 285 <p> 286 Use a dedicated thread or external process to perform 287 deadlock detection. Note that this thread must be 288 performing no other database operations beyond deadlock 289 detection. 290 </p> 291 <p> 292 To externally perform lock detection, you can use 293 either the 294 <tt class="methodname">DB_ENV->lock_detect()</tt> 295 296 297 method, or use the 298 <span><b class="command">db_deadlock</b></span> command line 299 utility. This method (or command) causes DB to walk the 300 lock table looking for deadlocks. 301 </p> 302 <p> 303 Note that like 304 <span><tt class="methodname">DB_ENV->set_lk_detect()</tt>,</span> 305 306 307 you also use this method (or command line utility) 308 to identify which lock requests are rejected in the 309 event that a deadlock is detected. 310 </p> 311 <p> 312 Applications that perform deadlock detection in 313 this way typically run deadlock detection between every few 314 seconds and a minute. This means that your 315 application may have to wait to be notified of a 316 deadlock, but you also save the overhead of walking 317 the lock table every time a lock request is blocked. 318 </p> 319 </li> 320 <li> 321 <p> 322 Lock timeouts. 323 </p> 324 <p> 325 You can configure your locking subsystem such that 326 it times out any lock that is not released within a 327 specified amount of time. To do this, use the 328 <span><tt class="methodname">DB_ENV->set_timeout()</tt></span> 329 330 331 method. 332 Note that lock timeouts are only checked when a 333 lock request is blocked or when deadlock 334 detection is otherwise performed. Therefore, a lock can have timed out and still be held for 335 some length of time until DB has a reason to examine its locking tables. 336 </p> 337 <p> 338 Be aware that extremely long-lived transactions, or 339 operations that hold locks for a long time, may be 340 inappropriately timed out before the transaction or 341 operation has a chance to complete. You should 342 therefore use this mechanism only if you know your 343 application will hold locks for very short periods 344 of time. 345 </p> 346 </li> 347 </ol> 348 </div> 349 <p> 350 For example, to configure your application such that DB 351 checks the lock table for deadlocks every time a lock 352 request is blocked: 353 </p> 354 <pre class="programlisting">#include <stdio.h> 355#include <stdlib.h> 356 357#include "db.h" 358 359int 360main(void) 361{ 362 int ret, ret_c; 363 u_int32_t db_flags, env_flags; 364 DB *dbp; 365 DB_ENV *envp; 366 DB_TXN *txn; 367 const char *db_home_dir = "/tmp/myEnvironment"; 368 const char *file_name = "mydb.db"; 369 370 envp = NULL; 371 372 /* Open the environment */ 373 ret = db_env_create(&envp, 0); 374 if (ret != 0) { 375 fprintf(stderr, "Error creating environment handle: %s\n", 376 db_strerror(ret)); 377 return (EXIT_FAILURE); 378 } 379 380 env_flags = DB_CREATE | /* If the environment does not 381 * exist, create it. */ 382 DB_INIT_LOCK | /* Initialize locking */ 383 DB_INIT_LOG | /* Initialize logging */ 384 DB_INIT_MPOOL | /* Initialize the cache */ 385 DB_THREAD | /* Free-thread the env handle. */ 386 DB_INIT_TXN; /* Initialize transactions */ 387 388 /* 389 * Configure db to perform deadlock detection internally, and to 390 * choose the transaction that has performed the least amount of writing 391 * to break the deadlock in the event that one is detected. 392 */ 393 ret = envp->set_lk_detect(envp, DB_LOCK_MINWRITE); 394 if (ret != 0) { 395 fprintf(stderr, "Error setting lk detect: %s\n", 396 db_strerror(ret)); 397 goto err; 398 } 399 400 ret = envp->open(envp, db_home_dir, env_flags, 0); 401 if (ret != 0) { 402 fprintf(stderr, "Error opening environment: %s\n", 403 db_strerror(ret)); 404 goto err; 405 } 406 407 /* 408 * From here, you open your databases, proceed with your 409 * database operations, and respond to deadlocks as 410 * is normal (omitted for brevity). 411 */ 412 413 ... </pre> 414 <p> 415 Finally, the following command line call causes 416 deadlock detection to be run against the 417 environment contained in <tt class="literal">/export/dbenv</tt>. The 418 transaction with the youngest lock is chosen to break the 419 deadlock: 420 </p> 421 <pre class="programlisting">> /usr/local/db_install/bin/db_deadlock -h /export/dbenv -a y</pre> 422 <p> 423 For more information, see the 424 <a href="http://www.oracle.com/technology/documentation/berkeley-db/db/utility/db_deadlock.html" target="_top"> 425 <tt class="literal">db_deadlock</tt> reference documentation. 426 </a> 427 </p> 428 </div> 429 <div class="sect2" lang="en" xml:lang="en"> 430 <div class="titlepage"> 431 <div> 432 <div> 433 <h3 class="title"><a id="deadlockresolve"></a>Resolving Deadlocks</h3> 434 </div> 435 </div> 436 <div></div> 437 </div> 438 <p> 439 When DB determines that a deadlock has occurred, it will 440 select a thread of control to resolve the deadlock and then 441 <span> 442 return <tt class="literal">DB_LOCK_DEADLOCK</tt> to that 443 thread. 444 </span> 445 446 447 448 If a deadlock is detected, the thread must: 449 </p> 450 <div class="orderedlist"> 451 <ol type="1"> 452 <li> 453 <p> 454 Cease all read and write operations. 455 </p> 456 </li> 457 <li> 458 <p> 459 Close all open cursors. 460 </p> 461 </li> 462 <li> 463 <p> 464 Abort the transaction. 465 </p> 466 </li> 467 <li> 468 <p> 469 Optionally retry the operation. If your application 470 retries deadlocked operations, the new attempt must 471 be made using a new transaction. 472 </p> 473 </li> 474 </ol> 475 </div> 476 <div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"> 477 <h3 class="title">Note</h3> 478 <p> 479 If a thread has deadlocked, it may not make any 480 additional database calls using the handle that has 481 deadlocked. 482 </p> 483 </div> 484 <p> 485 For example: 486 </p> 487 <pre class="programlisting">retry: 488 ret = envp->txn_begin(envp, NULL, &txn, 0); 489 if (ret != 0) { 490 envp->err(envp, ret, "txn_begin failed"); 491 return (EXIT_FAILURE); 492 } 493 ... 494 /* key and data are Dbts. Their usage is omitted for brevity. */ 495 ... 496 switch (ret = dbp->put(dbp, txn, &key, &data, 0)) { 497 case 0: 498 break; 499 /* Deadlock handling goes here */ 500 case DB_LOCK_DEADLOCK: 501 /* Abort the transaction */ 502 (void)txn->abort(txn); 503 504 /* 505 * retry_count is a counter used to identify how many times 506 * we've retried this operation. To avoid the potential for 507 * endless looping, we won't retry more than 508 * MAX_DEADLOCK_RETRIES times. 509 */ 510 if (retry_count < MAX_DEADLOCK_RETRIES) { 511 printf("Got DB_LOCK_DEADLOCK.\n"); 512 printf("Retrying write operation.\n"); 513 retry_count++; 514 goto retry; 515 } 516 printf("Got DB_LOCK_DEADLOCK and out of retries."); 517 printf("Giving up.\n"); 518 return (EXIT_FAILURE); 519 default: 520 /* If some random database error occurs, we just give up */ 521 envp->err(envp, ret, "db put failed"); 522 ret = txn->abort(txn); 523 if (ret != 0) { 524 envp->err(envp, ret, "txn abort failed"); 525 return (EXIT_FAILURE); 526 } 527 } 528 /* If all goes well, commit the transaction */ 529 ret = txn->commit(txn, 0); 530 if (ret != 0) { 531 envp->err(envp, ret, "txn commit failed"); 532 return (EXIT_FAILURE); 533 } 534 535 return (EXIT_SUCCESS); </pre> 536 </div> 537 </div> 538 <div class="navfooter"> 539 <hr /> 540 <table width="100%" summary="Navigation footer"> 541 <tr> 542 <td width="40%" align="left"><a accesskey="p" href="blocking_deadlocks.html">Prev</a> </td> 543 <td width="20%" align="center"> 544 <a accesskey="u" href="txnconcurrency.html">Up</a> 545 </td> 546 <td width="40%" align="right"> <a accesskey="n" href="isolation.html">Next</a></td> 547 </tr> 548 <tr> 549 <td width="40%" align="left" valign="top">Locks, Blocks, and Deadlocks </td> 550 <td width="20%" align="center"> 551 <a accesskey="h" href="index.html">Home</a> 552 </td> 553 <td width="40%" align="right" valign="top"> Isolation</td> 554 </tr> 555 </table> 556 </div> 557 </body> 558</html> 559