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>Isolation</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="lockingsubsystem.html" title="The Locking Subsystem" /> 12 <link rel="next" href="txn_ccursor.html" title="Transactional Cursors and Concurrent Applications" /> 13 </head> 14 <body> 15 <div class="navheader"> 16 <table width="100%" summary="Navigation header"> 17 <tr> 18 <th colspan="3" align="center">Isolation</th> 19 </tr> 20 <tr> 21 <td width="20%" align="left"><a accesskey="p" href="lockingsubsystem.html">Prev</a> </td> 22 <th width="60%" align="center">Chapter 4. Concurrency</th> 23 <td width="20%" align="right"> <a accesskey="n" href="txn_ccursor.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="isolation"></a>Isolation</h2> 33 </div> 34 </div> 35 <div></div> 36 </div> 37 <p> 38 Isolation guarantees are an important aspect of transactional 39 protection. Transactions 40 ensure the data your transaction is working with will not be changed by some other transaction. 41 Moreover, the modifications made by a transaction will never be viewable outside of that transaction until 42 the changes have been committed. 43 </p> 44 <p> 45 That said, there are different degrees of isolation, and you can choose to relax your isolation 46 guarantees to one degree or another depending on your application's requirements. The primary reason why 47 you might want to do this is because of performance; the more isolation you ask your transactions to 48 provide, the more locking that your application must do. With more locking comes a greater chance of 49 blocking, which in turn causes your threads to pause while waiting for a lock. Therefore, by relaxing 50 your isolation guarantees, you can <span class="emphasis"><em>potentially</em></span> improve your application's throughput. 51 Whether you actually see any improvement depends, of course, on 52 the nature of your application's data and transactions. 53 </p> 54 <div class="sect2" lang="en" xml:lang="en"> 55 <div class="titlepage"> 56 <div> 57 <div> 58 <h3 class="title"><a id="degreesofisolation"></a>Supported Degrees of Isolation</h3> 59 </div> 60 </div> 61 <div></div> 62 </div> 63 <p> 64 DB supports the following levels of isolation: 65 </p> 66 <div class="informaltable"> 67 <table border="1" width="80%"> 68 <colgroup> 69 <col /> 70 <col /> 71 <col /> 72 </colgroup> 73 <thead> 74 <tr> 75 <th>Degree</th> 76 <th>ANSI Term</th> 77 <th>Definition</th> 78 </tr> 79 </thead> 80 <tbody> 81 <tr> 82 <td>1</td> 83 <td>READ UNCOMMITTED</td> 84 <td> 85 Uncommitted reads means that one transaction will never 86 overwrite another transaction's dirty data. Dirty data is 87 data that a transaction has modified but not yet committed 88 to the underlying data store. However, uncommitted reads allows a 89 transaction to see data dirtied by another 90 transaction. In addition, a transaction may read data 91 dirtied by another transaction, but which subsequently 92 is aborted by that other transaction. In this latter 93 case, the reading transaction may be reading data that 94 never really existed in the database. 95 </td> 96 </tr> 97 <tr> 98 <td>2</td> 99 <td>READ COMMITTED</td> 100 <td> 101 <p> 102 Committed read isolation means that degree 1 is observed, except that dirty data is never read. 103 </p> 104 <p> 105 In addition, this isolation level guarantees that data will never change so long as 106 it is addressed by the cursor, but the data may change before the reading cursor is closed. 107 In the case of a transaction, data at the current 108 cursor position will not change, but once the cursor 109 moves, the previous referenced data can change. This 110 means that readers release read locks before the cursor 111 is closed, and therefore, before the transaction 112 completes. Note that this level of isolation causes the 113 cursor to operate in exactly the same way as it does in 114 the absence of a transaction. 115 </p> 116 </td> 117 </tr> 118 <tr> 119 <td>3</td> 120 <td>SERIALIZABLE</td> 121 <td> 122 <p> 123 Committed read is observed, plus the data read by a transaction, T, 124 will never be dirtied by another transaction before T completes. 125 This means that both read and write locks are not 126 released until the transaction completes. 127 </p> 128 <p> 129 <span> 130 In addition, 131 </span> 132 133 134 135 no transactions will see phantoms. Phantoms are records 136 returned as a result of a search, but which were not seen by 137 the same transaction when the identical 138 search criteria was previously used. 139 </p> 140 <p> 141 This is DB's default isolation guarantee. 142 </p> 143 </td> 144 </tr> 145 </tbody> 146 </table> 147 </div> 148 <p> 149 150 By default, DB transactions and transactional cursors offer 151 <span> 152 serializable isolation. 153 </span> 154 155 156 You can optionally reduce your isolation level by configuring DB to use 157 uncommitted read isolation. See 158 <a href="isolation.html#dirtyreads">Reading Uncommitted Data</a> 159 for more information. 160 161 You can also configure DB to use committed read isolation. See 162 <a href="isolation.html#readcommitted">Committed Reads</a> 163 for more information. 164 165 </p> 166 <p> 167 Finally, in addition to DB's normal degrees of isolation, you 168 can also use <span class="emphasis"><em>snapshot isolation</em></span>. This allows 169 you to avoid the read locks that serializable isolation requires. See 170 <a href="isolation.html#snapshot_isolation">Using Snapshot Isolation</a> 171 for details. 172 </p> 173 </div> 174 <div class="sect2" lang="en" xml:lang="en"> 175 <div class="titlepage"> 176 <div> 177 <div> 178 <h3 class="title"><a id="dirtyreads"></a>Reading Uncommitted Data</h3> 179 </div> 180 </div> 181 <div></div> 182 </div> 183 <p> 184 You can configure your application to read data that has been modified but not yet 185 committed by another transaction; that is, dirty data. When you do this, you 186 may see a performance benefit by allowing your 187 application to not have to block waiting for write locks. On the other hand, the data that your 188 application is reading may change before the transaction has completed. 189 </p> 190 <p> 191 When used with transactions, uncommitted reads means that one transaction can see data 192 modified but not yet committed by another transaction. When 193 used with transactional cursors, uncommitted reads means 194 that any database reader can see data modified by the 195 cursor before the cursor's transaction has committed. 196 </p> 197 <p> 198 Because of this, uncommitted reads allow a transaction to read data 199 that may subsequently be aborted by another transaction. In 200 this case, the reading transaction will have read data that 201 never really existed in the database. 202 </p> 203 <p> 204 To configure your application to read uncommitted data: 205 </p> 206 <div class="orderedlist"> 207 <ol type="1"> 208 <li> 209 <p> 210 Open your database such that it will allow uncommitted reads. You do this by 211 212 <span> 213 specifying <tt class="literal">true</tt> to 214 215 <span> 216 <tt class="methodname">DatabaseConfig.setReadUncommitted()</tt>. 217 (If you are using the DPL, you must 218 provide this 219 <tt class="classname">DatabaseConfig</tt> 220 object to the entity store using the 221 <tt class="methodname">EntityStore.setPrimaryConfig()</tt> 222 method.) 223 </span> 224 225 226 </span> 227 </p> 228 </li> 229 <li> 230 <p> 231 232 <span> 233 Specify that you want to use uncommitted reads when you 234 <span> 235 create a transaction or open the cursor. 236 </span> 237 238 To do this, you use the <tt class="methodname">setReadUncommitted()</tt> 239 <span> 240 method on the relevant configuration object 241 (<tt class="classname">TransactionConfig</tt> or 242 <tt class="classname">CursorConfig</tt>). 243 </span> 244 245 </span> 246 247 </p> 248 </li> 249 </ol> 250 </div> 251 <p> 252 For example, the following opens the database such that it supports uncommitted reads, and then creates a 253 transaction that causes all reads performed within it to use uncommitted reads. Remember that simply opening 254 the database to support uncommitted reads is not enough; you must also declare your read operations to be 255 performed using uncommitted reads. 256 </p> 257 <pre class="programlisting">package db.txn; 258 259import com.sleepycat.db.Database; 260import com.sleepycat.db.DatabaseConfig; 261import com.sleepycat.db.DatabaseEntry; 262import com.sleepycat.db.DatabaseException; 263import com.sleepycat.db.DatabaseType; 264import com.sleepycat.db.Environment; 265import com.sleepycat.db.EnvironmentConfig; 266import com.sleepycat.db.Transaction; 267import com.sleepycat.db.TransactionConfig; 268 269import java.io.File; 270 271... 272 273Database myDatabase = null; 274Environment myEnv = null; 275try { 276 EnvironmentConfig myEnvConfig = new EnvironmentConfig(); 277 myEnvConfig.setTransactional(true); 278 myEnvConfig.setInitializeCache(true); 279 myEnvConfig.setInitializeLocking(true); 280 myEnvConfig.setInitializeLogging(true); 281 282 myEnv = new Environment(new File("/my/env/home"), 283 myEnvConfig); 284 285 // Open the database. 286 DatabaseConfig dbConfig = new DatabaseConfig(); 287 dbConfig.setTransactional(true); 288 dbConfig.setType(DatabaseType.BTREE); 289 dbConfig.setAllowCreate(true); 290 dbConfig.setReadUncommitted(true); // Enable uncommitted reads. 291 myDatabase = myEnv.openDatabase(null, // txn handle 292 "sampleDatabase", // db file name 293 null, // db name 294 dbConfig); 295 TransactionConfig txnConfig = new TransactionConfig(); 296 txnConfig.setReadUncommitted(true); // Use uncommitted reads 297 // for this transaction. 298 Transaction txn = myEnv.beginTransaction(null, txnConfig); 299 300 // From here, you perform your database reads and writes as normal, 301 // committing and aborting the transactions as is necessary, and 302 // testing for deadlock exceptions as normal (omitted for brevity). 303 304 ...</pre> 305 <p> 306 If you are using the DPL: 307</p> 308 <pre class="programlisting">package persist.txn; 309 310import com.sleepycat.db.DatabaseConfig; 311import com.sleepycat.db.DatabaseEntry; 312import com.sleepycat.db.DatabaseException; 313import com.sleepycat.db.DatabaseType; 314import com.sleepycat.db.Environment; 315import com.sleepycat.db.EnvironmentConfig; 316import com.sleepycat.db.Transaction; 317import com.sleepycat.db.TransactionConfig; 318 319import com.sleepycat.persist.EntityStore; 320import com.sleepycat.persist.StoreConfig; 321 322import java.io.File; 323 324... 325 326EntityStore myStore = null; 327Environment myEnv = null; 328try { 329 EnvironmentConfig myEnvConfig = new EnvironmentConfig(); 330 myEnvConfig.setTransactional(true); 331 myEnvConfig.setInitializeCache(true); 332 myEnvConfig.setInitializeLocking(true); 333 myEnvConfig.setInitializeLogging(true); 334 335 myEnv = new Environment(new File("/my/env/home"), 336 myEnvConfig); 337 338 // Open the store. 339 StoreConfig myStoreConfig = new StoreConfig(); 340 myStoreConfig.setAllowCreate(true); 341 myStoreConfig.setTransactional(true); 342 343 // You must set all these fields if you are going to use 344 // a DatabaseConfig object with your new entity store. 345 DatabaseConfig dbConfig = new DatabaseConfig(); 346 dbConfig.setTransactional(true); 347 dbConfig.setAllowCreate(true); 348 dbConfig.setType(DatabaseType.BTREE); 349 dbConfig.setReadUncommitted(true); // Enable uncommitted reads. 350 351 myStore = new EntityStore(myEnv, "store_name", myStoreConfig); 352 353 // Set the DatabaseConfig object, so that the underlying 354 // database is configured for uncommitted reads. 355 myStore.setPrimaryConfig(SomeEntityClass.class, dbConfig); 356 357 TransactionConfig txnConfig = new TransactionConfig(); 358 txnConfig.setReadUncommitted(true); // Use uncommitted reads 359 // for this transaction. 360 Transaction txn = myEnv.beginTransaction(null, txnConfig); 361 362 // From here, you perform your store reads and writes as normal, 363 // committing and aborting the transactions as is necessary, and 364 // testing for deadlock exceptions as normal (omitted for brevity). 365 366 ...</pre> 367 <p> 368 You can also configure uncommitted read isolation on a read-by-read basis 369 by specifying <tt class="literal">LockMode.READ_UNCOMMITTED</tt>: 370 </p> 371 <pre class="programlisting">package db.txn; 372 373import com.sleepycat.db.Database; 374import com.sleepycat.db.DatabaseEntry; 375import com.sleepycat.db.Environment; 376import com.sleepycat.db.LockMode; 377import com.sleepycat.db.Transaction; 378 379... 380 381Database myDb = null; 382Environment myEnv = null; 383Transaction txn = null; 384 385try { 386 387 // Environment and database open omitted 388 389 ... 390 391 txn = myEnv.beginTransaction(null, null); 392 393 DatabaseEntry theKey = 394 new DatabaseEntry((new String("theKey")).getBytes("UTF-8")); 395 DatabaseEntry theData = new DatabaseEntry(); 396 397 myDb.get(txn, theKey, theData, LockMode.READ_UNCOMMITTED); 398} catch (Exception e) { 399 // Exception handling goes here 400} </pre> 401 <p> 402 Using the DPL: 403 </p> 404 <pre class="programlisting">package persist.txn; 405 406import com.sleepycat.db.Environment; 407import com.sleepycat.db.LockMode; 408import com.sleepycat.db.Transaction; 409 410import com.sleepycat.persist.PrimaryIndex; 411... 412 413Environment myEnv = null; 414Transaction txn = null; 415 416try { 417 418 // Environment and database open omitted 419 420 ... 421 422 txn = myEnv.beginTransaction(null, null); 423 424 AnEntityClass aec = aPrimaryIndex.get(txn, "pKeya", 425 LockMode.READ_UNCOMMITTED); 426} catch (Exception e) { 427 // Exception handling goes here 428} </pre> 429 </div> 430 <div class="sect2" lang="en" xml:lang="en"> 431 <div class="titlepage"> 432 <div> 433 <div> 434 <h3 class="title"><a id="readcommitted"></a>Committed Reads</h3> 435 </div> 436 </div> 437 <div></div> 438 </div> 439 <p> 440 You can configure your transaction so that the data being 441 read by a transactional cursor is consistent so long as it 442 is being addressed by the cursor. However, once the cursor is done reading the 443 444 445 <span> 446 object or record (that is, reading records from the page that it currently has locked), 447 </span> 448 the cursor releases its lock on that 449 450 451 <span> 452 object, record or page. 453 </span> 454 This means that the data the cursor has read and released 455 may change before the cursor's transaction has completed. 456 </p> 457 <p> 458 For example, 459 suppose you have two transactions, <tt class="literal">Ta</tt> and <tt class="literal">Tb</tt>. Suppose further that 460 <tt class="literal">Ta</tt> has a cursor that reads <tt class="literal">record R</tt>, but does not modify it. Normally, 461 <tt class="literal">Tb</tt> would then be unable to write <tt class="literal">record R</tt> because 462 <tt class="literal">Ta</tt> would be holding a read lock on it. But when you configure your transaction for 463 committed reads, <tt class="literal">Tb</tt> <span class="emphasis"><em>can</em></span> modify <tt class="literal">record 464 R</tt> before <tt class="literal">Ta</tt> completes, so long as the reading cursor is no longer 465 addressing the 466 467 468 <span> 469 object, record or page. 470 </span> 471 </p> 472 <p> 473 When you configure your application for this level of isolation, you may see better performance 474 throughput because there are fewer read locks being held by your transactions. 475 Read committed isolation is most useful when you have a cursor that is reading and/or writing records in 476 a single direction, and that does not ever have to go back to re-read those same records. In this case, 477 you can allow DB to release read locks as it goes, rather than hold them for the life of the 478 transaction. 479 </p> 480 <p> 481 To configure your application to use committed reads, do one of the following: 482 </p> 483 <div class="itemizedlist"> 484 <ul type="disc"> 485 <li> 486 <p> 487 Create your transaction such that it allows committed reads. You do this by 488 489 <span> 490 specifying <tt class="literal">true</tt> to 491 <tt class="methodname">TransactionConfig.setReadCommitted()</tt>. 492 </span> 493 </p> 494 </li> 495 <li> 496 <p> 497 498 <span> 499 Specify <tt class="literal">true</tt> to 500 <tt class="methodname">CursorConfig.setReadCommitted()</tt>. 501 </span> 502 </p> 503 </li> 504 </ul> 505 </div> 506 <p> 507 For example, the following creates a transaction that allows committed reads: 508 </p> 509 <pre class="programlisting">package db.txn; 510 511import com.sleepycat.db.Database; 512import com.sleepycat.db.DatabaseConfig; 513import com.sleepycat.db.DatabaseEntry; 514import com.sleepycat.db.DatabaseException; 515import com.sleepycat.db.Environment; 516import com.sleepycat.db.EnvironmentConfig; 517import com.sleepycat.db.Transaction; 518import com.sleepycat.db.TransactionConfig; 519 520import java.io.File; 521 522... 523 524Database myDatabase = null; 525Environment myEnv = null; 526try { 527 EnvironmentConfig myEnvConfig = new EnvironmentConfig(); 528 myEnvConfig.setTransactional(true); 529 myEnvConfig.setInitializeCache(true); 530 myEnvConfig.setInitializeLocking(true); 531 myEnvConfig.setInitializeLogging(true); 532 533 myEnv = new Environment(new File("/my/env/home"), 534 myEnvConfig); 535 536 // Open the database. 537 // Notice that we do not have to specify any properties to the 538 // database to allow committed reads (this is as opposed to 539 // uncommitted reads where we DO have to specify a property on 540 // the database open. 541 DatabaseConfig dbConfig = new DatabaseConfig(); 542 dbConfig.setTransactional(true); 543 dbConfig.setType(DatabaseType.BTREE); 544 545 myDatabase = myEnv.openDatabase(null, // txn handle 546 "sampleDatabase", // db file name 547 null, // db name 548 dbConfig); 549 String keyString = "thekey"; 550 String dataString = "thedata"; 551 DatabaseEntry key = 552 new DatabaseEntry(keyString.getBytes("UTF-8")); 553 DatabaseEntry data = 554 new DatabaseEntry(dataString.getBytes("UTF-8")); 555 556 TransactionConfig txnConfig = new TransactionConfig(); 557 558 // Open the transaction and enable committed reads. All cursors open 559 // with this transaction handle will use read committed isolation. 560 txnConfig.setReadCommitted(true); 561 Transaction txn = myEnv.beginTransaction(null, txnConfig); 562 563 // From here, you perform your database reads and writes as normal, 564 // committing and aborting the transactions as is necessary, and 565 // testing for deadlock exceptions as normal (omitted for brevity). 566 567 // Using transactional cursors with concurrent applications is 568 // described in more detail in the following section. 569 570 ...</pre> 571 <p> 572 Using the DPL: 573</p> 574 <pre class="programlisting">package persist.txn; 575 576import com.sleepycat.db.Environment; 577import com.sleepycat.db.EnvironmentConfig; 578import com.sleepycat.db.Transaction; 579import com.sleepycat.db.TransactionConfig; 580 581import com.sleepycat.persist.EntityStore; 582import com.sleepycat.persist.StoreConfig; 583 584import java.io.File; 585 586... 587 588EntityStore myStore = null; 589Environment myEnv = null; 590try { 591 EnvironmentConfig myEnvConfig = new EnvironmentConfig(); 592 myEnvConfig.setTransactional(true); 593 myEnvConfig.setInitializeCache(true); 594 myEnvConfig.setInitializeLocking(true); 595 myEnvConfig.setInitializeLogging(true); 596 597 myEnv = new Environment(new File("/my/env/home"), 598 myEnvConfig); 599 600 // Instantiate the store. 601 StoreConfig myStoreConfig = new StoreConfig(); 602 myStoreConfig.setAllowCreate(true); 603 myStoreConfig.setTransactional(true); 604 605 TransactionConfig txnConfig = new TransactionConfig(); 606 607 // Open the transaction and enable committed reads. All cursors open 608 // with this transaction handle will use read committed isolation. 609 txnConfig.setReadCommitted(true); 610 Transaction txn = myEnv.beginTransaction(null, txnConfig); 611 612 // From here, you perform your store reads and writes as normal, 613 // committing and aborting the transactions as is necessary, and 614 // testing for deadlock exceptions as normal (omitted for brevity). 615 616 // Using transactional cursors with concurrent applications is 617 // described in more detail in the following section. 618 619 ...</pre> 620 <p> 621 You can also configure read committed isolation on a read-by-read basis 622 by specifying <tt class="literal">LockMode.READ_COMMITTED</tt>: 623 </p> 624 <pre class="programlisting">package db.txn; 625 626import com.sleepycat.db.Database; 627import com.sleepycat.db.DatabaseEntry; 628import com.sleepycat.db.Environment; 629import com.sleepycat.db.LockMode; 630import com.sleepycat.db.Transaction; 631 632... 633 634Database myDb = null; 635Environment myEnv = null; 636Transaction txn = null; 637 638try { 639 640 // Environment and database open omitted 641 642 ... 643 644 txn = myEnv.beginTransaction(null, null); 645 646 DatabaseEntry theKey = 647 new DatabaseEntry((new String("theKey")).getBytes("UTF-8")); 648 DatabaseEntry theData = new DatabaseEntry(); 649 650 myDb.get(txn, theKey, theData, LockMode.READ_COMMITTED); 651} catch (Exception e) { 652 // Exception handling goes here 653} </pre> 654 <p> 655 Using the DPL: 656 </p> 657 <pre class="programlisting">package persist.txn; 658 659import com.sleepycat.db.Environment; 660import com.sleepycat.db.LockMode; 661import com.sleepycat.db.Transaction; 662 663import com.sleepycat.persist.PrimaryIndex; 664... 665 666Environment myEnv = null; 667Transaction txn = null; 668 669try { 670 671 // Environment and database open omitted 672 673 ... 674 675 txn = myEnv.beginTransaction(null, null); 676 677 // Primary index creation omitted 678 ... 679 680 AnEntityClass aec = aPrimaryIndex.get(txn, "pKeya", 681 LockMode.READ_COMMITTED); 682} catch (Exception e) { 683 // Exception handling goes here 684} </pre> 685 </div> 686 <div class="sect2" lang="en" xml:lang="en"> 687 <div class="titlepage"> 688 <div> 689 <div> 690 <h3 class="title"><a id="snapshot_isolation"></a>Using Snapshot Isolation</h3> 691 </div> 692 </div> 693 <div></div> 694 </div> 695 <p> 696 By default DB uses serializable isolation. An 697 important side effect of this isolation level is that 698 read operations obtain read locks on database pages, 699 and then hold those locks until the read operation is 700 completed. 701 702 <span> 703 When you are using transactional cursors, this 704 means that read locks are held until the transaction commits or 705 aborts. In that case, over time a transactional cursor 706 can gradually block all other transactions from writing 707 to the database. 708 </span> 709 </p> 710 <p> 711 You can avoid this by using snapshot isolation. 712 Snapshot isolation uses <span class="emphasis"><em>multiversion 713 concurrency control</em></span> to guarantee 714 repeatable reads. What this means is that every time a 715 writer would take a read lock on a page, instead a copy of 716 the page is made and the writer operates on that page 717 copy. This frees other writers from blocking due to a 718 read lock held on the page. 719 </p> 720 <div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"> 721 <h3 class="title">Note</h3> 722 <p> 723 Snapshot isolation is strongly recommended for read-only threads when writer 724 threads are also running, as this will eliminate read-write contention and 725 greatly improve transaction throughput for your writer threads. However, in 726 order for snapshot isolation to work for your reader-only threads, you must 727 of course use transactions for your DB reads. 728 </p> 729 </div> 730 <div class="sect3" lang="en" xml:lang="en"> 731 <div class="titlepage"> 732 <div> 733 <div> 734 <h4 class="title"><a id="sisolation_cost"></a>Snapshot Isolation Cost</h4> 735 </div> 736 </div> 737 <div></div> 738 </div> 739 <p> 740 Snapshot isolation does not come without a cost. 741 Because pages are being duplicated before being 742 operated upon, the cache will fill up faster. This 743 means that you might need a larger cache in order to 744 hold the entire working set in memory. 745 </p> 746 <p> 747 If the cache becomes full of page copies before old 748 copies can be discarded, additional I/O will occur as 749 pages are written to temporary "freezer" files on disk. 750 This can substantially reduce throughput, and should be 751 avoided if possible by configuring a large cache and 752 keeping snapshot isolation transactions short. 753 </p> 754 <p> 755 You can estimate how large your cache should be by 756 taking a checkpoint, followed by a call to the 757 758 759 <tt class="methodname">Environment.getArchiveLogFiles()</tt> 760 method. The amount of cache required is approximately 761 double the size of the remaining log files (that is, 762 the log files that cannot be archived). 763 </p> 764 </div> 765 <div class="sect3" lang="en" xml:lang="en"> 766 <div class="titlepage"> 767 <div> 768 <div> 769 <h4 class="title"><a id="sisolation_maxtxn"></a>Snapshot Isolation Transactional Requirements</h4> 770 </div> 771 </div> 772 <div></div> 773 </div> 774 <p> 775 In addition to an increased cache size, you may also 776 need to increase the maximum number of transactions 777 that your application supports. (See 778 <a href="maxtxns.html">Configuring the Transaction Subsystem</a> 779 for details on how to set this.) 780 In the worst case scenario, you might need to configure your application for one 781 more transaction for every page in the cache. This is 782 because transactions are retained until the last page 783 they created is evicted from the cache. 784 </p> 785 </div> 786 <div class="sect3" lang="en" xml:lang="en"> 787 <div class="titlepage"> 788 <div> 789 <div> 790 <h4 class="title"><a id="sisolation_whenuse"></a>When to Use Snapshot Isolation</h4> 791 </div> 792 </div> 793 <div></div> 794 </div> 795 <p> 796 Snapshot isolation is best used when all or most 797 of the following conditions are true: 798 </p> 799 <div class="itemizedlist"> 800 <ul type="disc"> 801 <li> 802 <p> 803 You can have a large cache relative to your working data set size. 804 </p> 805 </li> 806 <li> 807 <p> 808 You require repeatable reads. 809 </p> 810 </li> 811 <li> 812 <p> 813 You will be using transactions that routinely work on 814 the entire database, or more commonly, 815 there is data in your database that will be very 816 frequently written by more than one transaction. 817 </p> 818 </li> 819 <li> 820 <p> 821 Read/write contention is 822 limiting your application's 823 throughput, or the application 824 is all or mostly read-only and 825 contention for the lock manager 826 mutex is limiting throughput. 827 </p> 828 </li> 829 </ul> 830 </div> 831 </div> 832 <div class="sect3" lang="en" xml:lang="en"> 833 <div class="titlepage"> 834 <div> 835 <div> 836 <h4 class="title"><a id="sisolation_howuse"></a>How to use Snapshot Isolation</h4> 837 </div> 838 </div> 839 <div></div> 840 </div> 841 <p> 842 You use snapshot isolation by: 843 </p> 844 <div class="itemizedlist"> 845 <ul type="disc"> 846 <li> 847 <p> 848 Opening the database <span>or store</span> with 849 multiversion support. You can 850 configure this either when you 851 open your environment or when 852 you open your 853 854 855 <span> 856 database or store. 857 </span> 858 859 <span> 860 Use the 861 <tt class="literal">DB_MULTIVERSION</tt> 862 flag to configure this support. 863 </span> 864 865 <span> 866 Use either the 867 <tt class="methodname">EnvironmentConfig.setMultiversion()</tt> 868 or the 869 <tt class="methodname">DatabaseConfig.setMultiversion()</tt> 870 871 option to configure 872 this support. 873 </span> 874 </p> 875 </li> 876 <li> 877 <p> 878 Configure your <span>cursor or</span> 879 transaction to use snapshot isolation. 880 </p> 881 <p> 882 To do this, 883 884 885 886 <span> 887 specify the 888 <tt class="methodname">TransactionConfig.setSnapshot()</tt> 889 option when you configure your transaction. 890 </span> 891 </p> 892 </li> 893 </ul> 894 </div> 895 <p> 896 The simplest way to take advantage of snapshot 897 isolation is for queries: keep update 898 transactions using full read/write locking and 899 use snapshot isolation on read-only transactions or 900 cursors. This should minimize blocking of 901 snapshot isolation transactions and will avoid 902 deadlock errors. 903 </p> 904 <p> 905 If the application has update transactions which 906 read many items and only update a small set (for 907 example, scanning until a desired record is 908 found, then modifying it), throughput may be 909 improved by running some updates at snapshot 910 isolation as well. But doing this means that 911 you must manage deadlock errors. 912 See 913 <a href="lockingsubsystem.html#deadlockresolve">Resolving Deadlocks</a> 914 for details. 915 </p> 916 <p> 917 The following code fragment turns 918 on snapshot isolation for a transaction: 919 </p> 920 <pre class="programlisting">package db.txn; 921 922import com.sleepycat.db.Database; 923import com.sleepycat.db.DatabaseType; 924import com.sleepycat.db.DatabaseConfig; 925import com.sleepycat.db.DatabaseException; 926import com.sleepycat.db.Environment; 927import com.sleepycat.db.EnvironmentConfig; 928 929import java.io.File; 930import java.io.FileNotFoundException; 931 932... 933 934Database myDatabase = null; 935Environment myEnv = null; 936try { 937 EnvironmentConfig myEnvConfig = new EnvironmentConfig(); 938 myEnvConfig.setInitializeCache(true); 939 myEnvConfig.setInitializeLocking(true); 940 myEnvConfig.setInitializeLogging(true); 941 myEnvConfig.setTransactional(true); 942 <b class="userinput"><tt>myEnvConfig.setMultiversion(true);</tt></b> 943 944 myEnv = new Environment(new File("/my/env/home"), 945 myEnvConfig); 946 947 // Open the database. 948 DatabaseConfig dbConfig = new DatabaseConfig(); 949 dbConfig.setTransactional(true); 950 dbConfig.setType(DatabaseType.BTREE); 951 myDatabase = myEnv.openDatabase(null, // txn handle 952 "sampleDatabase", // db file name 953 null, // db name 954 dbConfig); 955 956... 957 958 <b class="userinput"><tt>TransactionConfig txnConfig = new TransactionConfig(); 959 txnConfig.setSnapshot(true);</tt></b> 960 txn = myEnv.beginTransaction(null, <b class="userinput"><tt>txnConfig</tt></b>); 961 962... 963 964} catch (DatabaseException de) { 965 // Exception handling goes here 966} catch (FileNotFoundException fnfe) { 967 // Exception handling goes here 968}</pre> 969 <p> 970 When using the DPL: 971</p> 972 <pre class="programlisting">package persist.txn; 973 974import com.sleepycat.db.DatabaseException; 975import com.sleepycat.db.Environment; 976import com.sleepycat.db.EnvironmentConfig; 977 978import com.sleepycat.persist.EntityStore; 979import com.sleepycat.persist.StoreConfig; 980 981import java.io.File; 982import java.io.FileNotFoundException; 983 984... 985 986EntityStore myStore = null; 987Environment myEnv = null; 988try { 989 EnvironmentConfig myEnvConfig = new EnvironmentConfig(); 990 myEnvConfig.setInitializeCache(true); 991 myEnvConfig.setInitializeLocking(true); 992 myEnvConfig.setInitializeLogging(true); 993 myEnvConfig.setTransactional(true); 994 <b class="userinput"><tt>myEnvConfig.setMultiversion(true);</tt></b> 995 996 myEnv = new Environment(new File("/my/env/home"), 997 myEnvConfig); 998 999 // Instantiate the store 1000 StoreConfig myStoreConfig = new StoreConfig(); 1001 myStoreConfig.setAllowCreate(true); 1002 myStoreConfig.setTransactional(true); 1003 1004 myStore = new EntityStore(myEnv, storeName, myStoreConfig); 1005 1006... 1007 1008 <b class="userinput"><tt>TransactionConfig txnConfig = new TransactionConfig(); 1009 txnConfig.setSnapshot(true);</tt></b> 1010 txn = myEnv.beginTransaction(null, <b class="userinput"><tt>txnConfig</tt></b>); 1011 1012... 1013 1014} catch (DatabaseException de) { 1015 // Exception handling goes here 1016} catch (FileNotFoundException fnfe) { 1017 // Exception handling goes here 1018}</pre> 1019 </div> 1020 </div> 1021 </div> 1022 <div class="navfooter"> 1023 <hr /> 1024 <table width="100%" summary="Navigation footer"> 1025 <tr> 1026 <td width="40%" align="left"><a accesskey="p" href="lockingsubsystem.html">Prev</a> </td> 1027 <td width="20%" align="center"> 1028 <a accesskey="u" href="txnconcurrency.html">Up</a> 1029 </td> 1030 <td width="40%" align="right"> <a accesskey="n" href="txn_ccursor.html">Next</a></td> 1031 </tr> 1032 <tr> 1033 <td width="40%" align="left" valign="top">The Locking Subsystem </td> 1034 <td width="20%" align="center"> 1035 <a accesskey="h" href="index.html">Home</a> 1036 </td> 1037 <td width="40%" align="right" valign="top"> Transactional Cursors and Concurrent Applications</td> 1038 </tr> 1039 </table> 1040 </div> 1041 </body> 1042</html> 1043