txn_region.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996, 1997, 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 
00008 #include "config.h"
00009 
00010 #ifndef lint
00011 static const char revid[] = "$Id: txn__region_8c-source.html,v 1.1 2008/06/08 10:24:57 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #if TIME_WITH_SYS_TIME
00018 #include <sys/time.h>
00019 #include <time.h>
00020 #else
00021 #if HAVE_SYS_TIME_H
00022 #include <sys/time.h>
00023 #else
00024 #include <time.h>
00025 #endif
00026 #endif
00027 
00028 #include <string.h>
00029 #endif
00030 
00031 #ifdef  HAVE_RPC
00032 #include "db_server.h"
00033 #endif
00034 
00035 #include "db_int.h"
00036 #include "db_page.h"
00037 #include "txn.h"
00038 #include "db_am.h"
00039 
00040 #ifdef HAVE_RPC
00041 #include "gen_client_ext.h"
00042 #include "rpc_client_ext.h"
00043 #endif
00044 
00045 static int __txn_init __P((DB_ENV *, DB_TXNMGR *));
00046 static int __txn_set_tx_max __P((DB_ENV *, u_int32_t));
00047 static int __txn_set_tx_recover __P((DB_ENV *,
00048                int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *)));
00049 static int __txn_set_tx_timestamp __P((DB_ENV *, time_t *));
00050 
00051 /*
00052  * CDB___txn_dbenv_create --
00053  *      Transaction specific initialization of the DB_ENV structure.
00054  *
00055  * PUBLIC: void CDB___txn_dbenv_create __P((DB_ENV *));
00056  */
00057 void
00058 CDB___txn_dbenv_create(dbenv)
00059         DB_ENV *dbenv;
00060 {
00061         dbenv->tx_max = DEF_MAX_TXNS;
00062 
00063         dbenv->set_tx_max = __txn_set_tx_max;
00064         dbenv->set_tx_recover = __txn_set_tx_recover;
00065         dbenv->set_tx_timestamp = __txn_set_tx_timestamp;
00066 
00067 #ifdef HAVE_RPC
00068         /*
00069          * If we have a client, overwrite what we just setup to point to
00070          * client functions.
00071          */
00072         if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) {
00073                 dbenv->set_tx_max = __dbcl_set_tx_max;
00074                 dbenv->set_tx_recover = __dbcl_set_tx_recover;
00075                 dbenv->set_tx_timestamp = __dbcl_set_tx_timestamp;
00076         }
00077 #endif
00078 }
00079 
00080 /*
00081  * __txn_set_tx_max --
00082  *      Set the size of the transaction table.
00083  */
00084 static int
00085 __txn_set_tx_max(dbenv, tx_max)
00086         DB_ENV *dbenv;
00087         u_int32_t tx_max;
00088 {
00089         ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_tx_max");
00090 
00091         dbenv->tx_max = tx_max;
00092         return (0);
00093 }
00094 
00095 /*
00096  * __txn_set_tx_recover --
00097  *      Set the transaction abort recover function.
00098  */
00099 static int
00100 __txn_set_tx_recover(dbenv, tx_recover)
00101         DB_ENV *dbenv;
00102         int (*tx_recover) __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00103 {
00104         dbenv->tx_recover = tx_recover;
00105         return (0);
00106 }
00107 
00108 /*
00109  * __txn_set_tx_timestamp --
00110  *      Set the transaction recovery timestamp.
00111  */
00112 static int
00113 __txn_set_tx_timestamp(dbenv, timestamp)
00114         DB_ENV *dbenv;
00115         time_t *timestamp;
00116 {
00117         ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_tx_timestamp");
00118 
00119         dbenv->tx_timestamp = *timestamp;
00120         return (0);
00121 }
00122 
00123 /*
00124  * CDB___txn_open --
00125  *      Open a transaction region.
00126  *
00127  * PUBLIC: int CDB___txn_open __P((DB_ENV *));
00128  */
00129 int
00130 CDB___txn_open(dbenv)
00131         DB_ENV *dbenv;
00132 {
00133         DB_TXNMGR *tmgrp;
00134         int ret;
00135 
00136         /* Create/initialize the transaction manager structure. */
00137         if ((ret = CDB___os_calloc(dbenv, 1, sizeof(DB_TXNMGR), &tmgrp)) != 0)
00138                 return (ret);
00139         TAILQ_INIT(&tmgrp->txn_chain);
00140         tmgrp->dbenv = dbenv;
00141         tmgrp->recover =
00142             dbenv->tx_recover == NULL ? CDB___db_dispatch : dbenv->tx_recover;
00143 
00144         /* Join/create the txn region. */
00145         tmgrp->reginfo.id = REG_ID_TXN;
00146         tmgrp->reginfo.mode = dbenv->db_mode;
00147         if (F_ISSET(dbenv, DB_ENV_CREATE))
00148                 F_SET(&tmgrp->reginfo, REGION_CREATE_OK);
00149         if ((ret = CDB___db_r_attach(dbenv,
00150             &tmgrp->reginfo, TXN_REGION_SIZE(dbenv->tx_max))) != 0)
00151                 goto err;
00152 
00153         /* If we created the region, initialize it. */
00154         if (F_ISSET(&tmgrp->reginfo, REGION_CREATE))
00155                 if ((ret = __txn_init(dbenv, tmgrp)) != 0)
00156                         goto err;
00157 
00158         /* Set the local addresses. */
00159         tmgrp->reginfo.primary =
00160             R_ADDR(&tmgrp->reginfo, tmgrp->reginfo.rp->primary);
00161 
00162         R_UNLOCK(dbenv, &tmgrp->reginfo);
00163 
00164         /* Acquire a mutex to protect the active TXN list. */
00165         if (F_ISSET(dbenv, DB_ENV_THREAD)) {
00166                 if ((ret = CDB___db_mutex_alloc(
00167                     dbenv, &tmgrp->reginfo, &tmgrp->mutexp)) != 0)
00168                         goto detach;
00169                 if ((ret = __db_mutex_init(
00170                     dbenv, tmgrp->mutexp, 0, MUTEX_THREAD)) != 0)
00171                         goto detach;
00172         }
00173 
00174         dbenv->tx_handle = tmgrp;
00175         return (0);
00176 
00177 err:    if (tmgrp->reginfo.addr != NULL) {
00178                 if (F_ISSET(&tmgrp->reginfo, REGION_CREATE))
00179                         F_SET(tmgrp->reginfo.rp, REG_DEAD);
00180                 R_UNLOCK(dbenv, &tmgrp->reginfo);
00181 
00182 detach:         (void)CDB___db_r_detach(dbenv, &tmgrp->reginfo, 0);
00183         }
00184         CDB___os_free(tmgrp, sizeof(*tmgrp));
00185         return (ret);
00186 }
00187 
00188 /*
00189  * __txn_init --
00190  *      Initialize a transaction region in shared memory.
00191  */
00192 static int
00193 __txn_init(dbenv, tmgrp)
00194         DB_ENV *dbenv;
00195         DB_TXNMGR *tmgrp;
00196 {
00197         DB_TXNREGION *region;
00198         int ret;
00199 
00200         if ((ret = CDB___db_shalloc(tmgrp->reginfo.addr,
00201             sizeof(DB_TXNREGION), 0, &tmgrp->reginfo.primary)) != 0) {
00202                 CDB___db_err(dbenv,
00203                     "Unable to allocate memory for the transaction region");
00204                 return (ret);
00205         }
00206         tmgrp->reginfo.rp->primary =
00207             R_OFFSET(&tmgrp->reginfo, tmgrp->reginfo.primary);
00208         region = tmgrp->reginfo.primary;
00209         memset(region, 0, sizeof(*region));
00210 
00211         region->maxtxns = dbenv->tx_max;
00212         region->last_txnid = TXN_MINIMUM;
00213         ZERO_LSN(region->pending_ckp);
00214         ZERO_LSN(region->last_ckp);
00215         region->time_ckp = time(NULL);
00216 
00217         /*
00218          * XXX
00219          * If we ever do more types of locking and logging, this changes.
00220          */
00221         region->logtype = 0;
00222         region->locktype = 0;
00223         region->naborts = 0;
00224         region->ncommits = 0;
00225         region->nbegins = 0;
00226         region->nactive = 0;
00227         region->maxnactive = 0;
00228 
00229         SH_TAILQ_INIT(&region->active_txn);
00230 
00231         return (0);
00232 }
00233 
00234 /*
00235  * CDB___txn_close --
00236  *      Close a transaction region.
00237  *
00238  * PUBLIC: int CDB___txn_close __P((DB_ENV *));
00239  */
00240 int
00241 CDB___txn_close(dbenv)
00242         DB_ENV *dbenv;
00243 {
00244         DB_TXN *txnp;
00245         DB_TXNMGR *tmgrp;
00246         int ret, t_ret;
00247 
00248         ret = 0;
00249         tmgrp = dbenv->tx_handle;
00250 
00251         /*
00252          * This function can only be called once per process (i.e., not
00253          * once per thread), so no synchronization is required.
00254          *
00255          * We would like to abort any running transactions, but the caller
00256          * is doing something wrong by calling close with active
00257          * transactions.  It's quite likely that this will fail because
00258          * recovery won't find open files.  If this happens, the right
00259          * solution is DB_RUNRECOVERY.  So, convert any failure messages
00260          * to that.
00261          */
00262         while ((txnp =
00263             TAILQ_FIRST(&tmgrp->txn_chain)) != TAILQ_END(&tmgrp->txn_chain))
00264                 if ((t_ret = CDB_txn_abort(txnp)) != 0) {
00265                         CDB___db_err(dbenv,
00266                             "Unable to abort transaction 0x%x: %s\n",
00267                             txnp->txnid, CDB_db_strerror(t_ret));
00268                         CDB___txn_end(txnp, 0);
00269                         if (ret == 0)
00270                                 ret = t_ret == 0 ? 0 : DB_RUNRECOVERY;
00271                 }
00272 
00273         /* Flush the log. */
00274         if (LOGGING_ON(dbenv) &&
00275             (t_ret = CDB_log_flush(dbenv, NULL)) != 0 && ret == 0)
00276                 ret = t_ret;
00277 
00278         /* Discard the per-thread lock. */
00279         if (tmgrp->mutexp != NULL)
00280                 CDB___db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp);
00281 
00282         /* Detach from the region. */
00283         if ((t_ret = CDB___db_r_detach(dbenv, &tmgrp->reginfo, 0)) != 0 && ret == 0)
00284                 ret = t_ret;
00285 
00286         CDB___os_free(tmgrp, sizeof(*tmgrp));
00287 
00288         dbenv->tx_handle = NULL;
00289         return (ret);
00290 }
00291 
00292 int
00293 CDB_txn_stat(dbenv, statp, db_malloc)
00294         DB_ENV *dbenv;
00295         DB_TXN_STAT **statp;
00296         void *(*db_malloc) __P((size_t));
00297 {
00298         DB_TXNMGR *mgr;
00299         DB_TXNREGION *region;
00300         DB_TXN_STAT *stats;
00301         TXN_DETAIL *txnp;
00302         size_t nbytes;
00303         u_int32_t nactive, ndx;
00304         int ret, slop;
00305 
00306 #ifdef HAVE_RPC
00307         if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00308                 return (__dbcl_txn_stat(dbenv, statp, db_malloc));
00309 #endif
00310 
00311         PANIC_CHECK(dbenv);
00312         ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, DB_INIT_TXN);
00313 
00314         *statp = NULL;
00315 
00316         slop = 200;
00317         mgr = dbenv->tx_handle;
00318         region = mgr->reginfo.primary;
00319 
00320 retry:  R_LOCK(dbenv, &mgr->reginfo);
00321         nactive = region->nactive;
00322         R_UNLOCK(dbenv, &mgr->reginfo);
00323 
00324         /*
00325          * Allocate extra active structures to handle any transactions that
00326          * are created while we have the region unlocked.
00327          */
00328         nbytes = sizeof(DB_TXN_STAT) + sizeof(DB_TXN_ACTIVE) * (nactive + slop);
00329         if ((ret = CDB___os_malloc(dbenv, nbytes, db_malloc, &stats)) != 0)
00330                 return (ret);
00331 
00332         R_LOCK(dbenv, &mgr->reginfo);
00333         stats->st_last_txnid = region->last_txnid;
00334         stats->st_last_ckp = region->last_ckp;
00335         stats->st_maxtxns = region->maxtxns;
00336         stats->st_naborts = region->naborts;
00337         stats->st_nbegins = region->nbegins;
00338         stats->st_ncommits = region->ncommits;
00339         stats->st_pending_ckp = region->pending_ckp;
00340         stats->st_time_ckp = region->time_ckp;
00341         stats->st_nactive = region->nactive;
00342         if (stats->st_nactive > nactive + 200) {
00343                 R_UNLOCK(dbenv, &mgr->reginfo);
00344                 slop *= 2;
00345                 goto retry;
00346         }
00347         stats->st_maxnactive = region->maxnactive;
00348         stats->st_txnarray = (DB_TXN_ACTIVE *)&stats[1];
00349 
00350         ndx = 0;
00351         for (txnp = SH_TAILQ_FIRST(&region->active_txn, __txn_detail);
00352             txnp != NULL;
00353             txnp = SH_TAILQ_NEXT(txnp, links, __txn_detail)) {
00354                 stats->st_txnarray[ndx].txnid = txnp->txnid;
00355                 if (txnp->parent == INVALID_ROFF)
00356                         stats->st_txnarray[ndx].parentid = TXN_INVALID_ID;
00357                 else
00358                         stats->st_txnarray[ndx].parentid =
00359                             ((TXN_DETAIL *)R_ADDR(&mgr->reginfo,
00360                             txnp->parent))->txnid;
00361                 stats->st_txnarray[ndx].lsn = txnp->begin_lsn;
00362                 ndx++;
00363 
00364                 if (ndx >= stats->st_nactive)
00365                         break;
00366         }
00367 
00368         stats->st_region_wait = mgr->reginfo.rp->mutex.mutex_set_wait;
00369         stats->st_region_nowait = mgr->reginfo.rp->mutex.mutex_set_nowait;
00370         stats->st_regsize = mgr->reginfo.rp->size;
00371 
00372         R_UNLOCK(dbenv, &mgr->reginfo);
00373 
00374         *statp = stats;
00375         return (0);
00376 }

Generated on Sun Jun 8 10:56:39 2008 for GNUmifluz by  doxygen 1.5.5