aboutsummaryrefslogtreecommitdiff
path: root/db2/xa/xa_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'db2/xa/xa_map.c')
-rw-r--r--db2/xa/xa_map.c305
1 files changed, 305 insertions, 0 deletions
diff --git a/db2/xa/xa_map.c b/db2/xa/xa_map.c
new file mode 100644
index 0000000000..d4ebbae22f
--- /dev/null
+++ b/db2/xa/xa_map.c
@@ -0,0 +1,305 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997, 1998
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)xa_map.c 10.4 (Sleepycat) 10/20/98";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "shqueue.h"
+#include "txn.h"
+
+/*
+ * This file contains all the mapping information that we need to support
+ * the DB/XA interface.
+ */
+
+/*
+ * __db_rmid_to_env
+ * Return the environment associated with a given XA rmid.
+ *
+ * PUBLIC: int __db_rmid_to_env __P((int rmid, DB_ENV **envp, int open_ok));
+ */
+int
+__db_rmid_to_env(rmid, envp, open_ok)
+ int rmid;
+ DB_ENV **envp;
+ int open_ok;
+{
+ DB_ENV *env;
+ char *dbhome;
+
+ env = TAILQ_FIRST(&DB_GLOBAL(db_envq));
+ if (env != NULL && env->xa_rmid == rmid) {
+ *envp = env;
+ return (0);
+ }
+
+ /*
+ * When we map an rmid, move that environment to be the first one in
+ * the list of environments, so we pass the correct environment from
+ * the upcoming db_xa_open() call into db_open().
+ */
+ for (; env != NULL; env = TAILQ_NEXT(env, links))
+ if (env->xa_rmid == rmid) {
+ TAILQ_REMOVE(&DB_GLOBAL(db_envq), env, links);
+ TAILQ_INSERT_HEAD(&DB_GLOBAL(db_envq), env, links);
+ *envp = env;
+ return (0);
+ }
+
+ /*
+ * We have not found the rmid on the environment list. If we
+ * are allowed to do an open, search for the rmid on the name
+ * list and, if we find it, then open it.
+ */
+ if (!open_ok)
+ return (1);
+
+ if (__db_rmid_to_name(rmid, &dbhome) != 0)
+ return (1);
+#undef XA_FLAGS
+#define XA_FLAGS \
+ DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN
+
+ if (__os_calloc(1, sizeof(DB_ENV), &env) != 0)
+ return (1);
+
+ if (db_appinit(dbhome, NULL, env, XA_FLAGS) != 0)
+ goto err;
+
+ if (__db_map_rmid(rmid, env) != 0)
+ goto err1;
+
+ __db_unmap_rmid_name(rmid);
+
+ *envp = env;
+ return (0);
+
+err1: (void)db_appexit(env);
+err: __os_free(env, sizeof(DB_ENV));
+ return (1);
+}
+
+/*
+ * __db_xid_to_txn
+ * Return the txn that corresponds to this XID.
+ *
+ * PUBLIC: int __db_xid_to_txn __P((DB_ENV *, XID *, size_t *));
+ */
+int
+__db_xid_to_txn(dbenv, xid, offp)
+ DB_ENV *dbenv;
+ XID *xid;
+ size_t *offp;
+{
+ DB_TXNREGION *tmr;
+ struct __txn_detail *td;
+
+ /*
+ * Search the internal active transaction table to find the
+ * matching xid. If this is a performance hit, then we
+ * can create a hash table, but I doubt it's worth it.
+ */
+ tmr = dbenv->tx_info->region;
+
+ LOCK_TXNREGION(dbenv->tx_info);
+ for (td = SH_TAILQ_FIRST(&tmr->active_txn, __txn_detail);
+ td != NULL;
+ td = SH_TAILQ_NEXT(td, links, __txn_detail))
+ if (memcmp(xid->data, td->xid, XIDDATASIZE) == 0)
+ break;
+ UNLOCK_TXNREGION(dbenv->tx_info);
+
+ if (td == NULL)
+ return (EINVAL);
+
+ *offp = (u_int8_t *)td - (u_int8_t *)tmr;
+ return (0);
+}
+
+/*
+ * __db_map_rmid
+ * Create a mapping between the specified rmid and environment.
+ *
+ * PUBLIC: int __db_map_rmid __P((int, DB_ENV *));
+ */
+int
+__db_map_rmid(rmid, env)
+ int rmid;
+ DB_ENV *env;
+{
+ if (__os_calloc(1, sizeof(DB_TXN), &env->xa_txn) != 0)
+ return (XAER_RMERR);
+ env->xa_txn->txnid = TXN_INVALID;
+ env->xa_rmid = rmid;
+ TAILQ_INSERT_HEAD(&DB_GLOBAL(db_envq), env, links);
+ return (XA_OK);
+}
+
+/*
+ * __db_unmap_rmid
+ * Destroy the mapping for the given rmid.
+ *
+ * PUBLIC: int __db_unmap_rmid __P((int));
+ */
+int
+__db_unmap_rmid(rmid)
+ int rmid;
+{
+ DB_ENV *e;
+
+ for (e = TAILQ_FIRST(&DB_GLOBAL(db_envq));
+ e->xa_rmid != rmid;
+ e = TAILQ_NEXT(e, links));
+
+ if (e == NULL)
+ return (EINVAL);
+
+ TAILQ_REMOVE(&DB_GLOBAL(db_envq), e, links);
+ if (e->xa_txn != NULL)
+ __os_free(e->xa_txn, sizeof(DB_TXN));
+ return (0);
+}
+
+/*
+ * __db_map_xid
+ * Create a mapping between this XID and the transaction at
+ * "off" in the shared region.
+ *
+ * PUBLIC: int __db_map_xid __P((DB_ENV *, XID *, size_t));
+ */
+int
+__db_map_xid(env, xid, off)
+ DB_ENV *env;
+ XID *xid;
+ size_t off;
+{
+ DB_TXNMGR *tm;
+ TXN_DETAIL *td;
+
+ tm = env->tx_info;
+ td = (TXN_DETAIL *)((u_int8_t *)tm->region + off);
+
+ LOCK_TXNREGION(tm);
+ memcpy(td->xid, xid->data, XIDDATASIZE);
+ UNLOCK_TXNREGION(tm);
+
+ return (0);
+}
+
+/*
+ * __db_unmap_xid
+ * Destroy the mapping for the specified XID.
+ *
+ * PUBLIC: void __db_unmap_xid __P((DB_ENV *, XID *, size_t));
+ */
+
+void
+__db_unmap_xid(env, xid, off)
+ DB_ENV *env;
+ XID *xid;
+ size_t off;
+{
+ TXN_DETAIL *td;
+
+ COMPQUIET(xid, NULL);
+
+ td = (TXN_DETAIL *)((u_int8_t *)env->tx_info->region + off);
+ memset(td->xid, 0, sizeof(td->xid));
+}
+
+/*
+ * __db_map_rmid_name --
+ * Create a mapping from an rmid to a name (the xa_info argument).
+ * We use this during create and then at some later point when we are
+ * trying to map an rmid, we might indicate that it's OK to do an open
+ * in which case, we'll get the xa_info parameter from here and then
+ * free it up.
+ *
+ * PUBLIC: int __db_map_rmid_name __P((int, char *));
+ */
+
+int
+__db_map_rmid_name(rmid, dbhome)
+ int rmid;
+ char *dbhome;
+{
+ struct __rmname *entry;
+ int ret;
+
+ if ((ret = __os_malloc(sizeof(struct __rmname), NULL, &entry)) != 0)
+ return (ret);
+
+ if ((ret = __os_strdup(dbhome, &entry->dbhome)) != 0) {
+ __os_free(entry, sizeof(struct __rmname));
+ return (ret);
+ }
+
+ entry->rmid = rmid;
+
+ TAILQ_INSERT_HEAD(&DB_GLOBAL(db_nameq), entry, links);
+ return (0);
+}
+
+/*
+ * __db_rmid_to_name --
+ * Given an rmid, return the name of the home directory for that
+ * rmid.
+ *
+ * PUBLIC: int __db_rmid_to_name __P((int, char **));
+ */
+int
+__db_rmid_to_name(rmid, dbhomep)
+ int rmid;
+ char **dbhomep;
+{
+ struct __rmname *np;
+
+ for (np = TAILQ_FIRST(&DB_GLOBAL(db_nameq)); np != NULL;
+ np = TAILQ_NEXT(np, links)) {
+ if (np->rmid == rmid) {
+ *dbhomep = np->dbhome;
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * __db_unmap_rmid_name --
+ * Given an rmid, remove its entry from the name list.
+ *
+ * PUBLIC: void __db_unmap_rmid_name __P((int));
+ */
+void
+__db_unmap_rmid_name(rmid)
+ int rmid;
+{
+ struct __rmname *np, *next;
+
+ for (np = TAILQ_FIRST(&DB_GLOBAL(db_nameq)); np != NULL; np = next) {
+ next = TAILQ_NEXT(np, links);
+ if (np->rmid == rmid) {
+ TAILQ_REMOVE(&DB_GLOBAL(db_nameq), np, links);
+ __os_freestr(np->dbhome);
+ __os_free(np, sizeof(struct __rmname));
+ return;
+ }
+ }
+ return;
+}