2
<!--Copyright 1997-2002 by Sleepycat Software, Inc.-->
3
<!--All rights reserved.-->
4
<!--See the file LICENSE for redistribution information.-->
7
<title>Berkeley DB Reference Guide: Isolation</title>
8
<meta name="description" content="Berkeley DB: An embedded database programmatic toolkit.">
9
<meta name="keywords" content="embedded,database,programmatic,toolkit,b+tree,btree,hash,hashing,transaction,transactions,locking,logging,access method,access methods,java,C,C++">
12
<table width="100%"><tr valign=top>
13
<td><h3><dl><dt>Berkeley DB Reference Guide:<dd>Berkeley DB Transactional Data Store Applications</dl></h3></td>
14
<td align=right><a href="../../ref/transapp/atomicity.html"><img src="../../images/prev.gif" alt="Prev"></a><a href="../../reftoc.html"><img src="../../images/ref.gif" alt="Ref"></a><a href="../../ref/transapp/read.html"><img src="../../images/next.gif" alt="Next"></a>
17
<h1 align=center>Isolation</h1>
18
<p>The third reason listed for using transactions was <i>isolation</i>.
19
Consider an application suite in which multiple threads of control
20
(multiple processes or threads in one or more processes) are changing
21
the values associated with a key in one or more databases. Specifically,
22
they are taking the current value, incrementing it, and then storing it
23
back into the database.
24
<p>Such an application requires isolation. Because we want to change a value
25
in the database, we must make sure that after we read it, no other thread
26
of control modifies it. For example, assume that both thread #1 and
27
thread #2 are doing similar operations in the database, where thread #1
28
is incrementing records by 3, and thread #2 is incrementing records by
29
5. We want to increment the record by a total of 8. If the operations
30
interleave in the right (well, wrong) order, that is not what will
32
<p><blockquote><pre>thread #1 <b>read</b> record: the value is 2
33
thread #2 <b>read</b> record: the value is 2
34
thread #2 <b>write</b> record + 5 back into the database (new value 7)
35
thread #1 <b>write</b> record + 3 back into the database (new value 5)</pre></blockquote>
36
<p>As you can see, instead of incrementing the record by a total of 8,
37
we've incremented it only by 3 because thread #1 overwrote thread #2's
38
change. By wrapping the operations in transactions, we ensure that this
39
cannot happen. In a transaction, when the first thread reads the
40
record, locks are acquired that will not be released until the
41
transaction finishes, guaranteeing that all other readers and writers
42
will block, waiting for the first thread's transaction to complete (or
44
<p>Here is an example function that does transaction-protected increments
45
on database records to ensure isolation:
46
<p><blockquote><pre>int
47
main(int argc, char *argv)
51
DB *db_cats, *db_color, *db_fruit;
56
while ((ch = getopt(argc, argv, "")) != EOF)
68
/* Open database: Key is fruit class; Data is specific type. */
69
db_open(dbenv, &db_fruit, "fruit", 0);
71
/* Open database: Key is a color; Data is an integer. */
72
db_open(dbenv, &db_color, "color", 0);
76
* Key is a name; Data is: company name, cat breeds.
78
db_open(dbenv, &db_cats, "cats", 1);
80
add_fruit(dbenv, db_fruit, "apple", "yellow delicious");
82
<b> add_color(dbenv, db_color, "blue", 0);
83
add_color(dbenv, db_color, "blue", 3);</b>
89
add_color(DB_ENV *dbenv, DB *dbp, char *color, int increment)
93
int fail, original, ret, t_ret;
97
memset(&key, 0, sizeof(key));
99
key.size = strlen(color);
100
memset(&data, 0, sizeof(data));
101
data.flags = DB_DBT_MALLOC;
104
/* Begin the transaction. */
105
if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
106
dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
111
* Get the key. If it exists, we increment the value. If it
112
* doesn't exist, we create it.
114
switch (ret = dbp->get(dbp, tid, &key, &data, 0)) {
116
original = atoi(data.data);
118
case DB_LOCK_DEADLOCK:
120
/* Retry the operation. */
121
if ((t_ret = tid->abort(tid)) != 0) {
122
dbenv->err(dbenv, t_ret, "DB_TXN->abort");
125
if (++fail == MAXIMUM_RETRY)
132
if (data.data != NULL)
135
/* Create the new data item. */
136
(void)snprintf(buf, sizeof(buf), "%d", original + increment);
138
data.size = strlen(buf) + 1;
140
/* Store the new value. */
141
switch (ret = dbp->put(dbp, tid, &key, &data, 0)) {
143
/* Success: commit the change. */
144
if ((ret = tid->commit(tid, 0)) != 0) {
145
dbenv->err(dbenv, ret, "DB_TXN->commit");
149
case DB_LOCK_DEADLOCK:
151
/* Retry the operation. */
152
if ((t_ret = tid->abort(tid)) != 0) {
153
dbenv->err(dbenv, t_ret, "DB_TXN->abort");
156
if (++fail == MAXIMUM_RETRY)
161
}</b></pre></blockquote>
162
<table width="100%"><tr><td><br></td><td align=right><a href="../../ref/transapp/atomicity.html"><img src="../../images/prev.gif" alt="Prev"></a><a href="../../reftoc.html"><img src="../../images/ref.gif" alt="Ref"></a><a href="../../ref/transapp/read.html"><img src="../../images/next.gif" alt="Next"></a>
164
<p><font size=1><a href="http://www.sleepycat.com">Copyright Sleepycat Software</a></font>