mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-16 17:16:25 +00:00
744 lines
32 KiB
HTML
744 lines
32 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
<title>Isolation</title>
|
||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
|
||
<link rel="start" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||
<link rel="up" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||
<link rel="prev" href="lockingsubsystem.html" title="The Locking Subsystem" />
|
||
<link rel="next" href="txn_ccursor.html" title="Transactional Cursors and Concurrent Applications" />
|
||
</head>
|
||
<body>
|
||
<div xmlns="" class="navheader">
|
||
<div class="libver">
|
||
<p>Library Version 11.2.5.3</p>
|
||
</div>
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Isolation</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="lockingsubsystem.html">Prev</a> </td>
|
||
<th width="60%" align="center">Chapter 4. Concurrency</th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="txn_ccursor.html">Next</a></td>
|
||
</tr>
|
||
</table>
|
||
<hr />
|
||
</div>
|
||
<div class="sect1" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h2 class="title" style="clear: both"><a id="isolation"></a>Isolation</h2>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="toc">
|
||
<dl>
|
||
<dt>
|
||
<span class="sect2">
|
||
<a href="isolation.html#degreesofisolation">Supported Degrees of Isolation</a>
|
||
</span>
|
||
</dt>
|
||
<dt>
|
||
<span class="sect2">
|
||
<a href="isolation.html#dirtyreads">Reading Uncommitted Data</a>
|
||
</span>
|
||
</dt>
|
||
<dt>
|
||
<span class="sect2">
|
||
<a href="isolation.html#readcommitted">Committed Reads</a>
|
||
</span>
|
||
</dt>
|
||
<dt>
|
||
<span class="sect2">
|
||
<a href="isolation.html#snapshot_isolation">Using Snapshot Isolation</a>
|
||
</span>
|
||
</dt>
|
||
</dl>
|
||
</div>
|
||
<p>
|
||
Isolation guarantees are an important aspect of transactional
|
||
protection. Transactions
|
||
ensure the data your transaction is working with will not be changed by some other transaction.
|
||
Moreover, the modifications made by a transaction will never be viewable outside of that transaction until
|
||
the changes have been committed.
|
||
</p>
|
||
<p>
|
||
That said, there are different degrees of isolation, and you can choose to relax your isolation
|
||
guarantees to one degree or another depending on your application's requirements. The primary reason why
|
||
you might want to do this is because of performance; the more isolation you ask your transactions to
|
||
provide, the more locking that your application must do. With more locking comes a greater chance of
|
||
blocking, which in turn causes your threads to pause while waiting for a lock. Therefore, by relaxing
|
||
your isolation guarantees, you can <span class="emphasis"><em>potentially</em></span> improve your application's throughput.
|
||
Whether you actually see any improvement depends, of course, on
|
||
the nature of your application's data and transactions.
|
||
</p>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="degreesofisolation"></a>Supported Degrees of Isolation</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
DB supports the following levels of isolation:
|
||
</p>
|
||
<div class="informaltable">
|
||
<table border="1" width="80%">
|
||
<colgroup>
|
||
<col />
|
||
<col />
|
||
<col />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Degree</th>
|
||
<th>ANSI Term</th>
|
||
<th>Definition</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>1</td>
|
||
<td>READ UNCOMMITTED</td>
|
||
<td>
|
||
Uncommitted reads means that one transaction will never
|
||
overwrite another transaction's dirty data. Dirty data is
|
||
data that a transaction has modified but not yet committed
|
||
to the underlying data store. However, uncommitted reads allows a
|
||
transaction to see data dirtied by another
|
||
transaction. In addition, a transaction may read data
|
||
dirtied by another transaction, but which subsequently
|
||
is aborted by that other transaction. In this latter
|
||
case, the reading transaction may be reading data that
|
||
never really existed in the database.
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>2</td>
|
||
<td>READ COMMITTED</td>
|
||
<td>
|
||
<p>
|
||
Committed read isolation means that degree 1 is observed, except that dirty data is never read.
|
||
</p>
|
||
<p>
|
||
In addition, this isolation level guarantees that data will never change so long as
|
||
it is addressed by the cursor, but the data may change before the reading cursor is closed.
|
||
In the case of a transaction, data at the current
|
||
cursor position will not change, but once the cursor
|
||
moves, the previous referenced data can change. This
|
||
means that readers release read locks before the cursor
|
||
is closed, and therefore, before the transaction
|
||
completes. Note that this level of isolation causes the
|
||
cursor to operate in exactly the same way as it does in
|
||
the absence of a transaction.
|
||
</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>3</td>
|
||
<td>SERIALIZABLE</td>
|
||
<td>
|
||
<p>
|
||
Committed read is observed, plus the data read by a transaction, T,
|
||
will never be dirtied by another transaction before T completes.
|
||
This means that both read and write locks are not
|
||
released until the transaction completes.
|
||
</p>
|
||
<p>
|
||
<span>
|
||
In addition,
|
||
</span>
|
||
|
||
|
||
|
||
no transactions will see phantoms. Phantoms are records
|
||
returned as a result of a search, but which were not seen by
|
||
the same transaction when the identical
|
||
search criteria was previously used.
|
||
</p>
|
||
<p>
|
||
This is DB's default isolation guarantee.
|
||
</p>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>
|
||
|
||
By default, DB transactions and transactional cursors offer
|
||
<span>
|
||
serializable isolation.
|
||
</span>
|
||
|
||
|
||
You can optionally reduce your isolation level by configuring DB to use
|
||
uncommitted read isolation. See
|
||
<a class="xref" href="isolation.html#dirtyreads" title="Reading Uncommitted Data">Reading Uncommitted Data</a>
|
||
for more information.
|
||
|
||
You can also configure DB to use committed read isolation. See
|
||
<a class="xref" href="isolation.html#readcommitted" title="Committed Reads">Committed Reads</a>
|
||
for more information.
|
||
|
||
</p>
|
||
<p>
|
||
Finally, in addition to DB's normal degrees of isolation, you
|
||
can also use <span class="emphasis"><em>snapshot isolation</em></span>. This allows
|
||
you to avoid the read locks that serializable isolation requires. See
|
||
<a class="xref" href="isolation.html#snapshot_isolation" title="Using Snapshot Isolation">Using Snapshot Isolation</a>
|
||
for details.
|
||
</p>
|
||
</div>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="dirtyreads"></a>Reading Uncommitted Data</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
Berkeley DB allows you to configure your application to read data that has been modified but not yet
|
||
committed by another transaction; that is, dirty data. When you do this, you
|
||
may see a performance benefit by allowing your
|
||
application to not have to block waiting for write locks. On the other hand, the data that your
|
||
application is reading may change before the transaction has completed.
|
||
</p>
|
||
<p>
|
||
When used with transactions, uncommitted reads means that one transaction can see data
|
||
modified but not yet committed by another transaction. When
|
||
used with transactional cursors, uncommitted reads means
|
||
that any database reader can see data modified by the
|
||
cursor before the cursor's transaction has committed.
|
||
</p>
|
||
<p>
|
||
Because of this, uncommitted reads allow a transaction to read data
|
||
that may subsequently be aborted by another transaction. In
|
||
this case, the reading transaction will have read data that
|
||
never really existed in the database.
|
||
</p>
|
||
<p>
|
||
To configure your application to read uncommitted data:
|
||
</p>
|
||
<div class="orderedlist">
|
||
<ol type="1">
|
||
<li>
|
||
<p>
|
||
Open your database such that it will allow uncommitted reads. You do this by
|
||
<span>
|
||
specifying <code class="literal">DB_READ_UNCOMMITTED</code> when you open your database.
|
||
</span>
|
||
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<span>
|
||
Specify <code class="literal">DB_READ_UNCOMMITTED</code>
|
||
when you create the transaction,
|
||
open the cursor, or read a record from the database.
|
||
</span>
|
||
|
||
|
||
</p>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
<p>
|
||
For example, the following opens the database such that it supports uncommitted reads, and then creates a
|
||
transaction that causes all reads performed within it to use uncommitted reads. Remember that simply opening
|
||
the database to support uncommitted reads is not enough; you must also declare your read operations to be
|
||
performed using uncommitted reads.
|
||
</p>
|
||
<pre class="programlisting">#include "db_cxx.h"
|
||
|
||
...
|
||
|
||
int main(void)
|
||
{
|
||
u_int32_t env_flags = DB_CREATE | // If the environment does not
|
||
// exist, create it.
|
||
DB_INIT_LOCK | // Initialize locking
|
||
DB_INIT_LOG | // Initialize logging
|
||
DB_INIT_MPOOL | // Initialize the cache
|
||
DB_THREAD | // Free-thread the env handle
|
||
DB_INIT_TXN; // Initialize transactions
|
||
|
||
u_int32_t db_flags = DB_CREATE | // Create the db if it does
|
||
// not exist
|
||
DB_AUTO_COMMIT | // Enable auto commit
|
||
DB_READ_UNCOMMITTED; // Enable uncommitted reads
|
||
|
||
Db *dbp = NULL;
|
||
const char *file_name = "mydb.db";
|
||
const char *keystr ="thekey";
|
||
const char *datastr = "thedata";
|
||
|
||
std::string envHome("/export1/testEnv");
|
||
DbEnv myEnv(0);
|
||
|
||
try {
|
||
|
||
myEnv.open(envHome.c_str(), env_flags, 0);
|
||
dbp = new Db(&myEnv, 0);
|
||
dbp->open(NULL, // Txn pointer
|
||
file_name, // File name
|
||
NULL, // Logical db name
|
||
DB_BTREE, // Database type (using btree)
|
||
db_flags, // Open flags
|
||
0); // File mode. Using defaults
|
||
|
||
DbTxn *txn = NULL;
|
||
myEnv.txn_begin(NULL, &txn, DB_READ_UNCOMMITTED);
|
||
|
||
// From here, you perform your database reads and writes as
|
||
// normal, committing and aborting the transactions as is
|
||
// necessary, and testing for deadlock exceptions as normal
|
||
// (omitted for brevity).
|
||
|
||
...</pre>
|
||
</div>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="readcommitted"></a>Committed Reads</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
You can configure your transaction so that the data being
|
||
read by a transactional cursor is consistent so long as it
|
||
is being addressed by the cursor. However, once the cursor is done reading the
|
||
|
||
<span>
|
||
record (that is, reading records from the page that it currently has locked),
|
||
</span>
|
||
|
||
the cursor releases its lock on that
|
||
|
||
<span>
|
||
record or page.
|
||
</span>
|
||
|
||
This means that the data the cursor has read and released
|
||
may change before the cursor's transaction has completed.
|
||
</p>
|
||
<p>
|
||
For example,
|
||
suppose you have two transactions, <code class="literal">Ta</code> and <code class="literal">Tb</code>. Suppose further that
|
||
<code class="literal">Ta</code> has a cursor that reads <code class="literal">record R</code>, but does not modify it. Normally,
|
||
<code class="literal">Tb</code> would then be unable to write <code class="literal">record R</code> because
|
||
<code class="literal">Ta</code> would be holding a read lock on it. But when you configure your transaction for
|
||
committed reads, <code class="literal">Tb</code> <span class="emphasis"><em>can</em></span> modify <code class="literal">record
|
||
R</code> before <code class="literal">Ta</code> completes, so long as the reading cursor is no longer
|
||
addressing the
|
||
|
||
<span>
|
||
record or page.
|
||
</span>
|
||
|
||
</p>
|
||
<p>
|
||
When you configure your application for this level of isolation, you may see better performance
|
||
throughput because there are fewer read locks being held by your transactions.
|
||
Read committed isolation is most useful when you have a cursor that is reading and/or writing records in
|
||
a single direction, and that does not ever have to go back to re-read those same records. In this case,
|
||
you can allow DB to release read locks as it goes, rather than hold them for the life of the
|
||
transaction.
|
||
</p>
|
||
<p>
|
||
To configure your application to use committed reads, do one of the following:
|
||
</p>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
Create your transaction such that it allows committed reads. You do this by
|
||
<span>
|
||
specifying <code class="literal">DB_READ_COMMITTED</code> when you open the transaction.
|
||
</span>
|
||
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
<span>
|
||
Specify <code class="literal">DB_READ_COMMITTED</code>
|
||
when you open the cursor.
|
||
</span>
|
||
|
||
</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<p>
|
||
For example, the following creates a transaction that allows committed reads:
|
||
</p>
|
||
<pre class="programlisting">#include "db_cxx.h"
|
||
|
||
...
|
||
|
||
int main(void)
|
||
{
|
||
u_int32_t env_flags = DB_CREATE | // If the environment does not
|
||
// exist, create it.
|
||
DB_INIT_LOCK | // Initialize locking
|
||
DB_INIT_LOG | // Initialize logging
|
||
DB_INIT_MPOOL | // Initialize the cache
|
||
DB_THREAD | // Free-thread the env handle
|
||
DB_INIT_TXN; // Initialize transactions
|
||
|
||
// Notice that we do not have to specify any flags to the database to
|
||
// allow committed reads (this is as opposed to uncommitted reads
|
||
// where we DO have to specify a flag on the database open.
|
||
u_int32_t db_flags = DB_CREATE | DB_AUTO_COMMIT;
|
||
Db *dbp = NULL;
|
||
const char *file_name = "mydb.db";
|
||
|
||
std::string envHome("/export1/testEnv");
|
||
DbEnv myEnv(0);
|
||
|
||
try {
|
||
|
||
myEnv.open(envHome.c_str(), env_flags, 0);
|
||
dbp = new Db(&myEnv, 0);
|
||
dbp->open(NULL, // Txn pointer
|
||
file_name, // File name
|
||
NULL, // Logical db name
|
||
DB_BTREE, // Database type (using btree)
|
||
db_flags, // Open flags
|
||
0); // File mode. Using defaults
|
||
|
||
DbTxn *txn = NULL;
|
||
|
||
// Open the transaction and enable committed reads. All cursors
|
||
// open with this transaction handle will use read committed
|
||
// isolation.
|
||
myEnv.txn_begin(NULL, &txn, DB_READ_COMMITTED);
|
||
|
||
// From here, you perform your database reads and writes as
|
||
// normal, committing and aborting the transactions as is
|
||
// necessary, testing for deadlock exceptions as normal
|
||
// (omitted for brevity).
|
||
|
||
// Using transactional cursors with concurrent applications is
|
||
// described in more detail in the following section.
|
||
|
||
...</pre>
|
||
</div>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="snapshot_isolation"></a>Using Snapshot Isolation</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
By default DB uses serializable isolation. An
|
||
important side effect of this isolation level is that
|
||
read operations obtain read locks on database pages,
|
||
and then hold those locks until the read operation is
|
||
completed.
|
||
|
||
<span>
|
||
When you are using transactional cursors, this
|
||
means that read locks are held until the transaction commits or
|
||
aborts. In that case, over time a transactional cursor
|
||
can gradually block all other transactions from writing
|
||
to the database.
|
||
</span>
|
||
</p>
|
||
<p>
|
||
You can avoid this by using snapshot isolation.
|
||
Snapshot isolation uses <span class="emphasis"><em>multiversion
|
||
concurrency control</em></span> to guarantee
|
||
repeatable reads. What this means is that every time a
|
||
writer would take a read lock on a page, instead a copy of
|
||
the page is made and the writer operates on that page
|
||
copy. This frees other writers from blocking due to a
|
||
read lock held on the page.
|
||
</p>
|
||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||
<h3 class="title">Note</h3>
|
||
<p>
|
||
Snapshot isolation is strongly recommended for read-only threads when writer
|
||
threads are also running, as this will eliminate read-write contention and
|
||
greatly improve transaction throughput for your writer threads. However, in
|
||
order for snapshot isolation to work for your reader-only threads, you must
|
||
of course use transactions for your DB reads.
|
||
</p>
|
||
</div>
|
||
<div class="sect3" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h4 class="title"><a id="sisolation_cost"></a>Snapshot Isolation Cost</h4>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
Snapshot isolation does not come without a cost.
|
||
Because pages are being duplicated before being
|
||
operated upon, the cache will fill up faster. This
|
||
means that you might need a larger cache in order to
|
||
hold the entire working set in memory.
|
||
</p>
|
||
<p>
|
||
If the cache becomes full of page copies before old
|
||
copies can be discarded, additional I/O will occur as
|
||
pages are written to temporary "freezer" files on disk.
|
||
This can substantially reduce throughput, and should be
|
||
avoided if possible by configuring a large cache and
|
||
keeping snapshot isolation transactions short.
|
||
</p>
|
||
<p>
|
||
You can estimate how large your cache should be by
|
||
taking a checkpoint, followed by a call to the
|
||
|
||
<code class="methodname">DbEnv::log_archive()</code>
|
||
|
||
method. The amount of cache required is approximately
|
||
double the size of the remaining log files (that is,
|
||
the log files that cannot be archived).
|
||
</p>
|
||
</div>
|
||
<div class="sect3" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h4 class="title"><a id="sisolation_maxtxn"></a>Snapshot Isolation Transactional Requirements</h4>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
In addition to an increased cache size, you may also
|
||
need to increase the number of transactions
|
||
that your application supports. (See
|
||
<a class="xref" href="maxtxns.html" title="Configuring the Transaction Subsystem">Configuring the Transaction Subsystem</a>
|
||
for details on how to set this.)
|
||
In the worst case scenario, you might need to configure your application for one
|
||
more transaction for every page in the cache. This is
|
||
because transactions are retained until the last page
|
||
they created is evicted from the cache.
|
||
</p>
|
||
</div>
|
||
<div class="sect3" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h4 class="title"><a id="sisolation_whenuse"></a>When to Use Snapshot Isolation</h4>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
Snapshot isolation is best used when all or most
|
||
of the following conditions are true:
|
||
</p>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
You can have a large cache relative to your working data set size.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
You require repeatable reads.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
You will be using transactions that routinely work on
|
||
the entire database, or more commonly,
|
||
there is data in your database that will be very
|
||
frequently written by more than one transaction.
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
Read/write contention is
|
||
limiting your application's
|
||
throughput, or the application
|
||
is all or mostly read-only and
|
||
contention for the lock manager
|
||
mutex is limiting throughput.
|
||
</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="sect3" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h4 class="title"><a id="sisolation_howuse"></a>How to use Snapshot Isolation</h4>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
You use snapshot isolation by:
|
||
</p>
|
||
<div class="itemizedlist">
|
||
<ul type="disc">
|
||
<li>
|
||
<p>
|
||
Opening the database with
|
||
multiversion support. You can
|
||
configure this either when you
|
||
open your environment or when
|
||
you open your
|
||
|
||
<span>
|
||
database.
|
||
</span>
|
||
|
||
|
||
<span>
|
||
Use the
|
||
<code class="literal">DB_MULTIVERSION</code>
|
||
flag to configure this support.
|
||
</span>
|
||
|
||
|
||
|
||
|
||
</p>
|
||
</li>
|
||
<li>
|
||
<p>
|
||
Configure your <span>cursor or</span>
|
||
transaction to use snapshot isolation.
|
||
</p>
|
||
<p>
|
||
To do this,
|
||
|
||
<span>
|
||
pass the <code class="literal">DB_TXN_SNAPSHOT</code> flag
|
||
when you
|
||
|
||
<span>
|
||
open the cursor or
|
||
</span>
|
||
|
||
create the transaction.
|
||
|
||
<span>
|
||
If configured for the transaction,
|
||
then this flag is not required
|
||
when the cursor is opened.
|
||
</span>
|
||
|
||
</span>
|
||
|
||
|
||
</p>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<p>
|
||
The simplest way to take advantage of snapshot
|
||
isolation is for queries: keep update
|
||
transactions using full read/write locking and
|
||
use snapshot isolation on read-only transactions or
|
||
cursors. This should minimize blocking of
|
||
snapshot isolation transactions and will avoid
|
||
deadlock errors.
|
||
</p>
|
||
<p>
|
||
If the application has update transactions which
|
||
read many items and only update a small set (for
|
||
example, scanning until a desired record is
|
||
found, then modifying it), throughput may be
|
||
improved by running some updates at snapshot
|
||
isolation as well. But doing this means that
|
||
you must manage deadlock errors.
|
||
See
|
||
<a class="xref" href="lockingsubsystem.html#deadlockresolve" title="Resolving Deadlocks">Resolving Deadlocks</a>
|
||
for details.
|
||
</p>
|
||
<p>
|
||
The following code fragment turns
|
||
on snapshot isolation for a transaction:
|
||
</p>
|
||
<pre class="programlisting">#include "db_cxx.h"
|
||
|
||
...
|
||
|
||
int main(void)
|
||
{
|
||
u_int32_t env_flags = DB_CREATE | // If the environment does not
|
||
// exist, create it.
|
||
DB_INIT_LOCK | // Initialize locking
|
||
DB_INIT_LOG | // Initialize logging
|
||
DB_INIT_MPOOL | // Initialize the cache
|
||
DB_INIT_TXN; // Initialize transactions
|
||
|
||
// Note that no special flags are required here for snapshot isolation.
|
||
// This is because it will be enabled at the environment level.
|
||
u_int32_t db_flags = DB_CREATE | DB_AUTO_COMMIT;
|
||
Db *dbp = NULL;
|
||
const char *file_name = "mydb.db";
|
||
|
||
std::string envHome("/export1/testEnv");
|
||
DbEnv myEnv(0);
|
||
|
||
try {
|
||
|
||
myEnv.open(envHome.c_str(), env_flags, 0);
|
||
<strong class="userinput"><code>// Support snapshot isolation
|
||
myEnv.set_flags(DB_MULTIVERSION, 1);</code></strong>
|
||
dbp = new Db(&myEnv, 0);
|
||
dbp->open(NULL, // Txn pointer
|
||
file_name, // File name
|
||
NULL, // Logical db name
|
||
DB_BTREE, // Database type (using btree)
|
||
db_flags, // Open flags
|
||
0); // File mode. Using defaults
|
||
|
||
} catch(DbException &e) {
|
||
std::cerr << "Error opening database and environment: "
|
||
<< file_name << ", "
|
||
<< envHome << std::endl;
|
||
std::cerr << e.what() << std::endl;
|
||
}
|
||
|
||
....
|
||
|
||
envp->txn_begin(NULL, txn, <strong class="userinput"><code>DB_TXN_SNAPSHOT</code></strong>);
|
||
|
||
// Remainder of program omitted for brevity.
|
||
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="lockingsubsystem.html">Prev</a> </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="u" href="txnconcurrency.html">Up</a>
|
||
</td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="txn_ccursor.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">The Locking Subsystem </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Transactional Cursors and Concurrent Applications</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</body>
|
||
</html>
|