2
* See the file LICENSE for redistribution information.
4
* Copyright (c) 2001-2002
5
* Sleepycat Software. All rights reserved.
11
static const char revid[] = "$Id: txn_util.c,v 11.18 2002/08/06 06:25:12 bostic Exp $";
14
#ifndef NO_SYSTEM_INCLUDES
15
#include <sys/types.h>
20
#include "dbinc/db_shash.h"
21
#include "dbinc/lock.h"
22
#include "dbinc/txn.h"
24
typedef struct __txn_event TXN_EVENT;
27
TAILQ_ENTRY(__txn_event) links;
46
* Creates a remove event that can be added to the commit list.
48
* PUBLIC: int __txn_remevent __P((DB_ENV *,
49
* PUBLIC: DB_TXN *, const char *, u_int8_t*));
52
__txn_remevent(dbenv, txn, name, fileid)
62
if ((ret = __os_calloc(dbenv, 1, sizeof(TXN_EVENT), &e)) != 0)
65
if ((ret = __os_strdup(dbenv, name, &e->u.r.name)) != 0)
69
if ((ret = __os_calloc(dbenv,
70
1, DB_FILE_ID_LEN, &e->u.r.fileid)) != 0)
72
memcpy(e->u.r.fileid, fileid, DB_FILE_ID_LEN);
76
TAILQ_INSERT_TAIL(&txn->events, e, links);
89
* Add a lockevent to the commit-queue. The lock event indicates a locker
92
* PUBLIC: int __txn_lockevent __P((DB_ENV *,
93
* PUBLIC: DB_TXN *, DB *, DB_LOCK *, u_int32_t));
96
__txn_lockevent(dbenv, txn, dbp, lock, locker)
106
if (!LOCKING_ON(dbenv))
110
if ((ret = __os_calloc(dbenv, 1, sizeof(TXN_EVENT), &e)) != 0)
113
e->u.t.locker = locker;
117
TAILQ_INSERT_TAIL(&txn->events, e, links);
124
* Remove a lock event because the locker is going away. We can remove
125
* by lock (using offset) or by locker_id (or by both).
127
* PUBLIC: void __txn_remlock __P((DB_ENV *, DB_TXN *, DB_LOCK *, u_int32_t));
130
__txn_remlock(dbenv, txn, lock, locker)
136
TXN_EVENT *e, *next_e;
138
for (e = TAILQ_FIRST(&txn->events); e != NULL; e = next_e) {
139
next_e = TAILQ_NEXT(e, links);
140
if ((e->op != TXN_TRADE && e->op != TXN_TRADED) ||
141
(e->u.t.lock.off != lock->off && e->u.t.locker != locker))
143
TAILQ_REMOVE(&txn->events, e, links);
152
* Process the list of events associated with a transaction. On commit,
153
* apply the events; on abort, just toss the entries.
155
* PUBLIC: int __txn_doevents __P((DB_ENV *, DB_TXN *, int, int));
157
#define DO_TRADE do { \
158
memset(&req, 0, sizeof(req)); \
159
req.lock = e->u.t.lock; \
160
req.op = DB_LOCK_TRADE; \
161
t_ret = __lock_vec(dbenv, e->u.t.locker, 0, &req, 1, NULL); \
163
e->u.t.dbp->cur_lid = e->u.t.locker; \
164
else if (t_ret == DB_NOTFOUND) \
166
if (t_ret != 0 && ret == 0) \
168
e->op = TXN_TRADED; \
172
__txn_doevents(dbenv, txn, is_commit, preprocess)
175
int is_commit, preprocess;
184
* This phase only gets called if we have a phase where we
185
* release read locks. Since not all paths will call this
186
* phase, we have to check for it below as well. So, when
187
* we do the trade, we update the opcode of the entry so that
188
* we don't try the trade again.
191
for (e = TAILQ_FIRST(&txn->events);
192
e != NULL; e = TAILQ_NEXT(e, links)) {
193
if (e->op != TXN_TRADE)
200
while ((e = TAILQ_FIRST(&txn->events)) != NULL) {
201
TAILQ_REMOVE(&txn->events, e, links);
206
if (e->u.r.fileid != NULL) {
207
if ((t_ret = dbenv->memp_nameop(dbenv,
209
NULL, e->u.r.name, NULL)) != 0 && ret == 0)
211
__os_free(dbenv, e->u.r.fileid);
213
__os_unlink(dbenv, e->u.r.name)) != 0 && ret == 0)
215
__os_free(dbenv, e->u.r.name);
221
/* Downgrade the lock. */
222
if ((t_ret = __lock_downgrade(dbenv,
223
&e->u.t.lock, DB_LOCK_READ, 0)) != 0 && ret == 0)
227
/* This had better never happen. */
230
dofree: __os_free(dbenv, e);