00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "config.h"
00040
00041 #ifndef lint
00042 static const char revid[] = "$Id: txn_8c-source.html,v 1.1 2008/06/08 10:24:47 sebdiaz Exp $";
00043 #endif
00044
00045 #ifndef NO_SYSTEM_INCLUDES
00046 #include <sys/types.h>
00047
00048 #if TIME_WITH_SYS_TIME
00049 #include <sys/time.h>
00050 #include <time.h>
00051 #else
00052 #if HAVE_SYS_TIME_H
00053 #include <sys/time.h>
00054 #else
00055 #include <time.h>
00056 #endif
00057 #endif
00058
00059 #include <errno.h>
00060 #include <string.h>
00061 #endif
00062
00063 #ifdef HAVE_RPC
00064 #include "db_server.h"
00065 #endif
00066
00067 #include "db_int.h"
00068 #include "db_shash.h"
00069 #include "txn.h"
00070 #include "lock.h"
00071 #include "log.h"
00072 #include "db_dispatch.h"
00073
00074 #ifdef HAVE_RPC
00075 #include "gen_client_ext.h"
00076 #include "rpc_client_ext.h"
00077 #endif
00078
00079 static int __txn_begin __P((DB_TXN *));
00080 static int __txn_check_running __P((const DB_TXN *, TXN_DETAIL **));
00081 static int __txn_count __P((DB_TXN *));
00082 static void __txn_freekids __P((DB_TXN *));
00083 static void __txn_lsn __P((DB_TXN *, DB_LSN **));
00084 static int __txn_makefamily __P((DB_ENV *, DB_TXN *, int *, DB_LSN **));
00085 static int __txn_undo __P((DB_TXN *));
00086
00087 #define TXN_BUBBLE(AP, MAX) { \
00088 int __j; \
00089 DB_LSN __tmp; \
00090 \
00091 for (__j = 0; __j < MAX - 1; __j++) \
00092 if (CDB_log_compare(&AP[__j], &AP[__j + 1]) < 0) { \
00093 __tmp = AP[__j]; \
00094 AP[__j] = AP[__j + 1]; \
00095 AP[__j + 1] = __tmp; \
00096 } \
00097 }
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 int
00110 CDB_txn_begin(dbenv, parent, txnpp, flags)
00111 DB_ENV *dbenv;
00112 DB_TXN *parent, **txnpp;
00113 u_int32_t flags;
00114 {
00115 DB_TXN *txn;
00116 int ret;
00117
00118 #ifdef HAVE_RPC
00119 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00120 return (__dbcl_txn_begin(dbenv, parent, txnpp, flags));
00121 #endif
00122
00123 PANIC_CHECK(dbenv);
00124 ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, DB_INIT_TXN);
00125
00126 if ((ret = CDB___db_fchk(dbenv,
00127 "CDB_txn_begin", flags,
00128 DB_TXN_NOWAIT | DB_TXN_NOSYNC | DB_TXN_SYNC)) != 0)
00129 return (ret);
00130 if ((ret = CDB___db_fcchk(dbenv,
00131 "CDB_txn_begin", flags, DB_TXN_NOSYNC, DB_TXN_SYNC)) != 0)
00132 return (ret);
00133
00134 if ((ret = CDB___os_calloc(dbenv, 1, sizeof(DB_TXN), &txn)) != 0)
00135 return (ret);
00136
00137 txn->mgrp = dbenv->tx_handle;
00138 txn->parent = parent;
00139 TAILQ_INIT(&txn->kids);
00140 txn->flags = TXN_MALLOC;
00141 if (LF_ISSET(DB_TXN_NOSYNC))
00142 F_SET(txn, TXN_NOSYNC);
00143 if (LF_ISSET(DB_TXN_SYNC))
00144 F_SET(txn, TXN_SYNC);
00145 if (LF_ISSET(DB_TXN_NOWAIT))
00146 F_SET(txn, TXN_NOWAIT);
00147
00148 if ((ret = __txn_begin(txn)) != 0) {
00149 CDB___os_free(txn, sizeof(DB_TXN));
00150 txn = NULL;
00151 }
00152
00153 if (txn != NULL && parent != NULL)
00154 TAILQ_INSERT_HEAD(&parent->kids, txn, klinks);
00155
00156 *txnpp = txn;
00157 return (ret);
00158 }
00159
00160
00161
00162
00163
00164
00165
00166 int
00167 CDB___txn_xa_begin(dbenv, txn)
00168 DB_ENV *dbenv;
00169 DB_TXN *txn;
00170 {
00171 PANIC_CHECK(dbenv);
00172
00173 memset(txn, 0, sizeof(DB_TXN));
00174
00175 txn->mgrp = dbenv->tx_handle;
00176
00177 return (__txn_begin(txn));
00178 }
00179
00180
00181
00182
00183
00184 static int
00185 __txn_begin(txn)
00186 DB_TXN *txn;
00187 {
00188 DB_ENV *dbenv;
00189 DB_LSN begin_lsn;
00190 DB_TXNMGR *mgr;
00191 DB_TXNREGION *region;
00192 TXN_DETAIL *td;
00193 size_t off;
00194 u_int32_t id;
00195 int ret;
00196
00197 mgr = txn->mgrp;
00198 dbenv = mgr->dbenv;
00199 region = mgr->reginfo.primary;
00200
00201
00202
00203
00204
00205
00206
00207 if (LOGGING_ON(dbenv) &&
00208 (ret = CDB_log_put(dbenv, &begin_lsn, NULL, DB_CURLSN)) != 0)
00209 goto err2;
00210
00211 R_LOCK(dbenv, &mgr->reginfo);
00212
00213
00214 if (region->last_txnid == TXN_INVALID) {
00215 CDB___db_err(dbenv, "CDB_txn_begin: %s %s",
00216 "Transaction ID wrapping.",
00217 "Snapshot your database and start a new log.");
00218 ret = EINVAL;
00219 goto err1;
00220 }
00221
00222
00223 if ((ret =
00224 CDB___db_shalloc(mgr->reginfo.addr, sizeof(TXN_DETAIL), 0, &td)) != 0) {
00225 CDB___db_err(dbenv,
00226 "Unable to allocate memory for transaction detail");
00227 goto err1;
00228 }
00229
00230
00231 SH_TAILQ_INSERT_HEAD(®ion->active_txn, td, links, __txn_detail);
00232
00233 id = ++region->last_txnid;
00234 ++region->nbegins;
00235 if (++region->nactive > region->maxnactive)
00236 region->maxnactive = region->nactive;
00237
00238 td->txnid = id;
00239 td->begin_lsn = begin_lsn;
00240 ZERO_LSN(td->last_lsn);
00241 td->status = TXN_RUNNING;
00242 if (txn->parent != NULL)
00243 td->parent = txn->parent->off;
00244 else
00245 td->parent = INVALID_ROFF;
00246
00247 off = R_OFFSET(&mgr->reginfo, td);
00248 R_UNLOCK(dbenv, &mgr->reginfo);
00249
00250 ZERO_LSN(txn->last_lsn);
00251 txn->txnid = id;
00252 txn->off = off;
00253
00254
00255
00256
00257
00258 if (txn->parent != NULL && LOCKING_ON(dbenv))
00259 if ((ret = CDB___lock_addfamilylocker(dbenv,
00260 txn->parent->txnid, txn->txnid)) != 0)
00261 goto err2;
00262
00263 if (F_ISSET(txn, TXN_MALLOC)) {
00264 MUTEX_THREAD_LOCK(mgr->mutexp);
00265 TAILQ_INSERT_TAIL(&mgr->txn_chain, txn, links);
00266 MUTEX_THREAD_UNLOCK(mgr->mutexp);
00267 }
00268
00269 return (0);
00270
00271 err1: R_UNLOCK(dbenv, &mgr->reginfo);
00272
00273 err2: return (ret);
00274 }
00275
00276
00277
00278
00279
00280 int
00281 CDB_txn_commit(txnp, flags)
00282 DB_TXN *txnp;
00283 u_int32_t flags;
00284 {
00285 DB_ENV *dbenv;
00286 DB_TXN *kids;
00287 DB_TXNMGR *mgr;
00288 int ret;
00289
00290 mgr = txnp->mgrp;
00291 dbenv = mgr->dbenv;
00292
00293 #ifdef HAVE_RPC
00294 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00295 return (__dbcl_txn_commit(txnp, flags));
00296 #endif
00297
00298 PANIC_CHECK(dbenv);
00299 if ((ret = CDB___db_fchk(dbenv,
00300 "CDB_txn_commit", flags, DB_TXN_NOSYNC | DB_TXN_SYNC)) != 0)
00301 return (ret);
00302
00303 if ((ret = CDB___db_fcchk(dbenv,
00304 "CDB_txn_commit", flags, DB_TXN_NOSYNC, DB_TXN_SYNC)) != 0)
00305 return (ret);
00306
00307 if ((ret = __txn_check_running(txnp, NULL)) != 0)
00308 return (ret);
00309
00310 if (LF_ISSET(DB_TXN_NOSYNC)) {
00311 F_CLR(txnp, TXN_SYNC);
00312 F_SET(txnp, TXN_NOSYNC);
00313 }
00314 if (LF_ISSET(DB_TXN_SYNC)) {
00315 F_CLR(txnp, TXN_NOSYNC);
00316 F_SET(txnp, TXN_SYNC);
00317 }
00318
00319
00320 for (kids = TAILQ_FIRST(&txnp->kids);
00321 kids != NULL;
00322 kids = TAILQ_NEXT(kids, klinks))
00323 if (!F_ISSET(kids, TXN_CHILDCOMMIT) &&
00324 (ret = CDB_txn_commit(kids, flags)) != 0)
00325 return (ret);
00326
00327
00328
00329
00330
00331
00332
00333
00334 if (LOGGING_ON(dbenv) &&
00335 (F_ISSET(txnp, TXN_MUSTFLUSH) || !IS_ZERO_LSN(txnp->last_lsn))) {
00336 if (txnp->parent == NULL)
00337 ret = CDB___txn_regop_log(dbenv, txnp, &txnp->last_lsn,
00338 (F_ISSET(mgr->dbenv, DB_ENV_TXN_NOSYNC) &&
00339 !F_ISSET(txnp, TXN_SYNC)) ||
00340 F_ISSET(txnp, TXN_NOSYNC) ? 0 : DB_FLUSH,
00341 TXN_COMMIT, (int32_t)time(NULL));
00342 else {
00343 F_SET(txnp->parent, TXN_MUSTFLUSH);
00344 ret = CDB___txn_child_log(dbenv, txnp, &txnp->last_lsn, 0,
00345 TXN_COMMIT, txnp->parent->txnid);
00346 }
00347 if (ret != 0)
00348 return (ret);
00349 }
00350
00351
00352
00353
00354
00355
00356
00357 if (txnp->parent == NULL)
00358 __txn_freekids(txnp);
00359
00360 return (CDB___txn_end(txnp, 1));
00361 }
00362
00363
00364
00365
00366
00367 int
00368 CDB_txn_abort(txnp)
00369 DB_TXN *txnp;
00370 {
00371 int ret;
00372
00373 #ifdef HAVE_RPC
00374 if (F_ISSET(txnp->mgrp->dbenv, DB_ENV_RPCCLIENT))
00375 return (__dbcl_txn_abort(txnp));
00376 #endif
00377
00378 PANIC_CHECK(txnp->mgrp->dbenv);
00379 if ((ret = __txn_check_running(txnp, NULL)) != 0)
00380 return (ret);
00381
00382 if ((ret = __txn_undo(txnp)) != 0) {
00383 return (ret);
00384 }
00385 return (CDB___txn_end(txnp, 0));
00386 }
00387
00388
00389
00390
00391
00392 int
00393 CDB_txn_prepare(txnp)
00394 DB_TXN *txnp;
00395 {
00396 DBT xid;
00397 DB_ENV *dbenv;
00398 TXN_DETAIL *td;
00399 int ret;
00400
00401 dbenv = txnp->mgrp->dbenv;
00402 #ifdef HAVE_RPC
00403 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00404 return (__dbcl_txn_prepare(txnp));
00405 #endif
00406
00407 if ((ret = __txn_check_running(txnp, &td)) != 0)
00408 return (ret);
00409
00410 memset(&xid, 0, sizeof(xid));
00411 xid.data = td->xid;
00412 xid.size = sizeof(td->xid);
00413 if (LOGGING_ON(dbenv) &&
00414 (ret = CDB___txn_xa_regop_log(dbenv, txnp, &txnp->last_lsn,
00415 (F_ISSET(dbenv, DB_ENV_TXN_NOSYNC) &&
00416 !F_ISSET(txnp, TXN_SYNC)) ||
00417 F_ISSET(txnp, TXN_NOSYNC) ? 0 : DB_FLUSH, TXN_PREPARE,
00418 &xid, td->format, td->gtrid, td->bqual)) != 0) {
00419 CDB___db_err(dbenv,
00420 "CDB_txn_prepare: log_write failed %s\n", CDB_db_strerror(ret));
00421 return (ret);
00422 }
00423
00424 MUTEX_THREAD_LOCK(txnp->mgrp->mutexp);
00425 td->status = TXN_PREPARED;
00426 MUTEX_THREAD_UNLOCK(txnp->mgrp->mutexp);
00427 return (ret);
00428 }
00429
00430
00431
00432
00433 u_int32_t
00434 CDB_txn_id(txnp)
00435 DB_TXN *txnp;
00436 {
00437 return (txnp->txnid);
00438 }
00439
00440
00441
00442
00443
00444
00445 static int
00446 __txn_check_running(txnp, tdp)
00447 const DB_TXN *txnp;
00448 TXN_DETAIL **tdp;
00449 {
00450 DB_TXNMGR *mgrp;
00451 TXN_DETAIL *tp;
00452
00453 tp = NULL;
00454 mgrp = txnp->mgrp;
00455 if (txnp != NULL && mgrp != NULL && mgrp->reginfo.primary != NULL) {
00456 tp = (TXN_DETAIL *)R_ADDR(&mgrp->reginfo, txnp->off);
00457
00458
00459
00460 if (tp->status != TXN_RUNNING &&
00461 tp->status != TXN_PREPARED && tp->status != TXN_COMMITTED)
00462 tp = NULL;
00463 if (tdp != NULL)
00464 *tdp = tp;
00465 }
00466
00467 return (tp == NULL ? EINVAL : 0);
00468 }
00469
00470
00471
00472
00473
00474
00475
00476 int
00477 CDB___txn_end(txnp, is_commit)
00478 DB_TXN *txnp;
00479 int is_commit;
00480 {
00481 DB_ENV *dbenv;
00482 DB_LOCKREQ request;
00483 DB_TXN *kids;
00484 DB_TXNMGR *mgr;
00485 DB_TXNREGION *region;
00486 TXN_DETAIL *tp;
00487 int ret;
00488
00489 mgr = txnp->mgrp;
00490 dbenv = mgr->dbenv;
00491 region = mgr->reginfo.primary;
00492
00493
00494
00495
00496
00497 if (!is_commit) {
00498 while ((kids = TAILQ_FIRST(&txnp->kids)) != NULL)
00499 if ((ret = CDB___txn_end(kids, is_commit)) != 0)
00500 return (DB_RUNRECOVERY);
00501 }
00502
00503
00504 request.op = txnp->parent == NULL ||
00505 is_commit == 0 ? DB_LOCK_PUT_ALL : DB_LOCK_INHERIT;
00506
00507 if (LOCKING_ON(dbenv)) {
00508 ret = CDB_lock_vec(dbenv, txnp->txnid, 0, &request, 1, NULL);
00509 if (ret != 0 && (ret != DB_LOCK_DEADLOCK || is_commit)) {
00510 CDB___db_err(dbenv, "%s: release locks failed %s",
00511 is_commit ? "CDB_txn_commit" : "CDB_txn_abort",
00512 CDB_db_strerror(ret));
00513 return (ret);
00514 }
00515 }
00516
00517
00518 R_LOCK(dbenv, &mgr->reginfo);
00519
00520
00521
00522
00523
00524
00525 tp = (TXN_DETAIL *)R_ADDR(&mgr->reginfo, txnp->off);
00526 if (txnp->parent == NULL || !is_commit) {
00527 SH_TAILQ_REMOVE(®ion->active_txn, tp, links, __txn_detail);
00528
00529 CDB___db_shalloc_free(mgr->reginfo.addr, tp);
00530 } else {
00531 tp->status = TXN_COMMITTED;
00532 F_SET(txnp, TXN_CHILDCOMMIT);
00533 }
00534
00535 if (is_commit)
00536 region->ncommits++;
00537 else
00538 region->naborts++;
00539 --region->nactive;
00540
00541 R_UNLOCK(dbenv, &mgr->reginfo);
00542
00543
00544
00545
00546
00547
00548
00549 if (txnp->parent != NULL) {
00550 if (LOCKING_ON(dbenv))
00551 CDB___lock_freefamilylocker(dbenv->lk_handle, txnp->txnid);
00552 if (!is_commit)
00553 TAILQ_REMOVE(&txnp->parent->kids, txnp, klinks);
00554 }
00555
00556
00557 if (F_ISSET(txnp, TXN_MALLOC) && (txnp->parent == NULL || !is_commit)) {
00558 MUTEX_THREAD_LOCK(mgr->mutexp);
00559 TAILQ_REMOVE(&mgr->txn_chain, txnp, links);
00560 MUTEX_THREAD_UNLOCK(mgr->mutexp);
00561
00562 CDB___os_free(txnp, sizeof(*txnp));
00563 }
00564
00565 return (0);
00566 }
00567
00568
00569
00570
00571
00572
00573 static int
00574 __txn_undo(txnp)
00575 DB_TXN *txnp;
00576 {
00577 DBT rdbt;
00578 DB_ENV *dbenv;
00579 DB_LSN *lsn_array, *key_lsnp;
00580 DB_TXNMGR *mgr;
00581 int ntxns, ret, threaded;
00582
00583 mgr = txnp->mgrp;
00584 dbenv = mgr->dbenv;
00585 lsn_array = NULL;
00586
00587 if (!LOGGING_ON(dbenv))
00588 return (0);
00589
00590
00591
00592
00593
00594
00595 memset(&rdbt, 0, sizeof(rdbt));
00596 threaded = F_ISSET(dbenv, DB_ENV_THREAD) ? 1 : 0;
00597 if (threaded)
00598 F_SET(&rdbt, DB_DBT_MALLOC);
00599
00600 key_lsnp = &txnp->last_lsn;
00601
00602 if (TAILQ_FIRST(&txnp->kids) != NULL) {
00603 if ((ret = __txn_makefamily(dbenv,
00604 txnp, &ntxns, &lsn_array)) != 0)
00605 return (ret);
00606 key_lsnp = &lsn_array[0];
00607 }
00608
00609 for (ret = 0; ret == 0 && !IS_ZERO_LSN(*key_lsnp);) {
00610
00611
00612
00613
00614 if ((ret = CDB_log_get(dbenv, key_lsnp, &rdbt, DB_SET)) == 0) {
00615 ret = mgr->recover(dbenv,
00616 &rdbt, key_lsnp, DB_TXN_ABORT, NULL);
00617 if (threaded && rdbt.data != NULL) {
00618 CDB___os_free(rdbt.data, rdbt.size);
00619 rdbt.data = NULL;
00620 }
00621 if (lsn_array != NULL)
00622 TXN_BUBBLE(lsn_array, ntxns);
00623 }
00624 if (ret != 0) {
00625 CDB___db_err(txnp->mgrp->dbenv,
00626 "CDB_txn_abort: Log undo failed for LSN: %lu %lu: %s",
00627 (u_long)key_lsnp->file, (u_long)key_lsnp->offset,
00628 CDB_db_strerror(ret));
00629 return (ret);
00630 }
00631 }
00632
00633 return (ret);
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 int
00647 CDB_txn_checkpoint(dbenv, kbytes, minutes, flags)
00648 DB_ENV *dbenv;
00649 u_int32_t kbytes, minutes, flags;
00650 {
00651 DB_LOG *dblp;
00652 DB_LSN ckp_lsn, sync_lsn, last_ckp;
00653 DB_TXNMGR *mgr;
00654 DB_TXNREGION *region;
00655 LOG *lp;
00656 TXN_DETAIL *txnp;
00657 time_t last_ckp_time, now;
00658 u_int32_t bytes, mbytes;
00659 int ret;
00660
00661 #ifdef HAVE_RPC
00662 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00663 return (__dbcl_txn_checkpoint(dbenv, kbytes, minutes));
00664 #endif
00665 PANIC_CHECK(dbenv);
00666 ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, DB_INIT_TXN);
00667
00668 mgr = dbenv->tx_handle;
00669 region = mgr->reginfo.primary;
00670 dblp = dbenv->lg_handle;
00671 lp = dblp->reginfo.primary;
00672
00673
00674
00675
00676 ZERO_LSN(ckp_lsn);
00677
00678 if (LF_ISSET(DB_FORCE))
00679 goto do_ckp;
00680
00681 R_LOCK(dbenv, &dblp->reginfo);
00682 mbytes = lp->stat.st_wc_mbytes;
00683 bytes = lp->stat.st_wc_bytes;
00684 ckp_lsn = lp->lsn;
00685 R_UNLOCK(dbenv, &dblp->reginfo);
00686
00687
00688 if (bytes == 0 && mbytes == 0)
00689 return (0);
00690
00691 if (kbytes != 0 && mbytes * 1024 + bytes / 1024 >= (u_int32_t)kbytes)
00692 goto do_ckp;
00693
00694 if (minutes != 0) {
00695 (void)time(&now);
00696
00697 R_LOCK(dbenv, &mgr->reginfo);
00698 last_ckp_time = region->time_ckp;
00699 R_UNLOCK(dbenv, &mgr->reginfo);
00700
00701 if (now - last_ckp_time >= (time_t)(minutes * 60))
00702 goto do_ckp;
00703 }
00704
00705
00706
00707
00708
00709 if (minutes != 0 || kbytes != 0)
00710 return (0);
00711
00712 do_ckp:
00713 if (IS_ZERO_LSN(ckp_lsn)) {
00714 R_LOCK(dbenv, &dblp->reginfo);
00715 ckp_lsn = lp->lsn;
00716 R_UNLOCK(dbenv, &dblp->reginfo);
00717 }
00718
00719
00720
00721
00722
00723 R_LOCK(dbenv, &mgr->reginfo);
00724
00725 if (IS_ZERO_LSN(region->pending_ckp)) {
00726 for (txnp =
00727 SH_TAILQ_FIRST(®ion->active_txn, __txn_detail);
00728 txnp != NULL;
00729 txnp = SH_TAILQ_NEXT(txnp, links, __txn_detail)) {
00730
00731
00732
00733
00734
00735 if (!IS_ZERO_LSN(txnp->begin_lsn) &&
00736 CDB_log_compare(&txnp->begin_lsn, &ckp_lsn) < 0)
00737 ckp_lsn = txnp->begin_lsn;
00738 }
00739 region->pending_ckp = ckp_lsn;
00740 } else
00741 ckp_lsn = region->pending_ckp;
00742
00743 R_UNLOCK(dbenv, &mgr->reginfo);
00744
00745
00746
00747
00748
00749 sync_lsn = ckp_lsn;
00750 if (MPOOL_ON(dbenv) && (ret = CDB_memp_sync(dbenv, &sync_lsn)) != 0) {
00751
00752
00753
00754
00755 if (ret > 0)
00756 CDB___db_err(dbenv,
00757 "CDB_txn_checkpoint: system failure in CDB_memp_sync %s\n",
00758 CDB_db_strerror(ret));
00759 return (ret);
00760 }
00761 if (LOGGING_ON(dbenv)) {
00762 R_LOCK(dbenv, &mgr->reginfo);
00763 last_ckp = region->last_ckp;
00764 ZERO_LSN(region->pending_ckp);
00765 R_UNLOCK(dbenv, &mgr->reginfo);
00766
00767 if ((ret = CDB___txn_ckp_log(dbenv,
00768 NULL, &ckp_lsn, DB_CHECKPOINT, &ckp_lsn,
00769 &last_ckp, (int32_t)time(NULL))) != 0) {
00770 CDB___db_err(dbenv,
00771 "CDB_txn_checkpoint: log failed at LSN [%ld %ld] %s\n",
00772 (long)ckp_lsn.file, (long)ckp_lsn.offset,
00773 CDB_db_strerror(ret));
00774 return (ret);
00775 }
00776
00777 R_LOCK(dbenv, &mgr->reginfo);
00778 region->last_ckp = ckp_lsn;
00779 (void)time(®ion->time_ckp);
00780 R_UNLOCK(dbenv, &mgr->reginfo);
00781 }
00782 return (0);
00783 }
00784
00785 static void
00786 __txn_freekids(txnp)
00787 DB_TXN *txnp;
00788 {
00789 DB_ENV *dbenv;
00790 DB_TXN *kids;
00791 DB_TXNMGR *mgr;
00792 DB_TXNREGION *region;
00793 TXN_DETAIL *tp;
00794
00795 mgr = txnp->mgrp;
00796 dbenv = mgr->dbenv;
00797 region = mgr->reginfo.primary;
00798
00799 for (kids = TAILQ_FIRST(&txnp->kids);
00800 kids != NULL;
00801 kids = TAILQ_FIRST(&txnp->kids)) {
00802
00803 __txn_freekids(kids);
00804
00805
00806 R_LOCK(dbenv, &mgr->reginfo);
00807 tp = (TXN_DETAIL *)R_ADDR(&mgr->reginfo, kids->off);
00808 SH_TAILQ_REMOVE(®ion->active_txn, tp, links, __txn_detail);
00809
00810 CDB___db_shalloc_free(mgr->reginfo.addr, tp);
00811 R_UNLOCK(dbenv, &mgr->reginfo);
00812
00813
00814 TAILQ_REMOVE(&txnp->kids, kids, klinks);
00815 if (F_ISSET(txnp, TXN_MALLOC)) {
00816 MUTEX_THREAD_LOCK(mgr->mutexp);
00817 TAILQ_REMOVE(&mgr->txn_chain, kids, links);
00818 MUTEX_THREAD_UNLOCK(mgr->mutexp);
00819 CDB___os_free(kids, sizeof(*kids));
00820 }
00821 }
00822 }
00823
00824
00825
00826
00827
00828
00829
00830 static int
00831 __txn_makefamily(dbenv, txnp, np, arrayp)
00832 DB_ENV *dbenv;
00833 DB_TXN *txnp;
00834 int *np;
00835 DB_LSN **arrayp;
00836 {
00837 DB_LSN *ap, *tmpp;
00838 int i, ret;
00839
00840
00841 *np = __txn_count(txnp);
00842
00843
00844 if ((ret = CDB___os_malloc(dbenv, *np * sizeof(DB_LSN), NULL, arrayp)) != 0)
00845 return (ret);
00846
00847
00848 tmpp = *arrayp;
00849 __txn_lsn(txnp, &tmpp);
00850
00851
00852 ap = *arrayp;
00853 for (i = 0; i < *np; i++)
00854 TXN_BUBBLE(ap, *np - i);
00855
00856 return (0);
00857 }
00858
00859
00860
00861
00862
00863
00864
00865 static int
00866 __txn_count(txnp)
00867 DB_TXN *txnp;
00868 {
00869 DB_TXN *kids;
00870 int n;
00871
00872 n = 1;
00873 for (kids = TAILQ_FIRST(&txnp->kids);
00874 kids != NULL;
00875 kids = TAILQ_NEXT(kids, klinks))
00876 n += __txn_count(kids);
00877
00878 return (n);
00879 }
00880
00881
00882
00883
00884
00885
00886
00887 static void
00888 __txn_lsn(txnp, array)
00889 DB_TXN *txnp;
00890 DB_LSN **array;
00891 {
00892 DB_LSN *lsn;
00893 DB_TXN *kids;
00894
00895 lsn = *array;
00896 lsn[0] = txnp->last_lsn;
00897 *array = &lsn[1];
00898
00899 for (kids = TAILQ_FIRST(&txnp->kids);
00900 kids != NULL;
00901 kids = TAILQ_NEXT(kids, klinks))
00902 __txn_lsn(kids, array);
00903 }
00904
00905
00906
00907
00908
00909
00910
00911
00912 int
00913 CDB___txn_activekids(txnp)
00914 DB_TXN *txnp;
00915 {
00916 DB_TXN *kids;
00917
00918 for (kids = TAILQ_FIRST(&txnp->kids);
00919 kids != NULL;
00920 kids = TAILQ_NEXT(kids, klinks))
00921 if (!F_ISSET(kids, TXN_CHILDCOMMIT))
00922 return (1);
00923 return (0);
00924 }