Import BSDDB 4.7.25 (as of svn r89086)

This commit is contained in:
Zachary Ware
2017-09-04 13:40:25 -05:00
parent 4b29e0458f
commit 8f590873d0
4781 changed files with 2241032 additions and 6 deletions

Binary file not shown.

View 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-&gt;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>

View 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-&gt;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-&gt;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-&gt;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>

View 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-&gt;set_flags()</tt>
or
<tt class="methodname">DB-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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(&amp;dbp, envp, 0);
if (ret != 0) {
envp-&gt;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-&gt;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-&gt;err(envp, ret, "Database '%s' open failed",
file_name);
goto err;
}
/* Prepare the DBTs */
memset(&amp;key, 0, sizeof(DBT));
memset(&amp;data, 0, sizeof(DBT));
key.data = &amp;keystr;
key.size = strlen(keystr) + 1;
data.data = &amp;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-&gt;put(dbp, NULL, &amp;key, &amp;data, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "Database put failed.");
goto err;
}
err:
/* Close the database */
if (dbp != NULL) {
ret_c = dbp-&gt;close(dbp, 0);
if (ret_c != 0) {
envp-&gt;err(envp, ret_c, "Database close failed.");
ret = ret_c
}
}
/* Close the environment */
if (envp != NULL) {
ret_c = envp-&gt;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>

View 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-&gt;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-&gt;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>

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View 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&#10; Database&#10; &#10; &#10; " />
</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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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
View 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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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(&amp;dbp, envp, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "Database creation failed");
goto err;
}
db_flags = DB_CREATE | DB_AUTO_COMMIT;
ret = dbp-&gt;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-&gt;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-&gt;close(dbp, 0);
if (ret_c != 0) {
envp-&gt;err(envp, ret_c, "Database close failed.");
ret = ret_c
}
}</tt></b>
/* Close the environment */
if (envp != NULL) {
ret_c = envp-&gt;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>

View 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-&gt;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-&gt;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 &lt;stdio.h&gt;
#include &lt;pthread.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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(
&amp;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-&gt;txn_checkpoint(dbenv, 0, 0, 0)) != 0) {
dbenv-&gt;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>

View 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; }

View 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
View 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>

View 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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;pthread.h&gt;
#include &lt;db.h&gt;
/* 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(&amp;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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(&amp;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(&amp;thread_num_lock, NULL);
/* Start the writer threads. */
for (i = 0; i &lt; NUMWRITERS; i++)
(void)pthread_create(
&amp;writer_threads[i], NULL, (void *)writer_thread, (void *)dbp);
/* Join the writers */
for (i = 0; i &lt; NUMWRITERS; i++)
(void)pthread_join(writer_threads[i], NULL);
err:
/* Close our database handle, if it was opened. */
if (dbp != NULL) {
ret_t = dbp-&gt;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-&gt;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-&gt;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-&gt;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-&gt;get_env(dbp);
/* Get the thread number */
(void)pthread_mutex_lock(&amp;thread_num_lock);
global_thread_num++;
thread_num = global_thread_num;
(void)pthread_mutex_unlock(&amp;thread_num_lock);
/* Initialize the random number generator */
srand((u_int)pthread_self());
/* Write 50 times and then quit */
for (i = 0; i &lt; 50; i++) {
retry_count = 0; /* Used for deadlock retries */
retry:
ret = envp-&gt;txn_begin(envp, NULL, &amp;txn, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "txn_begin failed");
return (EXIT_FAILURE);
}
for (j = 0; j &lt; 10; j++) {
/* Set up our key and values DBTs */
memset(&amp;key, 0, sizeof(DBT));
key.data = key_strings[j];
key.size = (strlen(key_strings[j]) + 1) * sizeof(char);
memset(&amp;value, 0, sizeof(DBT));
payload = rand() + i;
value.data = &amp;payload;
value.size = sizeof(int);
/* Perform the database put. */
switch (ret = dbp-&gt;put(dbp, txn, &amp;key, &amp;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-&gt;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 &lt; 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-&gt;err(envp, ret, "db put failed");
ret = txn-&gt;abort(txn);
if (ret != 0)
envp-&gt;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-&gt;commit(txn, 0);
if (ret != 0) {
envp-&gt;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-&gt;cursor(dbp, txn, &amp;cursorp, <b class="userinput"><tt>0</tt></b>);
if (ret != 0) {
dbp-&gt;err(dbp, ret, "count_records: cursor open failed.");
goto cursor_err;
}
/* Get the key DBT used for the database read */
memset(&amp;key, 0, sizeof(DBT));
memset(&amp;value, 0, sizeof(DBT));
do {
ret = cursorp-&gt;get(cursorp, &amp;key, &amp;value, DB_NEXT);
switch (ret) {
case 0:
count++;
break;
case DB_NOTFOUND:
break;
default:
dbp-&gt;err(envp, ret,
"Count records unspecified error");
goto cursor_err;
}
} while (ret == 0);
cursor_err:
if (cursorp != NULL) {
ret = cursorp-&gt;close(cursorp);
if (ret != 0) {
dbp-&gt;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(&amp;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-&gt;set_flags(dbp, extra_flags);
if (ret != 0) {
dbp-&gt;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-&gt;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-&gt;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>

View 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>

View 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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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(&amp;dbp, envp, 0);
if (ret != 0) {
envp-&gt;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-&gt;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-&gt;err(envp, ret, "Database '%s' open failed",
file_name);
goto err;
}
/* Get the txn handle */
txn = NULL;
ret = envp-&gt;txn_begin(envp, NULL, &amp;txn, DB_READ_UNCOMMITTED);
if (ret != 0) {
envp-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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(&amp;dbp, envp, 0);
if (ret != 0) {
envp-&gt;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-&gt;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-&gt;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-&gt;txn_begin(envp, NULL, &amp;txn, DB_READ_COMMITTED);
if (ret != 0) {
envp-&gt;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-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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(&amp;dbp, envp, 0);
if (ret != 0) {
envp-&gt;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-&gt;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-&gt;err(envp, ret, "Database '%s' open failed",
file_name);
goto err;
}
....
ret = envp-&gt;txn_begin(envp, NULL, &amp;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>

View 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-&gt;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-&gt;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-&gt;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-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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-&gt;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">&gt; /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-&gt;txn_begin(envp, NULL, &amp;txn, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "txn_begin failed");
return (EXIT_FAILURE);
}
...
/* key and data are Dbts. Their usage is omitted for brevity. */
...
switch (ret = dbp-&gt;put(dbp, txn, &amp;key, &amp;data, 0)) {
case 0:
break;
/* Deadlock handling goes here */
case DB_LOCK_DEADLOCK:
/* Abort the transaction */
(void)txn-&gt;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 &lt; 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-&gt;err(envp, ret, "db put failed");
ret = txn-&gt;abort(txn);
if (ret != 0) {
envp-&gt;err(envp, ret, "txn abort failed");
return (EXIT_FAILURE);
}
}
/* If all goes well, commit the transaction */
ret = txn-&gt;commit(txn, 0);
if (ret != 0) {
envp-&gt;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>

View 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-&gt;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-&gt;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-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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>

View 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-&gt;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-&gt;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
View 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-&gt;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-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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-&gt;set_tx_max(envp, 40);
if (ret != 0) {
fprintf(stderr, "Error setting max txns: %s\n",
db_strerror(ret));
goto err;
}
ret = envp-&gt;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>

View 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-&gt;txn_begin(envp, NULL, &amp;parent_txn, 0);
/* child transaction */
ret = envp-&gt;txn_begin(envp, parent_txn, &amp;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>

View 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
View 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-&gt;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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View 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-&gt;txn_begin(envp, NULL, &amp;txn, 0);
if (ret != 0) {
envp-&gt;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-&gt;get(dbp, txn, &amp;key, &amp;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-&gt;put(dbp, txn, &amp;key, &amp;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>

View 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>

View 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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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>

View 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-&gt;set_flags()</tt>
method.
</span>
</p>
<p>
For example:
</p>
<pre class="programlisting">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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(&amp;dbp, envp, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "Database creation failed");
goto err;
}
/* Set btree reverse split to off */
ret = db-&gt;set_flags(&amp;db, DB_REVSPLITOFF);
if (ret != 0) {
envp-&gt;err(envp, ret, "Turning off Btree reverse split failed");
goto err;
}
db_flags = DB_CREATE | DB_AUTO_COMMIT;
ret = dbp-&gt;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-&gt;err(envp, ret, "Database '%s' open failed",
file_name);
goto err;
}
err:
/* Close the database */
if (dbp != NULL) {
ret_c = dbp-&gt;close(dbp, 0);
if (ret_c != 0) {
envp-&gt;err(envp, ret_c, "Database close failed.");
ret = ret_c
}
}
/* Close the environment */
if (envp != NULL) {
ret_c = envp-&gt;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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View 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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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(&amp;dbp, envp, 0);
if (ret != 0) {
envp-&gt;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-&gt;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-&gt;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-&gt;txn_begin(envp, NULL, &amp;txn, 0);
if (ret != 0) {
envp-&gt;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-&gt;cursor(dbp, txn, &amp;cursorp, DB_READ_UNCOMMITTED);
if (ret != 0) {
envp-&gt;err(envp, ret, "Cursor open failed.");
txn-&gt;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>

View 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>

View 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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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-&gt;txn_begin(envp, NULL, &amp;txn, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "Transaction begin failed.");
goto err;
}
/* Get the cursor, supply the txn handle at that time */
ret = dbp-&gt;cursor(dbp, txn, &amp;cursorp, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "Cursor open failed.");
txn-&gt;abort(txn);
goto err;
}
/*
* Now use the cursor. Note that we do not supply any txn handles to these
* methods.
*/
/* Prepare the DBTs */
memset(&amp;key, 0, sizeof(DBT));
memset(&amp;data, 0, sizeof(DBT));
while (cursor-&gt;get(&amp;key, &amp;data, DB_NEXT) == 0) {
data-&gt;data = (void *)replacementString;
data-&gt;size = (strlen(replacementString) + 1) * sizeof(char);
c_ret = cursor-&gt;put(cursor, &amp;key, &amp;data, DB_CURRENT);
if (c_ret != 0) {
/* abort the transaction and goto error */
envp-&gt;err(envp, ret, "Cursor put failed.");
cursorp-&gt;close(cursorp);
cursorp = NULL;
txn-&gt;abort(txn);
goto err;
}
}
/*
* Commit the transaction. Note that the transaction handle
* can no longer be used.
*/
ret = cursorp-&gt;close(cursorp);
if (ret != 0) {
envp-&gt;err(envp, ret, "Cursor close failed.");
txn-&gt;abort(txn);
goto err;
}
ret = txn-&gt;commit(txn, 0);
if (ret != 0) {
envp-&gt;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>

View 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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;pthread.h&gt;
#include &lt;db.h&gt;
#ifdef _WIN32
extern int getopt(int, char * const *, const char *);
#else
#include &lt;unistd.h&gt;
#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 &lt;database_home_directory&gt;]\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(&amp;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-&gt;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-&gt;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(&amp;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(&amp;thread_num_lock, NULL);
/* Start the writer threads. */
for (i = 0; i &lt; NUMWRITERS; i++)
(void)pthread_create(&amp;writer_threads[i], NULL,
writer_thread, (void *)dbp);
/* Join the writers */
for (i = 0; i &lt; 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-&gt;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-&gt;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-&gt;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(&amp;thread_num_lock);
global_thread_num++;
thread_num = global_thread_num;
(void)pthread_mutex_unlock(&amp;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 &lt; 50; i++) {
retry_count = 0; /* Used for deadlock retries */
retry:
/* Begin our transaction. */
ret = envp-&gt;txn_begin(envp, NULL, &amp;txn, 0);
if (ret != 0) {
envp-&gt;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 &lt; 10; j++) {
/* Set up our key and values DBTs */
memset(&amp;key, 0, sizeof(DBT));
key.data = key_strings[j];
key.size = (strlen(key_strings[j]) + 1) * sizeof(char);
memset(&amp;value, 0, sizeof(DBT));
payload = rand() + i;
value.data = &amp;payload;
value.size = sizeof(int);
/* Perform the database put. */
switch (ret = dbp-&gt;put(dbp, txn, &amp;key, &amp;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-&gt;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 &lt; 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-&gt;err(envp, ret, "db put failed");
ret = txn-&gt;abort(txn);
if (ret != 0)
envp-&gt;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-&gt;commit(txn, 0);
if (ret != 0) {
envp-&gt;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-&gt;stat() or DB-&gt;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-&gt;cursor(dbp, txn, &amp;cursorp, DB_READ_UNCOMMITTED);
if (ret != 0) {
dbp-&gt;err(dbp, ret, "count_records: cursor open failed.");
goto cursor_err;
}
/* Get the key DBT used for the database read */
memset(&amp;key, 0, sizeof(DBT));
memset(&amp;value, 0, sizeof(DBT));
do {
ret = cursorp-&gt;get(cursorp, &amp;key, &amp;value, DB_NEXT);
switch (ret) {
case 0:
count++;
break;
case DB_NOTFOUND:
break;
default:
dbp-&gt;err(envp, ret, "Count records unspecified error");
goto cursor_err;
}
} while (ret == 0);
cursor_err:
if (cursorp != NULL) {
ret = cursorp-&gt;close(cursorp);
if (ret != 0) {
dbp-&gt;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(&amp;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-&gt;set_flags(dbp, extra_flags);
if (ret != 0) {
dbp-&gt;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-&gt;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-&gt;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>

View 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 &lt;db.h&gt;
...
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(&amp;sdbp, envp, 0);
if (ret != 0) {
/* Error handling goes here */
}
/* open the secondary database */
ret = sdbp-&gt;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-&gt;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>

View 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-&gt;txn_begin()</tt>
method.
</span>
</p>
<p>
For example:
</p>
<pre class="programlisting"> /* Get the transaction */
DB_TXN *txn = NULL;
ret = envp-&gt;txn_begin(envp, NULL, &amp;txn, DB_TXN_NOWAIT);
if (ret != 0) {
envp-&gt;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>

View 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&#10; Database&#10; &#10; &#10; " />
<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-&gt;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-&gt;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-&gt;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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#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(&amp;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-&gt;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(&amp;dbp, envp, 0);
if (ret != 0) {
envp-&gt;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-&gt;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-&gt;err(envp, ret, "Database '%s' open failed",
file_name);
goto err;
}
/* Prepare the DBTs */
memset(&amp;key, 0, sizeof(DBT));
memset(&amp;data, 0, sizeof(DBT));
key.data = &amp;keystr;
key.size = strlen(keystr) + 1;
data.data = &amp;datastr;
data.size = strlen(datastr) + 1;
/* Get the txn handle */
txn = NULL;
ret = envp-&gt;txn_begin(envp, NULL, &amp;txn, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "Transaction begin failed.");
goto err;
}
/*
* Perform the database write. If this fails, abort the transaction.
*/
ret = dbp-&gt;put(dbp, txn, &amp;key, &amp;data, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "Database put failed.");
txn-&gt;abort(txn);
goto err;
}
/*
* Commit the transaction. Note that the transaction handle
* can no longer be used.
*/
ret = txn-&gt;commit(txn, 0);
if (ret != 0) {
envp-&gt;err(envp, ret, "Transaction commit failed.");
goto err;
}
err:
/* Close the database */
if (dbp != NULL) {
ret_c = dbp-&gt;close(dbp, 0);
if (ret_c != 0) {
envp-&gt;err(envp, ret_c, "Database close failed.");
ret = ret_c
}
}
/* Close the environment */
if (envp != NULL) {
ret_c = envp-&gt;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-&gt;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-&gt;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-&gt;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-&gt;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
View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB