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