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 65 <tt class="methodname">DbEnv::open()</tt> 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 102 <tt class="methodname">DbEnv::set_lk_max_lockers()</tt> 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 122 <tt class="methodname">DbEnv::set_lk_max_locks()</tt> 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 142 <tt class="methodname">DbEnv::set_lk_max_objects()</tt> 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 "db_cxx.h" 164 165... 166 167int main(void) 168{ 169 u_int32_t env_flags = DB_CREATE | // If the environment does not 170 // exist, create it. 171 DB_INIT_LOCK | // Initialize locking 172 DB_INIT_LOG | // Initialize logging 173 DB_INIT_MPOOL | // Initialize the cache 174 DB_THREAD | // Free-thread the env handle. 175 DB_INIT_TXN; // Initialize transactions 176 177 std::string envHome("/export1/testEnv"); 178 DbEnv myEnv(0); 179 180 try { 181 182 // Configure max locks 183 myEnv.set_lk_max_locks(envp, 5000); 184 185 myEnv.open(envHome.c_str(), env_flags, 0); 186 187 } catch(DbException &e) { 188 std::cerr << "Error opening database environment: " 189 << envHome << std::endl; 190 std::cerr << e.what() << std::endl; 191 return (EXIT_FAILURE); 192 } 193 194 try { 195 myEnv.close(0); 196 } catch(DbException &e) { 197 std::cerr << "Error closing database environment: " 198 << envHome << std::endl; 199 std::cerr << e.what() << std::endl; 200 return (EXIT_FAILURE); 201 } 202 203 return (EXIT_SUCCESS); 204} </pre> 205 </div> 206 <div class="sect2" lang="en" xml:lang="en"> 207 <div class="titlepage"> 208 <div> 209 <div> 210 <h3 class="title"><a id="configdeadlkdetect"></a>Configuring Deadlock Detection</h3> 211 </div> 212 </div> 213 <div></div> 214 </div> 215 <p> 216 In order for DB to know that a deadlock has occurred, 217 some mechanism must be used to perform deadlock 218 detection. There are three ways that deadlock detection can 219 occur: 220 </p> 221 <div class="orderedlist"> 222 <ol type="1"> 223 <li> 224 <p> 225 Allow DB to internally detect deadlocks as they 226 occur. 227 </p> 228 <p> 229 To do this, you use 230 231 <span><tt class="methodname">DbEnv::set_lk_detect()</tt>.</span> 232 233 This method causes DB to walk its internal lock table 234 looking for a deadlock whenever a lock request 235 is blocked. This method also identifies how DB decides which lock 236 requests are rejected when deadlocks are detected. For example, 237 DB can decide to reject the lock request for the transaction 238 that has the most number of locks, the least number of locks, 239 holds the oldest lock, holds the most number of write locks, and 240 so forth (see the API reference documentation for a complete 241 list of the lock detection policies). 242 </p> 243 <p> 244 You can call this method at any time during your application's 245 lifetime, but typically it is used before you open your environment. 246 </p> 247 <p> 248 Note that how you want DB to decide which thread of control should break a deadlock is 249 extremely dependent on the nature of your application. It is not unusual for some performance 250 testing to be required in order to make this determination. That said, a transaction that is 251 holding the maximum number of locks is usually indicative of the transaction that has performed 252 the most amount of work. Frequently you will not want a transaction that has performed a lot of 253 work to abandon its efforts and start all over again. It is not therefore uncommon for 254 application developers to initially select the transaction with the <span class="emphasis"><em>minimum</em></span> 255 number of write locks to break the deadlock. 256 </p> 257 <p> 258 Using this mechanism for deadlock detection means 259 that your application will never have to wait on a 260 lock before discovering that a deadlock has 261 occurred. However, walking the lock table every 262 time a lock request is blocked can be expensive 263 from a performance perspective. 264 </p> 265 </li> 266 <li> 267 <p> 268 Use a dedicated thread or external process to perform 269 deadlock detection. Note that this thread must be 270 performing no other database operations beyond deadlock 271 detection. 272 </p> 273 <p> 274 To externally perform lock detection, you can use 275 either the 276 277 <tt class="methodname">DbEnv::lock_detect()</tt> 278 279 method, or use the 280 <span><b class="command">db_deadlock</b></span> command line 281 utility. This method (or command) causes DB to walk the 282 lock table looking for deadlocks. 283 </p> 284 <p> 285 Note that like 286 287 <span><tt class="methodname">DbEnv::set_lk_detect()</tt>,</span> 288 289 you also use this method (or command line utility) 290 to identify which lock requests are rejected in the 291 event that a deadlock is detected. 292 </p> 293 <p> 294 Applications that perform deadlock detection in 295 this way typically run deadlock detection between every few 296 seconds and a minute. This means that your 297 application may have to wait to be notified of a 298 deadlock, but you also save the overhead of walking 299 the lock table every time a lock request is blocked. 300 </p> 301 </li> 302 <li> 303 <p> 304 Lock timeouts. 305 </p> 306 <p> 307 You can configure your locking subsystem such that 308 it times out any lock that is not released within a 309 specified amount of time. To do this, use the 310 311 <span><tt class="methodname">DbEnv::set_timeout()</tt></span> 312 313 method. 314 Note that lock timeouts are only checked when a 315 lock request is blocked or when deadlock 316 detection is otherwise performed. Therefore, a lock can have timed out and still be held for 317 some length of time until DB has a reason to examine its locking tables. 318 </p> 319 <p> 320 Be aware that extremely long-lived transactions, or 321 operations that hold locks for a long time, may be 322 inappropriately timed out before the transaction or 323 operation has a chance to complete. You should 324 therefore use this mechanism only if you know your 325 application will hold locks for very short periods 326 of time. 327 </p> 328 </li> 329 </ol> 330 </div> 331 <p> 332 For example, to configure your application such that DB 333 checks the lock table for deadlocks every time a lock 334 request is blocked: 335 </p> 336 <pre class="programlisting">#include "db_cxx.h" 337 338... 339 340int main(void) 341{ 342 u_int32_t env_flags = DB_CREATE | // If the environment does not 343 // exist, create it. 344 DB_INIT_LOCK | // Initialize locking 345 DB_INIT_LOG | // Initialize logging 346 DB_INIT_MPOOL | // Initialize the cache 347 DB_THREAD | // Free-thread the env handle 348 DB_INIT_TXN; // Initialize transactions 349 350 std::string envHome("/export1/testEnv"); 351 DbEnv myEnv(0); 352 353 try { 354 355 // Configure db to perform deadlock detection internally, and to 356 // choose the transaction that has performed the least amount 357 // of writing to break the deadlock in the event that one 358 // is detected. 359 myEnv.set_lk_detect(DB_LOCK_MINWRITE); 360 myEnv.open(envHome.c_str(), env_flags, 0); 361 362 // From here, you open your databases, proceed with your 363 // database operations, and respond to deadlocks as 364 // is normal (omitted for brevity). 365 366 367 ...</pre> 368 <p> 369 Finally, the following command line call causes 370 deadlock detection to be run against the 371 environment contained in <tt class="literal">/export/dbenv</tt>. The 372 transaction with the youngest lock is chosen to break the 373 deadlock: 374 </p> 375 <pre class="programlisting">> /usr/local/db_install/bin/db_deadlock -h /export/dbenv -a y</pre> 376 <p> 377 For more information, see the 378 <a href="http://www.oracle.com/technology/documentation/berkeley-db/db/utility/db_deadlock.html" target="_top"> 379 <tt class="literal">db_deadlock</tt> reference documentation. 380 </a> 381 </p> 382 </div> 383 <div class="sect2" lang="en" xml:lang="en"> 384 <div class="titlepage"> 385 <div> 386 <div> 387 <h3 class="title"><a id="deadlockresolve"></a>Resolving Deadlocks</h3> 388 </div> 389 </div> 390 <div></div> 391 </div> 392 <p> 393 When DB determines that a deadlock has occurred, it will 394 select a thread of control to resolve the deadlock and then 395 396 <span> 397 throws <tt class="literal">DbDeadlockException</tt> in that 398 thread. 399 </span> 400 401 402 If a deadlock is detected, the thread must: 403 </p> 404 <div class="orderedlist"> 405 <ol type="1"> 406 <li> 407 <p> 408 Cease all read and write operations. 409 </p> 410 </li> 411 <li> 412 <p> 413 Close all open cursors. 414 </p> 415 </li> 416 <li> 417 <p> 418 Abort the transaction. 419 </p> 420 </li> 421 <li> 422 <p> 423 Optionally retry the operation. If your application 424 retries deadlocked operations, the new attempt must 425 be made using a new transaction. 426 </p> 427 </li> 428 </ol> 429 </div> 430 <div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"> 431 <h3 class="title">Note</h3> 432 <p> 433 If a thread has deadlocked, it may not make any 434 additional database calls using the handle that has 435 deadlocked. 436 </p> 437 </div> 438 <p> 439 For example: 440 </p> 441 <pre class="programlisting">// retry_count is a counter used to identify how many times 442// we've retried this operation. To avoid the potential for 443// endless looping, we won't retry more than MAX_DEADLOCK_RETRIES 444// times. 445 446// txn is a transaction handle. 447// key and data are DBT handles. Their usage is not shown here. 448while (retry_count < MAX_DEADLOCK_RETRIES) { 449 try { 450 envp->txn_begin(NULL, txn, 0); 451 dbp->put(txn, &key, &data, 0); 452 txn->commit(0); 453 return (EXIT_SUCCESS); 454 } catch (DbDeadlockException &de) { 455 try { 456 // Abort the transaction and increment the 457 // retry counter 458 txn->abort(); 459 retry_count++; 460 // If we've retried too many times, log it and exit 461 if (retry_count >= MAX_DEADLOCK_RETRIES) { 462 envp->errx("Exceeded retry limit. Giving up."); 463 return (EXIT_FAILURE); 464 } 465 } catch (DbException &ae) { 466 envp->err(ae.get_errno(), "txn abort failed."); 467 return (EXIT_FAILURE); 468 } 469 } catch (DbException &e) { 470 try { 471 // For a generic error, log it and abort. 472 envp->err(e.get_errno(), "Error putting data."); 473 txn->abort(); 474 } catch (DbException &ae) { 475 envp->err(ae.get_errno(), "txn abort failed."); 476 return (EXIT_FAILURE); 477 } 478 } 479} </pre> 480 </div> 481 </div> 482 <div class="navfooter"> 483 <hr /> 484 <table width="100%" summary="Navigation footer"> 485 <tr> 486 <td width="40%" align="left"><a accesskey="p" href="blocking_deadlocks.html">Prev</a>��</td> 487 <td width="20%" align="center"> 488 <a accesskey="u" href="txnconcurrency.html">Up</a> 489 </td> 490 <td width="40%" align="right">��<a accesskey="n" href="isolation.html">Next</a></td> 491 </tr> 492 <tr> 493 <td width="40%" align="left" valign="top">Locks, Blocks, and Deadlocks��</td> 494 <td width="20%" align="center"> 495 <a accesskey="h" href="index.html">Home</a> 496 </td> 497 <td width="40%" align="right" valign="top">��Isolation</td> 498 </tr> 499 </table> 500 </div> 501 </body> 502</html> 503