Import BSDDB 4.7.25 (as of svn r89086)
This commit is contained in:
BIN
docs/gsg_txn/C/BerkeleyDB-Core-C-Txn.pdf
Normal file
BIN
docs/gsg_txn/C/BerkeleyDB-Core-C-Txn.pdf
Normal file
Binary file not shown.
97
docs/gsg_txn/C/abortresults.html
Normal file
97
docs/gsg_txn/C/abortresults.html
Normal file
@@ -0,0 +1,97 @@
|
||||
<?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>Aborting a Transaction</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="usingtxns.html" title="Chapter 3. Transaction Basics" />
|
||||
<link rel="previous" href="usingtxns.html" title="Chapter 3. Transaction Basics" />
|
||||
<link rel="next" href="autocommit.html" title="Auto Commit" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Aborting a Transaction</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="usingtxns.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 3. Transaction Basics</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="autocommit.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="abortresults"></a>Aborting a Transaction</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
When you abort a transaction, all database
|
||||
|
||||
modifications performed
|
||||
under the protection of the transaction are discarded, and all
|
||||
locks currently held by the transaction are released. In this event,
|
||||
your data is simply left in the
|
||||
state that it was in before the transaction began performing data
|
||||
modifications.
|
||||
</p>
|
||||
<p>
|
||||
Note that aborting a transaction may result in disk
|
||||
<span>
|
||||
I/O if your logs are backed by the filesystem.
|
||||
</span>
|
||||
|
||||
It is possible that during the course of your transaction,
|
||||
logging data and/or database
|
||||
<span>pages</span>
|
||||
|
||||
were written to backing files on disk. For this reason, DB
|
||||
notes that the abort occurred in its log files so that at a
|
||||
minimum the database can be brought into a consistent state at
|
||||
recovery time.
|
||||
</p>
|
||||
<p>
|
||||
Also, once you have aborted a transaction, the transaction
|
||||
handle that you used for the transaction is no longer valid. To
|
||||
perform database activities under the control of a new
|
||||
transaction, you must obtain a fresh transactional handle.
|
||||
</p>
|
||||
<p>
|
||||
To abort a transaction, call
|
||||
<span><tt class="methodname">DB_TXN->abort()</tt>.</span>
|
||||
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="usingtxns.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="usingtxns.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="autocommit.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Chapter 3. Transaction Basics </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Auto Commit</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
446
docs/gsg_txn/C/architectrecovery.html
Normal file
446
docs/gsg_txn/C/architectrecovery.html
Normal file
@@ -0,0 +1,446 @@
|
||||
<?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>Designing Your Application for Recovery</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="filemanagement.html" title="Chapter 5. Managing DB Files" />
|
||||
<link rel="previous" href="recovery.html" title="Recovery Procedures" />
|
||||
<link rel="next" href="hotfailover.html" title="Using Hot Failovers" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Designing Your Application for Recovery</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="recovery.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 5. Managing DB Files</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="hotfailover.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="architectrecovery"></a>Designing Your Application for Recovery</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
When building your DB application, you should consider how you will run recovery. If you are building a
|
||||
single threaded, single process application, it is fairly simple to run recovery when your application first
|
||||
opens its environment. In this case, you need only decide if you want to run recovery every time you open
|
||||
your application (recommended) or only some of the time, presumably triggered by a start up option
|
||||
controlled by your application's user.
|
||||
</p>
|
||||
<p>
|
||||
However, for multi-threaded and multi-process applications, you need to carefully consider how you will
|
||||
design your application's startup code so as to run recovery only when it makes sense to do so.
|
||||
</p>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="multithreadrecovery"></a>Recovery for Multi-Threaded Applications</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
If your application uses only one environment handle, then handling recovery for a multi-threaded
|
||||
application is no more difficult than for a single threaded application. You simply open the environment
|
||||
in the application's main thread, and then pass that handle to each of the threads that will be
|
||||
performing DB operations. We illustrate this with our final example in this book (see
|
||||
<a href="txnexample_c.html">Transaction Example</a>
|
||||
|
||||
|
||||
|
||||
for more information).
|
||||
</p>
|
||||
<p>
|
||||
Alternatively, you can have each worker thread open its own environment handle. However, in this case,
|
||||
designing for recovery is a bit more complicated.
|
||||
</p>
|
||||
<p>
|
||||
Generally, when a thread performing database operations fails
|
||||
or hangs, it is frequently best to simply
|
||||
restart the application and run recovery upon application
|
||||
startup as normal. However, not all applications can afford
|
||||
to restart because a single thread has misbehaved.
|
||||
</p>
|
||||
<p>
|
||||
If you are attempting to continue operations in the face of a misbehaving thread,
|
||||
then at a minimum recovery must be run if a thread performing database operations fails or hangs.
|
||||
</p>
|
||||
<p>
|
||||
Remember that recovery clears the environment of all
|
||||
outstanding locks, including any that might be outstanding
|
||||
from an aborted thread. If these locks are not cleared,
|
||||
other threads performing database operations can back up
|
||||
behind the locks obtained but never cleared by the failed
|
||||
thread. The result will be an application that hangs
|
||||
indefinitely.
|
||||
</p>
|
||||
<p>
|
||||
To run recovery under these circumstances:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Suspend or shutdown all other threads performing
|
||||
database operations.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Discarding any open environment handles. Note that
|
||||
attempting to gracefully close these handles may be
|
||||
asking for trouble; the close can fail if the
|
||||
environment is already in need of recovery. For
|
||||
this reason, it is best and easiest to simply discard the handle.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Open new handles, running recovery as you open
|
||||
them.
|
||||
See <a href="recovery.html#normalrecovery">Normal Recovery</a> for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Restart all your database threads.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<p>
|
||||
A traditional way to handle this activity is to spawn a watcher thread that is responsible for making
|
||||
sure all is well with your threads, and performing the above actions if not.
|
||||
</p>
|
||||
<p>
|
||||
However, in the case where each worker thread opens and maintains its own environment handle, recovery
|
||||
is complicated for two reasons:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
For some applications and workloads, it might be
|
||||
worthwhile to give your database threads the
|
||||
ability to gracefully finalize any on-going
|
||||
transactions. If this is the case, your
|
||||
code must be capable of signaling each thread
|
||||
to halt DB activities and close its
|
||||
environment. If you simply run recovery against the
|
||||
environment, your database threads will
|
||||
detect this and fail in the midst of performing their
|
||||
database operations.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Your code must be capable of ensuring only one
|
||||
thread runs recovery before allowing all other
|
||||
threads to open their respective environment
|
||||
handles. Recovery should be single threaded because when
|
||||
recovery is run against an environment, it is
|
||||
deleted and then recreated. This will cause all
|
||||
other processes and threads to "fail" when they
|
||||
attempt operations against the newly recovered
|
||||
environment. If all threads run recovery
|
||||
when they start up, then it is likely that some
|
||||
threads will fail because the environment that they
|
||||
are using has been recovered. This will cause the thread to have to re-execute its own recovery
|
||||
path. At best, this is inefficient and at worst it could cause your application to fall into an
|
||||
endless recovery pattern.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="multiprocessrecovery"></a>Recovery in Multi-Process Applications</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Frequently, DB applications use multiple processes to interact with the databases. For example, you may
|
||||
have a long-running process, such as some kind of server, and then a series of administrative tools that
|
||||
you use to inspect and administer the underlying databases. Or, in some web-based architectures, different
|
||||
services are run as independent processes that are managed by the server.
|
||||
</p>
|
||||
<p>
|
||||
In any case, recovery for a multi-process environment is complicated for two reasons:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
In the event that recovery must be run, you might
|
||||
want to notify processes interacting with the environment
|
||||
that recovery is about to occur and give them a
|
||||
chance to gracefully terminate. Whether it is
|
||||
worthwhile for you to do this is entirely dependent
|
||||
upon the nature of your application. Some
|
||||
long-running applications with multiple processes
|
||||
performing meaningful work might want to do this.
|
||||
Other applications with processes performing database
|
||||
operations that are likely to be harmed by error conditions in other
|
||||
processes will likely find it to be not worth the
|
||||
effort. For this latter group, the chances of
|
||||
performing a graceful shutdown may be low anyway.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Unlike single process scenarios, it can quickly become wasteful for every process interacting
|
||||
with the databases to run recovery when it starts up. This is partly because recovery
|
||||
<span class="emphasis"><em>does</em></span> take some amount of time to run, but mostly you want to
|
||||
avoid a situation where your server must
|
||||
reopen all its environment handles just because you fire up a command line database
|
||||
administrative utility that always runs recovery.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<p>
|
||||
DB offers you two methods by which you can manage recovery for multi-process DB applications.
|
||||
Each has different strengths and weaknesses, and they are described in the next sections.
|
||||
</p>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="mp_recover_effects"></a>Effects of Multi-Process Recovery</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Before continuing, it is worth noting that the following sections describe recovery processes than
|
||||
can result in one process running recovery while other processes are currently actively performing
|
||||
database operations.
|
||||
</p>
|
||||
<p>
|
||||
When this happens, the current database operation will
|
||||
abnormally fail, indicating a DB_RUNRECOVERY condition.
|
||||
This means that your application should immediately abandon any database operations that it may have
|
||||
on-going, discard any environment handles it has opened, and obtain and open new handles.
|
||||
</p>
|
||||
<p>
|
||||
The net effect of this is that any writes performed by unresolved transactions will be lost.
|
||||
For persistent applications (servers, for example), the services it provides will also be
|
||||
unavailable for the amount of time that it takes to complete a recovery and for all participating
|
||||
processes to reopen their environment handles.
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="db_register"></a>Process Registration</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
One way to handle multi-process recovery is for every process to "register" its environment. In
|
||||
doing so, the process gains the ability to see if any other applications are using the
|
||||
environment and, if so, whether they have suffered an abnormal termination. If an abnormal
|
||||
termination is detected, the process runs recovery; otherwise, it does not.
|
||||
</p>
|
||||
<p>
|
||||
Note that using process registration also ensures that
|
||||
recovery is serialized across applications. That is,
|
||||
only one process at a time has a chance to run
|
||||
recovery. Generally this means that the first process
|
||||
to start up will run recovery, and all other processes
|
||||
will silently not run recovery because it is not
|
||||
needed.
|
||||
</p>
|
||||
<p>
|
||||
To cause your application to register its environment, you specify
|
||||
<span>
|
||||
the <tt class="literal">DB_REGISTER</tt> flag when you open your environment.
|
||||
Note that you must also specify <tt class="literal">DB_RECOVER</tt> or
|
||||
<tt class="literal">DB_RECOVER_FATAL</tt> for your environment open.
|
||||
</span>
|
||||
|
||||
|
||||
If during the open, DB determines that recovery must be run, this indicates the type of
|
||||
recovery that is run. If you do not specify either type of recovery, then no recovery is run if
|
||||
the registration process identifies a need for it. In this case, the environment open simply
|
||||
fails by
|
||||
<span>returning <tt class="literal">DB_RUNRECOVERY</tt>.</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Be aware that there are some limitations/requirements if you want your various processes to
|
||||
coordinate recovery using this registration process:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
There can be only one environment handle per
|
||||
environment per process. In the case of multi-threaded
|
||||
processes, the environment handle must be shared across threads.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
All processes sharing the environment must use registration. If registration is
|
||||
not uniformly used across all participating processes, then you can see inconsistent results
|
||||
in terms of your application's ability to recognize that recovery must be run.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
You can not use this mechanism with the <tt class="methodname">failchk()</tt>
|
||||
mechanism
|
||||
described in the next section.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="failchk"></a>Failure Checking</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
For very large and robust multi-process applications, the most common way to ensure all the
|
||||
processes are working as intended is to make use of a watchdog process. To assist a watchdog
|
||||
process, DB offers a failure checking mechanism.
|
||||
</p>
|
||||
<p>
|
||||
When a thread of control fails with open environment handles, the result is that there may be
|
||||
resources left locked or corrupted. Other threads of control may encountered these unavailable resources
|
||||
quickly or not at all, depending on data access patterns.
|
||||
</p>
|
||||
<p>
|
||||
In any case, the DB failure checking mechanism allows a watchdog to detect if an environment is
|
||||
unusable as a result of a thread of control failure. It should be called periodically
|
||||
(for example, once a minute) from the watchdog process. If the environment is deemed unusable, then
|
||||
the watchdog process is notified that recovery should be run. It is then up to the watchdog to
|
||||
actually run recovery. It is also the watchdog's responsibility to decide what to do about currently
|
||||
running processes before running recovery. The watchdog could, for example, attempt to
|
||||
gracefully shutdown or kill all relevant processes before running recovery.
|
||||
</p>
|
||||
<p>
|
||||
Note that failure checking need not be run from a separate process, although conceptually that is
|
||||
how the mechanism is meant to be used. This same mechanism could be used in a multi-threaded
|
||||
application that wants to have a watchdog thread.
|
||||
</p>
|
||||
<p>
|
||||
To use failure checking you must:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
<span>
|
||||
Provide an <tt class="function">is_alive()</tt> call back using the
|
||||
<tt class="methodname">DB_ENV->set_isalive()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
DB uses this method to determine whether a specified process and thread
|
||||
is alive when the failure checking is performed.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Possibly provide a
|
||||
|
||||
<span>
|
||||
<tt class="literal">thread_id</tt> callback
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
that uniquely identifies a process
|
||||
and thread of control. This
|
||||
<span>callback</span>
|
||||
|
||||
is only necessary if the standard process and thread
|
||||
identification functions for your platform are not sufficient to for use by failure
|
||||
checking. This is rarely necessary and is usually because the thread and/or process ids
|
||||
used by your system cannot fit into an unsigned integer.
|
||||
</p>
|
||||
<p>
|
||||
You provide this callback using the
|
||||
<tt class="methodname">DB_ENV->set_thread_id()</tt>
|
||||
|
||||
method. See the API reference for this method for more information on when setting a thread
|
||||
id callback might be necessary.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Call the
|
||||
<tt class="methodname">DB_ENV->failchk()</tt>
|
||||
|
||||
|
||||
method periodically. You can do this either periodically (once per minute, for example), or
|
||||
whenever a thread of control exits for your application.
|
||||
</p>
|
||||
<p>
|
||||
If this method determines that a thread of control exited holding read locks, those locks
|
||||
are automatically released. If the thread of control exited with an unresolved transaction,
|
||||
that transaction is aborted. If any other problems exist beyond these such that the
|
||||
environment must be recovered, the method will
|
||||
<span>return <tt class="literal">DB_RUNRECOVERY</tt>.</span>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<p>
|
||||
Note that this mechanism should not be mixed with the process registration method of multi-process
|
||||
recovery described in the previous section.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="recovery.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="filemanagement.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="hotfailover.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Recovery Procedures </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Using Hot Failovers</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
231
docs/gsg_txn/C/autocommit.html
Normal file
231
docs/gsg_txn/C/autocommit.html
Normal file
@@ -0,0 +1,231 @@
|
||||
<?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>Auto Commit</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="usingtxns.html" title="Chapter 3. Transaction Basics" />
|
||||
<link rel="previous" href="abortresults.html" title="Aborting a Transaction" />
|
||||
<link rel="next" href="nestedtxn.html" title="Nested Transactions" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Auto Commit</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="abortresults.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 3. Transaction Basics</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="nestedtxn.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="autocommit"></a>Auto Commit</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
While transactions are frequently used to provide atomicity to
|
||||
multiple database
|
||||
|
||||
operations, it is sometimes necessary to perform
|
||||
a single database
|
||||
|
||||
operation under the control of a transaction.
|
||||
Rather than force you to obtain a transaction, perform the single
|
||||
write operation, and then either commit or abort the transaction,
|
||||
you can automatically group this sequence of events using
|
||||
<span class="emphasis"><em>auto commit</em></span>.
|
||||
</p>
|
||||
<p>
|
||||
To use auto commit:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Open your environment and your databases
|
||||
|
||||
so that they support
|
||||
transactions. See <a href="enabletxn.html">Enabling Transactions</a>
|
||||
for details.
|
||||
</p>
|
||||
<p>
|
||||
Note that frequently auto commit is used for the environment
|
||||
or database open. To use auto commit for either your
|
||||
environment or database open, specify
|
||||
<tt class="literal">DB_AUTO_COMMIT</tt> to the
|
||||
|
||||
<tt class="methodname">DB_ENV->set_flags()</tt>
|
||||
|
||||
or
|
||||
<tt class="methodname">DB->open()</tt>
|
||||
|
||||
method. If you specify auto commit for the environment
|
||||
open, then you do not need to also specify auto commit
|
||||
for the database open.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Do not provide a transactional handle to the method that is
|
||||
performing the database
|
||||
|
||||
write operation.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<p>
|
||||
Note that auto commit is not available for cursors. You must always
|
||||
open your cursor using a transaction if you want the cursor's
|
||||
operations to be transactional protected. See
|
||||
<a href="txncursor.html">Transactional Cursors</a> for details on using
|
||||
transactional cursors.
|
||||
</p>
|
||||
<p>
|
||||
For example, the following uses auto commit to perform the database write operation:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t db_flags, env_flags;
|
||||
DB *dbp;
|
||||
DB_ENV *envp;
|
||||
DBT key, data;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
const char *file_name = "mydb.db";
|
||||
const char *keystr ="thekey";
|
||||
const char *datastr = "thedata";
|
||||
|
||||
dbp = NULL;
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
env_flags = DB_CREATE | /* Create the environment if it does
|
||||
* not already exist. */
|
||||
DB_INIT_TXN | /* Initialize transactions */
|
||||
DB_INIT_LOCK | /* Initialize locking. */
|
||||
DB_INIT_LOG | /* Initialize logging */
|
||||
DB_INIT_MPOOL; /* Initialize the in-memory cache. */
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database creation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
db_flags = DB_CREATE | DB_AUTO_COMMIT;
|
||||
/*
|
||||
* Open the database. Note that we are using auto commit for the open,
|
||||
* so the database is able to support transactions.
|
||||
*/
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
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 */
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database '%s' open failed",
|
||||
file_name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Prepare the DBTs */
|
||||
memset(&key, 0, sizeof(DBT));
|
||||
memset(&data, 0, sizeof(DBT));
|
||||
|
||||
key.data = &keystr;
|
||||
key.size = strlen(keystr) + 1;
|
||||
data.data = &datastr;
|
||||
data.size = strlen(datastr) + 1;
|
||||
|
||||
|
||||
/*
|
||||
* Perform the database write. A txn handle is not provided, but the
|
||||
* database support auto commit, so auto commit is used for the write.
|
||||
*/
|
||||
ret = dbp->put(dbp, NULL, &key, &data, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database put failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
/* Close the database */
|
||||
if (dbp != NULL) {
|
||||
ret_c = dbp->close(dbp, 0);
|
||||
if (ret_c != 0) {
|
||||
envp->err(envp, ret_c, "Database close failed.");
|
||||
ret = ret_c
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Close the environment */
|
||||
if (envp != NULL) {
|
||||
ret_c = envp->close(envp, 0);
|
||||
if (ret_c != 0) {
|
||||
fprintf(stderr, "environment close failed: %s\n",
|
||||
db_strerror(ret_c));
|
||||
ret = ret_c;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="abortresults.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="usingtxns.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="nestedtxn.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Aborting a Transaction </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Nested Transactions</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
341
docs/gsg_txn/C/backuprestore.html
Normal file
341
docs/gsg_txn/C/backuprestore.html
Normal file
@@ -0,0 +1,341 @@
|
||||
<?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>Backup Procedures</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="filemanagement.html" title="Chapter 5. Managing DB Files" />
|
||||
<link rel="previous" href="filemanagement.html" title="Chapter 5. Managing DB Files" />
|
||||
<link rel="next" href="recovery.html" title="Recovery Procedures" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Backup Procedures</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="filemanagement.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 5. Managing DB Files</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="recovery.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="backuprestore"></a>Backup Procedures</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
<span class="emphasis"><em>Durability</em></span> is an important part of your
|
||||
transactional guarantees. It means that once a transaction has been
|
||||
successfully committed, your application will always see the results of that
|
||||
transaction.
|
||||
</p>
|
||||
<p>
|
||||
Of course, no software algorithm can guarantee durability in the face of physical data loss. Hard drives
|
||||
can fail, and if you have not copied your data to locations other than your primary disk drives,
|
||||
then you will lose data when those drives fail. Therefore, in order to truly obtain a durability
|
||||
guarantee, you need to ensure that any data stored on disk is backed up to secondary or alternative storage,
|
||||
such as secondary disk drives, or offline tapes.
|
||||
</p>
|
||||
<p>
|
||||
There are three different types of backups that you can
|
||||
perform with DB databases and log files. They are:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Offline backups
|
||||
</p>
|
||||
<p>
|
||||
This type of backup is perhaps the easiest to perform as it
|
||||
involves simply copying database and log files to an
|
||||
offline storage area. It also gives you a snapshot of the
|
||||
database at a fixed, known point in time. However, you
|
||||
cannot perform this type of a backup while you are performing
|
||||
writes to the database.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Hot backups
|
||||
</p>
|
||||
<p>
|
||||
This type of backup gives you a snapshot of your database.
|
||||
Since your application can be writing to the database at the time that the
|
||||
snapshot is being taken, you do not necessarily know what
|
||||
the exact state of the database is for that given snapshot.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Incremental backups
|
||||
</p>
|
||||
<p>
|
||||
This type of backup refreshes a previously performed backup.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
Once you have performed a backup, you can
|
||||
perform <span class="emphasis"><em>catastrophic recovery</em></span> to restore
|
||||
your databases from the backup. See
|
||||
<a href="recovery.html#catastrophicrecovery">Catastrophic Recovery</a>
|
||||
for more information.
|
||||
</p>
|
||||
<p>
|
||||
Note that you can also maintain a hot failover. See
|
||||
<a href="hotfailover.html">Using Hot Failovers</a>
|
||||
for more information.
|
||||
</p>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="copyutilities"></a>About Unix Copy Utilities</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
|
||||
If you are copying database files you must copy databases atomically,
|
||||
in multiples of the database page size. In other words, the reads made by
|
||||
the copy program must not be interleaved with writes by
|
||||
other threads of control, and the copy program must read the
|
||||
databases in multiples of the underlying database page size.
|
||||
Generally, this is not a problem because operating systems
|
||||
already make this guarantee and system utilities normally
|
||||
read in power-of-2 sized chunks, which are larger than the
|
||||
largest possible Berkeley DB database page size.
|
||||
</p>
|
||||
<p>
|
||||
On some platforms (most notably, some releases of Solaris), the copy utility (<tt class="literal">cp</tt>) was
|
||||
implemented using the <tt class="function">mmap()</tt> system call rather than the
|
||||
<tt class="function">read()</tt> system call. Because <tt class="function">mmap()</tt> did not make the same
|
||||
guarantee of read atomicity as did <tt class="function">read()</tt>, the <tt class="literal">cp</tt> utility
|
||||
could create corrupted copies of the databases.
|
||||
</p>
|
||||
<p>
|
||||
Also, some platforms have implementations of the <tt class="literal">tar</tt> utility that performs 10KB block
|
||||
reads by default. Even when an output block size is specified, the utility will still not read the
|
||||
underlying databases in multiples of the specified block size. Again, the result can be a corrupted backup.
|
||||
</p>
|
||||
<p>
|
||||
To fix these problems, use the <tt class="literal">dd</tt> utility instead of <tt class="literal">cp</tt> or
|
||||
<tt class="literal">tar</tt>. When you use <tt class="literal">dd</tt>, make sure you specify a block size that is
|
||||
equal to, or an even multiple of, your database page size. Finally, if you plan to use a system
|
||||
utility to copy database files, you may want to use a system call trace utility (for example,
|
||||
<tt class="literal">ktrace</tt> or <tt class="literal">truss</tt>) to make sure you are not using a I/O size that is
|
||||
smaller than your database page size. You can also use these utilities to make sure the system utility is
|
||||
not using a system call other than <tt class="function">read()</tt>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="standardbackup"></a>Offline Backups</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
To create an offline backup:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Commit or abort all on-going transactions.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Pause all database writes.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Force a checkpoint. See
|
||||
<a href="filemanagement.html#checkpoints">Checkpoints</a>
|
||||
for details.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Copy all your database files to the backup location.
|
||||
<span>
|
||||
Note that you can simply copy all of the database
|
||||
files, or you can determine which database files
|
||||
have been written during the lifetime of the current
|
||||
logs. To do this, use either the
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->log_archive()</tt>
|
||||
|
||||
method with the <tt class="literal">DB_ARCH_DATA</tt>
|
||||
option,
|
||||
</span>
|
||||
|
||||
|
||||
or use the <span><b class="command">db_archive</b></span>
|
||||
command with the <tt class="literal">-s</tt> option.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
However, be aware that backing up just the modified databases only works if you have all of your
|
||||
log files. If you have been removing log files for any reason then using
|
||||
<span>
|
||||
<tt class="methodname">log_archive()</tt>
|
||||
</span>
|
||||
|
||||
|
||||
can result in an
|
||||
unrecoverable backup because you might not be notified of a database file that was modified.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Copy the <span class="emphasis"><em>last</em></span> log file to your backup location.
|
||||
Your log files are named
|
||||
<tt class="literal">log.<span class="emphasis"><em>xxxxxxxxxx</em></span></tt>,
|
||||
where <span class="emphasis"><em>xxxxxxxxxx</em></span> is a
|
||||
sequential number. The last log file is the file
|
||||
with the highest number.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="hotbackup"></a>Hot Backup</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
To create a hot backup, you do not have to stop database
|
||||
operations. Transactions may be on-going and you can be writing
|
||||
to your database at the time of the backup. However, this means
|
||||
that you do not know exactly what the state of your database is
|
||||
at the time of the backup.
|
||||
</p>
|
||||
<p>
|
||||
You can use the <span><b class="command">db_hotbackup</b></span> command line utility to create a hot backup for you. This
|
||||
utility will (optionally) run a checkpoint and the copy all necessary files to a target directory.
|
||||
</p>
|
||||
<p>
|
||||
Alternatively, you can manually create a hot backup as follows:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Copy all your database files to the backup location.
|
||||
<span>
|
||||
Note that you can simply copy all of the database
|
||||
files, or you can determine which database files
|
||||
have been written during the lifetime of the current
|
||||
logs. To do this, use either the
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->log_archive()</tt>
|
||||
|
||||
with the <tt class="literal">DB_ARCH_DATA</tt>
|
||||
option,
|
||||
</span>
|
||||
|
||||
|
||||
or use the <span><b class="command">db_archive</b></span>
|
||||
command with the <tt class="literal">-s</tt> option.
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Copy all logs to your backup location.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
It is important to copy your database files <span class="emphasis"><em>and
|
||||
then</em></span> your logs. In this way,
|
||||
you can complete or roll back any database operations that were only partially completed
|
||||
when you copied the databases.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="incrementalbackups"></a>Incremental Backups</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Once you have created a full backup (that is, either a
|
||||
offline or hot backup), you can create incremental backups.
|
||||
To do this, simply copy all of your currently existing log
|
||||
files to your backup location.
|
||||
</p>
|
||||
<p>
|
||||
Incremental backups do not require you to run a checkpoint
|
||||
or to cease database write operations.
|
||||
</p>
|
||||
<p>
|
||||
When you are working with incremental backups, remember
|
||||
that the greater the number of log files contained in
|
||||
your backup, the longer recovery will take.
|
||||
You should run full backups
|
||||
on some interval, and then do incremental backups on a shorter interval.
|
||||
How frequently you need to run a full backup
|
||||
is determined by the rate at which your databases change and
|
||||
how sensitive your application is to lengthy recoveries
|
||||
(should one be required).
|
||||
</p>
|
||||
<p>
|
||||
You can also shorten recovery time by running recovery against the backup as you take each incremental
|
||||
backup. Running recovery as you go means that there will be less work for DB to do if you should
|
||||
ever need to restore your environment from the backup.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="filemanagement.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="filemanagement.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="recovery.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Chapter 5. Managing DB Files </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Recovery Procedures</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
691
docs/gsg_txn/C/blocking_deadlocks.html
Normal file
691
docs/gsg_txn/C/blocking_deadlocks.html
Normal file
@@ -0,0 +1,691 @@
|
||||
<?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>Locks, Blocks, and Deadlocks</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||||
<link rel="previous" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||||
<link rel="next" href="lockingsubsystem.html" title="The Locking Subsystem" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Locks, Blocks, and Deadlocks</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="txnconcurrency.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 4. Concurrency</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="lockingsubsystem.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="blocking_deadlocks"></a>Locks, Blocks, and Deadlocks</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
It is important to understand how locking works in a
|
||||
concurrent application before continuing with a description of
|
||||
the concurrency mechanisms DB makes available to you.
|
||||
Blocking and deadlocking have important performance implications
|
||||
for your application. Consequently, this section provides a
|
||||
fundamental description of these concepts, and how they affect
|
||||
DB operations.
|
||||
</p>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="locks"></a>Locks</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
When one thread of control wants to obtain access to an
|
||||
object, it requests a <span class="emphasis"><em>lock</em></span> for that
|
||||
object. This lock is what allows DB to provide your
|
||||
application with its transactional isolation guarantees by
|
||||
ensuring that:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
no other thread of control can read that object (in
|
||||
the case of an exclusive lock), and
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
no other thread of control can modify that object
|
||||
(in the case of an exclusive or non-exclusive lock).
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="lockresources"></a>Lock Resources</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
When locking occurs, there are conceptually three resources
|
||||
in use:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
The locker.
|
||||
</p>
|
||||
<p>
|
||||
This is the thing that holds the lock. In a
|
||||
transactional application, the locker is a
|
||||
transaction handle.
|
||||
<span>
|
||||
For non-transactional operations, the locker is a cursor or a
|
||||
<span>DB</span>
|
||||
|
||||
|
||||
|
||||
handle.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
The lock.
|
||||
</p>
|
||||
<p>
|
||||
This is the actual data structure that locks
|
||||
the object. In DB, a locked
|
||||
object structure in the lock manager
|
||||
is representative of the object that
|
||||
is locked.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
The locked object.
|
||||
</p>
|
||||
<p>
|
||||
The thing that your application
|
||||
actually wants to lock.
|
||||
In a DB
|
||||
application, the locked object is usually a
|
||||
<span>
|
||||
database page, which in turn contains
|
||||
multiple database entries (key and data).
|
||||
<span>
|
||||
However, for Queue databases,
|
||||
individual database records are locked.
|
||||
</span>
|
||||
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<p>
|
||||
You can configure how many total lockers, locks,
|
||||
and locked objects your
|
||||
application is allowed to support. See
|
||||
<a href="lockingsubsystem.html#configuringlock">Configuring the Locking Subsystem</a>
|
||||
for details.
|
||||
</p>
|
||||
<p>
|
||||
The following figure shows a transaction handle,
|
||||
<tt class="literal">Txn A</tt>, that is holding a lock on
|
||||
database
|
||||
<span>page</span>
|
||||
|
||||
<tt class="literal">002</tt>. In this graphic, <tt class="literal">Txn
|
||||
A</tt> is the locker, and the locked object is
|
||||
<span>page</span>
|
||||
|
||||
<tt class="literal">002</tt>. Only a single lock is in use
|
||||
in this operation.
|
||||
</p>
|
||||
<div class="mediaobject">
|
||||
<img src="simplelock.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="locktypes"></a>Types of Locks</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
DB applications support both exclusive and
|
||||
non-exclusive locks. <span class="emphasis"><em>Exclusive
|
||||
locks</em></span> are granted when a
|
||||
locker wants to write to an object. For this reason,
|
||||
exclusive locks are also sometimes called
|
||||
<span class="emphasis"><em>write locks</em></span>.
|
||||
</p>
|
||||
<p>
|
||||
An exclusive lock prevents any other locker from
|
||||
obtaining any sort of a lock on the object. This
|
||||
provides isolation by ensuring that no other locker can
|
||||
observe or modify an exclusively locked object until the locker is done
|
||||
writing to that object.
|
||||
</p>
|
||||
<p>
|
||||
<span class="emphasis"><em>Non-exclusive locks</em></span> are granted
|
||||
for read-only access. For this reason, non-exclusive
|
||||
locks are also sometimes called <span class="emphasis"><em>read
|
||||
locks</em></span>. Since multiple lockers can
|
||||
simultaneously hold read locks on the same
|
||||
object, read locks are also
|
||||
sometimes called <span class="emphasis"><em>shared locks</em></span>.
|
||||
</p>
|
||||
<p>
|
||||
A non-exclusive lock prevents any other locker from
|
||||
modifying the locked object while the locker is still
|
||||
reading the object. This is how transactional cursors are able to
|
||||
achieve repeatable reads; by default, the
|
||||
cursor's transaction holds
|
||||
a read lock on any object that the cursor has examined until
|
||||
such a time as the transaction is committed
|
||||
or aborted.
|
||||
<span>
|
||||
You can avoid these read locks by using
|
||||
snapshot isolation. See <a href="isolation.html#snapshot_isolation">Using Snapshot Isolation</a>
|
||||
for details.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
In the following figure, <tt class="literal">Txn A</tt> and
|
||||
<tt class="literal">Txn B</tt> are both holding read locks on
|
||||
<span>page</span>
|
||||
|
||||
<tt class="literal">002</tt>, while <tt class="literal">Txn C</tt>
|
||||
is holding a write lock on
|
||||
<span>page</span>
|
||||
|
||||
<tt class="literal">003</tt>:
|
||||
</p>
|
||||
<div class="mediaobject">
|
||||
<img src="rwlocks1.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="locklifetime"></a>Lock Lifetime</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
A locker holds its locks until such a time as it does
|
||||
not need the lock any more. What this means is:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
A transaction holds any locks that it obtains
|
||||
until the transaction is committed or aborted.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
All non-transaction operations hold locks
|
||||
until such a time as the operation is completed.
|
||||
For cursor operations, the lock is held until the cursor is moved to a new position or
|
||||
closed.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="blocks"></a>Blocks</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Simply put, a thread of control is blocked when it attempts
|
||||
to obtain a lock, but that attempt is denied because some
|
||||
other thread of control holds a conflicting lock.
|
||||
Once blocked, the thread of control is temporarily unable
|
||||
to make any forward progress until the requested lock is
|
||||
obtained or the operation requesting the lock is
|
||||
abandoned.
|
||||
</p>
|
||||
<p>
|
||||
Be aware that when we talk about blocking, strictly
|
||||
speaking the thread is not what is attempting to obtain the
|
||||
lock. Rather, some object within the thread (such as a
|
||||
cursor) is attempting to obtain the
|
||||
lock. However, once a locker attempts to
|
||||
obtain a lock, the entire thread of control must pause until the lock
|
||||
request is in some way resolved.
|
||||
</p>
|
||||
<p>
|
||||
For example, if <tt class="literal">Txn A</tt> holds a write lock (an exclusive
|
||||
lock) on
|
||||
<span>object</span>
|
||||
|
||||
002, then if <tt class="literal">Txn B</tt> tries to obtain a read <span class="emphasis"><em>or</em></span> write lock on
|
||||
that
|
||||
<span>object,</span>
|
||||
|
||||
the thread of control in which <tt class="literal">Txn
|
||||
B</tt> is running
|
||||
is blocked:
|
||||
</p>
|
||||
<div class="mediaobject">
|
||||
<img src="writeblock.jpg" />
|
||||
</div>
|
||||
<p>
|
||||
However, if <tt class="literal">Txn A</tt> only holds a read
|
||||
lock (a shared lock) on
|
||||
<span>object</span>
|
||||
|
||||
<tt class="literal">002</tt>, then only those handles that attempt to obtain a
|
||||
write lock on that
|
||||
<span>object</span>
|
||||
|
||||
will block.
|
||||
</p>
|
||||
<div class="mediaobject">
|
||||
<img src="readblock.jpg" />
|
||||
</div>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
The previous description describes DB's default
|
||||
behavior when it cannot obtain a lock. It is
|
||||
possible to configure DB transactions so that
|
||||
they will not block. Instead, if a lock is
|
||||
unavailable, the application is immediately notified of a
|
||||
deadlock situation. See <a href="txnnowait.html">No Wait on Blocks</a>
|
||||
for more information.
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="blockperformance"></a>Blocking and Application Performance</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Multi-threaded
|
||||
<span>
|
||||
and multi-process
|
||||
</span>
|
||||
applications typically perform better than simple
|
||||
single-threaded applications because the
|
||||
application can perform one part of its workload
|
||||
(updating
|
||||
<span>a database record, </span>
|
||||
|
||||
for example) while it is waiting for some other
|
||||
lengthy operation to complete (performing disk or
|
||||
network I/O, for example). This performance
|
||||
improvement is particularly noticeable if you use
|
||||
hardware that offers multiple CPUs, because the threads
|
||||
<span>
|
||||
and processes
|
||||
</span>
|
||||
can run simultaneously.
|
||||
</p>
|
||||
<p>
|
||||
That said, concurrent applications can see reduced
|
||||
workload throughput if their threads of control are
|
||||
seeing a large amount of lock contention. That is,
|
||||
if threads are blocking on lock requests, then that
|
||||
represents a performance penalty for your
|
||||
application.
|
||||
</p>
|
||||
<p>
|
||||
Consider once again the previous diagram of a blocked write lock request.
|
||||
In that diagram, <tt class="literal">Txn C</tt> cannot
|
||||
obtain its requested write lock because
|
||||
<tt class="literal">Txn A</tt> and <tt class="literal">Txn
|
||||
B</tt> are both already holding read locks on
|
||||
the requested
|
||||
<span>object.</span>
|
||||
|
||||
In this case, the thread in which
|
||||
<tt class="literal">Txn C</tt> is running will pause until
|
||||
such a time as <tt class="literal">Txn C</tt> either
|
||||
obtains its write lock, or the operation
|
||||
that is requesting the lock is abandoned.
|
||||
The fact that <tt class="literal">Txn
|
||||
C</tt>'s thread has temporarily halted all
|
||||
forward progress represents a performance penalty
|
||||
for your application.
|
||||
</p>
|
||||
<p>
|
||||
Moreover, any read locks that are requested while
|
||||
<tt class="literal">Txn C</tt> is waiting for its write
|
||||
lock will also block until such a time as
|
||||
<tt class="literal">Txn C</tt> has obtained and
|
||||
subsequently released its write lock.
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="blockavoidance"></a>Avoiding Blocks</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Reducing lock contention is an important part of
|
||||
performance tuning your concurrent DB
|
||||
application. Applications that have multiple
|
||||
threads of control obtaining exclusive (write)
|
||||
locks are prone to contention issues. Moreover, as
|
||||
you increase the numbers of lockers and as you
|
||||
increase the time that a lock is held, you increase
|
||||
the chances of your application seeing lock contention.
|
||||
</p>
|
||||
<p>
|
||||
As you are designing your application, try to do
|
||||
the following in order to reduce lock contention:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Reduce the length of time your application
|
||||
holds locks.
|
||||
</p>
|
||||
<p>
|
||||
Shorter lived transactions will result in
|
||||
shorter lock lifetimes, which will in turn
|
||||
help to reduce lock contention.
|
||||
</p>
|
||||
<p>
|
||||
In addition, by default transactional cursors hold read
|
||||
locks until such a time as the transaction is completed.
|
||||
For this reason, try to minimize the time you keep
|
||||
transactional cursors opened, or reduce your isolation
|
||||
levels – see below.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
If possible, access heavily accessed (read
|
||||
or write) items toward the end of the
|
||||
transaction. This reduces the amount of
|
||||
time that a heavily used
|
||||
<span>
|
||||
page
|
||||
</span>
|
||||
|
||||
is locked by the transaction.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Reduce your application's isolation guarantees.
|
||||
</p>
|
||||
<p>
|
||||
By reducing your isolation guarantees, you
|
||||
reduce the situations in which a lock can
|
||||
block another lock. Try using uncommitted reads
|
||||
for your read operations in order to
|
||||
prevent a read lock being blocked by a
|
||||
write lock.
|
||||
</p>
|
||||
<p>
|
||||
In addition, for cursors you can use degree
|
||||
2 (read committed) isolation, which causes
|
||||
the cursor to release its read locks as
|
||||
soon as it is done reading the record (as
|
||||
opposed to holding its read locks until the
|
||||
transaction ends).
|
||||
</p>
|
||||
<p>
|
||||
Be aware that reducing your
|
||||
isolation guarantees can have
|
||||
adverse consequences for your
|
||||
application. Before deciding
|
||||
to reduce your isolation, take
|
||||
care to examine your
|
||||
application's isolation
|
||||
requirements.
|
||||
For information on isolation
|
||||
levels, see
|
||||
<a href="isolation.html">Isolation</a>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Use snapshot isolation for
|
||||
read-only threads.
|
||||
</p>
|
||||
<p>
|
||||
Snapshot isolation causes the
|
||||
transaction to make a copy of the
|
||||
page on which it is holding a lock.
|
||||
When a reader makes a copy of a
|
||||
page, write locks can still be
|
||||
obtained for the original page.
|
||||
This eliminates entirely read-write
|
||||
contention.
|
||||
</p>
|
||||
<p>
|
||||
Snapshot isolation is described in
|
||||
<a href="isolation.html#snapshot_isolation">Using Snapshot Isolation</a>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Consider your data access patterns.
|
||||
</p>
|
||||
<p>
|
||||
Depending on the nature of your application,
|
||||
this may be something that you can not
|
||||
do anything about. However, if it is
|
||||
possible to create your threads such that
|
||||
they operate only on non-overlapping
|
||||
portions of your database, then you can
|
||||
reduce lock contention because your
|
||||
threads will rarely (if ever) block on one another's
|
||||
locks.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
It is possible to configure DB's transactions
|
||||
so that they never wait on blocked lock requests.
|
||||
Instead, if they are blocked on a lock request,
|
||||
they will notify the application of a deadlock (see
|
||||
the next section).
|
||||
</p>
|
||||
<p>
|
||||
You configure this behavior on a transaction by
|
||||
transaction basis. See <a href="txnnowait.html">No Wait on Blocks</a> for more information.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="deadlocks"></a>Deadlocks</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
A deadlock occurs when two or more threads of control are
|
||||
blocked, each waiting on a resource held by the other
|
||||
thread. When this happens, there is no
|
||||
possibility of the threads ever making forward progress
|
||||
unless some outside agent takes action to break the
|
||||
deadlock.
|
||||
</p>
|
||||
<p>
|
||||
For example, if
|
||||
<tt class="literal">Txn A</tt> is
|
||||
blocked by <tt class="literal">Txn B</tt> at the same time
|
||||
<tt class="literal">Txn B</tt> is blocked by <tt class="literal">Txn
|
||||
A</tt> then the threads of control containing
|
||||
<tt class="literal">Txn A</tt> and <tt class="literal">Txn B</tt> are
|
||||
deadlocked; neither thread can make
|
||||
any forward progress because neither thread will ever release the lock
|
||||
that is blocking the other thread.
|
||||
</p>
|
||||
<div class="mediaobject">
|
||||
<img src="deadlock.jpg" />
|
||||
</div>
|
||||
<p>
|
||||
When two threads of control deadlock, the only
|
||||
solution is to have a mechanism external to the two threads
|
||||
capable of recognizing the deadlock and notifying at least
|
||||
one thread that it is in a deadlock situation.
|
||||
Once notified, a thread of
|
||||
control must abandon the attempted operation in order to
|
||||
resolve the deadlock.
|
||||
|
||||
<span>
|
||||
DB's locking subsystem offers a deadlock notification
|
||||
mechanism. See
|
||||
<a href="lockingsubsystem.html#configdeadlkdetect">Configuring Deadlock Detection</a>
|
||||
for more information.
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Note that when one locker in a thread of control is blocked
|
||||
waiting on a lock held by another locker in that same
|
||||
thread of the control, the thread is said to be
|
||||
<span class="emphasis"><em>self-deadlocked</em></span>.
|
||||
</p>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="deadlockavoidance"></a>Deadlock Avoidance</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
The things that you do to avoid lock contention also
|
||||
help to reduce deadlocks (see <a href="blocking_deadlocks.html#blockavoidance">Avoiding Blocks</a>).
|
||||
|
||||
<span>
|
||||
Beyond that, you can also do the following in order to
|
||||
avoid deadlocks:
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Make sure all threads access data in the same
|
||||
order as all other threads. So long as threads
|
||||
lock database pages
|
||||
in the same basic order, there is no
|
||||
possibility of a deadlock (threads can still
|
||||
block, however).
|
||||
</p>
|
||||
<p>
|
||||
Be aware that if you are using secondary databases (indices), it is not possible to obtain
|
||||
locks in a consistent order because you cannot predict the order in which locks are obtained
|
||||
in secondary databases. If you are writing a concurrent application and you are using
|
||||
secondary databases, you must be prepared to handle deadlocks.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
If you are using BTrees in which you are
|
||||
constantly adding and then deleting data, turn
|
||||
Btree reverse split off. See
|
||||
<a href="reversesplit.html">Reverse BTree Splits</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Declare a read/modify/write lock for those
|
||||
situations where you are reading a record in
|
||||
preparation of modifying and then writing the
|
||||
record. Doing this causes DB to give your
|
||||
read operation a write lock. This means that no
|
||||
other thread of control can share a read lock
|
||||
(which might cause contention), but it also
|
||||
means that the writer thread will not have to
|
||||
wait to obtain a write lock when it is ready to
|
||||
write the modified data back to the database.
|
||||
</p>
|
||||
<p>
|
||||
For information on declaring
|
||||
read/modify/write locks, see
|
||||
<a href="readmodifywrite.html">Read/Modify/Write</a>.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="txnconcurrency.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="lockingsubsystem.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Chapter 4. Concurrency </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> The Locking Subsystem</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
docs/gsg_txn/C/deadlock.jpg
Normal file
BIN
docs/gsg_txn/C/deadlock.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
938
docs/gsg_txn/C/enabletxn.html
Normal file
938
docs/gsg_txn/C/enabletxn.html
Normal file
@@ -0,0 +1,938 @@
|
||||
<?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>Chapter 2. Enabling Transactions</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="previous" href="perftune-intro.html" title="Performance Tuning" />
|
||||
<link rel="next" href="envopen.html" title="Opening a Transactional Environment and Database " />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Chapter 2. Enabling Transactions</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="perftune-intro.html">Prev</a> </td>
|
||||
<th width="60%" align="center"> </th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="envopen.html">Next</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="chapter" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title"><a id="enabletxn"></a>Chapter 2. Enabling Transactions</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="toc">
|
||||
<p>
|
||||
<b>Table of Contents</b>
|
||||
</p>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="enabletxn.html#environments">Environments</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="enabletxn.html#filenaming">File Naming</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="enabletxn.html#errorsupport">Error Support</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="enabletxn.html#sharedmemory">Shared Memory Regions</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="enabletxn.html#security">Security Considerations</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="envopen.html">Opening a Transactional Environment and
|
||||
Database
|
||||
|
||||
|
||||
</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</div>
|
||||
<p>
|
||||
In order to use transactions with your application, you must turn them
|
||||
on. To do this you must:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Use an
|
||||
environment (see <a href="enabletxn.html#environments">Environments</a> for details).
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Turn on transactions for your environment.
|
||||
|
||||
|
||||
|
||||
<span>
|
||||
You do this by providing the <tt class="literal">DB_INIT_TXN</tt>
|
||||
flag to the
|
||||
|
||||
<tt class="methodname">DB_ENV->open()</tt>
|
||||
method.
|
||||
</span>
|
||||
|
||||
<span>
|
||||
Note that initializing the transactional subsystem implies that
|
||||
the logging subsystem is also initialized. Also, note that
|
||||
if you do not initialize transactions when you first create
|
||||
your environment, then you cannot use transactions for that
|
||||
environment after that. This is because DB
|
||||
allocates certain structures needed for transactional
|
||||
locking that are not available if the environment is
|
||||
created without transactional support.
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Initialize the in-memory cache by
|
||||
<span>
|
||||
passing the <tt class="literal">DB_INIT_MPOOL</tt>
|
||||
flag to the
|
||||
|
||||
<tt class="methodname">DB_ENV->open()</tt>
|
||||
method.
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Initialize the locking subsystem. This is what provides locking for concurrent applications. It also is used
|
||||
to perform deadlock detection. See <a href="txnconcurrency.html">Concurrency</a>
|
||||
for more information.
|
||||
</p>
|
||||
<p>
|
||||
You initialize the locking subsystem by
|
||||
<span>
|
||||
passing the <tt class="literal">DB_INIT_LOCK</tt>
|
||||
flag to the
|
||||
|
||||
<tt class="methodname">DB_ENV->open()</tt>
|
||||
method.
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Initialize the logging subsystem. While this is enabled by
|
||||
default for transactional applications, we suggest that
|
||||
you explicitly initialize it anyway for the purposes of code readability. The logging
|
||||
subsystem is what provides your transactional application its durability guarantee, and it is required for
|
||||
recoverability purposes. See <a href="filemanagement.html">Managing DB Files</a>
|
||||
for more information.
|
||||
</p>
|
||||
<p>
|
||||
You initialize the logging subsystem by
|
||||
<span>
|
||||
passing the <tt class="literal">DB_INIT_LOG</tt>
|
||||
flag to the
|
||||
|
||||
<tt class="methodname">DB_ENV->open()</tt>
|
||||
method.
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span>
|
||||
Transaction-enable your databases.
|
||||
</span>
|
||||
<span>
|
||||
If you are using the base API, transaction-enable your databases.
|
||||
</span>
|
||||
You do this by
|
||||
|
||||
|
||||
<span>
|
||||
encapsulating the database open in a transaction.
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
<span>
|
||||
Note that the common practice is for auto commit to be used to
|
||||
transaction-protect the database open. To use auto-commit, you
|
||||
must still enable transactions as described here, but you do
|
||||
not have to explicitly use a transaction when you open your
|
||||
database. An example of this is given in the next section.
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sect1" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title" style="clear: both"><a id="environments"></a>Environments</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
For simple DB applications, environments are optional. However, in
|
||||
order to transaction protect your database operations, you must use an
|
||||
environment.
|
||||
</p>
|
||||
<p>
|
||||
An <span class="emphasis"><em>environment</em></span>, represents an
|
||||
encapsulation of one or more databases and any associated log and
|
||||
region files. They are used to support multi-threaded
|
||||
and multi-process applications by allowing different threads of
|
||||
control to share the in-memory cache, the locking tables, the
|
||||
logging subsystem, and the file namespace. By sharing these things,
|
||||
your concurrent application is more efficient than if each thread
|
||||
of control had to manage these resources on its own.
|
||||
</p>
|
||||
<p>
|
||||
By default all DB databases are backed by files on disk. In
|
||||
addition to these files, transactional DB applications create
|
||||
logs that are also by default stored on disk (they can optionally
|
||||
be backed using shared memory). Finally, transactional
|
||||
DB applications also create and use shared-memory regions that
|
||||
are also typically backed by the filesystem. But like databases and
|
||||
logs, the regions can be maintained strictly in-memory if your
|
||||
application requires it. For an example of an application that
|
||||
manages all environment files in-memory, see
|
||||
<span><a href="inmem_txnexample_c.html">In-Memory Transaction Example</a>.</span>
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="filenaming"></a>File Naming</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
In order to operate, your DB application must be able to
|
||||
locate its database files, log files, and region files. If these
|
||||
are stored in the filesystem, then you must tell DB where
|
||||
they are located (a number of mechanisms exist that allow you to
|
||||
identify the location of these files – see below). Otherwise,
|
||||
by default they are located in the current working directory.
|
||||
</p>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="envhome"></a>Specifying the Environment Home Directory</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
The environment home directory is used to determine where
|
||||
DB files are located. Its location
|
||||
is identified using one of the following mechanisms, in the
|
||||
following order of priority:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
If no information is given as to where to put the
|
||||
environment home, then the current working
|
||||
directory is used.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
If a home directory is specified on the
|
||||
<tt class="methodname">DB_ENV->open()</tt>
|
||||
|
||||
|
||||
<span>method,</span>
|
||||
|
||||
then that location is always used for the environment
|
||||
home.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
If a home directory is not supplied to
|
||||
<span><tt class="methodname">DB_ENV->open()</tt>, </span>
|
||||
|
||||
|
||||
then the directory identified by the <tt class="literal">DB_HOME</tt> environment variable
|
||||
is used <span class="emphasis"><em>if</em></span> you specify
|
||||
<span>
|
||||
either the <tt class="literal">DB_USE_ENVIRON</tt> or
|
||||
<tt class="literal">DB_USE_ENVIRON_ROOT</tt> flags to the
|
||||
<tt class="methodname">DB_ENV->open()</tt>
|
||||
|
||||
method. Both flags allow you to identify the
|
||||
path to the environment's home directory
|
||||
using the <tt class="literal">DB_HOME</tt> environment variable. However,
|
||||
<tt class="literal">DB_USE_ENVIRON_ROOT</tt> is honored only if the
|
||||
process is run with root or administrative privileges.
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="filelocation"></a>Specifying File Locations</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
By default, all DB files are created relative to the environment
|
||||
home directory. For example, suppose your environment home is in
|
||||
<tt class="literal">/export/myAppHome</tt>. Also suppose you name your database
|
||||
<span><tt class="literal">data/myDatabase.db</tt>.</span>
|
||||
|
||||
Then in this case, the database is placed in:
|
||||
<span><tt class="literal">/export/myAppHome/data/myDatabase.db</tt>.</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
That said, DB always defers to absolute pathnames.
|
||||
This means that if you provide an absolute filename when you
|
||||
name your database, then that file is <span class="emphasis"><em>not</em></span>
|
||||
placed relative to the environment home directory. Instead, it
|
||||
is placed in the exact location that you specified for the
|
||||
filename.
|
||||
</p>
|
||||
<p>
|
||||
On UNIX systems, an absolute pathname is a name that begins with a
|
||||
forward slash ('/'). On Windows systems, an absolute pathname is a
|
||||
name that begins with one of the following:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
A backslash ('\').
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Any alphabetic letter, followed by a colon (':'), followed
|
||||
by a backslash ('\').
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
Try not to use absolute path names for your
|
||||
environment's files. Under certain recovery scenarios, absolute path names can
|
||||
render your environment unrecoverable. This occurs if you are attempting to recover
|
||||
you environment on a system that does not support the absolute path name that you used.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="splittingdata"></a>Identifying Specific File Locations</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
As described in the previous sections, DB will place all its
|
||||
files in or relative to the environment home directory.
|
||||
You can also cause a
|
||||
specific database file to be placed in a particular location by
|
||||
using an absolute path name for its name. In this
|
||||
situation, the environment's home directory is not
|
||||
considered when naming the file.
|
||||
</p>
|
||||
<p>
|
||||
It is frequently desirable to place database, log, and region files on separate
|
||||
disk drives. By spreading I/O across multiple drives, you
|
||||
can increase parallelism and improve throughput.
|
||||
Additionally, by placing log files and database files on
|
||||
separate drives, you improve your application's
|
||||
reliability by providing your application with a greater
|
||||
chance of surviving a disk failure.
|
||||
</p>
|
||||
<p>
|
||||
You can cause DB's files to be placed in specific
|
||||
locations using the following mechanisms:
|
||||
</p>
|
||||
<div class="informaltable">
|
||||
<table border="1" width="80%">
|
||||
<colgroup>
|
||||
<col />
|
||||
<col />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>File Type</th>
|
||||
<th>To Override</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>database files</td>
|
||||
<td>
|
||||
<p>
|
||||
You can cause database files to be created
|
||||
in a directory other than the
|
||||
environment home by using the
|
||||
<tt class="methodname">DB_ENV->set_data_dir()</tt>
|
||||
|
||||
|
||||
method.
|
||||
The directory identified
|
||||
here must exist. If a relative path is
|
||||
provided, then the directory location is
|
||||
resolved relative to the environment's home
|
||||
directory.
|
||||
</p>
|
||||
<p>
|
||||
This method modifies the directory
|
||||
used for database files created and managed by
|
||||
a single environment handle; it does not
|
||||
configure the entire environment.
|
||||
<span>This
|
||||
method may not be called after the
|
||||
environment has been opened.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
You can also set a default data location that is used by
|
||||
the entire environment by using the
|
||||
<tt class="literal">set_data_dir</tt> parameter
|
||||
in the environment's <tt class="literal">DB_CONFIG</tt> file.
|
||||
Note that the <tt class="literal">set_data_dir</tt>
|
||||
parameter overrides any value set by the
|
||||
<tt class="methodname">DB_ENV->set_data_dir()</tt>
|
||||
|
||||
|
||||
method.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Log files</td>
|
||||
<td>
|
||||
<p>
|
||||
You can cause log files to be created
|
||||
in a directory other than the environment home
|
||||
directory by using the
|
||||
<tt class="methodname">DB_ENV->set_lg_dir()</tt>
|
||||
|
||||
|
||||
method. The directory identified
|
||||
here must exist. If a relative path is
|
||||
provided, then the directory location is
|
||||
resolved relative to the environment's home
|
||||
directory.
|
||||
</p>
|
||||
<p>
|
||||
This method modifies the directory
|
||||
used for database files created and managed by
|
||||
a single environment handle; it does not
|
||||
configure the entire environment.
|
||||
<span>This
|
||||
method may not be called after the
|
||||
environment has been opened.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
You can also set a default log file location that is used by
|
||||
the entire environment by using the
|
||||
<tt class="literal">set_lg_dir</tt> parameter
|
||||
in the environment's <tt class="literal">DB_CONFIG</tt> file.
|
||||
Note that the <tt class="literal">set_lg_dir</tt>
|
||||
parameter overrides any value set by the
|
||||
<tt class="methodname">DB_ENV->set_lg_dir()</tt>
|
||||
|
||||
|
||||
method.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Region files</td>
|
||||
<td>
|
||||
If backed by the filesystem, region
|
||||
files are always placed in the environment home
|
||||
directory.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>
|
||||
Note that the <tt class="literal">DB_CONFIG</tt> must reside in the
|
||||
environment home directory. Parameters are specified in it one
|
||||
parameter to a line. Each parameter is followed by a space,
|
||||
which is followed by the parameter value. For example:
|
||||
</p>
|
||||
<pre class="programlisting"> set_data_dir /export1/db/env_data_files </pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="errorsupport"></a>Error Support</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
To simplify error handling and to aid in application debugging, environments offer several useful
|
||||
methods.
|
||||
|
||||
<span>Note that many of these
|
||||
methods are identical to the error handling methods available for the
|
||||
<span>DB</span>
|
||||
|
||||
|
||||
<span>structure.</span>
|
||||
|
||||
|
||||
</span>
|
||||
|
||||
They are:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
<tt class="methodname">set_errcall()</tt>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Defines the function that is called when an error message is
|
||||
issued by DB. The error prefix and message are passed to
|
||||
this callback. It is up to the application to display this
|
||||
information correctly.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt class="methodname">set_errfile()</tt>
|
||||
</p>
|
||||
<p>
|
||||
Sets the C library <tt class="literal">FILE *</tt> to be used for
|
||||
displaying error messages issued by the DB library.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt class="methodname">set_errpfx()</tt>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Sets the prefix used to for any error messages issued by the
|
||||
DB library.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt class="methodname">err()</tt>
|
||||
</p>
|
||||
<p>
|
||||
Issues an error message based upon a DB error code a message text that you supply.
|
||||
The error message is sent to the
|
||||
callback function as defined by <tt class="methodname">set_errcall()</tt>.
|
||||
If that method has not been used, then the error message is sent to the
|
||||
file defined by
|
||||
<span><tt class="methodname">set_errfile()</tt>.</span>
|
||||
|
||||
If none of these methods have been used, then the error message is sent to
|
||||
standard error.
|
||||
</p>
|
||||
<p>
|
||||
The error message consists of the prefix string
|
||||
(as defined by <tt class="methodname">set_errprefix()</tt>),
|
||||
an optional <tt class="literal">printf</tt>-style formatted message,
|
||||
the DB error message associated with the supplied error code,
|
||||
and a trailing newline.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt class="methodname">errx()</tt>
|
||||
</p>
|
||||
<p>
|
||||
Behaves identically to <tt class="methodname">err()</tt> except
|
||||
that you do not provide the DB error code and so
|
||||
the DB message text is not displayed.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
In addition, you can use the <tt class="function">db_strerror()</tt>
|
||||
function to directly return the error string that corresponds to a
|
||||
particular error number. For more information on the
|
||||
<tt class="function">db_strerror()</tt> function, see the <tt class="literal">Error Returns</tt>
|
||||
section of the <i class="citetitle">Getting Started with Berkeley DB</i> guide.
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="sharedmemory"></a>Shared Memory Regions</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
The subsystems that you enable for an environment (in our case,
|
||||
transaction, logging, locking, and the memory pool)
|
||||
are described by one or more regions. The regions contain all of the
|
||||
state information that needs to be shared among threads and/or
|
||||
processes using the environment.
|
||||
</p>
|
||||
<p>
|
||||
Regions may be backed by the file system, by heap memory, or by
|
||||
system shared memory.
|
||||
</p>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="filebackedregions"></a>Regions Backed by Files</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
By default, shared memory regions are created as files in the environment's
|
||||
home directory (<span class="emphasis"><em>not</em></span> the environment's data
|
||||
directory). If it is available, the POSIX <tt class="literal">mmap</tt>
|
||||
interface is used to map these files into your application's
|
||||
address space. If <tt class="literal">mmap</tt>
|
||||
is not available, then the UNIX <tt class="literal">shmget</tt> interfaces
|
||||
are used instead (again, if they are available).
|
||||
</p>
|
||||
<p>
|
||||
In this default case, the region files are named
|
||||
<tt class="literal">__db.###</tt>
|
||||
(for example, <tt class="literal">__db.001</tt>, <tt class="literal">__db.002</tt>,
|
||||
and so on).
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="heapbackedregions"></a>Regions Backed by Heap Memory</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
If heap memory is used to back your shared memory regions,
|
||||
the environment may only be
|
||||
accessed by a single process, although that process may be
|
||||
multi-threaded. In this case, the regions are managed only in
|
||||
memory, and they are not written to the filesystem. You
|
||||
indicate that heap memory is to be used for the region files by
|
||||
specifying
|
||||
<span>
|
||||
<tt class="literal">DB_PRIVATE</tt> to the
|
||||
<tt class="methodname">DB_ENV->open()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
(For an example of an entirely in-memory transactional
|
||||
application, see
|
||||
<span>
|
||||
<a href="inmem_txnexample_c.html">In-Memory Transaction Example</a>.)
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect3" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h4 class="title"><a id="systembackedregions"></a>Regions Backed by System Memory</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Finally, you can cause system memory to be used for your
|
||||
regions instead of memory-mapped files. You do this by providing
|
||||
<span>
|
||||
<tt class="literal">DB_SYSTEM_MEM</tt> to the
|
||||
<tt class="methodname">DB_ENV->open()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
When region files are backed by system memory, DB creates a
|
||||
single file in the environment's home directory. This file
|
||||
contains information necessary to identify the system shared
|
||||
memory in use by the environment. By creating this file, DB
|
||||
enables multiple processes to share the environment.
|
||||
</p>
|
||||
<p>
|
||||
The system memory that is used is architecture-dependent. For
|
||||
example, on systems supporting X/Open-style shared memory
|
||||
interfaces, such as UNIX systems, the <tt class="literal">shmget(2)</tt>
|
||||
and related System V IPC interfaces are used.
|
||||
|
||||
<span>
|
||||
|
||||
Additionally, VxWorks systems use system memory. In these cases,
|
||||
an initial segment ID must be specified by the application to
|
||||
ensure that applications do not overwrite each other's
|
||||
environments, so that the number of segments created does not
|
||||
grow without bounds. See the
|
||||
|
||||
<tt class="methodname">DB_ENV->set_shm_key()</tt>
|
||||
|
||||
|
||||
method for more information.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
On Windows platforms, the use of system memory for the region files
|
||||
is problematic because the operating system uses reference counting
|
||||
to clean up shared objects in the paging file automatically. In
|
||||
addition, the default access permissions for shared objects are
|
||||
different from files, which may cause problems when an environment
|
||||
is accessed by multiple processes running as different users. See
|
||||
<a href="" target="_top">Windows notes</a>
|
||||
or more information.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="security"></a>Security Considerations</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
When using environments, there are some security considerations to
|
||||
keep in mind:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Database environment permissions
|
||||
</p>
|
||||
<p>
|
||||
The directory used for the environment
|
||||
should have its permissions set to ensure that files in the
|
||||
environment are not accessible to users without appropriate
|
||||
permissions. Applications that add to the user's permissions
|
||||
(for example, UNIX <tt class="literal">setuid</tt> or
|
||||
<tt class="literal">setgid</tt> applications), must be
|
||||
carefully checked to not permit illegal use of those
|
||||
permissions such as general file access in the environment
|
||||
directory.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Environment variables
|
||||
</p>
|
||||
<p>
|
||||
Setting
|
||||
|
||||
<span>
|
||||
the <tt class="literal">DB_USE_ENVIRON</tt> or
|
||||
<tt class="literal">DB_USE_ENVIRON_ROOT</tt> flags
|
||||
</span>
|
||||
|
||||
|
||||
so that environment variables can be used during file naming
|
||||
can be dangerous. Setting those flags in DB
|
||||
applications with additional permissions (for example, UNIX
|
||||
<tt class="literal">setuid</tt> or <tt class="literal">setgid</tt>
|
||||
applications) could potentially allow users
|
||||
to read and write databases to which they would not normally
|
||||
have access.
|
||||
</p>
|
||||
<p>
|
||||
For example, suppose you write a DB application
|
||||
that runs <tt class="literal">setuid</tt>. This means that
|
||||
when the application runs, it does so under a
|
||||
userid different than that of the application's caller.
|
||||
This is especially problematic if the application is
|
||||
granting stronger privileges to a user than the user
|
||||
might ordinarily have.
|
||||
</p>
|
||||
<p>
|
||||
Now, if
|
||||
<span>
|
||||
the <tt class="literal">DB_USE_ENVIRON</tt> or
|
||||
<tt class="literal">DB_USE_ENVIRON_ROOT</tt> flags
|
||||
are set for the environment,
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
then the environment that the application is
|
||||
using is modifiable using the
|
||||
<tt class="literal">DB_HOME</tt> environment variable. In
|
||||
this scenario, if the uid used by the application has
|
||||
sufficiently broad privileges, then the application's caller
|
||||
can read and/or write databases owned by another user
|
||||
simply by setting his
|
||||
<tt class="literal">DB_HOME</tt> environment variable to the
|
||||
environment used by that other user.
|
||||
</p>
|
||||
<p>
|
||||
Note that this scenario need not be malicious; the
|
||||
wrong environment could be used by the application
|
||||
simply by inadvertently specifying the wrong path to
|
||||
<tt class="literal">DB_HOME</tt>.
|
||||
</p>
|
||||
<p>
|
||||
As always, you should use <tt class="literal">setuid</tt>
|
||||
sparingly, if at all. But if you do use
|
||||
<tt class="literal">setuid</tt>, then you should refrain from
|
||||
specifying
|
||||
<span>
|
||||
the <tt class="literal">DB_USE_ENVIRON</tt> or
|
||||
<tt class="literal">DB_USE_ENVIRON_ROOT</tt> flags
|
||||
</span>
|
||||
|
||||
for the environment open. And, of course, if you must
|
||||
use <tt class="literal">setuid</tt>, then make sure you use
|
||||
the weakest uid possible – preferably one that is
|
||||
used only by the application itself.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
File permissions
|
||||
</p>
|
||||
<p>
|
||||
By default, DB always creates database and log files readable and
|
||||
writable by the owner and the group (that is,
|
||||
<tt class="literal">S_IRUSR</tt>,
|
||||
<tt class="literal">S_IWUSR</tt>, <tt class="literal">S_IRGRP</tt> and
|
||||
<tt class="literal">S_IWGRP</tt>; or octal mode 0660 on historic
|
||||
UNIX systems). The group ownership of created files is based
|
||||
on the system and directory defaults, and is not further
|
||||
specified by DB.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Temporary backing files
|
||||
</p>
|
||||
<p>
|
||||
If an unnamed database is created and the cache is too small
|
||||
to hold the database in memory, Berkeley DB will create a
|
||||
temporary physical file to enable it to page the database to
|
||||
disk as needed. In this case, environment variables such as
|
||||
<tt class="literal">TMPDIR</tt> may be used to specify the
|
||||
location of that temporary file. Although temporary backing
|
||||
files are created readable and writable by the owner only
|
||||
(<tt class="literal">S_IRUSR</tt> and <tt class="literal">S_IWUSR</tt>,
|
||||
or octal mode 0600 on historic UNIX systems), some
|
||||
filesystems may not sufficiently protect temporary files
|
||||
created in random directories from improper access. To be
|
||||
absolutely safe, applications storing sensitive data in
|
||||
unnamed databases should use the
|
||||
<tt class="methodname">DB_ENV->set_tmp_dir()</tt>
|
||||
|
||||
|
||||
method to specify a temporary directory with known permissions.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="perftune-intro.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="index.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="envopen.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Performance Tuning </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Opening a Transactional Environment and
|
||||
Database
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
250
docs/gsg_txn/C/envopen.html
Normal file
250
docs/gsg_txn/C/envopen.html
Normal file
@@ -0,0 +1,250 @@
|
||||
<?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>Opening a Transactional Environment and
|
||||
Database
|
||||
|
||||
|
||||
</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="enabletxn.html" title="Chapter 2. Enabling Transactions" />
|
||||
<link rel="previous" href="enabletxn.html" title="Chapter 2. Enabling Transactions" />
|
||||
<link rel="next" href="usingtxns.html" title="Chapter 3. Transaction Basics" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Opening a Transactional Environment and
|
||||
Database
|
||||
|
||||
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="enabletxn.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 2. Enabling Transactions</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="usingtxns.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="envopen"></a>Opening a Transactional Environment and
|
||||
<span>Database</span>
|
||||
|
||||
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
To enable transactions for your environment, you must initialize the
|
||||
transactional subsystem. Note that doing this also initializes the
|
||||
logging subsystem. In addition, you must initialize the memory pool
|
||||
(in-memory cache). Frequently, but not always, you will also
|
||||
initialize the locking subsystem.
|
||||
|
||||
|
||||
<span>
|
||||
For example:
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Notice in the following example that you create your environment
|
||||
handle using the <tt class="function">db_env_create()</tt> function before you open
|
||||
the environment:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t env_flags;
|
||||
DB_ENV *envp;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
env_flags = DB_CREATE | /* Create the environment if it does
|
||||
* not already exist. */
|
||||
DB_INIT_TXN | /* Initialize transactions */
|
||||
DB_INIT_LOCK | /* Initialize locking. */
|
||||
DB_INIT_LOG | /* Initialize logging */
|
||||
DB_INIT_MPOOL; /* Initialize the in-memory cache. */
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
/* Close the environment */
|
||||
if (envp != NULL) {
|
||||
ret_c = envp->close(envp, 0);
|
||||
if (ret_c != 0) {
|
||||
fprintf(stderr, "environment close failed: %s\n",
|
||||
db_strerror(ret_c));
|
||||
ret = ret_c;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
<p>
|
||||
You then create and open your database(s) as you would for a non-transactional system.
|
||||
<span>
|
||||
The only difference is that you must pass the environment handle to
|
||||
the
|
||||
<span>
|
||||
<tt class="function">db_create()</tt> function,
|
||||
</span>
|
||||
|
||||
and you must open the database within a transaction.
|
||||
Typically auto commit is used for this purpose. To do so, pass
|
||||
<tt class="literal">DB_AUTO_COMMIT</tt> to the database open command.
|
||||
Also, make sure you close all your databases before you close
|
||||
your environment.
|
||||
For example:
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t <b class="userinput"><tt>db_flags,</tt></b> env_flags;
|
||||
<b class="userinput"><tt>DB *dbp;</tt></b>
|
||||
DB_ENV *envp;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
<b class="userinput"><tt>const char *file_name = "mydb.db";
|
||||
|
||||
dbp = NULL;</tt></b>
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
env_flags = DB_CREATE | /* Create the environment if it does
|
||||
* not already exist. */
|
||||
DB_INIT_TXN | /* Initialize transactions */
|
||||
DB_INIT_LOCK | /* Initialize locking. */
|
||||
DB_INIT_LOG | /* Initialize logging */
|
||||
DB_INIT_MPOOL; /* Initialize the in-memory cache. */
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
<b class="userinput"><tt>/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database creation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
db_flags = DB_CREATE | DB_AUTO_COMMIT;
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
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 */
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database '%s' open failed",
|
||||
file_name);
|
||||
goto err;
|
||||
}</tt></b>
|
||||
|
||||
|
||||
err:
|
||||
<b class="userinput"><tt>/* Close the database */
|
||||
if (dbp != NULL) {
|
||||
ret_c = dbp->close(dbp, 0);
|
||||
if (ret_c != 0) {
|
||||
envp->err(envp, ret_c, "Database close failed.");
|
||||
ret = ret_c
|
||||
}
|
||||
}</tt></b>
|
||||
|
||||
|
||||
/* Close the environment */
|
||||
if (envp != NULL) {
|
||||
ret_c = envp->close(envp, 0);
|
||||
if (ret_c != 0) {
|
||||
fprintf(stderr, "environment close failed: %s\n",
|
||||
db_strerror(ret_c));
|
||||
ret = ret_c;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
Never close a database that has active transactions. Make sure
|
||||
all transactions are resolved (either committed or aborted)
|
||||
before closing the database.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="enabletxn.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="enabletxn.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="usingtxns.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Chapter 2. Enabling Transactions </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Chapter 3. Transaction Basics</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
403
docs/gsg_txn/C/filemanagement.html
Normal file
403
docs/gsg_txn/C/filemanagement.html
Normal file
@@ -0,0 +1,403 @@
|
||||
<?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>Chapter 5. Managing DB Files</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="previous" href="reversesplit.html" title="Reverse BTree Splits" />
|
||||
<link rel="next" href="backuprestore.html" title="Backup Procedures" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Chapter 5. Managing DB Files</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="reversesplit.html">Prev</a> </td>
|
||||
<th width="60%" align="center"> </th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="backuprestore.html">Next</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="chapter" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title"><a id="filemanagement"></a>Chapter 5. Managing DB Files</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="toc">
|
||||
<p>
|
||||
<b>Table of Contents</b>
|
||||
</p>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="filemanagement.html#checkpoints">Checkpoints</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="backuprestore.html">Backup Procedures</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="backuprestore.html#copyutilities">About Unix Copy Utilities</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="backuprestore.html#standardbackup">Offline Backups</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="backuprestore.html#hotbackup">Hot Backup</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="backuprestore.html#incrementalbackups">Incremental Backups</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="recovery.html">Recovery Procedures</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="recovery.html#normalrecovery">Normal Recovery</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="recovery.html#catastrophicrecovery">Catastrophic Recovery</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="architectrecovery.html">Designing Your Application for Recovery</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="architectrecovery.html#multithreadrecovery">Recovery for Multi-Threaded Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="architectrecovery.html#multiprocessrecovery">Recovery in Multi-Process Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="hotfailover.html">Using Hot Failovers</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="logfileremoval.html">Removing Log Files</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="logconfig.html">Configuring the Logging Subsystem</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="logconfig.html#logfilesize">Setting the Log File Size</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="logconfig.html#logregionsize">Configuring the Logging Region Size</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="logconfig.html#inmemorylogging">Configuring In-Memory Logging</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="logconfig.html#logbuffer">Setting the In-Memory Log Buffer Size</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<p>
|
||||
DB is capable of storing several types of files on disk:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Data files, which contain the actual data in your database.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Log files, which contain information required to recover your
|
||||
database in the event of a system or application failure.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Region files, which contain information necessary for the
|
||||
overall operation of your application.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Temporary files, which are created only under certain special circumstances. These files never need to
|
||||
be backed up or otherwise managed and so they are not a consideration for the topics described in this
|
||||
chapter. See <a href="enabletxn.html#security">Security Considerations</a>
|
||||
for more information on temporary files.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
Of these, you must manage your data and log files by ensuring that they
|
||||
are backed up. You should also pay attention to the amount of disk space
|
||||
your log files are consuming, and periodically remove any unneeded
|
||||
files. Finally, you can optionally tune your logging subsystem to best
|
||||
suit your application's needs and requirements.
|
||||
These topics are discussed in this chapter.
|
||||
</p>
|
||||
<div class="sect1" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title" style="clear: both"><a id="checkpoints"></a>Checkpoints</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Before we can discuss DB file management, we need to
|
||||
describe checkpoints. When databases are modified (that is, a
|
||||
transaction is committed), the modifications are recorded in
|
||||
DB's logs, but they are <span class="emphasis"><em>not</em></span>
|
||||
necessarily reflected in the actual database files on disk.
|
||||
</p>
|
||||
<p>
|
||||
This means that as time goes on, increasingly
|
||||
more data is contained in your log files that is not
|
||||
contained in your data files. As a result, you must keep more
|
||||
log files around than you might actually need. Also, any
|
||||
recovery run from your log files will take increasingly longer
|
||||
amounts of time, because there is more data in the log files
|
||||
that must be reflected back into the data files during the
|
||||
recovery process.
|
||||
</p>
|
||||
<p>
|
||||
You can reduce these problems by periodically
|
||||
running a checkpoint against your environment. The checkpoint:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Flushes dirty pages from the in-memory cache. This means that data modifications found in your
|
||||
in-memory cache are written to the database files on disk. Note that a checkpoint also causes data
|
||||
dirtied by an uncommitted transaction to also be written to your database files on disk. In this latter
|
||||
case, DB's normal recovery is used to remove any such modifications that were subsequently
|
||||
abandoned by your application using a transaction abort.
|
||||
</p>
|
||||
<p>
|
||||
Normal recovery is describe in <a href="recovery.html">Recovery Procedures</a>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Writes a checkpoint record.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Flushes the log. This causes all log data that has not yet been written to disk to be written.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Writes a list of open databases.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
There are several ways to run a checkpoint. One way is to use
|
||||
the <span><b class="command">db_checkpoint</b></span> command line utility. (Note, however, that this command line utility
|
||||
cannot be used if your environment was opened using
|
||||
<span>
|
||||
<tt class="literal">DB_PRIVATE</tt>.)
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
You can also run a thread that periodically checkpoints your
|
||||
environment for you by calling the
|
||||
<tt class="methodname">DB_ENV->txn_checkpoint()</tt>
|
||||
|
||||
|
||||
method.
|
||||
</p>
|
||||
<p>
|
||||
Note that you can prevent a checkpoint from occurring unless more
|
||||
than a specified amount of log data has been written since the
|
||||
last checkpoint. You can also prevent the checkpoint from
|
||||
running unless more than a specified amount of time has
|
||||
occurred since the last checkpoint. These conditions are
|
||||
particularly interesting if you have multiple threads
|
||||
<span>or processes</span>
|
||||
running checkpoints.
|
||||
</p>
|
||||
<p>
|
||||
For configuration information, see the
|
||||
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/api_c/txn_checkpoint.html" target="_top">
|
||||
DB_ENV->txn_checkpoint() API reference page.
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Note that running checkpoints can be quite expensive. DB must
|
||||
flush every dirty page to the backing database files. On the
|
||||
other hand, if you do not run checkpoints often enough, your
|
||||
recovery time can be unnecessarily long and you may be using more
|
||||
disk space than you really need. Also, you cannot remove log files
|
||||
until a checkpoint is run. Therefore, deciding how frequently
|
||||
to run a checkpoint is one of the most
|
||||
common tuning activity for DB applications.
|
||||
</p>
|
||||
<p>
|
||||
For example, to run a checkpoint from a separate thread of control:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "db.h"
|
||||
|
||||
void *checkpoint_thread(void *);
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret;
|
||||
u_int32_t env_flags;
|
||||
DB_ENV *envp;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
pthread_t ptid;
|
||||
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
/* Open the environment. */
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
/* Start a checkpoint thread. */
|
||||
if ((ret = pthread_create(
|
||||
&ptid, NULL, checkpoint_thread, (void *)envp)) != 0) {
|
||||
fprintf(stderr,
|
||||
"txnapp: failed spawning checkpoint thread: %s\n",
|
||||
strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* All other threads and application shutdown code
|
||||
* omitted for brevity.
|
||||
*/
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
checkpoint_thread(void *arg) {
|
||||
DB_ENV *dbenv;
|
||||
int ret;
|
||||
|
||||
dbenv = arg;
|
||||
|
||||
/* Checkpoint once a minute. */
|
||||
for (;; sleep(60))
|
||||
if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0)) != 0) {
|
||||
dbenv->err(dbenv, ret, "checkpoint thread");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* NOTREACHED */
|
||||
} </pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="reversesplit.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="index.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="backuprestore.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Reverse BTree Splits </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Backup Procedures</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
41
docs/gsg_txn/C/gettingStarted.css
Normal file
41
docs/gsg_txn/C/gettingStarted.css
Normal file
@@ -0,0 +1,41 @@
|
||||
body { width: 45em;
|
||||
margin-left: 3em;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
h2.title { margin-left: -1em;
|
||||
font-family: Verdana, serif;
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
||||
h3.title { font-family: Verdana, serif;
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
pre.programlisting {
|
||||
font-family: monospace;
|
||||
background-color: #eae8e9;
|
||||
}
|
||||
|
||||
div.navheader { font-size: 9pt;
|
||||
width: 60em;
|
||||
margin-left: -2em;
|
||||
}
|
||||
|
||||
div.navheader table tr td { font-size: 9pt; }
|
||||
|
||||
div.navfooter { font-size: 9pt;
|
||||
width: 60em;
|
||||
margin-left: -2em;
|
||||
}
|
||||
div.navfooter table tr td { font-size: 9pt; }
|
||||
|
||||
span.emphasis { font-style: italic; font-size: 9pt;}
|
||||
|
||||
div.appendix div.informaltable { font-size: 9pt; }
|
||||
div.appendix div.informaltable td { vertical-align: top; }
|
||||
div.appendix div.informaltable p { margin-top: .25em; }
|
||||
div.appendix div.informaltable p { margin-bottom: .25em; }
|
||||
|
||||
|
||||
210
docs/gsg_txn/C/hotfailover.html
Normal file
210
docs/gsg_txn/C/hotfailover.html
Normal file
@@ -0,0 +1,210 @@
|
||||
<?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>Using Hot Failovers</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="filemanagement.html" title="Chapter 5. Managing DB Files" />
|
||||
<link rel="previous" href="architectrecovery.html" title="Designing Your Application for Recovery" />
|
||||
<link rel="next" href="logfileremoval.html" title="Removing Log Files" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Using Hot Failovers</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="architectrecovery.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 5. Managing DB Files</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="logfileremoval.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="hotfailover"></a>Using Hot Failovers</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
You can maintain a backup that can be used for failover purposes.
|
||||
Hot failovers differ from the backup and restore
|
||||
procedures described previously in this chapter in that data
|
||||
used for traditional backups is typically copied to offline storage.
|
||||
Recovery time for a traditional backup is determined by:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
How quickly you can retrieve that storage media.
|
||||
Typically storage media for critical backups is moved
|
||||
to a safe facility in a remote location, so this step can
|
||||
take a relatively long time.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
How fast you can read the backup from the storage media
|
||||
to a local disk drive. If you have very large backups,
|
||||
or if your storage media is very slow, this can be a
|
||||
lengthy process.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
How long it takes you to run catastrophic recovery
|
||||
against the newly restored backup. As described earlier
|
||||
in this chapter, this process can be lengthy because
|
||||
every log file must be examined during the recovery
|
||||
process.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
When you use a hot failover, the backup is maintained
|
||||
at a location that is reasonably fast to access. Usually, this
|
||||
is a second disk drive local to the machine.
|
||||
In this situation, recovery time is very quick
|
||||
because you only have to reopen your
|
||||
environment and database, using the failover environment
|
||||
for the environment open.
|
||||
</p>
|
||||
<p>
|
||||
Hot failovers obviously do not protect you from truly
|
||||
catastrophic disasters (such as a fire in your machine room)
|
||||
because the backup is still local to the machine. However,
|
||||
you can guard against more mundane problems (such as a broken
|
||||
disk drive) by keeping the backup on a
|
||||
second drive that is managed by an alternate disk controller.
|
||||
</p>
|
||||
<p>
|
||||
To maintain a hot failover:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Copy all the active database files to the failover
|
||||
directory. Use the <span><b class="command">db_archive</b></span>
|
||||
command line utility with the
|
||||
<tt class="literal">-s</tt> option to identify all the active
|
||||
database files.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Identify all the inactive log files in your production
|
||||
environment and <span class="emphasis"><em>move</em></span> these to the failover
|
||||
directory. Use the <span><b class="command">db_archive</b></span>
|
||||
command with no command line options to obtain a list
|
||||
of these log files.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Identify the active log files in your production
|
||||
environment, and <span class="emphasis"><em>copy</em></span> these to the
|
||||
failover directory. Use the
|
||||
<span><b class="command">db_archive</b></span> command with the
|
||||
<tt class="literal">-l</tt> option to obtain a list of these
|
||||
log files.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Run catastrophic recovery against the failover
|
||||
directory. Use the <span><b class="command">db_recover</b></span>
|
||||
command with the <tt class="literal">-c</tt> option to do
|
||||
this.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Optionally copy the backup to an archival location.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<p>
|
||||
Once you have performed this procedure, you can maintain an
|
||||
active hot backup by repeating steps 2 - 5 as often
|
||||
as is required by your application.
|
||||
</p>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
If you perform step 1, steps 2-5 must follow in order to
|
||||
ensure consistency of your hot backup.
|
||||
</p>
|
||||
</div>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
Rather than use the previous procedure, you can use the <span><b class="command">db_hotbackup</b></span> command line utility
|
||||
to do the same thing. This utility will (optionally) run a checkpoint and then copy all necessary files to a target
|
||||
directory for you.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
To actually perform a failover, simply:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Shut down all processes which are running against the original environment.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
If you have an archival copy of the backup environment, you can optionally try copying the remaining
|
||||
log files from the original environment and running catastrophic recovery against that backup
|
||||
environment. Do this <span class="emphasis"><em>only</em></span> if you have a an archival copy of the backup
|
||||
environment.
|
||||
</p>
|
||||
<p>
|
||||
This step can allow you to recover data created or modified in the original environment, but which
|
||||
did not have a chance to be reflected in the hot backup environment.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Reopen your environment and databases as normal, but use
|
||||
the backup environment instead of the production
|
||||
environment.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="architectrecovery.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="filemanagement.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="logfileremoval.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Designing Your Application for Recovery </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Removing Log Files</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
526
docs/gsg_txn/C/index.html
Normal file
526
docs/gsg_txn/C/index.html
Normal file
@@ -0,0 +1,526 @@
|
||||
<?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>Getting Started with Berkeley DB Transaction Processing</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="next" href="preface.html" title="Preface" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Getting Started with Berkeley DB Transaction Processing</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"> </td>
|
||||
<th width="60%" align="center"> </th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="preface.html">Next</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="book" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h1 class="title"><a id="id613728"></a>Getting Started with Berkeley DB Transaction Processing</h1>
|
||||
</div>
|
||||
<div>
|
||||
<div class="legalnotice">
|
||||
<p class="legalnotice-title">
|
||||
<b>Legal Notice</b>
|
||||
</p>
|
||||
<p>
|
||||
This documentation is distributed under an open source license.
|
||||
You may review the terms of this license at:
|
||||
<a href="http://www.oracle.com/technology/software/products/berkeley-db/htdocs/oslicense.html" target="_top">http://www.oracle.com/technology/software/products/berkeley-db/htdocs/oslicense.html</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Oracle, Berkeley DB,
|
||||
|
||||
|
||||
and
|
||||
Sleepycat are trademarks or registered trademarks of
|
||||
Oracle. All rights to these marks are reserved.
|
||||
No third-party use is permitted without the
|
||||
express prior written consent of Oracle.
|
||||
</p>
|
||||
<p>
|
||||
To obtain a copy of this document's original source code, please
|
||||
submit a request to the Oracle Technology Network forum at:
|
||||
<a href="http://forums.oracle.com/forums/forum.jspa?forumID=271" target="_top">http://forums.oracle.com/forums/forum.jspa?forumID=271</a>
|
||||
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="pubdate">4/25/2008</p>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="toc">
|
||||
<p>
|
||||
<b>Table of Contents</b>
|
||||
</p>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="preface">
|
||||
<a href="preface.html">Preface</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="preface.html#conventions">Conventions Used in this Book</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="preface.html#moreinfo">For More Information</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="chapter">
|
||||
<a href="introduction.html">1. Introduction</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="introduction.html#txnintro">Transaction Benefits</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="introduction.html#sysfailure">A Note on System Failure</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="introduction.html#apireq">Application Requirements</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="introduction.html#multithread-intro">Multi-threaded
|
||||
and Multi-process
|
||||
Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="recovery-intro.html">Recoverability</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="perftune-intro.html">Performance Tuning</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="chapter">
|
||||
<a href="enabletxn.html">2. Enabling Transactions</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="enabletxn.html#environments">Environments</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="enabletxn.html#filenaming">File Naming</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="enabletxn.html#errorsupport">Error Support</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="enabletxn.html#sharedmemory">Shared Memory Regions</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="enabletxn.html#security">Security Considerations</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="envopen.html">Opening a Transactional Environment and
|
||||
Database
|
||||
|
||||
|
||||
</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="chapter">
|
||||
<a href="usingtxns.html">3. Transaction Basics</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="usingtxns.html#commitresults">Committing a Transaction</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="usingtxns.html#nodurabletxn">Non-Durable Transactions</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="abortresults.html">Aborting a Transaction</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="autocommit.html">Auto Commit</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="nestedtxn.html">Nested Transactions</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txncursor.html">Transactional Cursors</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txnindices.html">Secondary Indices with Transaction Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="maxtxns.html">Configuring the Transaction Subsystem</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="chapter">
|
||||
<a href="txnconcurrency.html">4. Concurrency</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txnconcurrency.html#concurrenthandles">Which DB Handles are Free-Threaded</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="blocking_deadlocks.html">Locks, Blocks, and Deadlocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="blocking_deadlocks.html#locks">Locks</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="blocking_deadlocks.html#blocks">Blocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="blocking_deadlocks.html#deadlocks">Deadlocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="lockingsubsystem.html">The Locking Subsystem</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="lockingsubsystem.html#configuringlock">Configuring the Locking Subsystem</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="lockingsubsystem.html#configdeadlkdetect">Configuring Deadlock Detection</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="lockingsubsystem.html#deadlockresolve">Resolving Deadlocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="isolation.html">Isolation</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<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>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txn_ccursor.html">Transactional Cursors and Concurrent Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="txn_ccursor.html#cursordirtyreads">Using Cursors with Uncommitted Data</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="readmodifywrite.html">Read/Modify/Write</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txnnowait.html">No Wait on Blocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="reversesplit.html">Reverse BTree Splits</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="chapter">
|
||||
<a href="filemanagement.html">5. Managing DB Files</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="filemanagement.html#checkpoints">Checkpoints</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="backuprestore.html">Backup Procedures</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="backuprestore.html#copyutilities">About Unix Copy Utilities</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="backuprestore.html#standardbackup">Offline Backups</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="backuprestore.html#hotbackup">Hot Backup</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="backuprestore.html#incrementalbackups">Incremental Backups</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="recovery.html">Recovery Procedures</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="recovery.html#normalrecovery">Normal Recovery</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="recovery.html#catastrophicrecovery">Catastrophic Recovery</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="architectrecovery.html">Designing Your Application for Recovery</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="architectrecovery.html#multithreadrecovery">Recovery for Multi-Threaded Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="architectrecovery.html#multiprocessrecovery">Recovery in Multi-Process Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="hotfailover.html">Using Hot Failovers</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="logfileremoval.html">Removing Log Files</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="logconfig.html">Configuring the Logging Subsystem</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="logconfig.html#logfilesize">Setting the Log File Size</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="logconfig.html#logregionsize">Configuring the Logging Region Size</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="logconfig.html#inmemorylogging">Configuring In-Memory Logging</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="logconfig.html#logbuffer">Setting the In-Memory Log Buffer Size</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="chapter">
|
||||
<a href="wrapup.html">6. Summary and Examples</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="wrapup.html#anatomy">Anatomy of a Transactional Application</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txnexample_c.html">Transaction Example</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="inmem_txnexample_c.html">In-Memory Transaction Example</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"> </td>
|
||||
<td width="20%" align="center"> </td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="preface.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top"> </td>
|
||||
<td width="20%" align="center"> </td>
|
||||
<td width="40%" align="right" valign="top"> Preface</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
618
docs/gsg_txn/C/inmem_txnexample_c.html
Normal file
618
docs/gsg_txn/C/inmem_txnexample_c.html
Normal file
@@ -0,0 +1,618 @@
|
||||
<?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>In-Memory Transaction Example</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="wrapup.html" title="Chapter 6. Summary and Examples" />
|
||||
<link rel="previous" href="txnexample_c.html" title="Transaction Example" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">In-Memory Transaction Example</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="txnexample_c.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 6. Summary and Examples</th>
|
||||
<td width="20%" align="right"> </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="inmem_txnexample_c"></a>In-Memory Transaction Example</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
DB is sometimes used for applications that simply need to cache
|
||||
data retrieved from some other location (such as a remote database
|
||||
server). DB is also often used in embedded systems.
|
||||
</p>
|
||||
<p>
|
||||
In both cases, applications may want to use transactions for
|
||||
atomicity, consistency, and isolation guarantees, but they may also want
|
||||
to forgo the durability guarantee entirely. In doing so, they can keep
|
||||
their DB environment and databases entirely in-memory so
|
||||
as to avoid the performance impact of unneeded disk I/O.
|
||||
</p>
|
||||
<p>
|
||||
To do this:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Refrain from specifying a home directory when you open your
|
||||
environment. The exception to this is if you are using the
|
||||
<tt class="literal">DB_CONFIG</tt> configuration file — in
|
||||
that case you must identify the environment's home
|
||||
directory so that the configuration file can be found.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Configure your environment to back your regions from
|
||||
system memory instead of the filesystem.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Configure your logging subsystem such that log files are kept
|
||||
entirely in-memory.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Increase the size of your in-memory log buffer so that it
|
||||
is large enough to hold the largest set of concurrent write operations.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Increase the size of your in-memory cache so that it can
|
||||
hold your entire data set. You do not want your cache to
|
||||
page to disk.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Do not specify a file name when you open your database(s).
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
As an example, this section takes the transaction example provided
|
||||
in <a href="txnexample_c.html">Transaction Example</a>
|
||||
and it updates that example so that the environment, database, log
|
||||
files, and regions are all kept entirely in-memory.
|
||||
</p>
|
||||
<p>
|
||||
For illustration purposes, we also modify this example so that
|
||||
uncommitted reads are no longer used to enable the
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
function. Instead, we simply provide a transaction handle to
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
so as to avoid the self-deadlock. Be aware that using a transaction handle here rather than
|
||||
uncommitted reads will work just as well as if we had continued to use uncommitted reads. However,
|
||||
the usage of the transaction handle here will
|
||||
probably cause more deadlocks than using read-uncommitted does, because more locking is being performed in
|
||||
this case.
|
||||
</p>
|
||||
<p>
|
||||
To begin, we simplify the beginning of our example a bit. Because
|
||||
we no longer need an environment home directory, we can remove all
|
||||
the code that we used to determine path delimiters
|
||||
and include the <tt class="function">getopt</tt> function. We can also
|
||||
remove our <tt class="function">usage()</tt> function because we no
|
||||
longer require any command line arguments.
|
||||
</p>
|
||||
<pre class="programlisting">/* File: txn_guide_inmemory.c */
|
||||
|
||||
/* We assume an ANSI-compatible compiler */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <db.h>
|
||||
|
||||
/* Run 5 writers threads at a time. */
|
||||
#define NUMWRITERS 5
|
||||
|
||||
/*
|
||||
* Printing of pthread_t is implementation-specific, so we
|
||||
* create our own thread IDs for reporting purposes.
|
||||
*/
|
||||
int global_thread_num;
|
||||
pthread_mutex_t thread_num_lock;
|
||||
|
||||
/* Forward declarations */
|
||||
int count_records(DB *, DB_TXN *);
|
||||
int open_db(DB **, const char *, const char *, DB_ENV *, u_int32_t);
|
||||
int writer_thread(void *); </pre>
|
||||
<p>
|
||||
Next, in our <tt class="function">main()</tt>, we also eliminate some
|
||||
variables that this example no longer needs. In particular, we are able to remove
|
||||
the
|
||||
<tt class="literal">db_home_dir</tt>
|
||||
|
||||
and
|
||||
<tt class="literal">file_name</tt>
|
||||
|
||||
variables. We also remove all our <tt class="function">getopt</tt> code.
|
||||
</p>
|
||||
<pre class="programlisting">int
|
||||
main(void)
|
||||
{
|
||||
/* Initialize our handles */
|
||||
DB *dbp = NULL;
|
||||
DB_ENV *envp = NULL;
|
||||
|
||||
pthread_t writer_threads[NUMWRITERS];
|
||||
int i, ret, ret_t;
|
||||
u_int32_t env_flags;
|
||||
|
||||
/* Application name */
|
||||
const char *prog_name = "txn_guide_inmemory"; </pre>
|
||||
<p>
|
||||
Next we create our environment as always. However, we add
|
||||
<tt class="literal">DB_PRIVATE</tt> to our environment open flags. This
|
||||
flag causes our environment to back regions using our
|
||||
application's heap memory rather than by using the filesystem.
|
||||
This is the first important step to keeping our DB data
|
||||
entirely in-memory.
|
||||
</p>
|
||||
<p>
|
||||
We also remove the <tt class="literal">DB_RECOVER</tt> flag from the environment open flags. Because our databases,
|
||||
logs, and regions are maintained in-memory, there will never be anything to recover.
|
||||
</p>
|
||||
<p>
|
||||
Note that we show the additional code here in
|
||||
<b class="userinput"><tt>bold.</tt></b>
|
||||
</p>
|
||||
<pre class="programlisting"> /* Create the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
env_flags =
|
||||
DB_CREATE | /* Create the environment if it does not exist */
|
||||
DB_INIT_LOCK | /* Initialize the locking subsystem */
|
||||
DB_INIT_LOG | /* Initialize the logging subsystem */
|
||||
DB_INIT_TXN | /* Initialize the transactional subsystem. This
|
||||
* also turns on logging. */
|
||||
DB_INIT_MPOOL | /* Initialize the memory pool (in-memory cache) */
|
||||
<b class="userinput"><tt>DB_PRIVATE | /* Region files are not backed by the filesystem.
|
||||
* Instead, they are backed by heap memory. */</tt></b>
|
||||
DB_THREAD; /* Cause the environment to be free-threaded */ </pre>
|
||||
<p>
|
||||
Now we configure our environment to keep the log files in memory,
|
||||
increase the log buffer size to 10 MB, and increase our in-memory
|
||||
cache to 10 MB. These values should be more than enough for our
|
||||
application's workload.
|
||||
</p>
|
||||
<pre class="programlisting">
|
||||
<b class="userinput">
|
||||
<tt> /* Specify in-memory logging */
|
||||
ret = envp->log_set_config(envp, DB_LOG_IN_MEMORY, 1);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error setting log subsystem to in-memory: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specify the size of the in-memory log buffer.
|
||||
*/
|
||||
ret = envp->set_lg_bsize(envp, 10 * 1024 * 1024);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error increasing the log buffer size: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specify the size of the in-memory cache.
|
||||
*/
|
||||
ret = envp->set_cachesize(envp, 0,
|
||||
10 * 1024 * 1024, 1);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error increasing the cache size: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}</tt>
|
||||
</b>
|
||||
</pre>
|
||||
<p>
|
||||
Next, we open the environment and setup our lock detection. This is
|
||||
identical to how the example previously worked, except that we do not
|
||||
provide a location for the environment's home directory.
|
||||
</p>
|
||||
<pre class="programlisting"> /*
|
||||
* Indicate that we want db to perform lock detection internally.
|
||||
* Also indicate that the transaction with the fewest number of
|
||||
* write locks will receive the deadlock notification in
|
||||
* the event of a deadlock.
|
||||
*/
|
||||
ret = envp->set_lk_detect(envp, DB_LOCK_MINWRITE);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error setting lock detect: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Now actually open the environment */
|
||||
ret = envp->open(envp, <b class="userinput"><tt>NULL</tt></b>, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
} </pre>
|
||||
<p>
|
||||
When we call
|
||||
<span><tt class="function">open_db()</tt>,</span>
|
||||
|
||||
which is what we use
|
||||
to open our database, we no not provide a database filename for the
|
||||
third parameter. When the filename is <tt class="literal">NULL</tt>, the database is not
|
||||
backed by the filesystem.
|
||||
</p>
|
||||
<pre class="programlisting"> /*
|
||||
* If we had utility threads (for running checkpoints or
|
||||
* deadlock detection, for example) we would spawn those
|
||||
* here. However, for a simple example such as this,
|
||||
* that is not required.
|
||||
*/
|
||||
|
||||
/* Open the database */
|
||||
ret = open_db(&dbp, prog_name, <b class="userinput"><tt>NULL</tt></b>,
|
||||
envp, DB_DUPSORT);
|
||||
if (ret != 0)
|
||||
goto err; </pre>
|
||||
<p>
|
||||
After that, our <tt class="function">main()</tt> function is unchanged,
|
||||
except that when we
|
||||
<span>close the database,</span>
|
||||
|
||||
we change the error message string so as to not reference the database filename.
|
||||
</p>
|
||||
<pre class="programlisting"> /* Initialize a pthread mutex. Used to help provide thread ids. */
|
||||
(void)pthread_mutex_init(&thread_num_lock, NULL);
|
||||
|
||||
/* Start the writer threads. */
|
||||
for (i = 0; i < NUMWRITERS; i++)
|
||||
(void)pthread_create(
|
||||
&writer_threads[i], NULL, (void *)writer_thread, (void *)dbp);
|
||||
|
||||
/* Join the writers */
|
||||
for (i = 0; i < NUMWRITERS; i++)
|
||||
(void)pthread_join(writer_threads[i], NULL);
|
||||
|
||||
err:
|
||||
/* Close our database handle, if it was opened. */
|
||||
if (dbp != NULL) {
|
||||
ret_t = dbp->close(dbp, 0);
|
||||
if (ret_t != 0) {
|
||||
<b class="userinput"><tt>fprintf(stderr, "%s database close failed.\n",
|
||||
db_strerror(ret_t));</tt></b>
|
||||
ret = ret_t;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close our environment, if it was opened. */
|
||||
if (envp != NULL) {
|
||||
ret_t = envp->close(envp, 0);
|
||||
if (ret_t != 0) {
|
||||
fprintf(stderr, "environment close failed: %s\n",
|
||||
db_strerror(ret_t));
|
||||
ret = ret_t;
|
||||
}
|
||||
}
|
||||
|
||||
/* Final status message and return. */
|
||||
printf("I'm all done.\n");
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
<p>
|
||||
That completes <tt class="function">main()</tt>. The bulk of our
|
||||
<tt class="function">writer_thread()</tt> function implementation is
|
||||
unchanged from the initial transaction example, except that we no
|
||||
longer check for <tt class="literal">DB_KEYEXISTS</tt> in our
|
||||
<tt class="methodname">DB->put()</tt> return code. Because we are
|
||||
configuring for a completely in-memory database, there is no
|
||||
possibility that we can run this code against an existing database.
|
||||
Therefore, there is no way that <tt class="literal">DB_KEYEXISTS</tt>
|
||||
will be returned by <tt class="methodname">DB->put()</tt>.
|
||||
</p>
|
||||
<pre class="programlisting">/*
|
||||
* A function that performs a series of writes to a
|
||||
* Berkeley DB database. The information written
|
||||
* to the database is largely nonsensical, but the
|
||||
* mechanism of transactional commit/abort and
|
||||
* deadlock detection is illustrated here.
|
||||
*/
|
||||
int
|
||||
writer_thread(void *args)
|
||||
{
|
||||
DBT key, value;
|
||||
DB_TXN *txn;
|
||||
int i, j, payload, ret, thread_num;
|
||||
int retry_count, max_retries = 20; /* Max retry on a deadlock */
|
||||
char *key_strings[] = {"key 1", "key 2", "key 3", "key 4",
|
||||
"key 5", "key 6", "key 7", "key 8",
|
||||
"key 9", "key 10"};
|
||||
|
||||
DB *dbp = (DB *)args;
|
||||
DB_ENV *envp = dbp->get_env(dbp);
|
||||
|
||||
/* Get the thread number */
|
||||
(void)pthread_mutex_lock(&thread_num_lock);
|
||||
global_thread_num++;
|
||||
thread_num = global_thread_num;
|
||||
(void)pthread_mutex_unlock(&thread_num_lock);
|
||||
|
||||
/* Initialize the random number generator */
|
||||
srand((u_int)pthread_self());
|
||||
|
||||
/* Write 50 times and then quit */
|
||||
for (i = 0; i < 50; i++) {
|
||||
retry_count = 0; /* Used for deadlock retries */
|
||||
|
||||
retry:
|
||||
ret = envp->txn_begin(envp, NULL, &txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "txn_begin failed");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
for (j = 0; j < 10; j++) {
|
||||
/* Set up our key and values DBTs */
|
||||
memset(&key, 0, sizeof(DBT));
|
||||
key.data = key_strings[j];
|
||||
key.size = (strlen(key_strings[j]) + 1) * sizeof(char);
|
||||
|
||||
memset(&value, 0, sizeof(DBT));
|
||||
payload = rand() + i;
|
||||
value.data = &payload;
|
||||
value.size = sizeof(int);
|
||||
|
||||
/* Perform the database put. */
|
||||
switch (ret = dbp->put(dbp, txn, &key, &value, 0)) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
/*
|
||||
* Here's where we perform deadlock detection. If
|
||||
* DB_LOCK_DEADLOCK is returned by the put operation,
|
||||
* then this thread has been chosen to break a deadlock.
|
||||
* It must abort its operation, and optionally retry the
|
||||
* put.
|
||||
*/
|
||||
case DB_LOCK_DEADLOCK:
|
||||
/*
|
||||
* First that we MUST do is abort the
|
||||
* transaction.
|
||||
*/
|
||||
(void)txn->abort(txn);
|
||||
/*
|
||||
* Now we decide if we want to retry the operation.
|
||||
* If we have retried less than max_retries,
|
||||
* increment the retry count and goto retry.
|
||||
*/
|
||||
if (retry_count < max_retries) {
|
||||
printf("Writer %i: Got DB_LOCK_DEADLOCK.\n",
|
||||
thread_num);
|
||||
printf("Writer %i: Retrying write operation.\n",
|
||||
thread_num);
|
||||
retry_count++;
|
||||
goto retry;
|
||||
}
|
||||
/*
|
||||
* Otherwise, just give up.
|
||||
*/
|
||||
printf("Writer %i: ", thread_num);
|
||||
printf("Got DB_LOCK_DEADLOCK and out of retries.\n");
|
||||
printf("Writer %i: Giving up.\n", thread_num);
|
||||
return (EXIT_FAILURE);
|
||||
/*
|
||||
* If a generic error occurs, we simply abort the
|
||||
* transaction and exit the thread completely.
|
||||
*/
|
||||
default:
|
||||
envp->err(envp, ret, "db put failed");
|
||||
ret = txn->abort(txn);
|
||||
if (ret != 0)
|
||||
envp->err(envp, ret, "txn abort failed");
|
||||
return (EXIT_FAILURE);
|
||||
} /** End case statement **/
|
||||
|
||||
} /** End for loop **/ </pre>
|
||||
<p>
|
||||
The only other change to <tt class="function">writer_thread()</tt>
|
||||
is that we pass <tt class="function">count_records()</tt> a
|
||||
transaction handle, rather than configuring our entire
|
||||
application for uncommitted reads. Both mechanisms work well-enough
|
||||
for preventing a self-deadlock. However, the individual count
|
||||
in this example will tend to be lower than the counts seen in
|
||||
the previous transaction example, because
|
||||
<tt class="function">count_records()</tt> can no longer see records
|
||||
created but not yet committed by other threads.
|
||||
</p>
|
||||
<pre class="programlisting"> /*
|
||||
* print the number of records found in the database.
|
||||
* See count_records() for usage information.
|
||||
*/
|
||||
printf("Thread %i. Record count: %i\n", thread_num,
|
||||
count_records(dbp, <b class="userinput"><tt>txn</tt></b>));
|
||||
|
||||
/*
|
||||
* If all goes well, we can commit the transaction and
|
||||
* loop to the next transaction.
|
||||
*/
|
||||
ret = txn->commit(txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "txn commit failed");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
return (EXIT_SUCCESS);
|
||||
} </pre>
|
||||
<p>
|
||||
Next we update
|
||||
<span><tt class="function">count_records()</tt>.</span>
|
||||
|
||||
The only difference
|
||||
here is that we no longer specify <tt class="literal">DB_READ_UNCOMMITTED</tt> when
|
||||
we open our cursor. Note that even this minor change is not required.
|
||||
If we do not configure our database to support uncommitted reads,
|
||||
<tt class="literal">DB_READ_UNCOMMITTED</tt> on the cursor open will be silently
|
||||
ignored. However, we remove the flag anyway from the cursor open so as to
|
||||
avoid confusion.
|
||||
</p>
|
||||
<pre class="programlisting">int
|
||||
count_records(DB *dbp, DB_TXN *txn)
|
||||
{
|
||||
DBT key, value;
|
||||
DBC *cursorp;
|
||||
int count, ret;
|
||||
|
||||
cursorp = NULL;
|
||||
count = 0;
|
||||
|
||||
/* Get the cursor */
|
||||
ret = dbp->cursor(dbp, txn, &cursorp, <b class="userinput"><tt>0</tt></b>);
|
||||
if (ret != 0) {
|
||||
dbp->err(dbp, ret, "count_records: cursor open failed.");
|
||||
goto cursor_err;
|
||||
}
|
||||
|
||||
/* Get the key DBT used for the database read */
|
||||
memset(&key, 0, sizeof(DBT));
|
||||
memset(&value, 0, sizeof(DBT));
|
||||
do {
|
||||
ret = cursorp->get(cursorp, &key, &value, DB_NEXT);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
count++;
|
||||
break;
|
||||
case DB_NOTFOUND:
|
||||
break;
|
||||
default:
|
||||
dbp->err(envp, ret,
|
||||
"Count records unspecified error");
|
||||
goto cursor_err;
|
||||
}
|
||||
} while (ret == 0);
|
||||
|
||||
cursor_err:
|
||||
if (cursorp != NULL) {
|
||||
ret = cursorp->close(cursorp);
|
||||
if (ret != 0) {
|
||||
dbp->err(dbp, ret,
|
||||
"count_records: cursor close failed.");
|
||||
}
|
||||
}
|
||||
|
||||
return (count);
|
||||
}</pre>
|
||||
<p>
|
||||
Finally, we update
|
||||
<span><tt class="function">open_db()</tt>.</span>
|
||||
|
||||
This involves
|
||||
removing <tt class="literal">DB_READ_UNCOMMITTED</tt> from the
|
||||
open flags.
|
||||
|
||||
<span>We are also careful to change our database open error
|
||||
message to no longer use the <tt class="literal">file_name</tt>
|
||||
variable because that value will always be <tt class="literal">NULL</tt> for this example.</span>
|
||||
</p>
|
||||
<pre class="programlisting">/* Open a Berkeley DB database */
|
||||
int
|
||||
open_db(DB **dbpp, const char *progname, const char *file_name,
|
||||
DB_ENV *envp, u_int32_t extra_flags)
|
||||
{
|
||||
int ret;
|
||||
u_int32_t open_flags;
|
||||
DB *dbp;
|
||||
|
||||
/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "%s: %s\n", progname,
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Point to the memory malloc'd by db_create() */
|
||||
*dbpp = dbp;
|
||||
|
||||
if (extra_flags != 0) {
|
||||
ret = dbp->set_flags(dbp, extra_flags);
|
||||
if (ret != 0) {
|
||||
dbp->err(dbp, ret,
|
||||
"open_db: Attempt to set extra flags failed.");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now open the database */
|
||||
<b class="userinput"><tt>open_flags = DB_CREATE | /* Allow database creation */
|
||||
DB_THREAD |
|
||||
DB_AUTO_COMMIT; /* Allow auto commit */</tt></b>
|
||||
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
NULL, /* Txn pointer */
|
||||
file_name, /* File name */
|
||||
NULL, /* Logical db name */
|
||||
DB_BTREE, /* Database type (using btree) */
|
||||
open_flags, /* Open flags */
|
||||
0); /* File mode. Using defaults */
|
||||
if (ret != 0) {
|
||||
<b class="userinput"><tt>dbp->err(dbp, ret, "Database open failed");
|
||||
return (EXIT_FAILURE);</tt></b>
|
||||
}
|
||||
return (EXIT_SUCCESS);
|
||||
} </pre>
|
||||
<p>
|
||||
This completes our in-memory transactional example. If you would like to
|
||||
experiment with this code, you can find the example in the following
|
||||
location in your DB distribution:
|
||||
</p>
|
||||
<pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_c/txn_guide</pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="txnexample_c.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="wrapup.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Transaction Example </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
465
docs/gsg_txn/C/introduction.html
Normal file
465
docs/gsg_txn/C/introduction.html
Normal file
@@ -0,0 +1,465 @@
|
||||
<?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>Chapter 1. Introduction</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="previous" href="preface.html" title="Preface" />
|
||||
<link rel="next" href="recovery-intro.html" title="Recoverability" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Chapter 1. Introduction</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="preface.html">Prev</a> </td>
|
||||
<th width="60%" align="center"> </th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="recovery-intro.html">Next</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="chapter" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title"><a id="introduction"></a>Chapter 1. Introduction</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="toc">
|
||||
<p>
|
||||
<b>Table of Contents</b>
|
||||
</p>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="introduction.html#txnintro">Transaction Benefits</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="introduction.html#sysfailure">A Note on System Failure</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="introduction.html#apireq">Application Requirements</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="introduction.html#multithread-intro">Multi-threaded
|
||||
and Multi-process
|
||||
Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="recovery-intro.html">Recoverability</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="perftune-intro.html">Performance Tuning</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</div>
|
||||
<p>
|
||||
This book provides a thorough introduction and discussion on transactions as
|
||||
used with Berkeley DB (DB). It begins by offering a general overview to
|
||||
transactions, the guarantees they provide, and the general application
|
||||
infrastructure required to obtain full transactional protection for your
|
||||
data.
|
||||
</p>
|
||||
<p>
|
||||
This book also provides detailed examples on how to write a
|
||||
transactional application. Both single threaded and multi-threaded <span>(as well as multi-process
|
||||
applications)</span> are discussed. A detailed description of various
|
||||
backup and recovery strategies is included in this manual, as is a
|
||||
discussion on performance considerations for your transactional application.
|
||||
</p>
|
||||
<p>
|
||||
You should understand the concepts from the
|
||||
<span>
|
||||
<i class="citetitle">Getting Started with Berkeley DB</i>
|
||||
</span>
|
||||
|
||||
|
||||
guide before reading this book.
|
||||
</p>
|
||||
<div class="sect1" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title" style="clear: both"><a id="txnintro"></a>Transaction Benefits</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Transactions offer your application's data protection from
|
||||
application or system failures. That is, DB transactions offer
|
||||
your application full ACID support:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
<span class="bold"><b>A</b></span>tomicity
|
||||
</p>
|
||||
<p>
|
||||
Multiple database operations are treated as a single unit of
|
||||
work. Once committed, all write operations performed under
|
||||
the protection of the transaction are saved to your databases.
|
||||
Further, in the event that you abort a transaction, all write
|
||||
operations performed during the transaction are discarded.
|
||||
In this event, your database is left in the state it was in
|
||||
before the transaction began, regardless of the number or
|
||||
type of write operations you may have performed during the
|
||||
course of the transaction.
|
||||
</p>
|
||||
<p>
|
||||
Note that DB transactions can span one or more
|
||||
database handles.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span class="bold"><b>C</b></span>onsistency
|
||||
</p>
|
||||
<p>
|
||||
Your databases will never see a partially completed
|
||||
transaction. This is true even if your application fails while there are
|
||||
in-progress transactions. If the application or system fails,
|
||||
then either all of the database changes appear when the
|
||||
application next runs, or none of them appear.
|
||||
</p>
|
||||
<p>
|
||||
In other words, whatever consistency requirements your application has will never be violated by DB.
|
||||
If, for example, your application requires every record to include an employee ID, and your
|
||||
code faithfully adds that ID to its database records, then DB will never
|
||||
violate that consistency requirement. The ID will remain in the database records until such a time as your
|
||||
application chooses to delete it.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span class="bold"><b>I</b></span>solation
|
||||
</p>
|
||||
<p>
|
||||
While a transaction is in progress, your databases will appear
|
||||
to the transaction as if there are no other operations
|
||||
occurring outside of the transaction. That is, operations
|
||||
wrapped inside a transaction will always have a clean and
|
||||
consistent view of your databases. They never have to see
|
||||
updates currently in progress under the protection of another transaction.
|
||||
Note, however, that isolation guarantees can be
|
||||
|
||||
relaxed from the default setting. See
|
||||
<a href="isolation.html">Isolation</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span class="bold"><b>D</b></span>urability
|
||||
</p>
|
||||
<p>
|
||||
Once committed to your databases, your modifications will
|
||||
persist even in the event of an application or system failure.
|
||||
Note that like isolation, your durability guarantee can be
|
||||
relaxed. See <a href="usingtxns.html#nodurabletxn">Non-Durable Transactions</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="sysfailure"></a>A Note on System Failure</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
From time to time this manual mentions that transactions protect your data against 'system or application
|
||||
failure.' This is
|
||||
true up to a certain extent. However, not all failures are created equal and no data protection
|
||||
mechanism can protect you against every conceivable way a computing system can find to die.
|
||||
</p>
|
||||
<p>
|
||||
Generally, when this book talks about protection against failures, it means that
|
||||
transactions offer protection against
|
||||
the likeliest culprits for system and application crashes. So long as your data modifications have been
|
||||
committed to disk, those modifications should persist even if your application or OS subsequently fails.
|
||||
And, even if the application or OS fails in the middle of a transaction commit (or abort), the data on disk
|
||||
should be either in a consistent state, or there should be enough data available to bring
|
||||
your databases into a consistent state (via a recovery procedure, for example). You may, however,
|
||||
lose whatever data you were committing at the
|
||||
time of the failure, but your databases will be otherwise unaffected.
|
||||
</p>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
Be aware that many disks have a disk write cache and on
|
||||
some systems it is enabled by default. This means that
|
||||
a transaction can have committed, and to your
|
||||
application the data may appear to reside on disk, but
|
||||
the data may in fact reside only in the write cache at
|
||||
that time. This means that if the disk write cache is
|
||||
enabled and there is no battery backup for it, data can
|
||||
be lost after an OS crash even when maximum durability
|
||||
mode is in use. For maximum durability, disable the
|
||||
disk write cache or use a disk write cache with a
|
||||
battery backup.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
Of course, if your <span class="emphasis"><em>disk</em></span> fails, then the transactional benefits described in this book
|
||||
are only as good as the backups you have taken.
|
||||
|
||||
|
||||
<span>
|
||||
By spreading your data and log files across separate disks,
|
||||
you can minimize the risk of data loss due to a disk failure, but even in this case it is possible to
|
||||
conjure a scenario where even this protection is insufficient (a fire in the machine room, for example) and
|
||||
you must go to your backups for protection.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
Finally, by following the programming examples shown in this book, you can write your code so as to protect
|
||||
your data in the event that your code crashes. However, no programming API can protect you against logic
|
||||
failures in your own code; transactions cannot protect you from simply writing the wrong thing to your
|
||||
databases.
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="apireq"></a>Application Requirements</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
In order to use transactions, your application has certain
|
||||
requirements beyond what is required of non-transactional protected
|
||||
applications. They are:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Environments.
|
||||
</p>
|
||||
<p>
|
||||
Environments are optional for non-transactional
|
||||
applications, but they are required for transactional
|
||||
applications.
|
||||
</p>
|
||||
<p>
|
||||
Environments are optional for non-transactional
|
||||
applications that use the base API, but they are required for transactional
|
||||
applications. (Of course, applications that use the
|
||||
DPL always require the DPL.)
|
||||
</p>
|
||||
<p>
|
||||
Environment usage is described in detail in
|
||||
<a href="usingtxns.html">Transaction Basics</a>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Transaction subsystem.
|
||||
</p>
|
||||
<p>
|
||||
In order to use transactions, you must explicitly
|
||||
enable the transactional subsystem for your
|
||||
application, and this must be done at the time that
|
||||
your environment is first created.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Logging subsystem.
|
||||
</p>
|
||||
<p>
|
||||
The logging subsystem is required for recovery purposes, but
|
||||
its usage also means your application may require a
|
||||
little more administrative effort than it does when logging
|
||||
is not in use. See <a href="filemanagement.html">Managing DB Files</a> for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span>DB_TXN</span>
|
||||
|
||||
|
||||
|
||||
handles.
|
||||
</p>
|
||||
<p>
|
||||
In order to obtain the atomicity guarantee offered by
|
||||
the transactional subsystem (that is, combine multiple
|
||||
operations in a single unit of work), your application must use
|
||||
transaction handles. These handles are obtained from your
|
||||
<span>DB_ENV</span>
|
||||
|
||||
|
||||
|
||||
objects. They should normally be short-lived, and their usage is
|
||||
reasonably simple. To complete a transaction and save
|
||||
the work it performed, you
|
||||
call its <tt class="methodname">commit()</tt> method. To
|
||||
complete a transaction and discard its work, you call its
|
||||
<tt class="methodname">abort()</tt> method.
|
||||
</p>
|
||||
<p>
|
||||
In addition, it is possible to use auto commit if you want
|
||||
to transactional protect a single write operation. Auto
|
||||
commit allows a transaction to be used without
|
||||
obtaining an explicit transaction handle. See
|
||||
<a href="autocommit.html">Auto Commit</a>
|
||||
for information on how to use auto commit.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span>Database</span>
|
||||
|
||||
open requirements.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
<span>In addition to using
|
||||
environments and initializing the
|
||||
correct subsystems, your</span>
|
||||
|
||||
application must transaction protect the database
|
||||
|
||||
opens<span>,
|
||||
and any secondary index associations,</span>
|
||||
|
||||
if subsequent operations on the databases are to be transaction
|
||||
protected. The database open and secondary index
|
||||
association are commonly transaction protected using
|
||||
auto commit.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Deadlock detection.
|
||||
</p>
|
||||
<p>
|
||||
Typically transactional applications use multiple
|
||||
threads of control when accessing the database. Any
|
||||
time multiple threads are used on a single resource,
|
||||
the potential for lock contention arises. In turn, lock
|
||||
contention can lead to deadlocks. See
|
||||
<a href="blocking_deadlocks.html">Locks, Blocks, and Deadlocks</a>
|
||||
for more information.
|
||||
</p>
|
||||
<p>
|
||||
Therefore, transactional applications must frequently
|
||||
include code for detecting and responding to deadlocks.
|
||||
Note that this requirement is not
|
||||
<span class="emphasis"><em>specific</em></span> to transactions
|
||||
– you can certainly write concurrent
|
||||
non-transactional DB applications. Further, not
|
||||
every transactional application uses concurrency and
|
||||
so not every transactional application must
|
||||
manage deadlocks. Still, deadlock management is so
|
||||
frequently a characteristic of transactional
|
||||
applications that we discuss it in this
|
||||
book. See <a href="txnconcurrency.html">Concurrency</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="multithread-intro"></a>Multi-threaded
|
||||
<span>and Multi-process</span>
|
||||
Applications</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
DB is designed to support multi-threaded <span>and
|
||||
multi-process</span> applications, but their usage means
|
||||
you must pay careful attention to issues of concurrency.
|
||||
Transactions help your application's concurrency by providing various levels of
|
||||
isolation for your threads of control. In addition, DB
|
||||
provides mechanisms that allow you to detect and respond to
|
||||
deadlocks (but strictly speaking, this is not limited to just
|
||||
transactional applications).
|
||||
</p>
|
||||
<p>
|
||||
<span class="emphasis"><em>Isolation</em></span> means that database modifications made by
|
||||
one transaction will not normally be seen by readers from another
|
||||
transaction until the first commits its changes. Different threads
|
||||
use different transaction handles, so
|
||||
this mechanism is normally used to provide isolation between
|
||||
database operations performed by different threads.
|
||||
</p>
|
||||
<p>
|
||||
Note that DB supports different isolation levels. For example,
|
||||
you can configure your application to see uncommitted reads, which means
|
||||
that one transaction can see data that has been modified but not yet
|
||||
committed by another transaction. Doing this might mean your
|
||||
transaction reads data "dirtied" by another transaction,
|
||||
but which subsequently might change before that
|
||||
other transaction commits its changes.
|
||||
On the other hand, lowering your isolation
|
||||
requirements means that your application can experience
|
||||
improved throughput due to reduced lock contention.
|
||||
</p>
|
||||
<p>
|
||||
For more information on concurrency, on managing isolation
|
||||
levels, and on deadlock detection, see <a href="txnconcurrency.html">Concurrency</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="preface.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="index.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="recovery-intro.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Preface </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Recoverability</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
828
docs/gsg_txn/C/isolation.html
Normal file
828
docs/gsg_txn/C/isolation.html
Normal file
@@ -0,0 +1,828 @@
|
||||
<?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.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||||
<link rel="previous" href="lockingsubsystem.html" title="The Locking Subsystem" />
|
||||
<link rel="next" href="txn_ccursor.html" title="Transactional Cursors and Concurrent Applications" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<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>
|
||||
</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></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 href="isolation.html#dirtyreads">Reading Uncommitted Data</a>
|
||||
for more information.
|
||||
|
||||
You can also configure DB to use committed read isolation. See
|
||||
<a href="isolation.html#readcommitted">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 href="isolation.html#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></div>
|
||||
</div>
|
||||
<p>
|
||||
You can 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 <tt class="literal">DB_READ_UNCOMMITTED</tt> when you open your database.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span>
|
||||
Specify <tt class="literal">DB_READ_UNCOMMITTED</tt>
|
||||
when you create the transaction,
|
||||
<span>
|
||||
open the cursor, or read a record from the database.
|
||||
</span>
|
||||
|
||||
</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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t db_flags, env_flags;
|
||||
DB *dbp;
|
||||
DB_ENV *envp;
|
||||
DB_TXN *txn;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
const char *file_name = "mydb.db";
|
||||
const char *keystr ="thekey";
|
||||
const char *datastr = "thedata";
|
||||
|
||||
dbp = NULL;
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database creation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
db_flags = DB_CREATE | /* Create the db if it does not
|
||||
* exist */
|
||||
DB_AUTO_COMMIT | /* Enable auto commit */
|
||||
DB_READ_UNCOMMITTED; /* Enable uncommitted reads */
|
||||
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
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 */
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database '%s' open failed",
|
||||
file_name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Get the txn handle */
|
||||
txn = NULL;
|
||||
ret = envp->txn_begin(envp, NULL, &txn, DB_READ_UNCOMMITTED);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Transaction begin failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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></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, <tt class="literal">Ta</tt> and <tt class="literal">Tb</tt>. Suppose further that
|
||||
<tt class="literal">Ta</tt> has a cursor that reads <tt class="literal">record R</tt>, but does not modify it. Normally,
|
||||
<tt class="literal">Tb</tt> would then be unable to write <tt class="literal">record R</tt> because
|
||||
<tt class="literal">Ta</tt> would be holding a read lock on it. But when you configure your transaction for
|
||||
committed reads, <tt class="literal">Tb</tt> <span class="emphasis"><em>can</em></span> modify <tt class="literal">record
|
||||
R</tt> before <tt class="literal">Ta</tt> 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 <tt class="literal">DB_READ_COMMITTED</tt> when you open the transaction.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span>
|
||||
Specify <tt class="literal">DB_READ_COMMITTED</tt>
|
||||
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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t db_flags, env_flags;
|
||||
DB *dbp;
|
||||
DB_ENV *envp;
|
||||
DB_TXN *txn;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
const char *file_name = "mydb.db";
|
||||
|
||||
dbp = NULL;
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database creation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
db_flags = DB_CREATE | DB_AUTO_COMMIT;
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
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 */
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database '%s' open failed",
|
||||
file_name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Get the txn handle */
|
||||
txn = NULL;
|
||||
/*
|
||||
* Open the transaction and enable committed reads. All cursors open
|
||||
* with this transaction handle will use read committed isolation.
|
||||
*/
|
||||
ret = envp->txn_begin(envp, NULL, &txn, DB_READ_COMMITTED);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Transaction begin failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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).
|
||||
*
|
||||
* 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></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></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
|
||||
<tt class="methodname">DB_ENV->log_archive()</tt>
|
||||
|
||||
|
||||
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></div>
|
||||
</div>
|
||||
<p>
|
||||
In addition to an increased cache size, you may also
|
||||
need to increase the maximum number of transactions
|
||||
that your application supports. (See
|
||||
<a href="maxtxns.html">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></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></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
|
||||
<tt class="literal">DB_MULTIVERSION</tt>
|
||||
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 <tt class="literal">DB_TXN_SNAPSHOT</tt> 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 href="lockingsubsystem.html#deadlockresolve">Resolving Deadlocks</a>
|
||||
for details.
|
||||
</p>
|
||||
<p>
|
||||
The following code fragment turns
|
||||
on snapshot isolation for a transaction:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t db_flags, env_flags;
|
||||
DB *dbp;
|
||||
DB_ENV *envp;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
const char *file_name = "mydb.db";
|
||||
|
||||
dbp = NULL;
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
env_flags = DB_CREATE | /* Create the environment if it does
|
||||
* not already exist. */
|
||||
DB_INIT_TXN | /* Initialize transactions */
|
||||
DB_INIT_LOCK | /* Initialize locking. */
|
||||
DB_INIT_LOG | /* Initialize logging */
|
||||
DB_INIT_MPOOL| /* Initialize the in-memory cache. */
|
||||
<b class="userinput"><tt>DB_MULTIVERSION; /* Support snapshot isolation */</tt></b>
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database creation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Nothing needs to be supplied here to support snapshot isolation.
|
||||
* The environment does, so its databases will too.
|
||||
*/
|
||||
db_flags = DB_CREATE | DB_AUTO_COMMIT;
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
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 */
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database '%s' open failed",
|
||||
file_name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
....
|
||||
|
||||
ret = envp->txn_begin(envp, NULL, &txn, <b class="userinput"><tt>DB_TXN_SNAPSHOT</tt></b>);
|
||||
|
||||
/* remainder of the 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>
|
||||
558
docs/gsg_txn/C/lockingsubsystem.html
Normal file
558
docs/gsg_txn/C/lockingsubsystem.html
Normal file
@@ -0,0 +1,558 @@
|
||||
<?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>The Locking Subsystem</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||||
<link rel="previous" href="blocking_deadlocks.html" title="Locks, Blocks, and Deadlocks" />
|
||||
<link rel="next" href="isolation.html" title="Isolation" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">The Locking Subsystem</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="blocking_deadlocks.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 4. Concurrency</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="isolation.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="lockingsubsystem"></a>The Locking Subsystem</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
In order to allow concurrent operations, DB provides the locking
|
||||
subsystem. This subsystem provides inter- and intra- process
|
||||
concurrency mechanisms. It is extensively used by DB concurrent
|
||||
applications, but it can also be generally used for non-DB
|
||||
resources.
|
||||
</p>
|
||||
<p>
|
||||
This section describes the locking subsystem as it is used to
|
||||
protect DB resources. In particular, issues on configuration are
|
||||
examined here. For information on using the locking subsystem to
|
||||
manage non-DB resources, see the
|
||||
<i class="citetitle">Berkeley DB Programmer's Reference Guide</i>.
|
||||
</p>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="configuringlock"></a>Configuring the Locking Subsystem</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
You initialize the locking subsystem by specifying
|
||||
<span>
|
||||
<tt class="literal">DB_INIT_LOCK</tt> to the
|
||||
<tt class="methodname">DB_ENV->open()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Before opening your environment, you can configure various
|
||||
maximum values for your locking subsystem. Note that these
|
||||
limits can only be configured before the environment is
|
||||
opened. Also, these methods configure the entire environment,
|
||||
not just a specific environment handle.
|
||||
</p>
|
||||
<p>
|
||||
Finally, each bullet below identifies the
|
||||
<tt class="filename">DB_CONFIG</tt> file parameter that can be used
|
||||
to specify the specific locking limit. If used, these
|
||||
<tt class="filename">DB_CONFIG</tt> file parameters override any
|
||||
value that you might specify using the environment handle.
|
||||
</p>
|
||||
<p>
|
||||
The limits that you can configure are as follows:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
The maximum number of lockers
|
||||
supported by the environment. This value is used by
|
||||
the environment when it is opened to estimate the amount
|
||||
of space that it should allocate for various internal
|
||||
data structures. By default, 1,000 lockers are
|
||||
supported.
|
||||
</p>
|
||||
<p>
|
||||
To configure this value, use the
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->set_lk_max_lockers()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
As an alternative to this method, you can configure this
|
||||
value using the <tt class="filename">DB_CONFIG</tt> file's
|
||||
<tt class="literal">set_lk_max_lockers</tt> parameter.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
The maximum number of locks supported by the environment.
|
||||
By default, 1,000 locks are supported.
|
||||
</p>
|
||||
<p>
|
||||
To configure this value, use the
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->set_lk_max_locks()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
As an alternative to this method, you can configure this
|
||||
value using the <tt class="filename">DB_CONFIG</tt> file's
|
||||
<tt class="literal">set_lk_max_locks</tt> parameter.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
The maximum number of locked objects supported by the environment.
|
||||
By default, 1,000 objects can be locked.
|
||||
</p>
|
||||
<p>
|
||||
To configure this value, use the
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->set_lk_max_objects()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
As an alternative to this method, you can configure this
|
||||
value using the <tt class="filename">DB_CONFIG</tt> file's
|
||||
<tt class="literal">set_lk_max_objects</tt> parameter.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
For a definition of lockers, locks, and locked objects, see
|
||||
<a href="blocking_deadlocks.html#lockresources">Lock Resources</a>.
|
||||
</p>
|
||||
<p>
|
||||
For example, to configure the maximum number of locks that your
|
||||
environment can use:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t env_flags;
|
||||
DB_ENV *envp;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
/* Configure max locks */
|
||||
ret = envp->set_lk_max_locks(envp, 5000);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error configuring locks: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Open the environment. */
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
/* Close the environment */
|
||||
if (envp != NULL) {
|
||||
ret_c = envp->close(envp, 0);
|
||||
if (ret_c != 0) {
|
||||
fprintf(stderr, "environment close failed: %s\n",
|
||||
db_strerror(ret_c));
|
||||
ret = ret_c;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="configdeadlkdetect"></a>Configuring Deadlock Detection</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
In order for DB to know that a deadlock has occurred,
|
||||
some mechanism must be used to perform deadlock
|
||||
detection. There are three ways that deadlock detection can
|
||||
occur:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Allow DB to internally detect deadlocks as they
|
||||
occur.
|
||||
</p>
|
||||
<p>
|
||||
To do this, you use
|
||||
<span><tt class="methodname">DB_ENV->set_lk_detect()</tt>.</span>
|
||||
|
||||
|
||||
This method causes DB to walk its internal lock table
|
||||
looking for a deadlock whenever a lock request
|
||||
is blocked. This method also identifies how DB decides which lock
|
||||
requests are rejected when deadlocks are detected. For example,
|
||||
DB can decide to reject the lock request for the transaction
|
||||
that has the most number of locks, the least number of locks,
|
||||
holds the oldest lock, holds the most number of write locks, and
|
||||
so forth (see the API reference documentation for a complete
|
||||
list of the lock detection policies).
|
||||
</p>
|
||||
<p>
|
||||
You can call this method at any time during your application's
|
||||
lifetime, but typically it is used before you open your environment.
|
||||
</p>
|
||||
<p>
|
||||
Note that how you want DB to decide which thread of control should break a deadlock is
|
||||
extremely dependent on the nature of your application. It is not unusual for some performance
|
||||
testing to be required in order to make this determination. That said, a transaction that is
|
||||
holding the maximum number of locks is usually indicative of the transaction that has performed
|
||||
the most amount of work. Frequently you will not want a transaction that has performed a lot of
|
||||
work to abandon its efforts and start all over again. It is not therefore uncommon for
|
||||
application developers to initially select the transaction with the <span class="emphasis"><em>minimum</em></span>
|
||||
number of write locks to break the deadlock.
|
||||
</p>
|
||||
<p>
|
||||
Using this mechanism for deadlock detection means
|
||||
that your application will never have to wait on a
|
||||
lock before discovering that a deadlock has
|
||||
occurred. However, walking the lock table every
|
||||
time a lock request is blocked can be expensive
|
||||
from a performance perspective.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Use a dedicated thread or external process to perform
|
||||
deadlock detection. Note that this thread must be
|
||||
performing no other database operations beyond deadlock
|
||||
detection.
|
||||
</p>
|
||||
<p>
|
||||
To externally perform lock detection, you can use
|
||||
either the
|
||||
<tt class="methodname">DB_ENV->lock_detect()</tt>
|
||||
|
||||
|
||||
method, or use the
|
||||
<span><b class="command">db_deadlock</b></span> command line
|
||||
utility. This method (or command) causes DB to walk the
|
||||
lock table looking for deadlocks.
|
||||
</p>
|
||||
<p>
|
||||
Note that like
|
||||
<span><tt class="methodname">DB_ENV->set_lk_detect()</tt>,</span>
|
||||
|
||||
|
||||
you also use this method (or command line utility)
|
||||
to identify which lock requests are rejected in the
|
||||
event that a deadlock is detected.
|
||||
</p>
|
||||
<p>
|
||||
Applications that perform deadlock detection in
|
||||
this way typically run deadlock detection between every few
|
||||
seconds and a minute. This means that your
|
||||
application may have to wait to be notified of a
|
||||
deadlock, but you also save the overhead of walking
|
||||
the lock table every time a lock request is blocked.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Lock timeouts.
|
||||
</p>
|
||||
<p>
|
||||
You can configure your locking subsystem such that
|
||||
it times out any lock that is not released within a
|
||||
specified amount of time. To do this, use the
|
||||
<span><tt class="methodname">DB_ENV->set_timeout()</tt></span>
|
||||
|
||||
|
||||
method.
|
||||
Note that lock timeouts are only checked when a
|
||||
lock request is blocked or when deadlock
|
||||
detection is otherwise performed. Therefore, a lock can have timed out and still be held for
|
||||
some length of time until DB has a reason to examine its locking tables.
|
||||
</p>
|
||||
<p>
|
||||
Be aware that extremely long-lived transactions, or
|
||||
operations that hold locks for a long time, may be
|
||||
inappropriately timed out before the transaction or
|
||||
operation has a chance to complete. You should
|
||||
therefore use this mechanism only if you know your
|
||||
application will hold locks for very short periods
|
||||
of time.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<p>
|
||||
For example, to configure your application such that DB
|
||||
checks the lock table for deadlocks every time a lock
|
||||
request is blocked:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t db_flags, env_flags;
|
||||
DB *dbp;
|
||||
DB_ENV *envp;
|
||||
DB_TXN *txn;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
const char *file_name = "mydb.db";
|
||||
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
* Configure db to perform deadlock detection internally, and to
|
||||
* choose the transaction that has performed the least amount of writing
|
||||
* to break the deadlock in the event that one is detected.
|
||||
*/
|
||||
ret = envp->set_lk_detect(envp, DB_LOCK_MINWRITE);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error setting lk detect: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* From here, you open your databases, proceed with your
|
||||
* database operations, and respond to deadlocks as
|
||||
* is normal (omitted for brevity).
|
||||
*/
|
||||
|
||||
... </pre>
|
||||
<p>
|
||||
Finally, the following command line call causes
|
||||
deadlock detection to be run against the
|
||||
environment contained in <tt class="literal">/export/dbenv</tt>. The
|
||||
transaction with the youngest lock is chosen to break the
|
||||
deadlock:
|
||||
</p>
|
||||
<pre class="programlisting">> /usr/local/db_install/bin/db_deadlock -h /export/dbenv -a y</pre>
|
||||
<p>
|
||||
For more information, see the
|
||||
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/utility/db_deadlock.html" target="_top">
|
||||
<tt class="literal">db_deadlock</tt> reference documentation.
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="deadlockresolve"></a>Resolving Deadlocks</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
When DB determines that a deadlock has occurred, it will
|
||||
select a thread of control to resolve the deadlock and then
|
||||
<span>
|
||||
return <tt class="literal">DB_LOCK_DEADLOCK</tt> to that
|
||||
thread.
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
If a deadlock is detected, the thread must:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Cease all read and write operations.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Close all open cursors.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Abort the transaction.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Optionally retry the operation. If your application
|
||||
retries deadlocked operations, the new attempt must
|
||||
be made using a new transaction.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
If a thread has deadlocked, it may not make any
|
||||
additional database calls using the handle that has
|
||||
deadlocked.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting">retry:
|
||||
ret = envp->txn_begin(envp, NULL, &txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "txn_begin failed");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
...
|
||||
/* key and data are Dbts. Their usage is omitted for brevity. */
|
||||
...
|
||||
switch (ret = dbp->put(dbp, txn, &key, &data, 0)) {
|
||||
case 0:
|
||||
break;
|
||||
/* Deadlock handling goes here */
|
||||
case DB_LOCK_DEADLOCK:
|
||||
/* Abort the transaction */
|
||||
(void)txn->abort(txn);
|
||||
|
||||
/*
|
||||
* retry_count is a counter used to identify how many times
|
||||
* we've retried this operation. To avoid the potential for
|
||||
* endless looping, we won't retry more than
|
||||
* MAX_DEADLOCK_RETRIES times.
|
||||
*/
|
||||
if (retry_count < MAX_DEADLOCK_RETRIES) {
|
||||
printf("Got DB_LOCK_DEADLOCK.\n");
|
||||
printf("Retrying write operation.\n");
|
||||
retry_count++;
|
||||
goto retry;
|
||||
}
|
||||
printf("Got DB_LOCK_DEADLOCK and out of retries.");
|
||||
printf("Giving up.\n");
|
||||
return (EXIT_FAILURE);
|
||||
default:
|
||||
/* If some random database error occurs, we just give up */
|
||||
envp->err(envp, ret, "db put failed");
|
||||
ret = txn->abort(txn);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "txn abort failed");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
/* If all goes well, commit the transaction */
|
||||
ret = txn->commit(txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "txn commit failed");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return (EXIT_SUCCESS); </pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="blocking_deadlocks.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="isolation.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Locks, Blocks, and Deadlocks </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Isolation</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
445
docs/gsg_txn/C/logconfig.html
Normal file
445
docs/gsg_txn/C/logconfig.html
Normal file
@@ -0,0 +1,445 @@
|
||||
<?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>Configuring the Logging Subsystem</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="filemanagement.html" title="Chapter 5. Managing DB Files" />
|
||||
<link rel="previous" href="logfileremoval.html" title="Removing Log Files" />
|
||||
<link rel="next" href="wrapup.html" title="Chapter 6. Summary and Examples" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Configuring the Logging Subsystem</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="logfileremoval.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 5. Managing DB Files</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="wrapup.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="logconfig"></a>Configuring the Logging Subsystem</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
You can configure the following aspects of the logging
|
||||
subsystem:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Size of the log files.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Size of the logging subsystem's region.
|
||||
See <a href="logconfig.html#logregionsize">Configuring the Logging Region Size</a>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Maintain logs entirely in-memory.
|
||||
See <a href="logconfig.html#inmemorylogging">Configuring In-Memory Logging</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Size of the log buffer in memory.
|
||||
See <a href="logconfig.html#logbuffer">Setting the In-Memory Log Buffer Size</a>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
On-disk location of your log files. See
|
||||
<a href="enabletxn.html#splittingdata">Identifying Specific File Locations</a>.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="logfilesize"></a>Setting the Log File Size</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Whenever a pre-defined amount of data is written to a
|
||||
log file (10 MB by default), DB stops using the
|
||||
current log file and starts writing to a new file.
|
||||
You can change the maximum amount of data contained in each
|
||||
log file by using the
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->set_lg_max()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
Note that this method can be used at any time
|
||||
during an application's lifetime.
|
||||
</p>
|
||||
<p>
|
||||
Setting the log file size to something larger than its
|
||||
default value is largely a matter of
|
||||
convenience and a reflection of the application's
|
||||
preference in backup media and frequency. However, if
|
||||
you set the log file size too low relative to your
|
||||
application's traffic patterns, you can cause
|
||||
yourself trouble.
|
||||
</p>
|
||||
<p>
|
||||
From a performance perspective, setting the log file
|
||||
size to a low value can cause your active transactions to
|
||||
pause their writing activities more frequently than would
|
||||
occur with larger log file sizes. Whenever a
|
||||
transaction completes the log buffer is flushed to
|
||||
disk. Normally other transactions can continue to
|
||||
write to the log buffer while this flush is in
|
||||
progress. However, when one log file is being closed
|
||||
and another created, all transactions must cease
|
||||
writing to the log buffer until the switch over is
|
||||
completed.
|
||||
</p>
|
||||
<p>
|
||||
Beyond performance concerns, using smaller log files
|
||||
can cause you to use more physical files on disk.
|
||||
As a result, your application could run out
|
||||
of log sequence numbers, depending on how busy your
|
||||
application is.
|
||||
</p>
|
||||
<p>
|
||||
Every log file is identified with a 10 digit number.
|
||||
Moreover, the maximum number of log files that your application
|
||||
is allowed to create in its lifetime is 2,000,000,000.
|
||||
</p>
|
||||
<p>
|
||||
For example, if your application performs 6,000 transactions per
|
||||
second for 24 hours a day, and you are logging 500 bytes of
|
||||
data per transaction into 10 MB log files, then you
|
||||
will run out of log files in around 221 years:
|
||||
</p>
|
||||
<pre class="programlisting"> (10 * 2^20 * 2000000000) / (6000 * 500 * 365 * 60 *60 * 24) = 221 </pre>
|
||||
<p>
|
||||
However, if you were writing 2000 bytes of data per
|
||||
transaction, and using 1 MB log files, then the same
|
||||
formula shows you running out of log files in 5 years time.
|
||||
</p>
|
||||
<p>
|
||||
All of these time frames are quite long, to be sure,
|
||||
but if you do run out of log files after, say, 5 years
|
||||
of continuous operations, then you must reset your log
|
||||
sequence numbers. To do so:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Backup your databases as if to prepare for
|
||||
catastrophic failure. See
|
||||
<a href="backuprestore.html">Backup Procedures</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Reset the log file's sequence number using the
|
||||
<span><b class="command">db_load</b></span> utility's
|
||||
<tt class="literal">-r</tt> option.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Remove all of the log files from your
|
||||
environment. Note that this is the only
|
||||
situation in which all of the log files are
|
||||
removed from an environment; in all other
|
||||
cases, at least a single log file is retained.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Restart your application.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="logregionsize"></a>Configuring the Logging Region Size</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
The logging subsystem's default region size is 60 KB. The
|
||||
logging region is used to store filenames, and so you may
|
||||
need to increase its size if a large number of files (that
|
||||
is, if you have a very large number of databases) will
|
||||
be opened and registered with DB's log manager.
|
||||
</p>
|
||||
<p>
|
||||
You can set the size of your logging region by using the
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->set_lg_regionmax()</tt>
|
||||
|
||||
</span>
|
||||
|
||||
method. Note that this method can only be called before the
|
||||
first environment handle for your application is opened.
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="inmemorylogging"></a>Configuring In-Memory Logging</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
It is possible to configure your logging subsystem such
|
||||
that logs are maintained entirely in memory. When
|
||||
you do this, you give up your transactional durability
|
||||
guarantee. Without log files, you have no way to run
|
||||
recovery so any system or software failures that you might
|
||||
experience can corrupt your databases.
|
||||
</p>
|
||||
<p>
|
||||
However, by giving up your durability guarantees, you can
|
||||
greatly improve your application's throughput by avoiding
|
||||
the disk I/O necessary to write logging information to
|
||||
disk. In this case, you still retain your transactional
|
||||
atomicity, consistency, and isolation guarantees.
|
||||
</p>
|
||||
<p>
|
||||
To configure your logging subsystem to maintain your logs
|
||||
entirely in-memory:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Make sure your log buffer is capable of holding all
|
||||
log information that can accumulate during the longest
|
||||
running transaction. See <a href="logconfig.html#logbuffer">Setting the In-Memory Log Buffer Size</a> for details.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Do not run normal recovery when you open your environment. In this configuration, there are no
|
||||
log files available against which you can run recovery. As a result, if you specify recovery
|
||||
when you open your environment, it is ignored.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Specify
|
||||
<span>
|
||||
<tt class="literal">DB_LOG_IN_MEMORY</tt> to the
|
||||
<tt class="methodname">DB_ENV->log_set_config()</tt>
|
||||
|
||||
</span>
|
||||
|
||||
|
||||
method. Note that you must specify this before
|
||||
your application opens its first environment
|
||||
handle.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t db_flags, env_flags;
|
||||
DB_ENV *envp;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
|
||||
envp = NULL;
|
||||
|
||||
/* Create the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Indicate that logging is to be performed only in memory.
|
||||
* Doing this means that we give up our transactional durability
|
||||
* guarantee.
|
||||
*/
|
||||
envp->log_set_config(envp, DB_LOG_IN_MEMORY, 1);
|
||||
|
||||
/*
|
||||
* Configure the size of our log memory buffer. This must be
|
||||
* large enough to hold all the logging information likely
|
||||
* to be created for our longest running transaction. The
|
||||
* default size for the logging buffer is 1 MB when logging
|
||||
* is performed in-memory. For this example, we arbitrarily
|
||||
* set the logging buffer to 5 MB.
|
||||
*/
|
||||
ret = envp->set_lg_bsize(envp, 5 * 1024 * 1024);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error setting log buffer size: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the normal flags for a transactional subsystem. Note that
|
||||
* we DO NOT specify DB_RECOVER. Also, remember that the logging
|
||||
* subsystem is automatically enabled when we initialize the
|
||||
* transactional subsystem, so we do not explicitly enable
|
||||
* logging here.
|
||||
*/
|
||||
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 */
|
||||
|
||||
/* Open the environment as normal */
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* From here, you create transactions and perform database operations
|
||||
* exactly as you would if you were logging to disk. This part is
|
||||
* omitted for brevity.
|
||||
*/
|
||||
|
||||
...
|
||||
|
||||
err:
|
||||
/* Close the databases (omitted) */
|
||||
|
||||
...
|
||||
|
||||
/* Close the environment */
|
||||
if (envp != NULL) {
|
||||
ret_c = envp->close(envp, 0);
|
||||
if (ret_c != 0) {
|
||||
fprintf(stderr, "environment close failed: %s\n",
|
||||
db_strerror(ret_c));
|
||||
ret = ret_c;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="logbuffer"></a>Setting the In-Memory Log Buffer Size</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
When your application is configured for on-disk logging
|
||||
(the default behavior for transactional applications), log
|
||||
information is stored in-memory until the storage space
|
||||
fills up, or a transaction commit forces the log
|
||||
information to be flushed to disk.
|
||||
</p>
|
||||
<p>
|
||||
It is possible to increase the amount of memory available
|
||||
to your file log buffer. Doing so improves throughput for
|
||||
long-running transactions, or for transactions that produce
|
||||
a large amount of data.
|
||||
</p>
|
||||
<p>
|
||||
When you have your logging subsystem configured to maintain
|
||||
your log entirely in memory (see
|
||||
<a href="logconfig.html#inmemorylogging">Configuring In-Memory Logging</a>), it is very important
|
||||
to configure your log buffer size because the log buffer
|
||||
must be capable of holding all log information that can
|
||||
accumulate during the longest running transaction.
|
||||
You must make sure that the in-memory log buffer size is
|
||||
large enough that no transaction will ever span the entire
|
||||
buffer. You must also avoid a state where the in-memory
|
||||
buffer is full and no space can be freed because a
|
||||
transaction that started the first log "file" is still
|
||||
active.
|
||||
</p>
|
||||
<p>
|
||||
When your logging subsystem is configured for on-disk
|
||||
logging, the default log buffer space is 32 KB. When
|
||||
in-memory logging is configured, the default log buffer
|
||||
space is 1 MB.
|
||||
</p>
|
||||
<p>
|
||||
You can increase your log buffer space using the
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->set_lg_bsize()</tt>
|
||||
|
||||
</span>
|
||||
|
||||
method. Note that this method can only be called before the
|
||||
first environment handle for your application is opened.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="logfileremoval.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="filemanagement.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="wrapup.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Removing Log Files </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Chapter 6. Summary and Examples</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
209
docs/gsg_txn/C/logfileremoval.html
Normal file
209
docs/gsg_txn/C/logfileremoval.html
Normal file
@@ -0,0 +1,209 @@
|
||||
<?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>Removing Log Files</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="filemanagement.html" title="Chapter 5. Managing DB Files" />
|
||||
<link rel="previous" href="hotfailover.html" title="Using Hot Failovers" />
|
||||
<link rel="next" href="logconfig.html" title="Configuring the Logging Subsystem" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Removing Log Files</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="hotfailover.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 5. Managing DB Files</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="logconfig.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="logfileremoval"></a>Removing Log Files</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
By default DB does not delete log files for you. For this reason,
|
||||
DB's log files will eventually grow to consume an
|
||||
unnecessarily large amount of disk space. To guard against
|
||||
this, you should periodically take administrative action to
|
||||
remove log files that are no longer in use by your application.
|
||||
</p>
|
||||
<p>
|
||||
You can remove a log file if all of the following are true:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
the log file is not involved in an active transaction.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
a checkpoint has been performed
|
||||
<span class="emphasis"><em>after</em></span> the log file was
|
||||
created.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
the log file is not the only log file in the
|
||||
environment.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
the log file that you want to remove has already been
|
||||
included in an offline or hot backup.
|
||||
Failure to observe this last condition can cause your
|
||||
backups to be unusable.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
DB provides several mechanisms to remove log files that
|
||||
meet all but the last criteria (DB has no way to know which
|
||||
log files have already been included in a backup). The
|
||||
following mechanisms make it easy to remove unneeded log files,
|
||||
but can result in an unusable backup if the log files are not first
|
||||
saved to your archive location. All of the following
|
||||
mechanisms automatically delete unneeded log files for you:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Run the <span><b class="command">db_archive</b></span> command line
|
||||
utility with the <tt class="literal">-d</tt> option.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
From within your application, call the
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->log_archive()</tt>
|
||||
|
||||
method with the <tt class="literal">DB_ARCH_REMOVE</tt> flag.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span>
|
||||
Call
|
||||
<span>
|
||||
<tt class="methodname">DB_ENV->log_set_config()</tt>
|
||||
|
||||
method with the <tt class="literal">DB_LOG_AUTO_REMOVE</tt> flag.
|
||||
</span>
|
||||
|
||||
Note that this flag can be set at any point in
|
||||
the lifetime of your application. Setting this
|
||||
parameter affects all environment handles
|
||||
opened against the environment; not just the
|
||||
handle used to set the flag.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Note that unlike the other log removal mechanisms
|
||||
identified here, this method actually causes log files
|
||||
to be removed on an on-going basis as they become
|
||||
unnecessary. This is extremely desirable behavior if
|
||||
what you want is to use the absolute minimum amount of
|
||||
disk space possible for your application. This
|
||||
mechanism <span class="emphasis"><em>will</em></span> leave you with
|
||||
the log files that are required to run normal recovery.
|
||||
However, it is highly likely that this mechanism will
|
||||
prevent you from running catastrophic recovery.
|
||||
</p>
|
||||
<p>
|
||||
Do NOT use this mechanism if you want to be able to
|
||||
perform catastrophic recovery, or if you want to be
|
||||
able to maintain a hot backup.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
In order to safely remove log files and still be able to
|
||||
perform catastrophic recovery, use the
|
||||
<span><b class="command">db_archive</b></span> command line utility as follows:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Run either a normal or hot backup as described in
|
||||
<a href="backuprestore.html">Backup Procedures</a>. Make
|
||||
sure that all of this data is safely stored to your
|
||||
backup media before continuing.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
If you have not already done so, perform a checkpoint.
|
||||
See <a href="filemanagement.html#checkpoints">Checkpoints</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
If you are maintaining a hot backup, perform the hot
|
||||
backup procedure as described in
|
||||
<a href="hotfailover.html">Using Hot Failovers</a>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Run the <span><b class="command">db_archive</b></span> command line
|
||||
utility with the <tt class="literal">-d</tt> option against
|
||||
your production environment.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Run the <span><b class="command">db_archive</b></span> command line
|
||||
utility with the <tt class="literal">-d</tt> option against
|
||||
your failover environment, if you are maintaining one.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="hotfailover.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="filemanagement.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="logconfig.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Using Hot Failovers </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Configuring the Logging Subsystem</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
239
docs/gsg_txn/C/maxtxns.html
Normal file
239
docs/gsg_txn/C/maxtxns.html
Normal file
@@ -0,0 +1,239 @@
|
||||
<?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>Configuring the Transaction Subsystem</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="usingtxns.html" title="Chapter 3. Transaction Basics" />
|
||||
<link rel="previous" href="txnindices.html" title="Secondary Indices with Transaction Applications" />
|
||||
<link rel="next" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Configuring the Transaction Subsystem</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="txnindices.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 3. Transaction Basics</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="txnconcurrency.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="maxtxns"></a>Configuring the Transaction Subsystem</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Most of the configuration activities that you need to perform
|
||||
for your transactional DB application will involve the
|
||||
locking and logging subsystems. See
|
||||
<a href="txnconcurrency.html">Concurrency</a>
|
||||
and
|
||||
<a href="filemanagement.html">Managing DB Files</a>
|
||||
for details.
|
||||
</p>
|
||||
<p>
|
||||
However, there are a couple of things that you can do to
|
||||
configure your transaction subsystem directly. These things
|
||||
are:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Configure the maximum number of simultaneous
|
||||
transactions needed by your application.
|
||||
In general, you should not need to do this unless you
|
||||
use deeply nested transactions or you have many threads all
|
||||
of which have active transactions. In addition, you may
|
||||
need to a higher maximum number of transactions if you
|
||||
are using snapshot isolation. See
|
||||
<a href="isolation.html#sisolation_maxtxn">Snapshot Isolation Transactional Requirements</a>
|
||||
for details.
|
||||
</p>
|
||||
<p>
|
||||
By default, your application can support 20 active
|
||||
transactions.
|
||||
</p>
|
||||
<p>
|
||||
You can set the maximum number of simultaneous
|
||||
transactions supported by your application using
|
||||
<span>
|
||||
the
|
||||
<tt class="methodname">DB_ENV->set_tx_max()</tt>
|
||||
|
||||
method. Note that this method must be called
|
||||
before the environment has been opened.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
If your application has exceeded this maximum value,
|
||||
then any attempt to begin a new transaction will fail.
|
||||
</p>
|
||||
<p>
|
||||
This value can also be set using the
|
||||
<tt class="literal">DB_CONFIG</tt> file's
|
||||
<tt class="literal">set_tx_max</tt> parameter. Remember that
|
||||
the <tt class="literal">DB_CONFIG</tt> must reside in your
|
||||
environment home directory.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
<p>
|
||||
<span>
|
||||
Configure the timeout value for your transactions.
|
||||
</span>
|
||||
|
||||
|
||||
This value represents the longest period of time a
|
||||
transaction can be active. Note, however, that
|
||||
transaction timeouts are checked only when DB
|
||||
examines its lock tables for blocked locks
|
||||
(see <a href="blocking_deadlocks.html">Locks, Blocks, and Deadlocks</a>
|
||||
for more information). Therefore, a transaction's timeout can
|
||||
have expired, but the application will not be notified until DB
|
||||
has a reason to examine its lock tables.
|
||||
</p>
|
||||
<p>
|
||||
Be aware that some transactions may be
|
||||
inappropriately timed out before the transaction has a
|
||||
chance to complete. You should therefore use this
|
||||
mechanism only if you know your application
|
||||
might have unacceptably long transactions and
|
||||
you want to make sure your application will
|
||||
not stall during their execution.
|
||||
(This might happen if, for example, your
|
||||
transaction blocks or requests too much
|
||||
data.)
|
||||
</p>
|
||||
<p>
|
||||
Note that by default transaction timeouts are set to 0 seconds, which means that they never time
|
||||
out.
|
||||
</p>
|
||||
<p>
|
||||
To set the maximum timeout value for your transactions,
|
||||
use the
|
||||
<span><tt class="methodname">DB_ENV->set_timeout()</tt></span>
|
||||
|
||||
|
||||
method. This method configures the entire
|
||||
environment; not just the handle used to set the
|
||||
configuration. Further, this value may
|
||||
be set at any time during the application's
|
||||
lifetime.
|
||||
</p>
|
||||
<p>
|
||||
This value can also be set using the
|
||||
<tt class="literal">DB_CONFIG</tt> file's
|
||||
<tt class="literal">set_txn_timeout</tt> parameter.
|
||||
</p>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t db_flags, env_flags;
|
||||
DB *dbp;
|
||||
DB_ENV *envp;
|
||||
DB_TXN *txn;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
const char *file_name = "mydb.db";
|
||||
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
* Configure a maximum transaction timeout of 1 second.
|
||||
*/
|
||||
ret = envp->set_timeout(envp, DB_SET_TXN_TIMEOUT, 1000000);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error setting txn timeout: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure 40 maximum transactions.
|
||||
*/
|
||||
ret = envp->set_tx_max(envp, 40);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error setting max txns: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* From here, you open your databases, proceed with your
|
||||
* database operations, and respond to deadlocks as
|
||||
* is normal (omitted for brevity).
|
||||
*/
|
||||
... </pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="txnindices.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="usingtxns.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="txnconcurrency.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Secondary Indices with Transaction Applications </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Chapter 4. Concurrency</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
140
docs/gsg_txn/C/nestedtxn.html
Normal file
140
docs/gsg_txn/C/nestedtxn.html
Normal file
@@ -0,0 +1,140 @@
|
||||
<?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>Nested Transactions</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="usingtxns.html" title="Chapter 3. Transaction Basics" />
|
||||
<link rel="previous" href="autocommit.html" title="Auto Commit" />
|
||||
<link rel="next" href="txncursor.html" title="Transactional Cursors" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Nested Transactions</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="autocommit.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 3. Transaction Basics</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="txncursor.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="nestedtxn"></a>Nested Transactions</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
A <span class="emphasis"><em>nested transaction</em></span> is used to provide a
|
||||
transactional guarantee for a subset of operations performed within
|
||||
the scope of a larger transaction. Doing this allows you to commit
|
||||
and abort the subset of operations independently of the larger
|
||||
transaction.
|
||||
</p>
|
||||
<p>
|
||||
The rules to the usage of a nested transaction are as follows:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
While the nested (child) transaction is active, the parent
|
||||
transaction may not perform any operations other than to commit
|
||||
or abort, or to create more child transactions.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Committing a nested transaction has no effect on the state
|
||||
of the parent transaction. The parent transaction is still
|
||||
uncommitted. However, the parent transaction can now
|
||||
see any modifications made by the child transaction.
|
||||
Those modifications, of course, are still hidden to all
|
||||
other transactions until the parent also commits.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Likewise, aborting the nested transaction has no effect on
|
||||
the state of the parent transaction. The only result of the
|
||||
abort is that neither the parent nor any
|
||||
other transactions will see any of the
|
||||
database modifications performed under the protection of the
|
||||
nested transaction.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
If the parent transaction commits or aborts while it has
|
||||
active children, the child transactions are resolved in the
|
||||
same way as the parent. That is, if the parent aborts, then
|
||||
the child transactions abort as well. If the parent commits,
|
||||
then whatever modifications have been performed by the child
|
||||
transactions are also committed.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
The locks held by a nested transaction are not released when
|
||||
that transaction commits. Rather, they are now held by the
|
||||
parent transaction until such a time as that parent commits.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Any database modifications performed by the nested transaction
|
||||
are not visible outside of the larger encompassing
|
||||
transaction until such a time as that parent transaction is
|
||||
committed.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
The depth of the nesting that you can achieve with nested
|
||||
transaction is limited only by memory.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
To create a nested transaction, simply pass the parent transaction's
|
||||
handle when you created the nested transaction's handle. For
|
||||
example:
|
||||
</p>
|
||||
<pre class="programlisting"> /* parent transaction */
|
||||
DB_TXN *parent_txn, *child_txn;
|
||||
ret = envp->txn_begin(envp, NULL, &parent_txn, 0);
|
||||
/* child transaction */
|
||||
ret = envp->txn_begin(envp, parent_txn, &child_txn, 0); </pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="autocommit.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="usingtxns.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="txncursor.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Auto Commit </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Transactional Cursors</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
88
docs/gsg_txn/C/perftune-intro.html
Normal file
88
docs/gsg_txn/C/perftune-intro.html
Normal file
@@ -0,0 +1,88 @@
|
||||
<?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>Performance Tuning</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="introduction.html" title="Chapter 1. Introduction" />
|
||||
<link rel="previous" href="recovery-intro.html" title="Recoverability" />
|
||||
<link rel="next" href="enabletxn.html" title="Chapter 2. Enabling Transactions" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Performance Tuning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="recovery-intro.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 1. Introduction</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="enabletxn.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="perftune-intro"></a>Performance Tuning</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
From a performance perspective, the use of transactions is not free.
|
||||
Depending on how you configure them, transaction commits
|
||||
usually require your application to perform disk I/O that a non-transactional
|
||||
application does not perform. Also, for multi-threaded
|
||||
<span>and
|
||||
multi-process</span> applications, the use of transactions can
|
||||
result in increased lock contention due to extra locking
|
||||
requirements driven by transactional isolation guarantees.
|
||||
</p>
|
||||
<p>
|
||||
There is therefore a performance tuning component to transactional applications
|
||||
that is not applicable for non-transactional applications (although
|
||||
some tuning considerations do exist whether or not your application uses
|
||||
transactions). Where appropriate, these tuning considerations are
|
||||
introduced in the following chapters.
|
||||
|
||||
<span>
|
||||
However, for a more complete description of them, see the
|
||||
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/ref/transapp/tune.html" target="_top">
|
||||
Transaction tuning
|
||||
</a>
|
||||
and
|
||||
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/ref/transapp/throughput.html" target="_top">
|
||||
Transaction throughput
|
||||
</a>
|
||||
sections of the <i class="citetitle">Berkeley DB Programmer's Reference Guide</i>.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="recovery-intro.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="introduction.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="enabletxn.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Recoverability </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Chapter 2. Enabling Transactions</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
215
docs/gsg_txn/C/preface.html
Normal file
215
docs/gsg_txn/C/preface.html
Normal file
@@ -0,0 +1,215 @@
|
||||
<?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>Preface</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="previous" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="next" href="introduction.html" title="Chapter 1. Introduction" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Preface</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td>
|
||||
<th width="60%" align="center"> </th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="introduction.html">Next</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="preface" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title"><a id="preface"></a>Preface</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="toc">
|
||||
<p>
|
||||
<b>Table of Contents</b>
|
||||
</p>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="preface.html#conventions">Conventions Used in this Book</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="preface.html#moreinfo">For More Information</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<p>
|
||||
This document describes how to use transactions with your Berkeley DB
|
||||
applications. It is intended to describe how to
|
||||
transaction protect your application's data. The APIs used to perform this task
|
||||
are described here, as are the environment infrastructure and administrative tasks
|
||||
required by a transactional application. This book also
|
||||
describes multi-threaded <span>and
|
||||
multi-process</span> DB applications and the requirements they
|
||||
have for deadlock detection.
|
||||
</p>
|
||||
<p>
|
||||
This book is aimed at the software engineer responsible for writing a
|
||||
transactional DB application.
|
||||
</p>
|
||||
<p>
|
||||
This book assumes that you have already read and understood the
|
||||
concepts contained in the
|
||||
<span><i class="citetitle">Getting Started with Berkeley DB</i>
|
||||
guide.</span>
|
||||
|
||||
|
||||
</p>
|
||||
<div class="sect1" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title" style="clear: both"><a id="conventions"></a>Conventions Used in this Book</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
The following typographical conventions are used within in this manual:
|
||||
</p>
|
||||
<p>
|
||||
Structure names are represented in <tt class="classname">monospaced font</tt>, as are <tt class="methodname">method
|
||||
names</tt>. For example: "<tt class="methodname">DB->open()</tt> is a method
|
||||
on a <tt class="classname">DB</tt> handle."
|
||||
</p>
|
||||
<p>
|
||||
Variable or non-literal text is presented in <span class="emphasis"><em>italics</em></span>. For example: "Go to your
|
||||
<span class="emphasis"><em>DB_INSTALL</em></span> directory."
|
||||
</p>
|
||||
<p>
|
||||
Program examples are displayed in a <tt class="classname">monospaced font</tt> on a shaded background.
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting">/* File: gettingstarted_common.h */
|
||||
typedef struct stock_dbs {
|
||||
DB *inventory_dbp; /* Database containing inventory information */
|
||||
DB *vendor_dbp; /* Database containing vendor information */
|
||||
|
||||
char *db_home_dir; /* Directory containing the database files */
|
||||
char *inventory_db_name; /* Name of the inventory database */
|
||||
char *vendor_db_name; /* Name of the vendor database */
|
||||
} STOCK_DBS; </pre>
|
||||
<p>
|
||||
In some situations, programming examples are updated from one chapter to the next. When
|
||||
this occurs, the new code is presented in <b class="userinput"><tt>monospaced bold</tt></b> font. For example:
|
||||
</p>
|
||||
<pre class="programlisting">typedef struct stock_dbs {
|
||||
DB *inventory_dbp; /* Database containing inventory information */
|
||||
DB *vendor_dbp; /* Database containing vendor information */
|
||||
<b class="userinput"><tt>DB *itemname_sdbp; /* Index based on the item name index */</tt></b>
|
||||
char *db_home_dir; /* Directory containing the database files */
|
||||
<b class="userinput"><tt>char *itemname_db_name; /* Itemname secondary database */</tt></b>
|
||||
char *inventory_db_name; /* Name of the inventory database */
|
||||
char *vendor_db_name; /* Name of the vendor database */
|
||||
} STOCK_DBS; </pre>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
Finally, notes of special interest are represented using a note block such
|
||||
as this.
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="moreinfo"></a>For More Information</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Beyond this manual, you may also find the following sources of information useful when building a
|
||||
transactional DB application:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/gsg/C/index.html" target="_top">
|
||||
Getting Started with Berkeley DB for C
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/gsg_db_rep/C/index.html" target="_top">
|
||||
Berkeley DB Getting Started with Replicated Applications for C
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/ref/toc.html" target="_top">
|
||||
Berkeley DB Programmer's Reference Guide
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<a href="http://www.oracle.com/technology/documentation/berkeley-db/db/api_c/frame.html" target="_top">
|
||||
Berkeley DB C API
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="index.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="index.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="introduction.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Getting Started with Berkeley DB Transaction Processing </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Chapter 1. Introduction</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
docs/gsg_txn/C/readblock.jpg
Normal file
BIN
docs/gsg_txn/C/readblock.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
123
docs/gsg_txn/C/readmodifywrite.html
Normal file
123
docs/gsg_txn/C/readmodifywrite.html
Normal file
@@ -0,0 +1,123 @@
|
||||
<?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>Read/Modify/Write</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||||
<link rel="previous" href="txn_ccursor.html" title="Transactional Cursors and Concurrent Applications" />
|
||||
<link rel="next" href="txnnowait.html" title="No Wait on Blocks" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Read/Modify/Write</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="txn_ccursor.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 4. Concurrency</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="txnnowait.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="readmodifywrite"></a>Read/Modify/Write</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
If you are retrieving
|
||||
<span>a record from the database</span>
|
||||
|
||||
|
||||
for the purpose of modifying or deleting it, you should declare
|
||||
a read-modify-write cycle at the time that you read the
|
||||
<span>record.</span>
|
||||
|
||||
Doing so causes DB to obtain write locks (instead of a read
|
||||
locks) at the time of the read. This helps to prevent deadlocks by
|
||||
preventing another transaction from acquiring a read lock on the same
|
||||
record while the read-modify-write cycle is in progress.
|
||||
</p>
|
||||
<p>
|
||||
Note that declaring a read-modify-write cycle may actually increase the amount of blocking that your
|
||||
application sees, because readers immediately obtain write locks and write locks cannot be shared. For this
|
||||
reason, you should use read-modify-write cycles only if you are seeing a large amount of deadlocking
|
||||
occurring in your application.
|
||||
</p>
|
||||
<p>
|
||||
In order to declare a read/modify/write cycle when you perform a
|
||||
read operation,
|
||||
|
||||
<span>
|
||||
pass the <tt class="literal">DB_RMW</tt> flag
|
||||
<span>
|
||||
to the database or cursor get method.
|
||||
</span>
|
||||
|
||||
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting">retry:
|
||||
/* Get the transaction */
|
||||
ret = envp->txn_begin(envp, NULL, &txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "txn_begin failed");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
...
|
||||
/* key and data are Dbts. Their usage is omitted for brevity. */
|
||||
...
|
||||
/* Get the data. Declare the read/modify/write cycle here */
|
||||
ret = dbp->get(dbp, txn, &key, &data, DB_RMW);
|
||||
|
||||
...
|
||||
/* Modify the key and data as is required (not shown here) */
|
||||
...
|
||||
|
||||
/* Put the data. Note that you do not have to provide any additional
|
||||
* flags here due to the read/modify/write cycle. Simply put the
|
||||
* data and perform your deadlock detection as normal.
|
||||
*/
|
||||
ret = dbp->put(dbp, txn, &key, &data, 0);
|
||||
switch (ret) {
|
||||
/* Deadlock detection omitted for brevity */
|
||||
.... </pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="txn_ccursor.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="txnnowait.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Transactional Cursors and Concurrent Applications </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> No Wait on Blocks</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
104
docs/gsg_txn/C/recovery-intro.html
Normal file
104
docs/gsg_txn/C/recovery-intro.html
Normal file
@@ -0,0 +1,104 @@
|
||||
<?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>Recoverability</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="introduction.html" title="Chapter 1. Introduction" />
|
||||
<link rel="previous" href="introduction.html" title="Chapter 1. Introduction" />
|
||||
<link rel="next" href="perftune-intro.html" title="Performance Tuning" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Recoverability</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="introduction.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 1. Introduction</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="perftune-intro.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="recovery-intro"></a>Recoverability</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
An important part of DB's transactional guarantees is durability.
|
||||
<span class="emphasis"><em>Durability</em></span> means that once a
|
||||
transaction has been committed, the database modifications performed
|
||||
under its protection will not be lost due to system failure.
|
||||
</p>
|
||||
<p>
|
||||
In order to provide the transactional durability guarantee,
|
||||
DB uses a write-ahead logging system. Every operation performed on
|
||||
your databases is described in a log before it is performed on
|
||||
your databases. This is done in order to ensure that an operation can be
|
||||
recovered in the event of an untimely application
|
||||
or system failure.
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
Beyond logging, another important aspect of durability is
|
||||
recoverability. That is, backup and restore. </span>
|
||||
|
||||
DB supports a normal recovery that runs against a subset of
|
||||
your log files. This is a routine procedure used whenever your
|
||||
environment is first opened upon application startup, and it is intended to
|
||||
ensure that your database is in a consistent state. DB also
|
||||
supports archival backup and recovery in the case of
|
||||
catastrophic failure, such as the loss of a physical disk
|
||||
drive.
|
||||
</p>
|
||||
<p>
|
||||
This book describes several different backup procedures
|
||||
you can use to protect your on-disk data. These procedures
|
||||
range from simple offline backup strategies to hot failovers. Hot failovers
|
||||
provide not only a backup mechanism, but
|
||||
also a way to recover from a fatal hardware failure.
|
||||
</p>
|
||||
<p>
|
||||
This book also describes the recovery procedures you should use
|
||||
for each of the backup strategies that you might employ.
|
||||
</p>
|
||||
<p>
|
||||
For a detailed description of backup and restore procedures, see
|
||||
<span>
|
||||
<a href="filemanagement.html">Managing DB Files</a>.
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="introduction.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="introduction.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="perftune-intro.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Chapter 1. Introduction </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Performance Tuning</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
322
docs/gsg_txn/C/recovery.html
Normal file
322
docs/gsg_txn/C/recovery.html
Normal file
@@ -0,0 +1,322 @@
|
||||
<?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>Recovery Procedures</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="filemanagement.html" title="Chapter 5. Managing DB Files" />
|
||||
<link rel="previous" href="backuprestore.html" title="Backup Procedures" />
|
||||
<link rel="next" href="architectrecovery.html" title="Designing Your Application for Recovery" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Recovery Procedures</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="backuprestore.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 5. Managing DB Files</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="architectrecovery.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="recovery"></a>Recovery Procedures</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
DB supports two types of recovery:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Normal recovery, which is run when your environment is
|
||||
opened upon application startup, examines only those
|
||||
log records needed to bring the databases to a consistent
|
||||
state since the last checkpoint. Normal recovery
|
||||
starts with any logs used by any transactions active at
|
||||
the time of the last checkpoint, and examines all logs
|
||||
from then to the current logs.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Catastrophic recovery, which is performed in the same
|
||||
way that normal recovery is except that it examines
|
||||
all available log files. You use catastrophic recovery
|
||||
to restore your databases from a previously created backup.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
Of these two, normal recovery should be considered a routine
|
||||
matter; in fact you should run normal
|
||||
recovery whenever you start up your application.
|
||||
</p>
|
||||
<p>
|
||||
Catastrophic recovery is run whenever you have lost or
|
||||
corrupted your database files and you want to restore from a
|
||||
backup. You also run catastrophic recovery when
|
||||
you create a hot backup
|
||||
(see <a href="hotfailover.html">Using Hot Failovers</a> for more information).
|
||||
</p>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="normalrecovery"></a>Normal Recovery</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Normal recovery examines the contents of your environment's
|
||||
log files, and uses this information to ensure that your
|
||||
database files are consistent relative to the
|
||||
information contained in the log files.
|
||||
</p>
|
||||
<p>
|
||||
Normal recovery also recreates your environment's region files.
|
||||
This has the desired effect of clearing any unreleased locks
|
||||
that your application may have held at the time of an
|
||||
unclean application shutdown.
|
||||
</p>
|
||||
<p>
|
||||
Normal recovery is run only against those log files created
|
||||
since the time of your last checkpoint. For this reason,
|
||||
your recovery time is dependent on how much data has been
|
||||
written since the last checkpoint, and therefore on how
|
||||
much log file information there is to examine. If you run
|
||||
checkpoints infrequently, then normal recovery can
|
||||
take a relatively long time.
|
||||
</p>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
You should run normal recovery every
|
||||
time you perform application startup.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
To run normal recovery:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Make sure all your environment handles are closed.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Normal recovery <span class="emphasis"><em>must
|
||||
be</em></span> single-threaded.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Provide the <tt class="literal">DB_RECOVER</tt> flag when
|
||||
you open your environment.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
You can also run recovery by pausing or shutting down your
|
||||
application and using the <span><b class="command">db_recover</b></span>
|
||||
command line utility.
|
||||
</p>
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret;
|
||||
u_int32_t env_flags;
|
||||
DB_ENV *envp;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Open the environment, specifying that recovery is to be run. */
|
||||
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 */
|
||||
DB_RECOVER; /* Run normal recovery */
|
||||
|
||||
/* Open the environment. */
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
...
|
||||
/*
|
||||
* All other operations are identical from here. Notice, however,
|
||||
* that we have not created any other threads of control before
|
||||
* recovery is complete. You want to run recovery for
|
||||
* the first thread in your application that opens an environment,
|
||||
* but not for any subsequent threads.
|
||||
*/ </pre>
|
||||
</div>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="catastrophicrecovery"></a>Catastrophic Recovery</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Use catastrophic recovery when you are
|
||||
recovering your databases from a previously created backup.
|
||||
Note that to restore your databases from a previous backup, you
|
||||
should copy the backup to a new environment directory, and
|
||||
then run catastrophic recovery. Failure to do so can lead to
|
||||
the internal database structures being out of sync with your log files.
|
||||
</p>
|
||||
<p>
|
||||
Catastrophic recovery must be run single-threaded.
|
||||
</p>
|
||||
<p>
|
||||
To run catastrophic recovery:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Shutdown all database operations.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Restore the backup to an empty directory.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Provide the <tt class="literal">DB_RECOVER_FATAL</tt> flag when
|
||||
you open your environment. This environment open
|
||||
must be single-threaded.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
You can also run recovery by pausing or shutting down your
|
||||
application and using the <span><b class="command">db_recover</b></span>
|
||||
command line utility with the the <tt class="literal">-c</tt> option.
|
||||
</p>
|
||||
<p>
|
||||
Note that catastrophic recovery examines every available
|
||||
log file — not just those log files created since the
|
||||
last checkpoint as is the case for normal recovery. For this reason,
|
||||
catastrophic recovery is likely to take longer than does
|
||||
normal recovery.
|
||||
</p>
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret;
|
||||
u_int32_t env_flags;
|
||||
DB_ENV *envp;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Open the environment, specifying that recovery is to be run. */
|
||||
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 */
|
||||
<b class="userinput"><tt>DB_RECOVER_FATAL; /* Run catastrophic recovery */</tt></b>
|
||||
|
||||
/* Open the environment. */
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
...
|
||||
/*
|
||||
* All other operations are identical from here. Notice, however,
|
||||
* that we have not created any other threads of control before
|
||||
* recovery is complete. You want to run recovery for
|
||||
* the first thread in your application that opens an environment,
|
||||
* but not for any subsequent threads.
|
||||
*/ </pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="backuprestore.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="filemanagement.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="architectrecovery.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Backup Procedures </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Designing Your Application for Recovery</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
195
docs/gsg_txn/C/reversesplit.html
Normal file
195
docs/gsg_txn/C/reversesplit.html
Normal file
@@ -0,0 +1,195 @@
|
||||
<?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>Reverse BTree Splits</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||||
<link rel="previous" href="txnnowait.html" title="No Wait on Blocks" />
|
||||
<link rel="next" href="filemanagement.html" title="Chapter 5. Managing DB Files" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Reverse BTree Splits</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="txnnowait.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 4. Concurrency</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="filemanagement.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="reversesplit"></a>Reverse BTree Splits</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
If your application is using the Btree access method, and your
|
||||
application is repeatedly deleting then adding records to your
|
||||
database, then you might be able to reduce lock contention by
|
||||
turning off reverse Btree splits.
|
||||
</p>
|
||||
<p>
|
||||
As pages are emptied in a database, DB attempts to
|
||||
delete empty pages in order to keep
|
||||
the database as small as possible and minimize search time.
|
||||
Moreover, when a page in the database fills
|
||||
up, DB, of course, adds additional pages
|
||||
to make room for more data.
|
||||
</p>
|
||||
<p>
|
||||
Adding and deleting pages in the database requires that the
|
||||
writing thread lock the parent page. Consequently, as the
|
||||
number of pages in your database diminishes, your application
|
||||
will see increasingly more lock contention; the maximum level
|
||||
of concurrency in a database of two pages is far smaller than
|
||||
that in a database of 100 pages, because there are fewer pages
|
||||
that can be locked.
|
||||
</p>
|
||||
<p>
|
||||
Therefore, if you prevent the database from being reduced to a
|
||||
minimum number of pages, you can improve your application's
|
||||
concurrency throughput. Note, however, that you should do so
|
||||
only if your application tends to delete and then add the same
|
||||
data. If this is not the case, then preventing reverse Btree
|
||||
splits can harm your database search time.
|
||||
</p>
|
||||
<p>
|
||||
To turn off reverse Btree splits,
|
||||
<span>
|
||||
provide the
|
||||
<tt class="literal">DB_REVSPLITOFF</tt> flag to the
|
||||
<tt class="methodname">DB->set_flags()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t db_flags, env_flags;
|
||||
DB *dbp;
|
||||
DB_ENV *envp;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
const char *file_name = "mydb.db";
|
||||
|
||||
dbp = NULL;
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
env_flags = DB_CREATE |
|
||||
DB_INIT_LOCK |
|
||||
DB_INIT_LOG |
|
||||
DB_INIT_TXN |
|
||||
DB_THREAD |
|
||||
DB_INIT_MPOOL;
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database creation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Set btree reverse split to off */
|
||||
ret = db->set_flags(&db, DB_REVSPLITOFF);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Turning off Btree reverse split failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
db_flags = DB_CREATE | DB_AUTO_COMMIT;
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
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 */
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database '%s' open failed",
|
||||
file_name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
err:
|
||||
/* Close the database */
|
||||
if (dbp != NULL) {
|
||||
ret_c = dbp->close(dbp, 0);
|
||||
if (ret_c != 0) {
|
||||
envp->err(envp, ret_c, "Database close failed.");
|
||||
ret = ret_c
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Close the environment */
|
||||
if (envp != NULL) {
|
||||
ret_c = envp->close(envp, 0);
|
||||
if (ret_c != 0) {
|
||||
fprintf(stderr, "environment close failed: %s\n",
|
||||
db_strerror(ret_c));
|
||||
ret = ret_c;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="txnnowait.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="filemanagement.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">No Wait on Blocks </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Chapter 5. Managing DB Files</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
docs/gsg_txn/C/rwlocks1.jpg
Normal file
BIN
docs/gsg_txn/C/rwlocks1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
BIN
docs/gsg_txn/C/simplelock.jpg
Normal file
BIN
docs/gsg_txn/C/simplelock.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
202
docs/gsg_txn/C/txn_ccursor.html
Normal file
202
docs/gsg_txn/C/txn_ccursor.html
Normal file
@@ -0,0 +1,202 @@
|
||||
<?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>Transactional Cursors and Concurrent Applications</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||||
<link rel="previous" href="isolation.html" title="Isolation" />
|
||||
<link rel="next" href="readmodifywrite.html" title="Read/Modify/Write" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Transactional Cursors and Concurrent Applications</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="isolation.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 4. Concurrency</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="readmodifywrite.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="txn_ccursor"></a>Transactional Cursors and Concurrent Applications</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
When you use transactional cursors with a concurrent application, remember that
|
||||
in the event of a deadlock you must make sure that you close your cursor before you abort and retry your
|
||||
transaction.
|
||||
</p>
|
||||
<p>
|
||||
Also, remember that when you are using the default isolation level,
|
||||
every time your cursor reads a record it locks
|
||||
that record until the encompassing transaction is resolved. This
|
||||
means that walking your database with a transactional cursor
|
||||
increases the chance of lock contention.
|
||||
</p>
|
||||
<p>
|
||||
For this reason, if you must routinely walk your database with a
|
||||
transactional cursor, consider using a reduced isolation level
|
||||
such as read committed.
|
||||
</p>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="cursordirtyreads"></a>Using Cursors with Uncommitted Data</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
|
||||
As described in <a href="isolation.html#dirtyreads">Reading Uncommitted Data</a>
|
||||
above, it is possible to relax your transaction's isolation
|
||||
level such that it can read data modified but not yet committed
|
||||
by another transaction. You can configure this when you create
|
||||
your transaction handle, and when you do so then all cursors opened
|
||||
inside that transaction will automatically use uncommitted reads.
|
||||
</p>
|
||||
<p>
|
||||
You can also do this when you create a cursor handle from within
|
||||
a serializable transaction. When you do this, only those
|
||||
cursors configured for uncommitted reads uses uncommitted reads.
|
||||
</p>
|
||||
<p>
|
||||
Either way, you must first configure your database
|
||||
handle to support
|
||||
uncommitted reads before you can configure your transactions or
|
||||
your cursors to use them.
|
||||
</p>
|
||||
<p>
|
||||
The following example shows how to configure an individual cursor handle
|
||||
to read uncommitted data from within a serializable (full isolation) transaction.
|
||||
For an example of
|
||||
configuring a transaction to perform uncommitted reads in
|
||||
general, see <a href="isolation.html#dirtyreads">Reading Uncommitted Data</a>.
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
DB *dbp;
|
||||
DBC *cursorp;
|
||||
DB_ENV *envp;
|
||||
DB_TXN *txn;
|
||||
int ret, c_ret;
|
||||
char *replacementString = "new string";
|
||||
|
||||
dbp = NULL;
|
||||
envp = NULL;
|
||||
txn = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
env_flags = DB_CREATE | /* Create the environment if it does
|
||||
* not already exist. */
|
||||
DB_INIT_TXN | /* Initialize transactions */
|
||||
DB_INIT_LOCK | /* Initialize locking. */
|
||||
DB_INIT_LOG | /* Initialize logging */
|
||||
DB_INIT_MPOOL; /* Initialize the in-memory cache. */
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database creation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
db_flags = DB_CREATE | /* Create the db if it does not
|
||||
* exist */
|
||||
DB_AUTO_COMMIT | /* Enable auto commit */
|
||||
DB_READ_UNCOMMITTED; /* Enable uncommitted reads */
|
||||
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
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 */
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database '%s' open failed",
|
||||
file_name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Get the txn handle */
|
||||
/* Note that this is a degree 3 transaction */
|
||||
ret = envp->txn_begin(envp, NULL, &txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Transaction begin failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Get the cursor, supply the txn handle at that time */
|
||||
/* Cause the cursor to perform uncommitted reads */
|
||||
ret = dbp->cursor(dbp, txn, &cursorp, DB_READ_UNCOMMITTED);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Cursor open failed.");
|
||||
txn->abort(txn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* From here, you perform your cursor 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>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="isolation.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="readmodifywrite.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Isolation </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Read/Modify/Write</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
360
docs/gsg_txn/C/txnconcurrency.html
Normal file
360
docs/gsg_txn/C/txnconcurrency.html
Normal file
@@ -0,0 +1,360 @@
|
||||
<?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>Chapter 4. Concurrency</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="previous" href="maxtxns.html" title="Configuring the Transaction Subsystem" />
|
||||
<link rel="next" href="blocking_deadlocks.html" title="Locks, Blocks, and Deadlocks" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Chapter 4. Concurrency</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="maxtxns.html">Prev</a> </td>
|
||||
<th width="60%" align="center"> </th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="blocking_deadlocks.html">Next</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="chapter" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title"><a id="txnconcurrency"></a>Chapter 4. Concurrency</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="toc">
|
||||
<p>
|
||||
<b>Table of Contents</b>
|
||||
</p>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txnconcurrency.html#concurrenthandles">Which DB Handles are Free-Threaded</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="blocking_deadlocks.html">Locks, Blocks, and Deadlocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="blocking_deadlocks.html#locks">Locks</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="blocking_deadlocks.html#blocks">Blocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="blocking_deadlocks.html#deadlocks">Deadlocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="lockingsubsystem.html">The Locking Subsystem</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="lockingsubsystem.html#configuringlock">Configuring the Locking Subsystem</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="lockingsubsystem.html#configdeadlkdetect">Configuring Deadlock Detection</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="lockingsubsystem.html#deadlockresolve">Resolving Deadlocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="isolation.html">Isolation</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<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>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txn_ccursor.html">Transactional Cursors and Concurrent Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="txn_ccursor.html#cursordirtyreads">Using Cursors with Uncommitted Data</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="readmodifywrite.html">Read/Modify/Write</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txnnowait.html">No Wait on Blocks</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="reversesplit.html">Reverse BTree Splits</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</div>
|
||||
<p>
|
||||
|
||||
DB offers a great deal of support for multi-threaded
|
||||
<span>
|
||||
and multi-process
|
||||
</span>
|
||||
applications even when transactions are not in use. Many of DB's
|
||||
handles are
|
||||
thread-safe<span>, or
|
||||
can be made thread-safe by providing the appropriate flag at handle creation time,</span>
|
||||
and DB provides a
|
||||
flexible locking subsystem for managing databases in a concurrent
|
||||
application. Further, DB provides a robust mechanism for
|
||||
detecting and responding to deadlocks. All of these concepts are
|
||||
explored in this chapter.
|
||||
</p>
|
||||
<p>
|
||||
Before continuing, it is useful to define a few terms that will appear
|
||||
throughout this chapter:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
<span class="emphasis"><em>Thread of control</em></span>
|
||||
</p>
|
||||
<p>
|
||||
Refers to a thread that is performing work in your application.
|
||||
Typically, in this book that thread will be performing DB
|
||||
operations.
|
||||
</p>
|
||||
<p>
|
||||
Note that this term can also be taken to mean a separate process
|
||||
that is performing work — DB supports multi-process
|
||||
operations on your databases.
|
||||
</p>
|
||||
<p>
|
||||
Also, DB is agnostic with regard to the type or style of
|
||||
threads in use in your application. So if you are using
|
||||
multiple threads
|
||||
(as opposed to multiple processes) to perform concurrent
|
||||
database access, you are free to use whatever thread package is
|
||||
best for your platform and application. That said, this manual
|
||||
will use pthreads for its threading examples because those have
|
||||
the best chance of being supported across a large range of
|
||||
platforms.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span class="emphasis"><em>Locking</em></span>
|
||||
</p>
|
||||
<p>
|
||||
When a thread of control obtains
|
||||
access to a shared resource, it is said to be
|
||||
<span class="emphasis"><em>locking</em></span> that resource. Note that
|
||||
DB supports both exclusive and non-exclusive locks. See
|
||||
<a href="blocking_deadlocks.html#locks">Locks</a> for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span class="emphasis"><em>Free-threaded</em></span>
|
||||
</p>
|
||||
<p>
|
||||
Data structures and objects are free-threaded if they can be
|
||||
shared across threads of control without any explicit locking on
|
||||
the part of the application. Some books, libraries, and
|
||||
programming languages may use the term
|
||||
<span class="emphasis"><em>thread-safe</em></span> for data structures or objects
|
||||
that have this characteristic. The two terms mean the
|
||||
same thing.
|
||||
</p>
|
||||
<p>
|
||||
For a description of free-threaded DB objects, see
|
||||
<a href="txnconcurrency.html#concurrenthandles">Which DB Handles are Free-Threaded</a>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span class="emphasis"><em>Blocked</em></span>
|
||||
</p>
|
||||
<p>
|
||||
When a thread cannot obtain a lock because some other
|
||||
thread already holds a lock on that object, the lock
|
||||
attempt is said to be <span class="emphasis"><em>blocked</em></span>. See
|
||||
<a href="blocking_deadlocks.html#blocks">Blocks</a> for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<span class="emphasis"><em>Deadlock</em></span>
|
||||
</p>
|
||||
<p>
|
||||
Occurs when two or more threads of control attempt to access conflicting resource in such a way as none
|
||||
of the threads can any longer may further progress.
|
||||
</p>
|
||||
<p>
|
||||
For example, if Thread A is blocked waiting for a resource held by Thread
|
||||
B, while at the same time Thread B is blocked waiting for a
|
||||
resource held by Thread A, then neither thread can make any
|
||||
forward progress. In this situation, Thread A and Thread B
|
||||
are said to be <span class="emphasis"><em>deadlocked.</em></span>
|
||||
</p>
|
||||
<p>
|
||||
For more information, see <a href="blocking_deadlocks.html#deadlocks">Deadlocks</a>.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sect1" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title" style="clear: both"><a id="concurrenthandles"></a>Which DB Handles are Free-Threaded</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
The following describes to what extent and under what conditions
|
||||
individual handles are free-threaded.
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
<tt class="classname">DB_ENV</tt>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Free-threaded so long as
|
||||
<span>
|
||||
the <tt class="literal">DB_THREAD</tt> flag is provided to
|
||||
the environment <tt class="methodname">open()</tt>
|
||||
method.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt class="classname">DB</tt>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Free-threaded so long as
|
||||
<span>
|
||||
the <tt class="literal">DB_THREAD</tt> flag is provided to
|
||||
the database <tt class="methodname">open()</tt>
|
||||
method, or if the database is opened using a
|
||||
free-threaded environment handle.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt class="classname">DBC</tt>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Cursors are not free-threaded. However, they
|
||||
can be used by multiple threads of control so
|
||||
long as the application serializes access to the handle.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt class="classname">DB_TXN</tt>
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Access must be serialized by the application across threads of control.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="maxtxns.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="index.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="blocking_deadlocks.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Configuring the Transaction Subsystem </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Locks, Blocks, and Deadlocks</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
155
docs/gsg_txn/C/txncursor.html
Normal file
155
docs/gsg_txn/C/txncursor.html
Normal file
@@ -0,0 +1,155 @@
|
||||
<?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>Transactional Cursors</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="usingtxns.html" title="Chapter 3. Transaction Basics" />
|
||||
<link rel="previous" href="nestedtxn.html" title="Nested Transactions" />
|
||||
<link rel="next" href="txnindices.html" title="Secondary Indices with Transaction Applications" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Transactional Cursors</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="nestedtxn.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 3. Transaction Basics</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="txnindices.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="txncursor"></a>Transactional Cursors</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
You can transaction-protect your cursor operations by
|
||||
specifying a transaction handle at the time that you create
|
||||
your cursor. Beyond that, you do not ever
|
||||
provide a transaction handle directly to a cursor method.
|
||||
</p>
|
||||
<p>
|
||||
Note that if you transaction-protect a cursor, then you must
|
||||
make sure that the cursor is closed before you either commit or
|
||||
abort the transaction. For example:
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
DBT key, data;
|
||||
DBC *cursorp;
|
||||
DB_TXN *txn = NULL;
|
||||
int ret, c_ret;
|
||||
char *replacementString = "new string";
|
||||
|
||||
...
|
||||
/* environment and db handle creation omitted */
|
||||
...
|
||||
|
||||
/* Get the txn handle */
|
||||
txn = NULL;
|
||||
ret = envp->txn_begin(envp, NULL, &txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Transaction begin failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Get the cursor, supply the txn handle at that time */
|
||||
ret = dbp->cursor(dbp, txn, &cursorp, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Cursor open failed.");
|
||||
txn->abort(txn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now use the cursor. Note that we do not supply any txn handles to these
|
||||
* methods.
|
||||
*/
|
||||
/* Prepare the DBTs */
|
||||
memset(&key, 0, sizeof(DBT));
|
||||
memset(&data, 0, sizeof(DBT));
|
||||
while (cursor->get(&key, &data, DB_NEXT) == 0) {
|
||||
data->data = (void *)replacementString;
|
||||
data->size = (strlen(replacementString) + 1) * sizeof(char);
|
||||
c_ret = cursor->put(cursor, &key, &data, DB_CURRENT);
|
||||
if (c_ret != 0) {
|
||||
/* abort the transaction and goto error */
|
||||
envp->err(envp, ret, "Cursor put failed.");
|
||||
cursorp->close(cursorp);
|
||||
cursorp = NULL;
|
||||
txn->abort(txn);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Commit the transaction. Note that the transaction handle
|
||||
* can no longer be used.
|
||||
*/
|
||||
ret = cursorp->close(cursorp);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Cursor close failed.");
|
||||
txn->abort(txn);
|
||||
goto err;
|
||||
}
|
||||
ret = txn->commit(txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Transaction commit failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
/* Close the cursor (if the handle is not NULL)
|
||||
* and perform whatever other cleanup is required */
|
||||
|
||||
/* Close the database */
|
||||
|
||||
/* Close the environment */
|
||||
|
||||
...
|
||||
|
||||
if (c_ret != 0)
|
||||
ret = c_ret;
|
||||
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="nestedtxn.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="usingtxns.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="txnindices.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Nested Transactions </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Secondary Indices with Transaction Applications</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
757
docs/gsg_txn/C/txnexample_c.html
Normal file
757
docs/gsg_txn/C/txnexample_c.html
Normal file
@@ -0,0 +1,757 @@
|
||||
<?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>Transaction Example</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="wrapup.html" title="Chapter 6. Summary and Examples" />
|
||||
<link rel="previous" href="wrapup.html" title="Chapter 6. Summary and Examples" />
|
||||
<link rel="next" href="inmem_txnexample_c.html" title="In-Memory Transaction Example" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Transaction Example</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="wrapup.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 6. Summary and Examples</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="inmem_txnexample_c.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="txnexample_c"></a>Transaction Example</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
The following code provides a fully functional example of a
|
||||
multi-threaded transactional DB application. For improved
|
||||
portability across platforms, this examples uses pthreads to
|
||||
provide threading support.
|
||||
</p>
|
||||
<p>
|
||||
The example opens an environment and database and then creates 5
|
||||
threads, each of which writes 500 records to the database. The keys
|
||||
used for these writes are pre-determined strings, while the data is
|
||||
a random value. This means that the actual data is arbitrary and
|
||||
therefore uninteresting; we picked it only because it requires
|
||||
minimum code to implement and therefore will stay out of the way of
|
||||
the main points of this example.
|
||||
</p>
|
||||
<p>
|
||||
Each thread writes 10 records under a single transaction
|
||||
before committing and writing another 10 (this is repeated 50
|
||||
times). At the end of each transaction, but before committing, each
|
||||
thread calls a function that uses a cursor to read every record in
|
||||
the database. We do this in order to make some points about
|
||||
database reads in a transactional environment.
|
||||
</p>
|
||||
<p>
|
||||
Of course, each writer thread performs deadlock detection as
|
||||
described in this manual. In addition, normal recovery is performed
|
||||
when the environment is opened.
|
||||
</p>
|
||||
<p>
|
||||
We start with our normal <tt class="literal">include</tt> directives:
|
||||
</p>
|
||||
<pre class="programlisting">/* File: txn_guide.c */
|
||||
|
||||
/* We assume an ANSI-compatible compiler */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <db.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
extern int getopt(int, char * const *, const char *);
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif </pre>
|
||||
<p>
|
||||
We also need a directive that we use to identify how many threads we
|
||||
want our program to create:
|
||||
</p>
|
||||
<pre class="programlisting">/* Run 5 writers threads at a time. */
|
||||
#define NUMWRITERS 5 </pre>
|
||||
<p>
|
||||
Next we declare a couple of global
|
||||
variables (used by our threads), and we provide our forward
|
||||
declarations for the functions used by this example.
|
||||
</p>
|
||||
<pre class="programlisting">/*
|
||||
* Printing of pthread_t is implementation-specific, so we
|
||||
* create our own thread IDs for reporting purposes.
|
||||
*/
|
||||
int global_thread_num;
|
||||
pthread_mutex_t thread_num_lock;
|
||||
|
||||
/* Forward declarations */
|
||||
int count_records(DB *, DB_TXN *);
|
||||
int open_db(DB **, const char *, const char *, DB_ENV *, u_int32_t);
|
||||
int usage(void);
|
||||
void *writer_thread(void *); </pre>
|
||||
<p>
|
||||
We now implement our usage function, which identifies our only command line
|
||||
parameter:
|
||||
</p>
|
||||
<pre class="programlisting">/* Usage function */
|
||||
int
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, " [-h <database_home_directory>]\n");
|
||||
return (EXIT_FAILURE);
|
||||
} </pre>
|
||||
<p>
|
||||
With that, we have finished up our program's housekeeping, and we can
|
||||
now move on to the main part of our program. As usual, we begin with
|
||||
<tt class="function">main()</tt>. First we declare all our variables, and
|
||||
then we initialize our DB handles.
|
||||
</p>
|
||||
<pre class="programlisting">int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
/* Initialize our handles */
|
||||
DB *dbp = NULL;
|
||||
DB_ENV *envp = NULL;
|
||||
|
||||
pthread_t writer_threads[NUMWRITERS];
|
||||
int ch, i, ret, ret_t;
|
||||
u_int32_t env_flags;
|
||||
char *db_home_dir;
|
||||
/* Application name */
|
||||
const char *prog_name = "txn_guide";
|
||||
/* Database file name */
|
||||
const char *file_name = "mydb.db"; </pre>
|
||||
<p>
|
||||
Now we need to parse our command line. In this case, all we want is to
|
||||
know where our environment directory is. If the <tt class="literal">-h</tt>
|
||||
option is not provided when this example is run, the current working
|
||||
directory is used instead.
|
||||
</p>
|
||||
<pre class="programlisting"> /* Parse the command line arguments */
|
||||
#ifdef _WIN32
|
||||
db_home_dir = ".\\";
|
||||
#else
|
||||
db_home_dir = "./";
|
||||
#endif
|
||||
while ((ch = getopt(argc, argv, "h:")) != EOF)
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
db_home_dir = optarg;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
return (usage());
|
||||
} </pre>
|
||||
<p>
|
||||
Next we create our database handle, and we define our environment open flags.
|
||||
There are a few things to notice here:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
We specify <tt class="literal">DB_RECOVER</tt>, which means that normal
|
||||
recovery is run every time we start the application. This is
|
||||
highly desirable and recommended for most
|
||||
applications.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
We also specify <tt class="literal">DB_THREAD</tt>, which means our
|
||||
environment handle will be free-threaded. This is very
|
||||
important because we will be sharing the environment handle
|
||||
across threads.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<pre class="programlisting"> /* Create the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
env_flags =
|
||||
DB_CREATE | /* Create the environment if it does not exist */
|
||||
DB_RECOVER | /* Run normal recovery. */
|
||||
DB_INIT_LOCK | /* Initialize the locking subsystem */
|
||||
DB_INIT_LOG | /* Initialize the logging subsystem */
|
||||
DB_INIT_TXN | /* Initialize the transactional subsystem. This
|
||||
* also turns on logging. */
|
||||
DB_INIT_MPOOL | /* Initialize the memory pool (in-memory cache) */
|
||||
DB_THREAD; /* Cause the environment to be free-threaded */ </pre>
|
||||
<p>
|
||||
Now we configure how we want deadlock detection performed. In our case, we will cause DB to perform deadlock
|
||||
detection by walking its internal lock tables looking for a block every time a lock is requested. Further, in the
|
||||
event of a deadlock, the thread that holds the youngest lock will receive the deadlock notification.
|
||||
</p>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
You will notice that every database operation checks the
|
||||
operation's status return code, and if an error
|
||||
(non-zero) status is returned, we log the error and then go to
|
||||
a <tt class="literal">err</tt> label in our program. Unlike
|
||||
object-oriented programs such as C++ or Java, we do not have
|
||||
<tt class="literal">try</tt> blocks in C. Therefore, this is the best
|
||||
way for us to implement cascading error handling for this
|
||||
example.
|
||||
</p>
|
||||
</div>
|
||||
<pre class="programlisting"> /*
|
||||
* Indicate that we want db to perform lock detection internally.
|
||||
* Also indicate that the transaction with the fewest number of
|
||||
* write locks will receive the deadlock notification in
|
||||
* the event of a deadlock.
|
||||
*/
|
||||
ret = envp->set_lk_detect(envp, DB_LOCK_MINWRITE);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error setting lock detect: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
} </pre>
|
||||
<p>
|
||||
Now we open our environment.
|
||||
</p>
|
||||
<pre class="programlisting"> /*
|
||||
* If we had utility threads (for running checkpoints or
|
||||
* deadlock detection, for example) we would spawn those
|
||||
* here. However, for a simple example such as this,
|
||||
* that is not required.
|
||||
*/
|
||||
|
||||
/* Now actually open the environment */
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
} </pre>
|
||||
<p>
|
||||
Now we call the function that will open our database for us. This is
|
||||
not very interesting, except that you will notice that we are
|
||||
specifying <tt class="literal">DB_DUPSORT</tt>. This is required purely by
|
||||
the data that we are writing to the database, and it is only necessary
|
||||
if you run the application more than once without first deleting the environment.
|
||||
</p>
|
||||
<p>
|
||||
Also, we do not provide any error logging here because the
|
||||
<tt class="function">open_db()</tt> function does that for us.
|
||||
(The implementation of <tt class="function">open_db()</tt> is described
|
||||
later in this section.)
|
||||
</p>
|
||||
<pre class="programlisting"> /* Open the database */
|
||||
ret = open_db(&dbp, prog_name, file_name, envp, DB_DUPSORT);
|
||||
if (ret != 0)
|
||||
goto err; </pre>
|
||||
<p>
|
||||
Now we create our threads. In this example we are using pthreads
|
||||
for our threading package. A description of threading (beyond how
|
||||
it impacts DB usage) is beyond the scope of this manual.
|
||||
However, the things that we are doing here should be familiar to
|
||||
anyone who has prior experience with any threading package. We are
|
||||
simply initializing a mutex, creating our threads, and then joining
|
||||
our threads, which causes our program to wait until the joined
|
||||
threads have completed before continuing operations in the main
|
||||
thread.
|
||||
</p>
|
||||
<pre class="programlisting"> /* Initialize a pthread mutex. Used to help provide thread ids. */
|
||||
(void)pthread_mutex_init(&thread_num_lock, NULL);
|
||||
|
||||
/* Start the writer threads. */
|
||||
for (i = 0; i < NUMWRITERS; i++)
|
||||
(void)pthread_create(&writer_threads[i], NULL,
|
||||
writer_thread, (void *)dbp);
|
||||
|
||||
/* Join the writers */
|
||||
for (i = 0; i < NUMWRITERS; i++)
|
||||
(void)pthread_join(writer_threads[i], NULL); </pre>
|
||||
<p>
|
||||
Finally, to wrap up <tt class="function">main()</tt>, we close out our
|
||||
database and environment handle, as is normal for any DB
|
||||
application. Notice that this is where our <tt class="literal">err</tt>
|
||||
label is placed in our application. If any database operation prior
|
||||
to this point in the program returns an error status, the program
|
||||
simply jumps to this point and closes our handles if necessary
|
||||
before exiting the application completely.
|
||||
</p>
|
||||
<pre class="programlisting">err:
|
||||
/* Close our database handle, if it was opened. */
|
||||
if (dbp != NULL) {
|
||||
ret_t = dbp->close(dbp, 0);
|
||||
if (ret_t != 0) {
|
||||
fprintf(stderr, "%s database close failed: %s\n",
|
||||
file_name, db_strerror(ret_t));
|
||||
ret = ret_t;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close our environment, if it was opened. */
|
||||
if (envp != NULL) {
|
||||
ret_t = envp->close(envp, 0);
|
||||
if (ret_t != 0) {
|
||||
fprintf(stderr, "environment close failed: %s\n",
|
||||
db_strerror(ret_t));
|
||||
ret = ret_t;
|
||||
}
|
||||
}
|
||||
|
||||
/* Final status message and return. */
|
||||
printf("I'm all done.\n");
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
<p>
|
||||
Now that we have completed <tt class="function">main()</tt>, we need to
|
||||
implement the function that our writer threads will actually run. This
|
||||
is where the bulk of our transactional code resides.
|
||||
</p>
|
||||
<p>
|
||||
We start as usual with variable declarations and initialization.
|
||||
</p>
|
||||
<pre class="programlisting">/*
|
||||
* A function that performs a series of writes to a
|
||||
* Berkeley DB database. The information written
|
||||
* to the database is largely nonsensical, but the
|
||||
* mechanisms of transactional commit/abort and
|
||||
* deadlock detection are illustrated here.
|
||||
*/
|
||||
void *
|
||||
writer_thread(void *args)
|
||||
{
|
||||
DBT key, value;
|
||||
DB_TXN *txn;
|
||||
int i, j, payload, ret, thread_num;
|
||||
int retry_count, max_retries = 20; /* Max retry on a deadlock */
|
||||
char *key_strings[] = {"key 1", "key 2", "key 3", "key 4",
|
||||
"key 5", "key 6", "key 7", "key 8",
|
||||
"key 9", "key 10"};
|
||||
|
||||
DB *dbp = (DB *)args;
|
||||
DB_ENV *envp = dbp->get_env(dbp); </pre>
|
||||
<p>
|
||||
Now we want a thread number for reporting purposes. It is possible to
|
||||
use the <tt class="literal">pthread_t</tt> value directly for this purpose,
|
||||
but how that is done unfortunately differs depending
|
||||
on the pthread implementation you are using. So instead we use a
|
||||
mutex-protected global variable to obtain a simple integer for
|
||||
our reporting purposes.
|
||||
</p>
|
||||
<p>
|
||||
Note that we are also use this thread id for initializing a random number generator, which we do here.
|
||||
We use this random number generator for data generation.
|
||||
</p>
|
||||
<pre class="programlisting"> /* Get the thread number */
|
||||
(void)pthread_mutex_lock(&thread_num_lock);
|
||||
global_thread_num++;
|
||||
thread_num = global_thread_num;
|
||||
(void)pthread_mutex_unlock(&thread_num_lock);
|
||||
|
||||
/* Initialize the random number generator */
|
||||
srand((u_int)pthread_self()); </pre>
|
||||
<p>
|
||||
Now we begin the loop that we use to write data to the database.
|
||||
<span>
|
||||
Notice that at the beginning of the top loop, we begin a new
|
||||
transaction.
|
||||
</span>
|
||||
|
||||
|
||||
We will actually use 50 transactions per writer
|
||||
thread, although we will only ever have one active transaction per
|
||||
thread at a time. Within each transaction, we will perform 10
|
||||
database writes.
|
||||
</p>
|
||||
<p>
|
||||
By combining multiple writes together under a single transaction,
|
||||
we increase the likelihood that a deadlock will occur. Normally,
|
||||
you want to reduce the potential for a deadlock and in this case
|
||||
the way to do that is to perform a single write per transaction.
|
||||
To avoid deadlocks, we could be using auto commit to
|
||||
write to our database for this workload.
|
||||
</p>
|
||||
<p>
|
||||
However, we want to show deadlock handling and by performing
|
||||
multiple writes per transaction we can actually observe deadlocks
|
||||
occurring. We also want to underscore the idea that you can
|
||||
combing multiple database operations together in a single atomic
|
||||
unit of work in order to improve the efficiency of your writes.
|
||||
</p>
|
||||
<p>
|
||||
Finally, on an issue of style, you will notice the
|
||||
<tt class="literal">retry</tt> label that we place immediately before our
|
||||
transaction begin code. We use this to loop in the event that a
|
||||
deadlock is detected and the write operation has to be performed. A
|
||||
great many people dislike looping with <tt class="literal">goto</tt>
|
||||
statements, and we certainly could have written this code to avoid
|
||||
it. However, we find that using the
|
||||
<tt class="literal">goto</tt> in this case greatly helps to clarify the
|
||||
code, so we ignore the bias against <tt class="literal">goto</tt>
|
||||
programming in order to clearly support looping in the event of
|
||||
what is really an error condition.
|
||||
</p>
|
||||
<pre class="programlisting"> /* Write 50 times and then quit */
|
||||
for (i = 0; i < 50; i++) {
|
||||
retry_count = 0; /* Used for deadlock retries */
|
||||
|
||||
retry:
|
||||
/* Begin our transaction. */
|
||||
ret = envp->txn_begin(envp, NULL, &txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "txn_begin failed");
|
||||
return ((void *)EXIT_FAILURE);
|
||||
} </pre>
|
||||
<p>
|
||||
Now we begin the inner loop that we use to actually
|
||||
perform the write. Notice that we use a <tt class="literal">case</tt>
|
||||
statement to examine the return code from the database put.
|
||||
This case statement is what we use to determine whether we need
|
||||
to abort (or abort/retry in the case of a deadlock) our current
|
||||
transaction.
|
||||
</p>
|
||||
<pre class="programlisting"> for (j = 0; j < 10; j++) {
|
||||
/* Set up our key and values DBTs */
|
||||
memset(&key, 0, sizeof(DBT));
|
||||
key.data = key_strings[j];
|
||||
key.size = (strlen(key_strings[j]) + 1) * sizeof(char);
|
||||
|
||||
memset(&value, 0, sizeof(DBT));
|
||||
payload = rand() + i;
|
||||
value.data = &payload;
|
||||
value.size = sizeof(int);
|
||||
|
||||
/* Perform the database put. */
|
||||
switch (ret = dbp->put(dbp, txn, &key, &value, 0)) {
|
||||
case 0:
|
||||
break;
|
||||
/*
|
||||
* Our database is configured for sorted duplicates,
|
||||
* so there is a potential for a KEYEXIST error return.
|
||||
* If we get one, simply ignore it and continue on.
|
||||
*
|
||||
* Note that you will see KEYEXIST errors only after you
|
||||
* have run this program at least once.
|
||||
*/
|
||||
case DB_KEYEXIST:
|
||||
printf("Got keyexists.\n");
|
||||
break;
|
||||
/*
|
||||
* Here's where we perform deadlock detection. If
|
||||
* DB_LOCK_DEADLOCK is returned by the put operation,
|
||||
* then this thread has been chosen to break a deadlock.
|
||||
* It must abort its operation, and optionally retry the
|
||||
* put.
|
||||
*/
|
||||
case DB_LOCK_DEADLOCK:
|
||||
/*
|
||||
* First thing we MUST do is abort the
|
||||
* transaction.
|
||||
*/
|
||||
(void)txn->abort(txn);
|
||||
/*
|
||||
* Now we decide if we want to retry the operation.
|
||||
* If we have retried less than max_retries,
|
||||
* increment the retry count and goto retry.
|
||||
*/
|
||||
if (retry_count < max_retries) {
|
||||
printf("Writer %i: Got DB_LOCK_DEADLOCK.\n",
|
||||
thread_num);
|
||||
printf("Writer %i: Retrying write operation.\n",
|
||||
thread_num);
|
||||
retry_count++;
|
||||
goto retry;
|
||||
}
|
||||
/*
|
||||
* Otherwise, just give up.
|
||||
*/
|
||||
printf("Writer %i: ", thread_num);
|
||||
printf("Got DB_LOCK_DEADLOCK and out of retries.\n");
|
||||
printf("Writer %i: Giving up.\n", thread_num);
|
||||
return ((void *)EXIT_FAILURE);
|
||||
/*
|
||||
* If a generic error occurs, we simply abort the
|
||||
* transaction and exit the thread completely.
|
||||
*/
|
||||
default:
|
||||
envp->err(envp, ret, "db put failed");
|
||||
ret = txn->abort(txn);
|
||||
if (ret != 0)
|
||||
envp->err(envp, ret, "txn abort failed");
|
||||
return ((void *)EXIT_FAILURE);
|
||||
} /** End case statement **/
|
||||
|
||||
} /** End for loop **/ </pre>
|
||||
<p>
|
||||
Having completed the inner database write loop, we could simply
|
||||
commit the transaction and continue on to the next block of 10
|
||||
writes. However, we want to first illustrate a few points about
|
||||
transactional processing so instead we call our
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
|
||||
function before calling the transaction
|
||||
commit.
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
uses a cursor to read every
|
||||
record in the database and return a count of the number of records
|
||||
that it found.
|
||||
</p>
|
||||
<pre class="programlisting"> /*
|
||||
* print the number of records found in the database.
|
||||
* See count_records() for usage information.
|
||||
*/
|
||||
printf("Thread %i. Record count: %i\n", thread_num,
|
||||
count_records(dbp, NULL));
|
||||
|
||||
/*
|
||||
* If all goes well, we can commit the transaction and
|
||||
* loop to the next transaction.
|
||||
*/
|
||||
ret = txn->commit(txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "txn commit failed");
|
||||
return ((void *)EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
return ((void *)EXIT_SUCCESS);
|
||||
} </pre>
|
||||
<p>
|
||||
|
||||
If you look at the
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
function prototype at the beginning of this example, you will see that the
|
||||
function's second parameter takes a transaction handle. However,
|
||||
our usage of the function here does not pass a transaction handle
|
||||
through to the function.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
Because
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
reads every record in the database, if used incorrectly the thread
|
||||
will self-deadlock. The writer thread has just written 500 records
|
||||
to the database, but because the transaction used for that write
|
||||
has not yet been committed, each of those 500 records are still
|
||||
locked by the thread's transaction. If we then simply run a
|
||||
non-transactional cursor over the database from within the same
|
||||
thread that has locked those 500 records, the cursor will
|
||||
block when it tries to read one of those transactional
|
||||
protected records. The thread immediately stops operation at that
|
||||
point while the cursor waits for the read lock it has
|
||||
requested. Because that read lock will never be released (the thread
|
||||
can never make any forward progress), this represents a
|
||||
self-deadlock for the the thread.
|
||||
</p>
|
||||
<p>
|
||||
There are three ways to prevent this self-deadlock:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
We can move the call to
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
to a point after the thread's transaction has committed.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
We can allow
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
to operate under the same transaction as all of the writes
|
||||
were performed (this is what the transaction parameter for
|
||||
the function is for).
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
We can reduce our isolation guarantee for the application
|
||||
by allowing uncommitted reads.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<p>
|
||||
For this example, we choose to use option 3 (uncommitted reads) to avoid
|
||||
the deadlock. This means that we have to open our database such
|
||||
that it supports uncommitted reads, and we have to open our cursor handle
|
||||
so that it knows to perform uncommitted reads.
|
||||
</p>
|
||||
<p>
|
||||
Note that in <a href="inmem_txnexample_c.html">In-Memory Transaction Example</a>,
|
||||
we simply perform the cursor operation using the same transaction
|
||||
as is used for the thread's writes.
|
||||
</p>
|
||||
<p>
|
||||
The following is the
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
implementation. There is not anything particularly interesting
|
||||
about this function other than specifying uncommitted reads when
|
||||
we open the cursor handle, but we include the function here anyway
|
||||
for the sake of completeness.
|
||||
</p>
|
||||
<pre class="programlisting">/*
|
||||
* This simply counts the number of records contained in the
|
||||
* database and returns the result.
|
||||
*
|
||||
* Note that this function exists only for illustrative purposes.
|
||||
* A more straight-forward way to count the number of records in
|
||||
* a database is to use DB->stat() or DB->stat_print().
|
||||
*/
|
||||
|
||||
int
|
||||
count_records(DB *dbp, DB_TXN *txn)
|
||||
{
|
||||
DBT key, value;
|
||||
DBC *cursorp;
|
||||
int count, ret;
|
||||
|
||||
cursorp = NULL;
|
||||
count = 0;
|
||||
|
||||
/* Get the cursor */
|
||||
ret = dbp->cursor(dbp, txn, &cursorp, DB_READ_UNCOMMITTED);
|
||||
if (ret != 0) {
|
||||
dbp->err(dbp, ret, "count_records: cursor open failed.");
|
||||
goto cursor_err;
|
||||
}
|
||||
|
||||
/* Get the key DBT used for the database read */
|
||||
memset(&key, 0, sizeof(DBT));
|
||||
memset(&value, 0, sizeof(DBT));
|
||||
do {
|
||||
ret = cursorp->get(cursorp, &key, &value, DB_NEXT);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
count++;
|
||||
break;
|
||||
case DB_NOTFOUND:
|
||||
break;
|
||||
default:
|
||||
dbp->err(envp, ret, "Count records unspecified error");
|
||||
goto cursor_err;
|
||||
}
|
||||
} while (ret == 0);
|
||||
|
||||
cursor_err:
|
||||
if (cursorp != NULL) {
|
||||
ret = cursorp->close(cursorp);
|
||||
if (ret != 0) {
|
||||
dbp->err(dbp, ret,
|
||||
"count_records: cursor close failed.");
|
||||
}
|
||||
}
|
||||
|
||||
return (count);
|
||||
} </pre>
|
||||
<p>
|
||||
Finally, we provide the implementation of our
|
||||
<tt class="function">open_db()</tt>
|
||||
|
||||
function. This function should hold
|
||||
no surprises for you. Note, however, that we do specify uncommitted reads
|
||||
when we open the database. If we did not do this, then our
|
||||
<tt class="function">count_records()</tt>
|
||||
|
||||
function would cause our
|
||||
thread to self-deadlock because the cursor could not be opened to
|
||||
support uncommitted reads (that flag on the cursor open would, in fact,
|
||||
be silently ignored by DB).
|
||||
</p>
|
||||
<pre class="programlisting">/* Open a Berkeley DB database */
|
||||
int
|
||||
open_db(DB **dbpp, const char *progname, const char *file_name,
|
||||
DB_ENV *envp, u_int32_t extra_flags)
|
||||
{
|
||||
int ret;
|
||||
u_int32_t open_flags;
|
||||
DB *dbp;
|
||||
|
||||
/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "%s: %s\n", progname,
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Point to the memory malloc'd by db_create() */
|
||||
*dbpp = dbp;
|
||||
|
||||
if (extra_flags != 0) {
|
||||
ret = dbp->set_flags(dbp, extra_flags);
|
||||
if (ret != 0) {
|
||||
dbp->err(dbp, ret,
|
||||
"open_db: Attempt to set extra flags failed.");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now open the database */
|
||||
open_flags = DB_CREATE | /* Allow database creation */
|
||||
DB_READ_UNCOMMITTED | /* Allow uncommitted reads */
|
||||
DB_AUTO_COMMIT; /* Allow auto commit */
|
||||
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
NULL, /* Txn pointer */
|
||||
file_name, /* File name */
|
||||
NULL, /* Logical db name */
|
||||
DB_BTREE, /* Database type (using btree) */
|
||||
open_flags, /* Open flags */
|
||||
0); /* File mode. Using defaults */
|
||||
if (ret != 0) {
|
||||
dbp->err(dbp, ret, "Database '%s' open failed",
|
||||
file_name);
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
return (EXIT_SUCCESS);
|
||||
} </pre>
|
||||
<p>
|
||||
This completes our transactional example. If you would like to
|
||||
experiment with this code, you can find the example in the following
|
||||
location in your DB distribution:
|
||||
</p>
|
||||
<pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_c/txn_guide</pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="wrapup.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="wrapup.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="inmem_txnexample_c.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Chapter 6. Summary and Examples </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> In-Memory Transaction Example</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
137
docs/gsg_txn/C/txnindices.html
Normal file
137
docs/gsg_txn/C/txnindices.html
Normal file
@@ -0,0 +1,137 @@
|
||||
<?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>Secondary Indices with Transaction Applications</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="usingtxns.html" title="Chapter 3. Transaction Basics" />
|
||||
<link rel="previous" href="txncursor.html" title="Transactional Cursors" />
|
||||
<link rel="next" href="maxtxns.html" title="Configuring the Transaction Subsystem" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Secondary Indices with Transaction Applications</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="txncursor.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 3. Transaction Basics</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="maxtxns.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="txnindices"></a>Secondary Indices with Transaction Applications</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
<span>
|
||||
You
|
||||
</span>
|
||||
|
||||
|
||||
can use transactions with your secondary indices so long as you
|
||||
|
||||
<span>
|
||||
open the secondary index so that it supports transactions (that is,
|
||||
you wrap the database open in a transaction, or use auto commit,
|
||||
in the same way as when you open a primary transactional database).
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
<span>
|
||||
In addition, you must make sure that when you associate the
|
||||
secondary index with the primary database, the association is
|
||||
performed using a transaction. The easiest thing to do here is
|
||||
to simply specify <tt class="literal">DB_AUTO_COMMIT</tt> when you
|
||||
perform the association.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
All other aspects of using secondary indices with transactions are
|
||||
identical to using secondary indices without transactions. In
|
||||
addition, transaction-protecting
|
||||
<span>
|
||||
cursors opened against secondary indices is performed in
|
||||
exactly the same way as when you use transactional cursors
|
||||
against a primary database.
|
||||
</span>
|
||||
|
||||
See <a href="txncursor.html">Transactional Cursors</a> for details.
|
||||
</p>
|
||||
<p>
|
||||
Note that when you use transactions to protect your database writes, your secondary indices are protected from
|
||||
corruption because updates to the primary and the secondaries are performed in a single atomic transaction.
|
||||
</p>
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting">#include <db.h>
|
||||
|
||||
...
|
||||
|
||||
DB_ENV *envp; /* Environment pointer */
|
||||
DB *dbp, *sdbp; /* Primary and secondary DB handles */
|
||||
u_int32_t flags; /* Primary database open flags */
|
||||
int ret; /* Function return value */
|
||||
|
||||
/* Environment and primary database opens omitted */
|
||||
|
||||
/* Secondary */
|
||||
ret = db_create(&sdbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
/* Error handling goes here */
|
||||
}
|
||||
/* open the secondary database */
|
||||
ret = sdbp->open(sdbp, /* DB structure pointer */
|
||||
NULL, /* Transaction pointer */
|
||||
"my_secdb.db", /* On-disk file that holds the database. */
|
||||
NULL, /* Optional logical database name */
|
||||
DB_BTREE, /* Database access method */
|
||||
DB_AUTO_COMMIT, /* Open flags */
|
||||
0); /* File mode (using defaults) */
|
||||
if (ret != 0) {
|
||||
/* Error handling goes here */
|
||||
}
|
||||
|
||||
/* Now associate the secondary to the primary */
|
||||
dbp->associate(dbp, /* Primary database */
|
||||
NULL, /* TXN id */
|
||||
sdbp, /* Secondary database */
|
||||
get_sales_rep, /* Callback used for key creation. This
|
||||
* is described in the Getting Started
|
||||
* guide. */
|
||||
DB_AUTO_COMMIT);/* Flags */</pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="txncursor.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="usingtxns.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="maxtxns.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Transactional Cursors </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Configuring the Transaction Subsystem</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
91
docs/gsg_txn/C/txnnowait.html
Normal file
91
docs/gsg_txn/C/txnnowait.html
Normal file
@@ -0,0 +1,91 @@
|
||||
<?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>No Wait on Blocks</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="txnconcurrency.html" title="Chapter 4. Concurrency" />
|
||||
<link rel="previous" href="readmodifywrite.html" title="Read/Modify/Write" />
|
||||
<link rel="next" href="reversesplit.html" title="Reverse BTree Splits" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">No Wait on Blocks</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="readmodifywrite.html">Prev</a> </td>
|
||||
<th width="60%" align="center">Chapter 4. Concurrency</th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="reversesplit.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="txnnowait"></a>No Wait on Blocks</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Normally when a DB transaction is blocked on a lock request, it
|
||||
must wait until the requested lock becomes available before its
|
||||
thread-of-control can proceed. However, it is possible to configure a
|
||||
transaction handle such that it will report a deadlock rather
|
||||
than wait for the block to clear.
|
||||
</p>
|
||||
<p>
|
||||
You do this on a transaction by transaction basis by specifying
|
||||
|
||||
<span>
|
||||
<tt class="literal">DB_TXN_NOWAIT</tt>
|
||||
to the
|
||||
<tt class="methodname">DB_ENV->txn_begin()</tt>
|
||||
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
For example:
|
||||
</p>
|
||||
<pre class="programlisting"> /* Get the transaction */
|
||||
DB_TXN *txn = NULL;
|
||||
ret = envp->txn_begin(envp, NULL, &txn, DB_TXN_NOWAIT);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "txn_begin failed");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
....
|
||||
/* Deadlock detection and exception handling omitted for brevity. */</pre>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="readmodifywrite.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="reversesplit.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Read/Modify/Write </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Reverse BTree Splits</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
595
docs/gsg_txn/C/usingtxns.html
Normal file
595
docs/gsg_txn/C/usingtxns.html
Normal file
@@ -0,0 +1,595 @@
|
||||
<?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>Chapter 3. Transaction Basics</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="previous" href="envopen.html" title="Opening a Transactional Environment and Database " />
|
||||
<link rel="next" href="abortresults.html" title="Aborting a Transaction" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Chapter 3. Transaction Basics</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="envopen.html">Prev</a> </td>
|
||||
<th width="60%" align="center"> </th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="abortresults.html">Next</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="chapter" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title"><a id="usingtxns"></a>Chapter 3. Transaction Basics</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="toc">
|
||||
<p>
|
||||
<b>Table of Contents</b>
|
||||
</p>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="usingtxns.html#commitresults">Committing a Transaction</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect2">
|
||||
<a href="usingtxns.html#nodurabletxn">Non-Durable Transactions</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="abortresults.html">Aborting a Transaction</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="autocommit.html">Auto Commit</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="nestedtxn.html">Nested Transactions</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txncursor.html">Transactional Cursors</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txnindices.html">Secondary Indices with Transaction Applications</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="maxtxns.html">Configuring the Transaction Subsystem</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</div>
|
||||
<p>
|
||||
Once you have enabled transactions for your environment and your databases,
|
||||
you can use them to protect your database operations. You do this by
|
||||
acquiring a transaction handle and then using that handle for any
|
||||
database operation that you want to participate in that transaction.
|
||||
</p>
|
||||
<p>
|
||||
You obtain a transaction handle using the
|
||||
<span><tt class="methodname">DB_ENV->txn_begin()</tt> method.</span>
|
||||
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Once you have completed all of the operations that you want to include
|
||||
in the transaction, you must commit the transaction using the
|
||||
<span><tt class="methodname">DB_TXN->commit()</tt> method.</span>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
If, for any reason, you want to abandon the transaction, you abort
|
||||
it using
|
||||
<span><tt class="methodname">DB_TXN->abort()</tt>.</span>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Any transaction handle that has been committed or aborted can no longer
|
||||
be used by your application.
|
||||
</p>
|
||||
<p>
|
||||
Finally, you must make sure that all transaction handles are either
|
||||
committed or aborted before closing your databases and environment.
|
||||
</p>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
If you only want to transaction protect a single database write operation, you can use auto commit to
|
||||
perform the transaction administration. When you use auto commit, you do not need an explicit transaction
|
||||
handle. See <a href="autocommit.html">Auto Commit</a> for more information.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
For example, the following example opens a transactional-enabled environment and
|
||||
database, obtains a transaction handle, and then performs a write
|
||||
operation under its protection. In the event of any failure in the
|
||||
write operation, the transaction is aborted and the database is left in a
|
||||
state as if no operations had ever been attempted in the first place.
|
||||
</p>
|
||||
<pre class="programlisting">#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret, ret_c;
|
||||
u_int32_t db_flags, env_flags;
|
||||
DB *dbp;
|
||||
DB_ENV *envp;
|
||||
DBT key, data;
|
||||
DB_TXN *txn;
|
||||
const char *db_home_dir = "/tmp/myEnvironment";
|
||||
const char *file_name = "mydb.db";
|
||||
const char *keystr ="thekey";
|
||||
const char *datastr = "thedata";
|
||||
|
||||
dbp = NULL;
|
||||
envp = NULL;
|
||||
|
||||
/* Open the environment */
|
||||
ret = db_env_create(&envp, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error creating environment handle: %s\n",
|
||||
db_strerror(ret));
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
env_flags = DB_CREATE | /* Create the environment if it does
|
||||
* not already exist. */
|
||||
DB_INIT_TXN | /* Initialize transactions */
|
||||
DB_INIT_LOCK | /* Initialize locking. */
|
||||
DB_INIT_LOG | /* Initialize logging */
|
||||
DB_INIT_MPOOL; /* Initialize the in-memory cache. */
|
||||
|
||||
ret = envp->open(envp, db_home_dir, env_flags, 0);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error opening environment: %s\n",
|
||||
db_strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Initialize the DB handle */
|
||||
ret = db_create(&dbp, envp, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database creation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
db_flags = DB_CREATE | DB_AUTO_COMMIT;
|
||||
/*
|
||||
* Open the database. Note that we are using auto commit for the open,
|
||||
* so the database is able to support transactions.
|
||||
*/
|
||||
ret = dbp->open(dbp, /* Pointer to the database */
|
||||
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 */
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database '%s' open failed",
|
||||
file_name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Prepare the DBTs */
|
||||
memset(&key, 0, sizeof(DBT));
|
||||
memset(&data, 0, sizeof(DBT));
|
||||
|
||||
key.data = &keystr;
|
||||
key.size = strlen(keystr) + 1;
|
||||
data.data = &datastr;
|
||||
data.size = strlen(datastr) + 1;
|
||||
|
||||
/* Get the txn handle */
|
||||
txn = NULL;
|
||||
ret = envp->txn_begin(envp, NULL, &txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Transaction begin failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the database write. If this fails, abort the transaction.
|
||||
*/
|
||||
ret = dbp->put(dbp, txn, &key, &data, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Database put failed.");
|
||||
txn->abort(txn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Commit the transaction. Note that the transaction handle
|
||||
* can no longer be used.
|
||||
*/
|
||||
ret = txn->commit(txn, 0);
|
||||
if (ret != 0) {
|
||||
envp->err(envp, ret, "Transaction commit failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
/* Close the database */
|
||||
if (dbp != NULL) {
|
||||
ret_c = dbp->close(dbp, 0);
|
||||
if (ret_c != 0) {
|
||||
envp->err(envp, ret_c, "Database close failed.");
|
||||
ret = ret_c
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Close the environment */
|
||||
if (envp != NULL) {
|
||||
ret_c = envp->close(envp, 0);
|
||||
if (ret_c != 0) {
|
||||
fprintf(stderr, "environment close failed: %s\n",
|
||||
db_strerror(ret_c));
|
||||
ret = ret_c;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} </pre>
|
||||
<div class="sect1" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title" style="clear: both"><a id="commitresults"></a>Committing a Transaction</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
In order to fully understand what is happening when you commit
|
||||
a transaction, you must first understand a little about what
|
||||
DB is doing with
|
||||
|
||||
<span>
|
||||
the logging subsystem.
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
Logging causes all database write operations to be identified in
|
||||
|
||||
<span>logs, and by default these
|
||||
logs are backed by files on disk. These logs are used to restore your databases
|
||||
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
in the event of a system or application failure, so by performing
|
||||
logging, DB ensures the integrity of your data.
|
||||
</p>
|
||||
<p>
|
||||
Moreover, DB performs <span class="emphasis"><em>write-ahead</em></span>
|
||||
logging. This means that information is written to the logs
|
||||
<span class="emphasis"><em>before</em></span> the actual database
|
||||
|
||||
is changed.
|
||||
This means that all write activity performed under the
|
||||
protection of the transaction is noted in the log before
|
||||
the transaction is committed. Be aware, however, that database
|
||||
maintains logs in-memory. If you are backing your logs on
|
||||
disk, the log information will eventually be written to the log
|
||||
files, but while the transaction is on-going the log data may be
|
||||
held only in memory.
|
||||
</p>
|
||||
<p>
|
||||
When you commit a transaction, the following occurs:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
A commit record is written to the log. This
|
||||
indicates that the modifications made by the
|
||||
transaction are now permanent. By default, this write is performed synchronously to disk so the
|
||||
commit record arrives in the log files before any other actions are taken.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Any log information held in memory is (by default)
|
||||
synchronously written to disk. Note that this requirement can be
|
||||
relaxed, depending on the type of commit you perform.
|
||||
See <a href="usingtxns.html#nodurabletxn">Non-Durable Transactions</a> for
|
||||
more information.
|
||||
<span>Also, if you are
|
||||
maintaining your logs entirely in-memory, then this
|
||||
step will of course not be taken. To configure your
|
||||
logging system for in-memory usage, see
|
||||
<a href="logconfig.html#inmemorylogging">Configuring In-Memory Logging</a>.
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
All locks held by the transaction are released. This means
|
||||
that read operations performed by other transactions or
|
||||
threads of control can now see the modifications without
|
||||
resorting to uncommitted reads (see <a href="isolation.html#dirtyreads">Reading Uncommitted Data</a> for more information).
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
To commit a transaction, you simply call
|
||||
<span><tt class="methodname">DB_TXN->commit()</tt>.</span>
|
||||
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Notice that committing a transaction does not necessarily cause data
|
||||
modified in your memory cache to be written to the files
|
||||
backing your databases on disk. Dirtied database pages are written
|
||||
for a number of reasons, but a transactional
|
||||
commit is not one of them. The following are the things that can cause a dirtied
|
||||
database page to be written to the backing database file:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Checkpoints.
|
||||
</p>
|
||||
<p>
|
||||
Checkpoints cause all dirtied pages currently existing
|
||||
in the cache to be written to disk, and a checkpoint
|
||||
record is then written to the logs. You can run checkpoints
|
||||
explicitly. For more information on checkpoints,
|
||||
see <a href="filemanagement.html#checkpoints">Checkpoints</a>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Cache is full.
|
||||
</p>
|
||||
<p>
|
||||
If the in-memory cache fills up, then dirtied pages
|
||||
might be written to disk in order to free up space for other
|
||||
pages that your application needs to use. Note that if
|
||||
dirtied pages are written to the database files, then
|
||||
any log records that describe how those pages were
|
||||
dirtied are written to disk before the database
|
||||
pages are written.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
Be aware that because your transaction commit caused database
|
||||
|
||||
modifications recorded in your logs to be forced to disk, your modifications
|
||||
are by default "persistent" in that they can be recovered in the event of
|
||||
an application or system failure. However, recovery time is
|
||||
gated by how much data has been modified since the last
|
||||
checkpoint, so for applications that perform a lot of writes,
|
||||
you may want to run a checkpoint with some frequency.
|
||||
</p>
|
||||
<p>
|
||||
Note that once you have committed a transaction, the transaction
|
||||
handle that you used for the transaction is no longer valid. To
|
||||
perform database activities under the control of a new
|
||||
transaction, you must obtain a fresh transaction handle.
|
||||
</p>
|
||||
<div class="sect2" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="title"><a id="nodurabletxn"></a>Non-Durable Transactions</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
As previously noted, by default transaction commits are
|
||||
durable because they cause the modifications performed
|
||||
under the transaction to be synchronously recorded in
|
||||
your on-disk log files. However, it is possible to use
|
||||
non-durable transactions.
|
||||
</p>
|
||||
<p>
|
||||
You may want non-durable transactions for performance
|
||||
reasons. For example, you might be using transactions
|
||||
simply for the isolation guarantee.
|
||||
|
||||
<span>
|
||||
In this case, you might
|
||||
not want a durability guarantee and so you may want to
|
||||
prevent the disk I/O that normally accompanies a
|
||||
transaction commit.
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
There are several ways to remove the durability guarantee
|
||||
for your transactions:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Specify
|
||||
<span>
|
||||
<tt class="literal">DB_TXN_NOSYNC</tt> using the
|
||||
<tt class="methodname">DB_ENV->set_flags()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
This causes DB to not synchronously force any
|
||||
<span>
|
||||
log
|
||||
</span>
|
||||
data to disk upon transaction commit.
|
||||
|
||||
<span>
|
||||
That is, the modifications are held entirely
|
||||
in the in-memory cache and the logging
|
||||
information is not forced to the filesystem for
|
||||
long-term storage.
|
||||
</span>
|
||||
|
||||
Note, however, that the
|
||||
<span>
|
||||
logging
|
||||
</span>
|
||||
data will eventually make it to the filesystem (assuming no
|
||||
application or OS crashes) as a part of DB's
|
||||
management of its logging buffers and/or cache.
|
||||
</p>
|
||||
<p>
|
||||
This form of a commit provides a weak durability
|
||||
guarantee because data loss can occur due to
|
||||
an application
|
||||
or OS crash.
|
||||
</p>
|
||||
<p>
|
||||
This behavior is specified on a per-environment
|
||||
handle basis. In order for your application to exhibit consistent
|
||||
behavior, you need to specify this
|
||||
<span>flag</span>
|
||||
|
||||
for all of the environment handles used in your application.
|
||||
</p>
|
||||
<p>
|
||||
You can achieve this behavior on a transaction by transaction basis by
|
||||
<span>
|
||||
specifying <tt class="literal">DB_TXN_NOSYNC</tt> to the
|
||||
<tt class="methodname">DB_TXN->commit()</tt>
|
||||
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Specify
|
||||
<span>
|
||||
<tt class="literal">DB_TXN_WRITE_NOSYNC</tt> using the
|
||||
<tt class="methodname">DB_ENV->set_flags()</tt>
|
||||
|
||||
method.
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
This causes
|
||||
<span>
|
||||
logging
|
||||
</span>
|
||||
data to be synchronously
|
||||
written to the OS's file system buffers upon
|
||||
transaction commit. The data will eventually be
|
||||
written to disk, but this occurs when the
|
||||
operating system chooses to schedule the
|
||||
activity; the transaction commit can complete
|
||||
successfully before this disk I/O is performed
|
||||
by the OS.
|
||||
</p>
|
||||
<p>
|
||||
This form of commit protects you against application
|
||||
crashes, but not against OS
|
||||
crashes. This method offers less room for the possibility of data loss than does
|
||||
<span><tt class="literal">DB_TXN_NOSYNC</tt>.</span>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
This behavior is specified on a per-environment
|
||||
handle basis. In order for your application to exhibit consistent
|
||||
behavior, you need to specify this
|
||||
<span>flag</span>
|
||||
|
||||
for all of the environment handles used in your application.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Maintain your logs entirely in-memory. In this
|
||||
case, your logs are never written to disk. The
|
||||
result is that you lose all durability guarantees.
|
||||
See
|
||||
<a href="logconfig.html#inmemorylogging">Configuring In-Memory Logging</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="envopen.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="index.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="abortresults.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Opening a Transactional Environment and
|
||||
Database
|
||||
|
||||
|
||||
</td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Aborting a Transaction</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
282
docs/gsg_txn/C/wrapup.html
Normal file
282
docs/gsg_txn/C/wrapup.html
Normal file
@@ -0,0 +1,282 @@
|
||||
<?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>Chapter 6. Summary and Examples</title>
|
||||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
|
||||
<link rel="home" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="up" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
|
||||
<link rel="previous" href="logconfig.html" title="Configuring the Logging Subsystem" />
|
||||
<link rel="next" href="txnexample_c.html" title="Transaction Example" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="navheader">
|
||||
<table width="100%" summary="Navigation header">
|
||||
<tr>
|
||||
<th colspan="3" align="center">Chapter 6. Summary and Examples</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%" align="left"><a accesskey="p" href="logconfig.html">Prev</a> </td>
|
||||
<th width="60%" align="center"> </th>
|
||||
<td width="20%" align="right"> <a accesskey="n" href="txnexample_c.html">Next</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="chapter" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title"><a id="wrapup"></a>Chapter 6. Summary and Examples</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="toc">
|
||||
<p>
|
||||
<b>Table of Contents</b>
|
||||
</p>
|
||||
<dl>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="wrapup.html#anatomy">Anatomy of a Transactional Application</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="txnexample_c.html">Transaction Example</a>
|
||||
</span>
|
||||
</dt>
|
||||
<dt>
|
||||
<span class="sect1">
|
||||
<a href="inmem_txnexample_c.html">In-Memory Transaction Example</a>
|
||||
</span>
|
||||
</dt>
|
||||
</dl>
|
||||
</div>
|
||||
<p>
|
||||
Throughout this manual we have presented the concepts and
|
||||
mechanisms that you need to provide transactional protection for
|
||||
your application. In this chapter, we summarize these
|
||||
mechanisms, and we provide a complete example of a multi-threaded
|
||||
transactional DB application.
|
||||
</p>
|
||||
<div class="sect1" lang="en" xml:lang="en">
|
||||
<div class="titlepage">
|
||||
<div>
|
||||
<div>
|
||||
<h2 class="title" style="clear: both"><a id="anatomy"></a>Anatomy of a Transactional Application</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<p>
|
||||
Transactional applications are characterized by performing the
|
||||
following activities:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="1">
|
||||
<li>
|
||||
<p>
|
||||
Create your environment handle.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Open your environment, specifying that the following
|
||||
subsystems be used:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Transactional Subsystem (this also initializes the
|
||||
logging subsystem).
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Memory pool (the in-memory cache).
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Logging subsystem.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Locking subsystem (if your application is multi-process or multi-threaded).
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
It is also highly recommended that you run normal recovery
|
||||
upon first environment open. Normal recovery examines only those logs required
|
||||
to ensure your database files are consistent relative to the information found in your
|
||||
log files.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Optionally spawn off any utility threads that you might need. Utility
|
||||
threads can be used to run checkpoints periodically, or to
|
||||
periodically run a deadlock detector if you do not want to
|
||||
use DB's built-in deadlock detector.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Open whatever database handles that you need.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Spawn off worker threads. How many of these you need and
|
||||
how they split their DB workload is entirely up to your
|
||||
application's requirements. However, any worker threads
|
||||
that perform write operations will do the following:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="a">
|
||||
<li>
|
||||
<p>
|
||||
Begin a transaction.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Perform one or more read and write
|
||||
operations.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Commit the transaction if all goes well.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Abort and retry the operation if a deadlock is
|
||||
detected.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Abort the transaction for most other errors.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
On application shutdown:
|
||||
</p>
|
||||
<div class="orderedlist">
|
||||
<ol type="a">
|
||||
<li>
|
||||
<p>
|
||||
Make sure there are no opened cursors.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Make sure there are no active transactions. Either
|
||||
abort or commit all transactions before shutting
|
||||
down.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Close your databases.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Close your environment.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
|
||||
<h3 class="title">Note</h3>
|
||||
<p>
|
||||
Robust DB applications should monitor their worker threads to
|
||||
make sure they have not died unexpectedly. If a thread does
|
||||
terminate abnormally, you must shutdown all your worker threads
|
||||
and then run normal recovery (you will have to reopen your
|
||||
environment to do this). This is the only way to clear any
|
||||
resources (such as a lock or a mutex) that the abnormally
|
||||
exiting worker thread might have been holding at the time that
|
||||
it died.
|
||||
</p>
|
||||
<p>
|
||||
Failure to perform this recovery can cause your
|
||||
still-functioning worker threads to eventually block forever
|
||||
while waiting for a lock that will never be released.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
In addition to these activities, which are all entirely handled by
|
||||
code within your application, there are some administrative
|
||||
activities that you should perform:
|
||||
</p>
|
||||
<div class="itemizedlist">
|
||||
<ul type="disc">
|
||||
<li>
|
||||
<p>
|
||||
Periodically checkpoint your application. Checkpoints will
|
||||
reduce the time to run recovery in the event that one is
|
||||
required. See <a href="filemanagement.html#checkpoints">Checkpoints</a>
|
||||
for details.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Periodically back up your database and log files. This is
|
||||
required in order to fully obtain the durability guarantee
|
||||
made by DB's transaction ACID support. See
|
||||
<a href="backuprestore.html">Backup Procedures</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
You may want to maintain a hot failover if 24x7 processing
|
||||
with rapid restart in the face of a disk hit is important
|
||||
to you. See <a href="hotfailover.html">Using Hot Failovers</a>
|
||||
for more information.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navfooter">
|
||||
<hr />
|
||||
<table width="100%" summary="Navigation footer">
|
||||
<tr>
|
||||
<td width="40%" align="left"><a accesskey="p" href="logconfig.html">Prev</a> </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="u" href="index.html">Up</a>
|
||||
</td>
|
||||
<td width="40%" align="right"> <a accesskey="n" href="txnexample_c.html">Next</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%" align="left" valign="top">Configuring the Logging Subsystem </td>
|
||||
<td width="20%" align="center">
|
||||
<a accesskey="h" href="index.html">Home</a>
|
||||
</td>
|
||||
<td width="40%" align="right" valign="top"> Transaction Example</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
docs/gsg_txn/C/writeblock.jpg
Normal file
BIN
docs/gsg_txn/C/writeblock.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
Reference in New Issue
Block a user