mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-16 17:16:25 +00:00
193 lines
12 KiB
HTML
193 lines
12 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
<title>Chapter 10. Berkeley DB Concurrent Data Store Applications</title>
|
||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
|
||
<link rel="start" href="index.html" title="Berkeley DB Programmer's Reference Guide" />
|
||
<link rel="up" href="index.html" title="Berkeley DB Programmer's Reference Guide" />
|
||
<link rel="prev" href="env_faq.html" title="Environment FAQ" />
|
||
<link rel="next" href="cam_fail.html" title="Handling failure in Data Store and Concurrent Data Store applications" />
|
||
</head>
|
||
<body>
|
||
<div xmlns="" class="navheader">
|
||
<div class="libver">
|
||
<p>Library Version 11.2.5.2</p>
|
||
</div>
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Chapter 10.
|
||
Berkeley DB Concurrent Data Store Applications
|
||
</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="env_faq.html">Prev</a> </td>
|
||
<th width="60%" align="center"> </th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="cam_fail.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="cam"></a>Chapter 10.
|
||
Berkeley DB Concurrent Data Store Applications
|
||
</h2>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="toc">
|
||
<p>
|
||
<b>Table of Contents</b>
|
||
</p>
|
||
<dl>
|
||
<dt>
|
||
<span class="sect1">
|
||
<a href="cam.html#cam_intro">Concurrent Data Store introduction</a>
|
||
</span>
|
||
</dt>
|
||
<dt>
|
||
<span class="sect1">
|
||
<a href="cam_fail.html">Handling failure in Data Store and Concurrent Data Store applications</a>
|
||
</span>
|
||
</dt>
|
||
<dt>
|
||
<span class="sect1">
|
||
<a href="cam_app.html">Architecting Data Store and Concurrent Data Store applications</a>
|
||
</span>
|
||
</dt>
|
||
</dl>
|
||
</div>
|
||
<div class="sect1" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h2 class="title" style="clear: both"><a id="cam_intro"></a>Concurrent Data Store introduction</h2>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>It is often desirable to have concurrent read-write access to a database
|
||
when there is no need for full recoverability or transaction semantics.
|
||
For this class of applications, Berkeley DB provides interfaces supporting
|
||
deadlock-free, multiple-reader/single writer access to the database.
|
||
This means that at any instant in time, there may be either multiple
|
||
readers accessing data or a single writer modifying data. The
|
||
application is entirely unaware of which is happening, and Berkeley DB
|
||
implements the necessary locking and blocking to ensure this behavior.</p>
|
||
<p>To create Berkeley DB Concurrent Data Store applications, you must first initialize an environment
|
||
by calling <a href="../api_reference/C/envopen.html" class="olink">DB_ENV->open()</a>. You must specify the <a href="../api_reference/C/envopen.html#envopen_DB_INIT_CDB" class="olink">DB_INIT_CDB</a> and <a href="../api_reference/C/envopen.html#envopen_DB_INIT_MPOOL" class="olink">DB_INIT_MPOOL</a>
|
||
flags to that method. It is an error to
|
||
specify any of the other <a href="../api_reference/C/envopen.html" class="olink">DB_ENV->open()</a> subsystem or recovery
|
||
configuration flags, for example, <a href="../api_reference/C/envopen.html#envopen_DB_INIT_LOCK" class="olink">DB_INIT_LOCK</a>, <a href="../api_reference/C/envopen.html#envopen_DB_INIT_TXN" class="olink">DB_INIT_TXN</a> or <a href="../api_reference/C/envopen.html#envopen_DB_RECOVER" class="olink">DB_RECOVER</a>
|
||
All databases must, of
|
||
course, be created in this environment by using the <a href="../api_reference/C/dbcreate.html" class="olink">db_create()</a>
|
||
function or <a href="../api_reference/CXX/db.html" class="olink">Db</a> constructor, and specifying the environment
|
||
as an argument.</p>
|
||
<p>Berkeley DB performs appropriate locking so that safe enforcement of the
|
||
deadlock-free, multiple-reader/single-writer semantic is transparent to
|
||
the application. However, a basic understanding of Berkeley DB Concurrent Data Store locking
|
||
behavior is helpful when writing Berkeley DB Concurrent Data Store applications.</p>
|
||
<p>Berkeley DB Concurrent Data Store
|
||
avoids deadlocks without the need for a deadlock detector by performing
|
||
all locking on an entire database at once (or on an entire environment
|
||
in the case of the <a href="../api_reference/C/envset_flags.html#set_flags_DB_CDB_ALLDB" class="olink">DB_CDB_ALLDB</a> flag), and by ensuring that at
|
||
any given time only one thread of control is allowed to simultaneously
|
||
hold a read (shared) lock and attempt to acquire a write (exclusive)
|
||
lock.</p>
|
||
<p>All open Berkeley DB cursors hold a read lock, which serves as a guarantee
|
||
that the database will not change beneath them; likewise, all
|
||
non-cursor <a href="../api_reference/C/dbget.html" class="olink">DB->get()</a> operations temporarily acquire and release
|
||
a read lock that is held during the actual traversal of the database.
|
||
Because read locks will not conflict with each other, any number of
|
||
cursors in any number of threads of control may be open simultaneously,
|
||
and any number of <a href="../api_reference/C/dbget.html" class="olink">DB->get()</a> operations may be concurrently in
|
||
progress.</p>
|
||
<p>To enforce the rule that only one thread of control at a time can
|
||
attempt to upgrade a read lock to a write lock, however, Berkeley DB must
|
||
forbid multiple cursors from attempting to write concurrently. This is
|
||
done using the <a href="../api_reference/C/dbcursor.html#cursor_DB_WRITECURSOR" class="olink">DB_WRITECURSOR</a> flag to the <a href="../api_reference/C/dbcursor.html" class="olink">DB->cursor()</a> method.
|
||
This is the only difference between access method calls in Berkeley DB Concurrent Data Store and
|
||
in the other Berkeley DB products. The <a href="../api_reference/C/dbcursor.html#cursor_DB_WRITECURSOR" class="olink">DB_WRITECURSOR</a> flag causes the
|
||
newly created cursor to be a "write" cursor; that is, a cursor capable
|
||
of performing writes as well as reads. Only cursors thus created are
|
||
permitted to perform write operations (either deletes or puts), and only
|
||
one such cursor can exist at any given time.</p>
|
||
<p>Any attempt to create a second write cursor or to perform a non-cursor
|
||
write operation while a write cursor is open will block until that write
|
||
cursor is closed. Read cursors may open and perform reads without blocking
|
||
while a write cursor is extant. However, any attempts to actually perform
|
||
a write, either using the write cursor or directly using the
|
||
<a href="../api_reference/C/dbput.html" class="olink">DB->put()</a> or <a href="../api_reference/C/dbdel.html" class="olink">DB->del()</a> methods, will block until all read cursors
|
||
are closed. This is how the multiple-reader/single-writer semantic is
|
||
enforced, and prevents reads from seeing an inconsistent database state
|
||
that may be an intermediate stage of a write operation.</p>
|
||
<p>By default, Berkeley DB Concurrent Data Store does locking on a per-database basis. For this
|
||
reason, using cursors to access multiple databases in different orders
|
||
in different threads or processes, or leaving cursors open on one
|
||
database while accessing another database, can cause an application to
|
||
hang. If this behavior is a requirement for the application, Berkeley DB
|
||
should be configured to do locking on an environment-wide basis. See
|
||
the <a href="../api_reference/C/envset_flags.html#set_flags_DB_CDB_ALLDB" class="olink">DB_CDB_ALLDB</a> flag of the <a href="../api_reference/C/envset_flags.html" class="olink">DB_ENV->set_flags()</a> method
|
||
for more information.</p>
|
||
<p>With these behaviors, Berkeley DB can guarantee deadlock-free concurrent
|
||
database access, so that multiple threads of control are free to perform
|
||
reads and writes without needing to handle synchronization themselves
|
||
or having to run a deadlock detector. Berkeley DB has no direct knowledge of
|
||
which cursors belong to which threads, so some care must be taken to
|
||
ensure that applications do not inadvertently block themselves, causing
|
||
the application to hang and be unable to proceed.</p>
|
||
<p>As a consequence of the Berkeley DB Concurrent Data Store locking model, the following sequences
|
||
of operations will cause a thread to block itself indefinitely:</p>
|
||
<div class="orderedlist">
|
||
<ol type="1">
|
||
<li>Keeping a cursor open while issuing a <a href="../api_reference/C/dbput.html" class="olink">DB->put()</a> or <a href="../api_reference/C/dbdel.html" class="olink">DB->del()</a>
|
||
access method call.</li>
|
||
<li>Attempting to open a write cursor while another cursor is already being
|
||
held open by the same thread of control. Note that it is correct
|
||
operation for one thread of control to attempt to open a write cursor
|
||
or to perform a non-cursor write (<a href="../api_reference/C/dbput.html" class="olink">DB->put()</a> or <a href="../api_reference/C/dbdel.html" class="olink">DB->del()</a>)
|
||
while a write cursor is already active in another thread. It is only a
|
||
problem if these things are done within a single thread of control --
|
||
in which case that thread will block and never be able to release the
|
||
lock that is blocking it.</li>
|
||
<li>Not testing Berkeley DB error return codes (if any cursor operation returns
|
||
an unexpected error, that cursor must still be closed).</li>
|
||
</ol>
|
||
</div>
|
||
<p>If the application needs to open multiple cursors in a single thread to
|
||
perform an operation, it can indicate to Berkeley DB that the cursor locks
|
||
should not block each other by creating a Berkeley DB Concurrent Data Store <span class="bold"><strong>group</strong></span>, using
|
||
<a href="../api_reference/C/envcdsgroup_begin.html" class="olink">DB_ENV->cdsgroup_begin()</a>. This creates a locker ID that is shared by all
|
||
cursors opened in the group.</p>
|
||
<p>Berkeley DB Concurrent Data Store groups use a <a href="../api_reference/C/txn.html" class="olink">TXN</a> handle to indicate the shared locker
|
||
ID to Berkeley DB calls, and call <a href="../api_reference/C/txncommit.html" class="olink">DB_TXN->commit()</a> to end the group. This
|
||
is a convenient way to pass the locked ID to the calls where it is
|
||
needed, but should not be confused with the real transactional semantics
|
||
provided by Berkeley DB Transactional Data Store. In particular, Berkeley DB Concurrent Data Store groups do not provide any
|
||
abort or recovery facilities, and have no impact on durability of
|
||
operations.</p>
|
||
</div>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="env_faq.html">Prev</a> </td>
|
||
<td width="20%" align="center"> </td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="cam_fail.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">Environment FAQ </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Handling failure in Data Store and Concurrent Data Store applications</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</body>
|
||
</html>
|