1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
<?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>Deadlock detection</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="transapp.html" title="Chapter 11. Berkeley DB Transactional Data Store Applications" />
<link rel="prev" href="transapp_admin.html" title="Environment infrastructure" />
<link rel="next" href="transapp_checkpoint.html" title="Checkpoints" />
</head>
<body>
<div xmlns="" class="navheader">
<div class="libver">
<p>Library Version 12.1.6.1</p>
</div>
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Deadlock detection</th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="transapp_admin.html">Prev</a> </td>
<th width="60%" align="center">Chapter 11. Berkeley DB Transactional Data Store Applications </th>
<td width="20%" align="right"> <a accesskey="n" href="transapp_checkpoint.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="transapp_deadlock"></a>Deadlock detection</h2>
</div>
</div>
</div>
<p>
The first component of the infrastructure,
<span class="emphasis"><em>deadlock detection</em></span>, is not so much a
requirement specific to transaction-protected applications,
but instead is necessary for almost all applications in which
more than a single thread of control will be accessing the
database at one time. Even when Berkeley DB automatically
handles database locking, it is normally possible for deadlock
to occur. Because the underlying database access methods may
update multiple pages during a single Berkeley DB API call,
deadlock is possible even when threads of control are making
only single update calls into the database. The exception to
this rule is when all the threads of control accessing the
database are read-only or when the Berkeley DB Concurrent Data
Store product is used; the Berkeley DB Concurrent Data Store
product guarantees deadlock-free operation at the expense of
reduced concurrency.
</p>
<p>
When the deadlock occurs, two (or more) threads of control
each request additional locks that can never be granted
because one of the threads of control waiting holds the
requested resource. For example, consider two processes: A and
B. Let's say that A obtains a write lock on item X, and B
obtains a write lock on item Y. Then, A requests a lock on Y,
and B requests a lock on X. A will wait until resource Y
becomes available and B will wait until resource X becomes
available. Unfortunately, because both A and B are waiting,
neither will release the locks they hold and neither will ever
obtain the resource on which it is waiting. For another
example, consider two transactions, A and B, each of which may
want to modify item X. Assume that transaction A obtains a
read lock on X and confirms that a modification is needed.
Then it is descheduled and the thread containing transaction B
runs. At that time, transaction B obtains a read lock on X and
confirms that it also wants to make a modification. Both
transactions A and B will block when they attempt to upgrade
their read locks to write locks because the other already
holds a read lock. This is a deadlock. Transaction A cannot
make forward progress until Transaction B releases its read
lock on X, but Transaction B cannot make forward progress
until Transaction A releases its read lock on X.
</p>
<p>
In order to detect that deadlock has happened, a separate
process or thread must review the locks currently held in the
database. If deadlock has occurred, a victim must be selected,
and that victim will then return the error <a class="link" href="program_errorret.html#program_errorret.DB_LOCK_DEADLOCK">DB_LOCK_DEADLOCK</a> from
whatever Berkeley DB call it was making. Berkeley DB provides the <a href="../api_reference/C/db_deadlock.html" class="olink">db_deadlock</a> utility that
can be used to perform this deadlock detection. Alternatively,
applications can create their own deadlock utility or thread
using the underlying <a href="../api_reference/C/lockdetect.html" class="olink">DB_ENV->lock_detect()</a> function, or specify that
Berkeley DB run the deadlock detector internally whenever
there is a conflict over a lock (see <a href="../api_reference/C/envset_lk_detect.html" class="olink">DB_ENV->set_lk_detect()</a> for
more information). The following code fragment does the
latter:
</p>
<pre class="programlisting">void
env_open(DB_ENV **dbenvp)
{
DB_ENV *dbenv;
int ret;
/* Create the environment handle. */
if ((ret = db_env_create(&dbenv, 0)) != 0) {
fprintf(stderr,
"txnapp: db_env_create: %s\n", db_strerror(ret));
exit (1);
}
/* Set up error handling. */
dbenv->set_errpfx(dbenv, "txnapp");
dbenv->set_errfile(dbenv, stderr);
<span class="bold"><strong> /* Do deadlock detection internally. */
if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT)) != 0) {
dbenv->err(dbenv, ret, "set_lk_detect: DB_LOCK_DEFAULT");
exit (1);
}</strong></span>
/*
* Open a transactional environment:
* create if it doesn't exist
* free-threaded handle
* run recovery
* read/write owner only
*/
if ((ret = dbenv->open(dbenv, ENV_DIRECTORY,
DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG |
DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD,
S_IRUSR | S_IWUSR)) != 0) {
dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY);
exit (1);
}
*dbenvp = dbenv;
}</pre>
<p>
Deciding how often to run the deadlock detector and which
of the deadlocked transactions will be forced to abort when
the deadlock is detected is a common tuning parameter for
Berkeley DB applications.
</p>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="transapp_admin.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="transapp.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="transapp_checkpoint.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Environment
infrastructure </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Checkpoints</td>
</tr>
</table>
</div>
</body>
</html>
|