File: inc.html

package info (click to toggle)
evolution-data-server 1.0.4-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 39,504 kB
  • ctags: 26,423
  • sloc: ansic: 175,347; tcl: 30,499; sh: 20,699; perl: 11,320; xml: 9,039; java: 7,653; cpp: 6,029; makefile: 4,866; awk: 1,338; yacc: 1,103; sed: 772; cs: 505; lex: 134; asm: 14
file content (166 lines) | stat: -rw-r--r-- 5,888 bytes parent folder | download | duplicates (3)
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
165
166
<!--$Id: inc.html,v 1.1.1.1 2003/11/20 22:14:21 toshok Exp $-->
<!--Copyright 1997-2002 by Sleepycat Software, Inc.-->
<!--All rights reserved.-->
<!--See the file LICENSE for redistribution information.-->
<html>
<head>
<title>Berkeley DB Reference Guide: Isolation</title>
<meta name="description" content="Berkeley DB: An embedded database programmatic toolkit.">
<meta name="keywords" content="embedded,database,programmatic,toolkit,b+tree,btree,hash,hashing,transaction,transactions,locking,logging,access method,access methods,java,C,C++">
</head>
<body bgcolor=white>
<table width="100%"><tr valign=top>
<td><h3><dl><dt>Berkeley DB Reference Guide:<dd>Berkeley DB Transactional Data Store Applications</dl></h3></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>
</td></tr></table>
<p>
<h1 align=center>Isolation</h1>
<p>The third reason listed for using transactions was <i>isolation</i>.
Consider an application suite in which multiple threads of control
(multiple processes or threads in one or more processes) are changing
the values associated with a key in one or more databases.  Specifically,
they are taking the current value, incrementing it, and then storing it
back into the database.
<p>Such an application requires isolation.  Because we want to change a value
in the database, we must make sure that after we read it, no other thread
of control modifies it.  For example, assume that both thread #1 and
thread #2 are doing similar operations in the database, where thread #1
is incrementing records by 3, and thread #2 is incrementing records by
5.  We want to increment the record by a total of 8.  If the operations
interleave in the right (well, wrong) order, that is not what will
happen:
<p><blockquote><pre>thread #1  <b>read</b> record: the value is 2
thread #2  <b>read</b> record: the value is 2
thread #2  <b>write</b> record + 5 back into the database (new value 7)
thread #1  <b>write</b> record + 3 back into the database (new value 5)</pre></blockquote>
<p>As you can see, instead of incrementing the record by a total of 8,
we've incremented it only by 3 because thread #1 overwrote thread #2's
change.  By wrapping the operations in transactions, we ensure that this
cannot happen.  In a transaction, when the first thread reads the
record, locks are acquired that will not be released until the
transaction finishes, guaranteeing that all other readers and writers
will block, waiting for the first thread's transaction to complete (or
to be aborted).
<p>Here is an example function that does transaction-protected increments
on database records to ensure isolation:
<p><blockquote><pre>int
main(int argc, char *argv)
{
	extern char *optarg;
	extern int optind;
	DB *db_cats, *db_color, *db_fruit;
	DB_ENV *dbenv;
	pthread_t ptid;
	int ch;
<p>
	while ((ch = getopt(argc, argv, "")) != EOF)
		switch (ch) {
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;
<p>
	env_dir_create();
	env_open(&dbenv);
<p>
	/* Open database: Key is fruit class; Data is specific type. */
	db_open(dbenv, &db_fruit, "fruit", 0);
<p>
	/* Open database: Key is a color; Data is an integer. */
	db_open(dbenv, &db_color, "color", 0);
<p>
	/*
	 * Open database:
	 *	Key is a name; Data is: company name, cat breeds.
	 */
	db_open(dbenv, &db_cats, "cats", 1);
<p>
	add_fruit(dbenv, db_fruit, "apple", "yellow delicious");
<p>
<b>	add_color(dbenv, db_color, "blue", 0);
	add_color(dbenv, db_color, "blue", 3);</b>
<p>
	return (0);
}
<p>
<b>int
add_color(DB_ENV *dbenv, DB *dbp, char *color, int increment)
{
	DBT key, data;
	DB_TXN *tid;
	int fail, original, ret, t_ret;
	char buf64;
<p>
	/* Initialization. */
	memset(&key, 0, sizeof(key));
	key.data = color;
	key.size = strlen(color);
	memset(&data, 0, sizeof(data));
	data.flags = DB_DBT_MALLOC;
<p>
	for (fail = 0;;) {
		/* Begin the transaction. */
		if ((ret = dbenv-&gt;txn_begin(dbenv, NULL, &tid, 0)) != 0) {
			dbenv-&gt;err(dbenv, ret, "DB_ENV-&gt;txn_begin");
			exit (1);
		}
<p>
		/*
		 * Get the key.  If it exists, we increment the value.  If it
		 * doesn't exist, we create it.
		 */
		switch (ret = dbp-&gt;get(dbp, tid, &key, &data, 0)) {
		case 0:
			original = atoi(data.data);
			break;
		case DB_LOCK_DEADLOCK:
		default:
			/* Retry the operation. */
			if ((t_ret = tid-&gt;abort(tid)) != 0) {
				dbenv-&gt;err(dbenv, t_ret, "DB_TXN-&gt;abort");
				exit (1);
			}
			if (++fail == MAXIMUM_RETRY)
				return (ret);
			continue;
		case DB_NOTFOUND:
			original = 0;
			break;
		}
		if (data.data != NULL)
			free(data.data);
<p>
		/* Create the new data item. */
		(void)snprintf(buf, sizeof(buf), "%d", original + increment);
		data.data = buf;
		data.size = strlen(buf) + 1;
<p>
		/* Store the new value. */
		switch (ret = dbp-&gt;put(dbp, tid, &key, &data, 0)) {
		case 0:
			/* Success: commit the change. */
			if ((ret = tid-&gt;commit(tid, 0)) != 0) {
				dbenv-&gt;err(dbenv, ret, "DB_TXN-&gt;commit");
				exit (1);
			}
			return (0);
		case DB_LOCK_DEADLOCK:
		default:
			/* Retry the operation. */
			if ((t_ret = tid-&gt;abort(tid)) != 0) {
				dbenv-&gt;err(dbenv, t_ret, "DB_TXN-&gt;abort");
				exit (1);
			}
			if (++fail == MAXIMUM_RETRY)
				return (ret);
			break;
		}
	}
}</b></pre></blockquote>
<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>
</td></tr></table>
<p><font size=1><a href="http://www.sleepycat.com">Copyright Sleepycat Software</a></font>
</body>
</html>