00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #if TIME_WITH_SYS_TIME
00016 #include <sys/time.h>
00017 #include <time.h>
00018 #else
00019 #if HAVE_SYS_TIME_H
00020 #include <sys/time.h>
00021 #else
00022 #include <time.h>
00023 #endif
00024 #endif
00025
00026 #include <string.h>
00027 #endif
00028
00029 #include "db_int.h"
00030 #include "dbinc/log.h"
00031 #include "dbinc/txn.h"
00032
00033 static int __txn_init __P((DB_ENV *, DB_TXNMGR *));
00034 static size_t __txn_region_size __P((DB_ENV *));
00035
00036
00037
00038
00039
00040
00041
00042 int
00043 __txn_open(dbenv)
00044 DB_ENV *dbenv;
00045 {
00046 DB_TXNMGR *mgr;
00047 int ret;
00048
00049
00050 if ((ret = __os_calloc(dbenv, 1, sizeof(DB_TXNMGR), &mgr)) != 0)
00051 return (ret);
00052 TAILQ_INIT(&mgr->txn_chain);
00053 mgr->dbenv = dbenv;
00054
00055
00056 mgr->reginfo.dbenv = dbenv;
00057 mgr->reginfo.type = REGION_TYPE_TXN;
00058 mgr->reginfo.id = INVALID_REGION_ID;
00059 mgr->reginfo.flags = REGION_JOIN_OK;
00060 if (F_ISSET(dbenv, DB_ENV_CREATE))
00061 F_SET(&mgr->reginfo, REGION_CREATE_OK);
00062 if ((ret = __db_r_attach(dbenv,
00063 &mgr->reginfo, __txn_region_size(dbenv))) != 0)
00064 goto err;
00065
00066
00067 if (F_ISSET(&mgr->reginfo, REGION_CREATE))
00068 if ((ret = __txn_init(dbenv, mgr)) != 0)
00069 goto err;
00070
00071
00072 mgr->reginfo.primary =
00073 R_ADDR(&mgr->reginfo, mgr->reginfo.rp->primary);
00074
00075
00076 if ((ret = __mutex_alloc(
00077 dbenv, MTX_TXN_ACTIVE, DB_MUTEX_THREAD, &mgr->mutex)) != 0)
00078 goto err;
00079
00080 dbenv->tx_handle = mgr;
00081 return (0);
00082
00083 err: dbenv->tx_handle = NULL;
00084 if (mgr->reginfo.addr != NULL)
00085 (void)__db_r_detach(dbenv, &mgr->reginfo, 0);
00086
00087 (void)__mutex_free(dbenv, &mgr->mutex);
00088 __os_free(dbenv, mgr);
00089 return (ret);
00090 }
00091
00092
00093
00094
00095
00096 static int
00097 __txn_init(dbenv, mgr)
00098 DB_ENV *dbenv;
00099 DB_TXNMGR *mgr;
00100 {
00101 DB_LSN last_ckp;
00102 DB_TXNREGION *region;
00103 int ret;
00104
00105
00106
00107
00108 ZERO_LSN(last_ckp);
00109 if (LOGGING_ON(dbenv)) {
00110
00111
00112
00113
00114 if ((ret = __log_get_cached_ckp_lsn(dbenv, &last_ckp)) != 0)
00115 return (ret);
00116
00117
00118
00119
00120
00121 if (IS_ZERO_LSN(last_ckp) &&
00122 (ret = __txn_findlastckp(dbenv, &last_ckp, NULL)) != 0)
00123 return (ret);
00124 }
00125
00126 if ((ret = __db_shalloc(&mgr->reginfo,
00127 sizeof(DB_TXNREGION), 0, &mgr->reginfo.primary)) != 0) {
00128 __db_err(dbenv,
00129 "Unable to allocate memory for the transaction region");
00130 return (ret);
00131 }
00132 mgr->reginfo.rp->primary =
00133 R_OFFSET(&mgr->reginfo, mgr->reginfo.primary);
00134 region = mgr->reginfo.primary;
00135 memset(region, 0, sizeof(*region));
00136
00137 if ((ret = __mutex_alloc(
00138 dbenv, MTX_TXN_REGION, 0, ®ion->mtx_region)) != 0)
00139 return (ret);
00140
00141 region->maxtxns = dbenv->tx_max;
00142 region->last_txnid = TXN_MINIMUM;
00143 region->cur_maxid = TXN_MAXIMUM;
00144
00145 if ((ret = __mutex_alloc(
00146 dbenv, MTX_TXN_CHKPT, 0, ®ion->mtx_ckp)) != 0)
00147 return (ret);
00148 region->last_ckp = last_ckp;
00149 region->time_ckp = time(NULL);
00150
00151 memset(®ion->stat, 0, sizeof(region->stat));
00152 region->stat.st_maxtxns = region->maxtxns;
00153
00154 SH_TAILQ_INIT(®ion->active_txn);
00155 return (ret);
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 int
00167 __txn_findlastckp(dbenv, lsnp, max_lsn)
00168 DB_ENV *dbenv;
00169 DB_LSN *lsnp;
00170 DB_LSN *max_lsn;
00171 {
00172 DB_LOGC *logc;
00173 DB_LSN lsn;
00174 DBT dbt;
00175 int ret, t_ret;
00176 u_int32_t rectype;
00177
00178 ZERO_LSN(*lsnp);
00179
00180 if ((ret = __log_cursor(dbenv, &logc)) != 0)
00181 return (ret);
00182
00183
00184 memset(&dbt, 0, sizeof(dbt));
00185 if (max_lsn != NULL) {
00186 lsn = *max_lsn;
00187 if ((ret = __log_c_get(logc, &lsn, &dbt, DB_SET)) != 0)
00188 goto err;
00189 } else {
00190 if ((ret = __log_c_get(logc, &lsn, &dbt, DB_LAST)) != 0)
00191 goto err;
00192
00193
00194
00195
00196
00197 lsn.offset = 0;
00198 }
00199
00200
00201 while ((ret = __log_c_get(logc, &lsn, &dbt, DB_PREV)) == 0) {
00202 if (dbt.size < sizeof(u_int32_t))
00203 continue;
00204 memcpy(&rectype, dbt.data, sizeof(u_int32_t));
00205 if (rectype == DB___txn_ckp) {
00206 *lsnp = lsn;
00207 break;
00208 }
00209 }
00210
00211 err: if ((t_ret = __log_c_close(logc)) != 0 && ret == 0)
00212 ret = t_ret;
00213
00214
00215
00216
00217
00218 return ((ret == 0 || ret == DB_NOTFOUND) ? 0 : ret);
00219 }
00220
00221
00222
00223
00224
00225
00226
00227 int
00228 __txn_dbenv_refresh(dbenv)
00229 DB_ENV *dbenv;
00230 {
00231 DB_TXN *txn;
00232 DB_TXNMGR *mgr;
00233 REGINFO *reginfo;
00234 u_int32_t txnid;
00235 int aborted, ret, t_ret;
00236
00237 ret = 0;
00238 mgr = dbenv->tx_handle;
00239 reginfo = &mgr->reginfo;
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 aborted = 0;
00253 if (TAILQ_FIRST(&mgr->txn_chain) != NULL) {
00254 while ((txn = TAILQ_FIRST(&mgr->txn_chain)) != NULL) {
00255
00256 txnid = txn->txnid;
00257 if (((TXN_DETAIL *)txn->td)->status == TXN_PREPARED) {
00258 if ((ret = __txn_discard_int(txn, 0)) != 0) {
00259 __db_err(dbenv,
00260 "Unable to discard txn 0x%x: %s",
00261 txnid, db_strerror(ret));
00262 break;
00263 }
00264 continue;
00265 }
00266 aborted = 1;
00267 if ((t_ret = __txn_abort(txn)) != 0) {
00268 __db_err(dbenv,
00269 "Unable to abort transaction 0x%x: %s",
00270 txnid, db_strerror(t_ret));
00271 ret = __db_panic(dbenv, t_ret);
00272 break;
00273 }
00274 }
00275 if (aborted) {
00276 __db_err(dbenv,
00277 "Error: closing the transaction region with active transactions");
00278 if (ret == 0)
00279 ret = EINVAL;
00280 }
00281 }
00282
00283
00284 if (LOGGING_ON(dbenv) &&
00285 (t_ret = __log_flush(dbenv, NULL)) != 0 && ret == 0)
00286 ret = t_ret;
00287
00288
00289 if ((t_ret = __mutex_free(dbenv, &mgr->mutex)) != 0 && ret == 0)
00290 ret = t_ret;
00291
00292
00293 if ((t_ret = __db_r_detach(dbenv, reginfo, 0)) != 0 && ret == 0)
00294 ret = t_ret;
00295
00296 __os_free(dbenv, mgr);
00297
00298 dbenv->tx_handle = NULL;
00299 return (ret);
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 static size_t
00311 __txn_region_size(dbenv)
00312 DB_ENV *dbenv;
00313 {
00314 size_t s;
00315
00316 s = sizeof(DB_TXNREGION) +
00317 dbenv->tx_max * sizeof(TXN_DETAIL) + 10 * 1024;
00318 return (s);
00319 }
00320
00321
00322
00323
00324
00325
00326
00327
00328 int
00329 __txn_id_set(dbenv, cur_txnid, max_txnid)
00330 DB_ENV *dbenv;
00331 u_int32_t cur_txnid, max_txnid;
00332 {
00333 DB_TXNMGR *mgr;
00334 DB_TXNREGION *region;
00335 int ret;
00336
00337 ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "txn_id_set", DB_INIT_TXN);
00338
00339 mgr = dbenv->tx_handle;
00340 region = mgr->reginfo.primary;
00341 region->last_txnid = cur_txnid;
00342 region->cur_maxid = max_txnid;
00343
00344 ret = 0;
00345 if (cur_txnid < TXN_MINIMUM) {
00346 __db_err(dbenv, "Current ID value %lu below minimum",
00347 (u_long)cur_txnid);
00348 ret = EINVAL;
00349 }
00350 if (max_txnid < TXN_MINIMUM) {
00351 __db_err(dbenv, "Maximum ID value %lu below minimum",
00352 (u_long)max_txnid);
00353 ret = EINVAL;
00354 }
00355 return (ret);
00356 }