txn_util.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:5k
- /*-
- * See the file LICENSE for redistribution information.
- *
- * Copyright (c) 2001-2002
- * Sleepycat Software. All rights reserved.
- */
- #include "db_config.h"
- #ifndef lint
- static const char revid[] = "$Id: txn_util.c,v 11.18 2002/08/06 06:25:12 bostic Exp $";
- #endif /* not lint */
- #ifndef NO_SYSTEM_INCLUDES
- #include <sys/types.h>
- #include <string.h>
- #endif
- #include "db_int.h"
- #include "dbinc/db_shash.h"
- #include "dbinc/lock.h"
- #include "dbinc/txn.h"
- typedef struct __txn_event TXN_EVENT;
- struct __txn_event {
- TXN_EVENT_T op;
- TAILQ_ENTRY(__txn_event) links;
- union {
- struct {
- /* Delayed remove. */
- char *name;
- u_int8_t *fileid;
- } r;
- struct {
- /* Lock event. */
- DB_LOCK lock;
- u_int32_t locker;
- DB *dbp;
- } t;
- } u;
- };
- /*
- * __txn_remevent --
- *
- * Creates a remove event that can be added to the commit list.
- *
- * PUBLIC: int __txn_remevent __P((DB_ENV *,
- * PUBLIC: DB_TXN *, const char *, u_int8_t*));
- */
- int
- __txn_remevent(dbenv, txn, name, fileid)
- DB_ENV *dbenv;
- DB_TXN *txn;
- const char *name;
- u_int8_t *fileid;
- {
- int ret;
- TXN_EVENT *e;
- e = NULL;
- if ((ret = __os_calloc(dbenv, 1, sizeof(TXN_EVENT), &e)) != 0)
- return (ret);
- if ((ret = __os_strdup(dbenv, name, &e->u.r.name)) != 0)
- goto err;
- if (fileid != NULL) {
- if ((ret = __os_calloc(dbenv,
- 1, DB_FILE_ID_LEN, &e->u.r.fileid)) != 0)
- return (ret);
- memcpy(e->u.r.fileid, fileid, DB_FILE_ID_LEN);
- }
- e->op = TXN_REMOVE;
- TAILQ_INSERT_TAIL(&txn->events, e, links);
- return (0);
- err: if (e != NULL)
- __os_free(dbenv, e);
- return (ret);
- }
- /*
- * __txn_lockevent --
- *
- * Add a lockevent to the commit-queue. The lock event indicates a locker
- * trade.
- *
- * PUBLIC: int __txn_lockevent __P((DB_ENV *,
- * PUBLIC: DB_TXN *, DB *, DB_LOCK *, u_int32_t));
- */
- int
- __txn_lockevent(dbenv, txn, dbp, lock, locker)
- DB_ENV *dbenv;
- DB_TXN *txn;
- DB *dbp;
- DB_LOCK *lock;
- u_int32_t locker;
- {
- int ret;
- TXN_EVENT *e;
- if (!LOCKING_ON(dbenv))
- return (0);
- e = NULL;
- if ((ret = __os_calloc(dbenv, 1, sizeof(TXN_EVENT), &e)) != 0)
- return (ret);
- e->u.t.locker = locker;
- e->u.t.lock = *lock;
- e->u.t.dbp = dbp;
- e->op = TXN_TRADE;
- TAILQ_INSERT_TAIL(&txn->events, e, links);
- return (0);
- }
- /*
- * __txn_remlock --
- * Remove a lock event because the locker is going away. We can remove
- * by lock (using offset) or by locker_id (or by both).
- *
- * PUBLIC: void __txn_remlock __P((DB_ENV *, DB_TXN *, DB_LOCK *, u_int32_t));
- */
- void
- __txn_remlock(dbenv, txn, lock, locker)
- DB_ENV *dbenv;
- DB_TXN *txn;
- DB_LOCK *lock;
- u_int32_t locker;
- {
- TXN_EVENT *e, *next_e;
- for (e = TAILQ_FIRST(&txn->events); e != NULL; e = next_e) {
- next_e = TAILQ_NEXT(e, links);
- if ((e->op != TXN_TRADE && e->op != TXN_TRADED) ||
- (e->u.t.lock.off != lock->off && e->u.t.locker != locker))
- continue;
- TAILQ_REMOVE(&txn->events, e, links);
- __os_free(dbenv, e);
- }
- return;
- }
- /*
- * __txn_doevents --
- * Process the list of events associated with a transaction. On commit,
- * apply the events; on abort, just toss the entries.
- *
- * PUBLIC: int __txn_doevents __P((DB_ENV *, DB_TXN *, int, int));
- */
- #define DO_TRADE do {
- memset(&req, 0, sizeof(req));
- req.lock = e->u.t.lock;
- req.op = DB_LOCK_TRADE;
- t_ret = __lock_vec(dbenv, e->u.t.locker, 0, &req, 1, NULL);
- if (t_ret == 0)
- e->u.t.dbp->cur_lid = e->u.t.locker;
- else if (t_ret == DB_NOTFOUND)
- t_ret = 0;
- if (t_ret != 0 && ret == 0)
- ret = t_ret;
- e->op = TXN_TRADED;
- } while (0)
- int
- __txn_doevents(dbenv, txn, is_commit, preprocess)
- DB_ENV *dbenv;
- DB_TXN *txn;
- int is_commit, preprocess;
- {
- DB_LOCKREQ req;
- TXN_EVENT *e;
- int ret, t_ret;
- ret = 0;
- /*
- * This phase only gets called if we have a phase where we
- * release read locks. Since not all paths will call this
- * phase, we have to check for it below as well. So, when
- * we do the trade, we update the opcode of the entry so that
- * we don't try the trade again.
- */
- if (preprocess) {
- for (e = TAILQ_FIRST(&txn->events);
- e != NULL; e = TAILQ_NEXT(e, links)) {
- if (e->op != TXN_TRADE)
- continue;
- DO_TRADE;
- }
- return (ret);
- }
- while ((e = TAILQ_FIRST(&txn->events)) != NULL) {
- TAILQ_REMOVE(&txn->events, e, links);
- if (!is_commit)
- goto dofree;
- switch (e->op) {
- case TXN_REMOVE:
- if (e->u.r.fileid != NULL) {
- if ((t_ret = dbenv->memp_nameop(dbenv,
- e->u.r.fileid,
- NULL, e->u.r.name, NULL)) != 0 && ret == 0)
- ret = t_ret;
- __os_free(dbenv, e->u.r.fileid);
- } else if ((t_ret =
- __os_unlink(dbenv, e->u.r.name)) != 0 && ret == 0)
- ret = t_ret;
- __os_free(dbenv, e->u.r.name);
- break;
- case TXN_TRADE:
- DO_TRADE;
- /* Fall through */
- case TXN_TRADED:
- /* Downgrade the lock. */
- if ((t_ret = __lock_downgrade(dbenv,
- &e->u.t.lock, DB_LOCK_READ, 0)) != 0 && ret == 0)
- ret = t_ret;
- break;
- default:
- /* This had better never happen. */
- DB_ASSERT(0);
- }
- dofree: __os_free(dbenv, e);
- }
- return (ret);
- }