mirror of
https://github.com/yasuhirokimura/db18
synced 2026-06-08 18:29:23 +00:00
207 lines
12 KiB
HTML
207 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>Berkeley DB Transactional Data Store locking conventions</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="lock.html" title="Chapter 17. The Locking Subsystem" />
|
||
<link rel="prev" href="lock_cam_conv.html" title="Berkeley DB Concurrent Data Store locking conventions" />
|
||
<link rel="next" href="lock_nondb.html" title="Locking and non-Berkeley DB applications" />
|
||
</head>
|
||
<body>
|
||
<div xmlns="" class="navheader">
|
||
<div class="libver">
|
||
<p>Library Version 18.1.40</p>
|
||
</div>
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Berkeley DB Transactional Data
|
||
Store locking conventions</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="lock_cam_conv.html">Prev</a> </td>
|
||
<th width="60%" align="center">Chapter 17. The Locking Subsystem </th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="lock_nondb.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="lock_am_conv"></a>Berkeley DB Transactional Data
|
||
Store locking conventions</h2>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
All Berkeley DB access methods follow the same conventions
|
||
for locking database objects. Applications that do their own
|
||
locking and also do locking via the access methods must be
|
||
careful to adhere to these conventions.
|
||
</p>
|
||
<p>
|
||
Whenever a Berkeley DB database is opened, the <a href="../api_reference/C/db.html" class="olink">DB</a> handle
|
||
is assigned a unique locker ID. Unless transactions are
|
||
specified, that ID is used as the locker for all calls that
|
||
the Berkeley DB methods make to the lock subsystem. In order
|
||
to lock a file, pages in the file, or records in the file, we
|
||
must create a unique ID that can be used as the object to be
|
||
locked in calls to the lock manager. Under normal operation,
|
||
that object is a 28-byte value created by the concatenation of
|
||
a unique file identifier, a page or record number, and an
|
||
object type (page or record).
|
||
</p>
|
||
<p>
|
||
In a transaction-protected environment, database create and
|
||
delete operations are recoverable and single-threaded. This
|
||
single-threading is achieved using a single lock for the
|
||
entire environment that must be acquired before beginning a
|
||
create or delete operation. In this case, the object on which
|
||
Berkeley DB will lock is a 4-byte unsigned integer with a
|
||
value of 0.
|
||
</p>
|
||
<p>
|
||
If applications are using the lock subsystem directly while
|
||
they are also using locking via the access methods, they must
|
||
take care not to inadvertently lock objects that happen to be
|
||
equal to the unique file IDs used to lock files. This is most
|
||
easily accomplished by using a lock object with a length
|
||
different from the values used by Berkeley DB.
|
||
</p>
|
||
<p>
|
||
All the access methods other than Queue use standard
|
||
read/write locks in a simple multiple-reader/single writer
|
||
page-locking scheme. An operation that returns data (for
|
||
example, <a href="../api_reference/C/dbget.html" class="olink">DB->get()</a> or <a href="../api_reference/C/dbcget.html" class="olink">DBC->get()</a>) obtains a read lock on all the
|
||
pages accessed while locating the requested record. When an
|
||
update operation is requested (for example, <a href="../api_reference/C/dbput.html" class="olink">DB->put()</a> or
|
||
<a href="../api_reference/C/dbcdel.html" class="olink">DBC->del()</a>), the page containing the updated (or new) data is
|
||
write-locked. As read-modify-write cycles are quite common and
|
||
are deadlock-prone under normal circumstances, the Berkeley DB
|
||
interfaces allow the application to specify the <a href="../api_reference/C/dbcget.html#dbcget_DB_RMW" class="olink">DB_RMW</a> flag,
|
||
which causes operations to immediately obtain a write lock,
|
||
even though they are only reading the data. Although this may
|
||
reduce concurrency somewhat, it reduces the probability of
|
||
deadlock. In the presence of transactions, page locks are held
|
||
until transaction commit.
|
||
</p>
|
||
<p>
|
||
The Queue access method does not hold long-term page locks.
|
||
Instead, page locks are held only long enough to locate
|
||
records or to change metadata on a page, and record locks are
|
||
held for the appropriate duration. In the presence of
|
||
transactions, record locks are held until transaction commit.
|
||
For <a href="../api_reference/C/db.html" class="olink">DB</a> operations, record locks are held until operation
|
||
completion; for <a href="../api_reference/C/dbc.html" class="olink">DBC</a> operations, record locks are held until
|
||
subsequent records are returned or the cursor is
|
||
closed.
|
||
</p>
|
||
<p>
|
||
Under non-transaction operations, the access methods do not
|
||
normally hold locks across calls to the Berkeley DB
|
||
interfaces. The one exception to this rule is when cursors are
|
||
used. Because cursors maintain a position in a file, they must
|
||
hold locks across calls; in fact, they will hold a lock until
|
||
the cursor is closed.
|
||
</p>
|
||
<p>
|
||
In this mode, the assignment of locker IDs to <a href="../api_reference/C/db.html" class="olink">DB</a> and
|
||
cursor handles is complicated. If the <a href="../api_reference/C/dbopen.html#open_DB_THREAD" class="olink">DB_THREAD</a> option was
|
||
specified when the <a href="../api_reference/C/db.html" class="olink">DB</a> handle was opened, each use of <a href="../api_reference/C/db.html" class="olink">DB</a>
|
||
has its own unique locker ID, and each cursor is assigned its
|
||
own unique locker ID when it is created, so <a href="../api_reference/C/db.html" class="olink">DB</a> handle and
|
||
cursor operations can all conflict with one another. (This is
|
||
because when Berkeley DB handles may be shared by multiple
|
||
threads of control the Berkeley DB library cannot identify
|
||
which operations are performed by which threads of control,
|
||
and it must ensure that two different threads of control are
|
||
not simultaneously modifying the same data structure. By
|
||
assigning each <a href="../api_reference/C/db.html" class="olink">DB</a> handle and cursor its own locker, two
|
||
threads of control sharing a handle cannot inadvertently
|
||
interfere with each other.)
|
||
</p>
|
||
<p>
|
||
This has important implications. If a single thread of
|
||
control opens two cursors, uses a combination of cursor and
|
||
non-cursor operations, or begins two separate transactions,
|
||
the operations are performed on behalf of different lockers.
|
||
Conflicts that arise between these different lockers may not
|
||
cause actual deadlocks, but can, in fact, permanently block
|
||
the thread of control. For example, assume that an application
|
||
creates a cursor and uses it to read record A. Now, assume a
|
||
second cursor is opened, and the application attempts to write
|
||
record A using the second cursor. Unfortunately, the first
|
||
cursor has a read lock, so the second cursor cannot obtain its
|
||
write lock. However, that read lock is held by the same thread
|
||
of control, so the read lock can never be released if we block
|
||
waiting for the write lock. This might appear to be a deadlock
|
||
from the application's perspective, but Berkeley DB cannot
|
||
identify it as such because it has no knowledge of which
|
||
lockers belong to which threads of control. For this reason,
|
||
application designers are encouraged to close cursors as soon
|
||
as they are done with them.
|
||
</p>
|
||
<p>
|
||
If the <a href="../api_reference/C/dbopen.html#open_DB_THREAD" class="olink">DB_THREAD</a> option was not specified when the <a href="../api_reference/C/db.html" class="olink">DB</a>
|
||
handle was opened, all uses of the <a href="../api_reference/C/db.html" class="olink">DB</a> handle and all cursors
|
||
created using that handle will use the same locker ID for all
|
||
operations. In this case, if a single thread of control opens
|
||
two cursors or uses a combination of cursor and non-cursor
|
||
operations, these operations are performed on behalf of the
|
||
same locker, and so cannot deadlock or block the thread of
|
||
control.
|
||
</p>
|
||
<p>
|
||
Complicated operations that require multiple cursors (or
|
||
combinations of cursor and non-cursor operations) can be
|
||
performed in two ways. First, they may be performed within a
|
||
transaction, in which case all operations lock on behalf of
|
||
the designated transaction. Second, they may be performed
|
||
using a local <a href="../api_reference/C/db.html" class="olink">DB</a> handle, although, as <a href="../api_reference/C/dbopen.html" class="olink">DB->open()</a> operations
|
||
are relatively slow, this may not be a good idea. Finally, the
|
||
<a href="../api_reference/C/dbcdup.html" class="olink">DBC->dup()</a> function duplicates a cursor, using the same locker
|
||
ID as the originating cursor. There is no way to achieve this
|
||
duplication functionality through the <a href="../api_reference/C/db.html" class="olink">DB</a> handle calls, but
|
||
any <a href="../api_reference/C/db.html" class="olink">DB</a> call can be implemented by one or more calls through
|
||
a cursor.
|
||
</p>
|
||
<p>
|
||
When the access methods use transactions, many of these
|
||
problems disappear. The transaction ID is used as the locker
|
||
ID for all operations performed on behalf of the transaction.
|
||
This means that the application may open multiple cursors on
|
||
behalf of the same transaction and these cursors will all
|
||
share a common locker ID. This is safe because transactions
|
||
cannot span threads of control, so the library knows that two
|
||
cursors in the same transaction cannot modify the database
|
||
concurrently.
|
||
</p>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="lock_cam_conv.html">Prev</a> </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="u" href="lock.html">Up</a>
|
||
</td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="lock_nondb.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">Berkeley DB Concurrent Data Store locking conventions </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Locking and non-Berkeley DB
|
||
applications</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</body>
|
||
</html>
|