add packaging
[platform/upstream/db4.git] / txn / txn.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996-2009 Oracle.  All rights reserved.
5  */
6 /*
7  * Copyright (c) 1995, 1996
8  *      The President and Fellows of Harvard University.  All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Margo Seltzer.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * $Id$
38  */
39
40 #include "db_config.h"
41
42 #include "db_int.h"
43 #include "dbinc/crypto.h"
44 #include "dbinc/hmac.h"
45 #include "dbinc/db_page.h"
46 #include "dbinc/hash.h"
47 #include "dbinc/lock.h"
48 #include "dbinc/log.h"
49 #include "dbinc/mp.h"
50 #include "dbinc/txn.h"
51
52 #define LOG_FLAGS(txn)                                          \
53                 (DB_LOG_COMMIT | (F_ISSET(txn, TXN_SYNC) ?      \
54                 DB_FLUSH : (F_ISSET(txn, TXN_WRITE_NOSYNC) ?    \
55                 DB_LOG_WRNOSYNC : 0)))
56
57 /*
58  * __txn_isvalid enumerated types.  We cannot simply use the transaction
59  * statuses, because different statuses need to be handled differently
60  * depending on the caller.
61  */
62 typedef enum {
63         TXN_OP_ABORT,
64         TXN_OP_COMMIT,
65         TXN_OP_DISCARD,
66         TXN_OP_PREPARE
67 } txnop_t;
68
69 static int  __txn_abort_pp __P((DB_TXN *));
70 static int  __txn_begin_int __P((DB_TXN *));
71 static int  __txn_commit_pp __P((DB_TXN *, u_int32_t));
72 static int  __txn_discard __P((DB_TXN *, u_int32_t));
73 static int  __txn_dispatch_undo
74                 __P((ENV *, DB_TXN *, DBT *, DB_LSN *, DB_TXNHEAD *));
75 static int  __txn_end __P((DB_TXN *, int));
76 static int  __txn_isvalid __P((const DB_TXN *, txnop_t));
77 static int  __txn_undo __P((DB_TXN *));
78 static void __txn_set_txn_lsnp __P((DB_TXN *, DB_LSN **, DB_LSN **));
79
80 static char *TxnAlloc = "Unable to allocate a transaction handle";
81
82 /*
83  * __txn_begin_pp --
84  *      ENV->txn_begin pre/post processing.
85  *
86  * PUBLIC: int __txn_begin_pp __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t));
87  */
88 int
89 __txn_begin_pp(dbenv, parent, txnpp, flags)
90         DB_ENV *dbenv;
91         DB_TXN *parent, **txnpp;
92         u_int32_t flags;
93 {
94         DB_THREAD_INFO *ip;
95         ENV *env;
96         int rep_check, ret;
97
98         env = dbenv->env;
99
100         ENV_REQUIRES_CONFIG(env, env->tx_handle, "txn_begin", DB_INIT_TXN);
101
102         if ((ret = __db_fchk(env,
103             "txn_begin", flags,
104             DB_READ_COMMITTED | DB_READ_UNCOMMITTED |
105             DB_TXN_NOSYNC | DB_TXN_SNAPSHOT | DB_TXN_SYNC |
106             DB_TXN_WAIT | DB_TXN_WRITE_NOSYNC | DB_TXN_NOWAIT)) != 0)
107                 return (ret);
108         if ((ret = __db_fcchk(env, "txn_begin", flags,
109             DB_TXN_WRITE_NOSYNC | DB_TXN_NOSYNC, DB_TXN_SYNC)) != 0)
110                 return (ret);
111         if ((ret = __db_fcchk(env, "txn_begin",
112             flags, DB_TXN_WRITE_NOSYNC, DB_TXN_NOSYNC)) != 0)
113                 return (ret);
114         if (parent != NULL && !F_ISSET(parent, TXN_SNAPSHOT) &&
115             LF_ISSET(DB_TXN_SNAPSHOT)) {
116                 __db_errx(env,
117                     "Child transaction snapshot setting must match parent");
118                 return (EINVAL);
119         }
120
121         ENV_ENTER(env, ip);
122
123         if (parent == NULL) {
124                 rep_check = IS_ENV_REPLICATED(env) ? 1 : 0;
125                 if (rep_check && (ret = __op_rep_enter(env)) != 0)
126                         goto err;
127         } else
128                 rep_check = 0;
129         ret = __txn_begin(env, ip, parent, txnpp, flags);
130         /*
131          * We only decrement the count if the operation fails.
132          * Otherwise the count will be decremented when the
133          * txn is resolved by txn_commit, txn_abort, etc.
134          */
135         if (ret != 0 && rep_check)
136                 (void)__op_rep_exit(env);
137
138 err:    ENV_LEAVE(env, ip);
139         return (ret);
140 }
141
142 /*
143  * __txn_begin --
144  *      ENV->txn_begin.
145  *
146  * This is a wrapper to the actual begin process.  We allocate a DB_TXN
147  * structure for the caller and then call into __txn_begin_int code.
148  *
149  * Internally, we use TXN_DETAIL structures, but the DB_TXN structure
150  * provides access to the transaction ID and the offset in the transaction
151  * region of the TXN_DETAIL structure.
152  *
153  * PUBLIC: int __txn_begin __P((ENV *,
154  * PUBLIC:      DB_THREAD_INFO *, DB_TXN *, DB_TXN **, u_int32_t));
155  */
156 int
157 __txn_begin(env, ip, parent, txnpp, flags)
158         ENV *env;
159         DB_THREAD_INFO *ip;
160         DB_TXN *parent, **txnpp;
161         u_int32_t flags;
162 {
163         DB_ENV *dbenv;
164         DB_LOCKREGION *region;
165         DB_TXN *txn;
166         TXN_DETAIL *ptd, *td;
167         int ret;
168
169         *txnpp = NULL;
170         if ((ret = __os_calloc(env, 1, sizeof(DB_TXN), &txn)) != 0) {
171                 __db_errx(env, TxnAlloc);
172                 return (ret);
173         }
174
175         dbenv = env->dbenv;
176         txn->mgrp = env->tx_handle;
177         txn->parent = parent;
178         TAILQ_INIT(&txn->kids);
179         TAILQ_INIT(&txn->events);
180         STAILQ_INIT(&txn->logs);
181         txn->flags = TXN_MALLOC;
182         txn->thread_info =
183              ip != NULL ? ip : (parent != NULL ? parent->thread_info : NULL);
184
185         /*
186          * Set the sync mode for commit.  Any local bits override those
187          * in the environment.  SYNC is the default.
188          */
189         if (LF_ISSET(DB_TXN_SYNC))
190                 F_SET(txn, TXN_SYNC);
191         else if (LF_ISSET(DB_TXN_NOSYNC))
192                 F_SET(txn, TXN_NOSYNC);
193         else if (LF_ISSET(DB_TXN_WRITE_NOSYNC))
194                 F_SET(txn, TXN_WRITE_NOSYNC);
195         else if (F_ISSET(dbenv, DB_ENV_TXN_NOSYNC))
196                 F_SET(txn, TXN_NOSYNC);
197         else if (F_ISSET(dbenv, DB_ENV_TXN_WRITE_NOSYNC))
198                 F_SET(txn, TXN_WRITE_NOSYNC);
199         else
200                 F_SET(txn, TXN_SYNC);
201
202         if (LF_ISSET(DB_TXN_NOWAIT) ||
203             (F_ISSET(dbenv, DB_ENV_TXN_NOWAIT) && !LF_ISSET(DB_TXN_WAIT)))
204                 F_SET(txn, TXN_NOWAIT);
205         if (LF_ISSET(DB_READ_COMMITTED))
206                 F_SET(txn, TXN_READ_COMMITTED);
207         if (LF_ISSET(DB_READ_UNCOMMITTED))
208                 F_SET(txn, TXN_READ_UNCOMMITTED);
209         if (LF_ISSET(DB_TXN_SNAPSHOT) || F_ISSET(dbenv, DB_ENV_TXN_SNAPSHOT) ||
210             (parent != NULL && F_ISSET(parent, TXN_SNAPSHOT)))
211                 F_SET(txn, TXN_SNAPSHOT);
212
213         if ((ret = __txn_begin_int(txn)) != 0)
214                 goto err;
215         td = txn->td;
216
217         if (parent != NULL) {
218                 ptd = parent->td;
219                 TAILQ_INSERT_HEAD(&parent->kids, txn, klinks);
220                 SH_TAILQ_INSERT_HEAD(&ptd->kids, td, klinks, __txn_detail);
221         }
222
223         if (LOCKING_ON(env)) {
224                 region = env->lk_handle->reginfo.primary;
225                 if (parent != NULL) {
226                         ret = __lock_inherit_timeout(env,
227                             parent->locker, txn->locker);
228                         /* No parent locker set yet. */
229                         if (ret == EINVAL) {
230                                 parent = NULL;
231                                 ret = 0;
232                         }
233                         if (ret != 0)
234                                 goto err;
235                 }
236
237                 /*
238                  * Parent is NULL if we have no parent
239                  * or it has no timeouts set.
240                  */
241                 if (parent == NULL && region->tx_timeout != 0)
242                         if ((ret = __lock_set_timeout(env, txn->locker,
243                             region->tx_timeout, DB_SET_TXN_TIMEOUT)) != 0)
244                                 goto err;
245         }
246
247         *txnpp = txn;
248         return (0);
249
250 err:
251         __os_free(env, txn);
252         return (ret);
253 }
254
255 /*
256  * __txn_recycle_id --
257  *      Find a range of useable transaction ids.
258  *
259  * PUBLIC: int __txn_recycle_id __P((ENV *));
260  */
261 int
262 __txn_recycle_id(env)
263         ENV *env;
264 {
265         DB_LSN null_lsn;
266         DB_TXNMGR *mgr;
267         DB_TXNREGION *region;
268         TXN_DETAIL *td;
269         u_int32_t *ids;
270         int nids, ret;
271
272         mgr = env->tx_handle;
273         region = mgr->reginfo.primary;
274
275         if ((ret = __os_malloc(env,
276             sizeof(u_int32_t) * region->maxtxns, &ids)) != 0) {
277                 __db_errx(env, "Unable to allocate transaction recycle buffer");
278                 return (ret);
279         }
280         nids = 0;
281         SH_TAILQ_FOREACH(td, &region->active_txn, links, __txn_detail)
282                 ids[nids++] = td->txnid;
283         region->last_txnid = TXN_MINIMUM - 1;
284         region->cur_maxid = TXN_MAXIMUM;
285         if (nids != 0)
286                 __db_idspace(ids, nids,
287                     &region->last_txnid, &region->cur_maxid);
288         __os_free(env, ids);
289
290         /*
291          * Check LOGGING_ON rather than DBENV_LOGGING as we want to emit this
292          * record at the end of recovery.
293          */
294         if (LOGGING_ON(env))
295             ret = __txn_recycle_log(env, NULL, &null_lsn,
296                 0, region->last_txnid + 1, region->cur_maxid);
297
298         return (ret);
299 }
300
301 /*
302  * __txn_compensate_begin
303  *      Begin an compensation transaction.  This is a special interface
304  * that is used only for transactions that must be started to compensate
305  * for actions during an abort.  Currently only used for allocations.
306  *
307  * PUBLIC: int __txn_compensate_begin __P((ENV *, DB_TXN **));
308  */
309 int
310 __txn_compensate_begin(env, txnpp)
311         ENV *env;
312         DB_TXN **txnpp;
313 {
314         DB_TXN *txn;
315         int ret;
316
317         if ((ret = __os_calloc(env, 1, sizeof(DB_TXN), &txn)) != 0) {
318                 __db_errx(env, TxnAlloc);
319                 return (ret);
320         }
321
322         txn->mgrp = env->tx_handle;
323         TAILQ_INIT(&txn->kids);
324         TAILQ_INIT(&txn->events);
325         STAILQ_INIT(&txn->logs);
326         txn->flags = TXN_COMPENSATE | TXN_MALLOC;
327
328         *txnpp = txn;
329         return (__txn_begin_int(txn));
330 }
331
332 /*
333  * __txn_begin_int --
334  *      Normal DB version of txn_begin.
335  */
336 static int
337 __txn_begin_int(txn)
338         DB_TXN *txn;
339 {
340         DB_ENV *dbenv;
341         DB_TXNMGR *mgr;
342         DB_TXNREGION *region;
343         ENV *env;
344         TXN_DETAIL *td;
345         u_int32_t id;
346         int ret;
347
348         mgr = txn->mgrp;
349         env = mgr->env;
350         dbenv = env->dbenv;
351         region = mgr->reginfo.primary;
352
353         TXN_SYSTEM_LOCK(env);
354         if (!F_ISSET(txn, TXN_COMPENSATE) && F_ISSET(region, TXN_IN_RECOVERY)) {
355                 __db_errx(env, "operation not permitted during recovery");
356                 ret = EINVAL;
357                 goto err;
358         }
359
360         /*
361          * Allocate a new transaction id. Our current valid range can span
362          * the maximum valid value, so check for it and wrap manually.
363          */
364         if (region->last_txnid == TXN_MAXIMUM &&
365             region->cur_maxid != TXN_MAXIMUM)
366                 region->last_txnid = TXN_MINIMUM - 1;
367
368         if (region->last_txnid == region->cur_maxid &&
369             (ret = __txn_recycle_id(env)) != 0)
370                 goto err;
371
372         /* Allocate a new transaction detail structure. */
373         if ((ret =
374             __env_alloc(&mgr->reginfo, sizeof(TXN_DETAIL), &td)) != 0) {
375                 __db_errx(env,
376                     "Unable to allocate memory for transaction detail");
377                 goto err;
378         }
379
380         /* Place transaction on active transaction list. */
381         SH_TAILQ_INSERT_HEAD(&region->active_txn, td, links, __txn_detail);
382
383         id = ++region->last_txnid;
384
385 #ifdef HAVE_STATISTICS
386         ++region->stat.st_nbegins;
387         if (++region->stat.st_nactive > region->stat.st_maxnactive)
388                 region->stat.st_maxnactive = region->stat.st_nactive;
389 #endif
390
391         td->txnid = id;
392         dbenv->thread_id(dbenv, &td->pid, &td->tid);
393
394         /* allocate a locker for this txn */
395         if (LOCKING_ON(env) && (ret =
396             __lock_getlocker(env->lk_handle, id, 1, &txn->locker)) != 0)
397                 goto err;
398
399         ZERO_LSN(td->last_lsn);
400         ZERO_LSN(td->begin_lsn);
401         SH_TAILQ_INIT(&td->kids);
402         if (txn->parent != NULL)
403                 td->parent = R_OFFSET(&mgr->reginfo, txn->parent->td);
404         else
405                 td->parent = INVALID_ROFF;
406         td->name = INVALID_ROFF;
407         MAX_LSN(td->read_lsn);
408         MAX_LSN(td->visible_lsn);
409         td->mvcc_ref = 0;
410         td->mvcc_mtx = MUTEX_INVALID;
411         td->status = TXN_RUNNING;
412         td->flags = 0;
413         td->nlog_dbs = 0;
414         td->nlog_slots = TXN_NSLOTS;
415         td->log_dbs = R_OFFSET(&mgr->reginfo, td->slots);
416
417         TXN_SYSTEM_UNLOCK(env);
418
419         txn->txnid = id;
420         txn->td  = td;
421
422         txn->abort = __txn_abort_pp;
423         txn->commit = __txn_commit_pp;
424         txn->discard = __txn_discard;
425         txn->get_name = __txn_get_name;
426         txn->id = __txn_id;
427         txn->prepare = __txn_prepare;
428         txn->set_txn_lsnp = __txn_set_txn_lsnp;
429         txn->set_name = __txn_set_name;
430         txn->set_timeout = __txn_set_timeout;
431
432         /*
433          * If this is a transaction family, we must link the child to the
434          * maximal grandparent in the lock table for deadlock detection.
435          */
436         if (txn->parent != NULL && LOCKING_ON(env))
437                 if ((ret = __lock_addfamilylocker(env,
438                     txn->parent->txnid, txn->txnid)) != 0)
439                         return (ret);
440
441         if (F_ISSET(txn, TXN_MALLOC)) {
442                 MUTEX_LOCK(env, mgr->mutex);
443                 TAILQ_INSERT_TAIL(&mgr->txn_chain, txn, links);
444                 MUTEX_UNLOCK(env, mgr->mutex);
445         }
446
447         return (0);
448
449 err:    TXN_SYSTEM_UNLOCK(env);
450         return (ret);
451 }
452
453 /*
454  * __txn_continue
455  *      Fill in the fields of the local transaction structure given
456  *      the detail transaction structure.
457  *
458  * PUBLIC: int __txn_continue __P((ENV *, DB_TXN *, TXN_DETAIL *));
459  */
460 int
461 __txn_continue(env, txn, td)
462         ENV *env;
463         DB_TXN *txn;
464         TXN_DETAIL *td;
465 {
466         int ret;
467
468         ret = 0;
469
470         txn->mgrp = env->tx_handle;
471         txn->parent = NULL;
472         txn->txnid = td->txnid;
473         txn->td = td;
474
475         txn->abort = __txn_abort_pp;
476         txn->commit = __txn_commit_pp;
477         txn->discard = __txn_discard;
478         txn->get_name = __txn_get_name;
479         txn->id = __txn_id;
480         txn->prepare = __txn_prepare;
481         txn->set_name = __txn_set_name;
482
483         txn->flags = 0;
484         /*
485          * If this is a restored transaction, we need to propagate that fact
486          * to the process-local structure.  However, if it's not a restored
487          * transaction, we need to make sure that we have a locker associated
488          * with this transaction.
489          */
490         if (F_ISSET(td, TXN_DTL_RESTORED))
491                 F_SET(txn, TXN_RESTORED);
492         else
493                 ret = __lock_getlocker(env->lk_handle,
494                     txn->txnid, 0, &txn->locker);
495
496         return (ret);
497 }
498
499 /*
500  * __txn_commit_pp --
501  *      Interface routine to TXN->commit.
502  */
503 static int
504 __txn_commit_pp(txn, flags)
505         DB_TXN *txn;
506         u_int32_t flags;
507 {
508         DB_THREAD_INFO *ip;
509         ENV *env;
510         int not_child, ret, t_ret;
511
512         env = txn->mgrp->env;
513         not_child = txn->parent == NULL;
514
515         ENV_ENTER(env, ip);
516
517         ret = __txn_commit(txn, flags);
518         if (not_child && IS_ENV_REPLICATED(env) &&
519             (t_ret = __op_rep_exit(env)) != 0 && ret == 0)
520                 ret = t_ret;
521         ENV_LEAVE(env, ip);
522         return (ret);
523 }
524
525 /*
526  * __txn_commit --
527  *      Commit a transaction.
528  *
529  * PUBLIC: int __txn_commit __P((DB_TXN *, u_int32_t));
530  */
531 int
532 __txn_commit(txn, flags)
533         DB_TXN *txn;
534         u_int32_t flags;
535 {
536         DBT list_dbt;
537         DB_LOCKREQ request;
538         DB_TXN *kid;
539         ENV *env;
540         REGENV *renv;
541         REGINFO *infop;
542         TXN_DETAIL *td;
543         u_int32_t id;
544         int ret, t_ret;
545
546         env = txn->mgrp->env;
547         td = txn->td;
548
549         /*
550          * A common mistake in Berkeley DB programs is to mis-handle deadlock
551          * return.  If the transaction deadlocked, they want abort, not commit.
552          */
553         if (F_ISSET(txn, TXN_DEADLOCK)) {
554                 ret = __db_txn_deadlock_err(env, txn);
555                 goto err;
556         }
557
558         if ((ret = __txn_isvalid(txn, TXN_OP_COMMIT)) != 0)
559                 return (ret);
560
561         /*
562          * Check for master leases at the beginning.  If we are a
563          * master and cannot have valid leases now, we error and
564          * abort this txn.  There should always be a perm record
565          * in the log because the master writes a checkpoint when it
566          * becomes master if there isn't already a perm record in the log.
567          */
568         if (txn->parent == NULL && IS_REP_MASTER(env) &&
569             IS_USING_LEASES(env) && (ret = __rep_lease_check(env, 1)) != 0) {
570                 DB_ASSERT(env, ret != DB_NOTFOUND);
571                 goto err;
572         }
573
574         infop = env->reginfo;
575         renv = infop->primary;
576         /*
577          * No mutex is needed as envid is read-only once it is set.
578          */
579         id = renv->envid;
580
581         /*
582          * We clear flags that are incorrect, ignoring any flag errors, and
583          * default to synchronous operations.  By definition, transaction
584          * handles are dead when we return, and this error should never
585          * happen, but we don't want to fail in the field 'cause the app is
586          * specifying the wrong flag for some reason.
587          */
588         if (__db_fchk(env, "DB_TXN->commit", flags,
589             DB_TXN_NOSYNC | DB_TXN_SYNC | DB_TXN_WRITE_NOSYNC) != 0)
590                 flags = DB_TXN_SYNC;
591         if (__db_fcchk(env, "DB_TXN->commit", flags,
592             DB_TXN_SYNC, DB_TXN_NOSYNC | DB_TXN_WRITE_NOSYNC) != 0)
593                 flags = DB_TXN_SYNC;
594
595         if (LF_ISSET(DB_TXN_WRITE_NOSYNC)) {
596                 F_CLR(txn, TXN_SYNC_FLAGS);
597                 F_SET(txn, TXN_WRITE_NOSYNC);
598         }
599         if (LF_ISSET(DB_TXN_NOSYNC)) {
600                 F_CLR(txn, TXN_SYNC_FLAGS);
601                 F_SET(txn, TXN_NOSYNC);
602         }
603         if (LF_ISSET(DB_TXN_SYNC)) {
604                 F_CLR(txn, TXN_SYNC_FLAGS);
605                 F_SET(txn, TXN_SYNC);
606         }
607
608         DB_ASSERT(env, F_ISSET(txn, TXN_SYNC_FLAGS));
609
610         /*
611          * Commit any unresolved children.  If anyone fails to commit,
612          * then try to abort the rest of the kids and then abort the parent.
613          * Abort should never fail; if it does, we bail out immediately.
614          */
615         while ((kid = TAILQ_FIRST(&txn->kids)) != NULL)
616                 if ((ret = __txn_commit(kid, flags)) != 0)
617                         while ((kid = TAILQ_FIRST(&txn->kids)) != NULL)
618                                 if ((t_ret = __txn_abort(kid)) != 0)
619                                         return (__env_panic(env, t_ret));
620
621         /*
622          * If there are any log records, write a log record and sync the log,
623          * else do no log writes.  If the commit is for a child transaction,
624          * we do not need to commit the child synchronously since it may still
625          * abort (if its parent aborts), and otherwise its parent or ultimate
626          * ancestor will write synchronously.
627          */
628         if (DBENV_LOGGING(env) && (!IS_ZERO_LSN(td->last_lsn) ||
629             STAILQ_FIRST(&txn->logs) != NULL)) {
630                 if (txn->parent == NULL) {
631                         /*
632                          * We are about to free all the read locks for this
633                          * transaction below.  Some of those locks might be
634                          * handle locks which should not be freed, because
635                          * they will be freed when the handle is closed. Check
636                          * the events and preprocess any trades now so we don't
637                          * release the locks below.
638                          */
639                         if ((ret =
640                             __txn_doevents(env, txn, TXN_PREPARE, 1)) != 0)
641                                 goto err;
642
643                         memset(&request, 0, sizeof(request));
644                         if (LOCKING_ON(env)) {
645                                 request.op = DB_LOCK_PUT_READ;
646                                 if (IS_REP_MASTER(env) &&
647                                     !IS_ZERO_LSN(td->last_lsn)) {
648                                         memset(&list_dbt, 0, sizeof(list_dbt));
649                                         request.obj = &list_dbt;
650                                 }
651                                 ret = __lock_vec(env,
652                                     txn->locker, 0, &request, 1, NULL);
653                         }
654
655                         if (ret == 0 && !IS_ZERO_LSN(td->last_lsn)) {
656                                 ret = __txn_regop_log(env, txn,
657                                     &td->visible_lsn, LOG_FLAGS(txn),
658                                     TXN_COMMIT,
659                                     (int32_t)time(NULL), id, request.obj);
660                                 if (ret == 0)
661                                         td->last_lsn = td->visible_lsn;
662 #ifdef DIAGNOSTIC
663                                 if (ret == 0) {
664                                         DB_LSN s_lsn;
665
666                                         DB_ASSERT(env, __log_current_lsn(
667                                             env, &s_lsn, NULL, NULL) == 0);
668                                         DB_ASSERT(env, LOG_COMPARE(
669                                             &td->visible_lsn, &s_lsn) <= 0);
670                                         COMPQUIET(s_lsn.file, 0);
671                                 }
672 #endif
673                         }
674
675                         if (request.obj != NULL && request.obj->data != NULL)
676                                 __os_free(env, request.obj->data);
677                         if (ret != 0)
678                                 goto err;
679                 } else {
680                         /* Log the commit in the parent! */
681                         if (!IS_ZERO_LSN(td->last_lsn) &&
682                             (ret = __txn_child_log(env, txn->parent,
683                             &((TXN_DETAIL *)txn->parent->td)->last_lsn,
684                             0, txn->txnid, &td->last_lsn)) != 0) {
685                                 goto err;
686                         }
687                         if (STAILQ_FIRST(&txn->logs) != NULL) {
688                                 /*
689                                  * Put the child first so we back it out first.
690                                  * All records are undone in reverse order.
691                                  */
692                                 STAILQ_CONCAT(&txn->logs, &txn->parent->logs);
693                                 txn->parent->logs = txn->logs;
694                                 STAILQ_INIT(&txn->logs);
695                         }
696
697                         F_SET(txn->parent, TXN_CHILDCOMMIT);
698                 }
699         }
700
701         if (txn->txn_list != NULL) {
702                 __db_txnlist_end(env, txn->txn_list);
703                 txn->txn_list = NULL;
704         }
705
706         if (ret != 0)
707                 goto err;
708
709         /*
710          * Check for master leases at the end of only a normal commit.
711          * If we're a child, that is not a perm record.  If we are a
712          * master and cannot get valid leases now, something happened
713          * during the commit.  The only thing to do is panic.
714          */
715         if (txn->parent == NULL && IS_REP_MASTER(env) && IS_USING_LEASES(env) &&
716             (ret = __rep_lease_check(env, 1)) != 0)
717                 return (__env_panic(env, ret));
718
719         /* This is OK because __txn_end can only fail with a panic. */
720         return (__txn_end(txn, 1));
721
722 err:    /*
723          * If we are prepared, then we "must" be able to commit.  We panic here
724          * because even though the coordinator might be able to retry it is not
725          * clear it would know to do that.  Otherwise  we'll try to abort.  If
726          * that is successful, then we return whatever was in ret (that is, the
727          * reason we failed).  If the abort was unsuccessful, abort probably
728          * returned DB_RUNRECOVERY and we need to propagate that up.
729          */
730         if (td->status == TXN_PREPARED)
731                 return (__env_panic(env, ret));
732
733         if ((t_ret = __txn_abort(txn)) != 0)
734                 ret = t_ret;
735         return (ret);
736 }
737
738 /*
739  * __txn_abort_pp --
740  *      Interface routine to TXN->abort.
741  */
742 static int
743 __txn_abort_pp(txn)
744         DB_TXN *txn;
745 {
746         DB_THREAD_INFO *ip;
747         ENV *env;
748         int not_child, ret, t_ret;
749
750         env = txn->mgrp->env;
751         not_child = txn->parent == NULL;
752
753         ENV_ENTER(env, ip);
754
755         ret = __txn_abort(txn);
756         if (not_child && IS_ENV_REPLICATED(env) &&
757             (t_ret = __op_rep_exit(env)) != 0 && ret == 0)
758                 ret = t_ret;
759         ENV_LEAVE(env, ip);
760         return (ret);
761 }
762
763 /*
764  * __txn_abort --
765  *      Abort a transaction.
766  *
767  * PUBLIC: int __txn_abort __P((DB_TXN *));
768  */
769 int
770 __txn_abort(txn)
771         DB_TXN *txn;
772 {
773         DB_LOCKREQ request;
774         DB_TXN *kid;
775         ENV *env;
776         REGENV *renv;
777         REGINFO *infop;
778         TXN_DETAIL *td;
779         u_int32_t id;
780         int ret;
781
782         env = txn->mgrp->env;
783         td = txn->td;
784
785         /* Ensure that abort always fails fatally. */
786         if ((ret = __txn_isvalid(txn, TXN_OP_ABORT)) != 0)
787                 return (__env_panic(env, ret));
788
789         /*
790          * Try to abort any unresolved children.
791          *
792          * Abort either succeeds or panics the region.  As soon as we
793          * see any failure, we just get out of here and return the panic
794          * up.
795          */
796         while ((kid = TAILQ_FIRST(&txn->kids)) != NULL)
797                 if ((ret = __txn_abort(kid)) != 0)
798                         return (ret);
799
800         infop = env->reginfo;
801         renv = infop->primary;
802         /*
803          * No mutex is needed as envid is read-only once it is set.
804          */
805         id = renv->envid;
806
807         /*
808          * Fast path -- no need to do anything fancy if there were no
809          * modifications (e.g., log records) for this transaction.
810          * We still call txn_undo to cleanup the txn_list from our
811          * children.
812          */
813         if (IS_ZERO_LSN(td->last_lsn) && STAILQ_FIRST(&txn->logs) == NULL) {
814                 if (txn->txn_list == NULL)
815                         goto done;
816                 else
817                         goto undo;
818         }
819
820         if (LOCKING_ON(env)) {
821                 /* Allocate a locker for this restored txn if necessary. */
822                 if (txn->locker == NULL &&
823                     (ret = __lock_getlocker(env->lk_handle,
824                     txn->txnid, 1, &txn->locker)) != 0)
825                         return (__env_panic(env, ret));
826                 /*
827                  * We are about to free all the read locks for this transaction
828                  * below.  Some of those locks might be handle locks which
829                  * should not be freed, because they will be freed when the
830                  * handle is closed.  Check the events and preprocess any
831                  * trades now so that we don't release the locks below.
832                  */
833                 if ((ret = __txn_doevents(env, txn, TXN_ABORT, 1)) != 0)
834                         return (__env_panic(env, ret));
835
836                 /* Turn off timeouts. */
837                 if ((ret = __lock_set_timeout(env,
838                     txn->locker, 0, DB_SET_TXN_TIMEOUT)) != 0)
839                         return (__env_panic(env, ret));
840
841                 if ((ret = __lock_set_timeout(env,
842                     txn->locker, 0, DB_SET_LOCK_TIMEOUT)) != 0)
843                         return (__env_panic(env, ret));
844
845                 request.op = DB_LOCK_UPGRADE_WRITE;
846                 request.obj = NULL;
847                 if ((ret = __lock_vec(
848                     env, txn->locker, 0, &request, 1, NULL)) != 0)
849                         return (__env_panic(env, ret));
850         }
851 undo:   if ((ret = __txn_undo(txn)) != 0)
852                 return (__env_panic(env, ret));
853
854         /*
855          * Normally, we do not need to log aborts.  However, if we
856          * are a distributed transaction (i.e., we have a prepare),
857          * then we log the abort so we know that this transaction
858          * was actually completed.
859          */
860 done:    if (DBENV_LOGGING(env) && td->status == TXN_PREPARED &&
861             (ret = __txn_regop_log(env, txn, &td->last_lsn,
862             LOG_FLAGS(txn), TXN_ABORT, (int32_t)time(NULL), id, NULL)) != 0)
863                 return (__env_panic(env, ret));
864
865         /* __txn_end always panics if it errors, so pass the return along. */
866         return (__txn_end(txn, 0));
867 }
868
869 /*
870  * __txn_discard --
871  *      Interface routine to TXN->discard.
872  */
873 static int
874 __txn_discard(txn, flags)
875         DB_TXN *txn;
876         u_int32_t flags;
877 {
878         DB_THREAD_INFO *ip;
879         ENV *env;
880         int ret, t_ret;
881
882         env = txn->mgrp->env;
883
884         ENV_ENTER(env, ip);
885         ret = __txn_discard_int(txn, flags);
886         if (IS_ENV_REPLICATED(env) &&
887             (t_ret = __op_rep_exit(env)) != 0 && ret == 0)
888                 ret = t_ret;
889         ENV_LEAVE(env, ip);
890         return (ret);
891 }
892
893 /*
894  * __txn_discard --
895  *      Free the per-process resources associated with this txn handle.
896  *
897  * PUBLIC: int __txn_discard_int __P((DB_TXN *, u_int32_t flags));
898  */
899 int
900 __txn_discard_int(txn, flags)
901         DB_TXN *txn;
902         u_int32_t flags;
903 {
904         DB_TXN *freep;
905         DB_TXNMGR *mgr;
906         ENV *env;
907         int ret;
908
909         COMPQUIET(flags, 0);
910
911         mgr = txn->mgrp;
912         env = mgr->env;
913         freep = NULL;
914
915         if ((ret = __txn_isvalid(txn, TXN_OP_DISCARD)) != 0)
916                 return (ret);
917
918         /* Should be no children. */
919         DB_ASSERT(env, TAILQ_FIRST(&txn->kids) == NULL);
920
921         /* Free the space. */
922         MUTEX_LOCK(env, mgr->mutex);
923         mgr->n_discards++;
924         if (F_ISSET(txn, TXN_MALLOC)) {
925                 TAILQ_REMOVE(&mgr->txn_chain, txn, links);
926                 freep = txn;
927         }
928         MUTEX_UNLOCK(env, mgr->mutex);
929         if (freep != NULL)
930                 __os_free(env, freep);
931
932         return (0);
933 }
934
935 /*
936  * __txn_prepare --
937  *      Flush the log so a future commit is guaranteed to succeed.
938  *
939  * PUBLIC: int __txn_prepare __P((DB_TXN *, u_int8_t *));
940  */
941 int
942 __txn_prepare(txn, gid)
943         DB_TXN *txn;
944         u_int8_t *gid;
945 {
946         DBT list_dbt, gid_dbt;
947         DB_LOCKREQ request;
948         DB_THREAD_INFO *ip;
949         DB_TXN *kid;
950         ENV *env;
951         TXN_DETAIL *td;
952         u_int32_t lflags;
953         int ret;
954
955         env = txn->mgrp->env;
956         td = txn->td;
957
958         if ((ret = __txn_isvalid(txn, TXN_OP_PREPARE)) != 0)
959                 return (ret);
960         if (F_ISSET(txn, TXN_DEADLOCK))
961                 return (__db_txn_deadlock_err(env, txn));
962
963         ENV_ENTER(env, ip);
964
965         /* Commit any unresolved children. */
966         while ((kid = TAILQ_FIRST(&txn->kids)) != NULL)
967                 if ((ret = __txn_commit(kid, DB_TXN_NOSYNC)) != 0)
968                         goto err;
969
970         /* We must set the global transaction ID here.  */
971         memcpy(td->gid, gid, DB_GID_SIZE);
972         if ((ret = __txn_doevents(env, txn, TXN_PREPARE, 1)) != 0)
973                 goto err;
974         memset(&request, 0, sizeof(request));
975         if (LOCKING_ON(env)) {
976                 request.op = DB_LOCK_PUT_READ;
977                 if (!IS_ZERO_LSN(td->last_lsn)) {
978                         memset(&list_dbt, 0, sizeof(list_dbt));
979                         request.obj = &list_dbt;
980                 }
981                 if ((ret = __lock_vec(env,
982                     txn->locker, 0, &request, 1, NULL)) != 0)
983                         goto err;
984
985         }
986         if (DBENV_LOGGING(env)) {
987                 memset(&gid_dbt, 0, sizeof(gid));
988                 gid_dbt.data = gid;
989                 gid_dbt.size = DB_GID_SIZE;
990                 lflags = DB_LOG_COMMIT | DB_FLUSH;
991                 if ((ret = __txn_prepare_log(env,
992                     txn, &td->last_lsn, lflags, TXN_PREPARE,
993                     &gid_dbt, &td->begin_lsn, request.obj)) != 0)
994                         __db_err(
995                             env, ret, "DB_TXN->prepare: log_write failed");
996
997                 if (request.obj != NULL && request.obj->data != NULL)
998                         __os_free(env, request.obj->data);
999                 if (ret != 0)
1000                         goto err;
1001
1002         }
1003
1004         MUTEX_LOCK(env, txn->mgrp->mutex);
1005         td->status = TXN_PREPARED;
1006         MUTEX_UNLOCK(env, txn->mgrp->mutex);
1007 err:    ENV_LEAVE(env, ip);
1008         return (ret);
1009 }
1010
1011 /*
1012  * __txn_id --
1013  *      Return the transaction ID.
1014  *
1015  * PUBLIC: u_int32_t __txn_id __P((DB_TXN *));
1016  */
1017 u_int32_t
1018 __txn_id(txn)
1019         DB_TXN *txn;
1020 {
1021         return (txn->txnid);
1022 }
1023
1024 /*
1025  * __txn_get_name --
1026  *      Get a descriptive string from a transaction.
1027  *
1028  * PUBLIC: int __txn_get_name __P((DB_TXN *, const char **));
1029  */
1030 int
1031 __txn_get_name(txn, namep)
1032         DB_TXN *txn;
1033         const char **namep;
1034 {
1035         *namep = txn->name;
1036
1037         return (0);
1038 }
1039
1040 /*
1041  * __txn_set_name --
1042  *      Set a descriptive string for a transaction.
1043  *
1044  * PUBLIC: int __txn_set_name __P((DB_TXN *, const char *));
1045  */
1046 int
1047 __txn_set_name(txn, name)
1048         DB_TXN *txn;
1049         const char *name;
1050 {
1051         DB_THREAD_INFO *ip;
1052         DB_TXNMGR *mgr;
1053         ENV *env;
1054         TXN_DETAIL *td;
1055         size_t len;
1056         int ret;
1057         char *p;
1058
1059         mgr = txn->mgrp;
1060         env = mgr->env;
1061         td = txn->td;
1062         len = strlen(name) + 1;
1063
1064         if ((ret = __os_realloc(env, len, &txn->name)) != 0)
1065                 return (ret);
1066         memcpy(txn->name, name, len);
1067
1068         ENV_ENTER(env, ip);
1069         TXN_SYSTEM_LOCK(env);
1070         if (td->name != INVALID_ROFF) {
1071                 __env_alloc_free(
1072                     &mgr->reginfo, R_ADDR(&mgr->reginfo, td->name));
1073                 td->name = INVALID_ROFF;
1074         }
1075         if ((ret = __env_alloc(&mgr->reginfo, len, &p)) != 0) {
1076                 TXN_SYSTEM_UNLOCK(env);
1077                 __db_errx(env,
1078                     "Unable to allocate memory for transaction name");
1079
1080                 __os_free(env, txn->name);
1081                 txn->name = NULL;
1082
1083                 ENV_LEAVE(env, ip);
1084                 return (ret);
1085         }
1086         TXN_SYSTEM_UNLOCK(env);
1087         td->name = R_OFFSET(&mgr->reginfo, p);
1088         memcpy(p, name, len);
1089
1090 #ifdef DIAGNOSTIC
1091         /*
1092          * If DIAGNOSTIC is set, map the name into the log so users can track
1093          * operations through the log.
1094          */
1095         if (DBENV_LOGGING(env))
1096                 (void)__log_printf(env, txn,
1097                     "transaction %#lx named %s", (u_long)txn->txnid, name);
1098 #endif
1099
1100         ENV_LEAVE(env, ip);
1101         return (0);
1102 }
1103
1104 /*
1105  * __txn_set_timeout --
1106  *      ENV->set_txn_timeout.
1107  * PUBLIC: int  __txn_set_timeout __P((DB_TXN *, db_timeout_t, u_int32_t));
1108  */
1109 int
1110 __txn_set_timeout(txn, timeout, op)
1111         DB_TXN *txn;
1112         db_timeout_t timeout;
1113         u_int32_t op;
1114 {
1115         DB_THREAD_INFO *ip;
1116         ENV *env;
1117         int ret;
1118
1119         env = txn->mgrp->env;
1120
1121         if (op != DB_SET_TXN_TIMEOUT && op != DB_SET_LOCK_TIMEOUT)
1122                 return (__db_ferr(env, "DB_TXN->set_timeout", 0));
1123
1124         ENV_ENTER(env, ip);
1125         ret = __lock_set_timeout( env, txn->locker, timeout, op);
1126         ENV_LEAVE(txn->mgrp->env, ip);
1127         return (ret);
1128 }
1129
1130 /*
1131  * __txn_isvalid --
1132  *      Return 0 if the DB_TXN is reasonable, otherwise panic.
1133  */
1134 static int
1135 __txn_isvalid(txn, op)
1136         const DB_TXN *txn;
1137         txnop_t op;
1138 {
1139         DB_TXNMGR *mgr;
1140         DB_TXNREGION *region;
1141         ENV *env;
1142         TXN_DETAIL *td;
1143
1144         mgr = txn->mgrp;
1145         env = mgr->env;
1146         region = mgr->reginfo.primary;
1147
1148         /* Check for recovery. */
1149         if (!F_ISSET(txn, TXN_COMPENSATE) &&
1150             F_ISSET(region, TXN_IN_RECOVERY)) {
1151                 __db_errx(env, "operation not permitted during recovery");
1152                 goto err;
1153         }
1154
1155         /* Check for live cursors. */
1156         if (txn->cursors != 0) {
1157                 __db_errx(env, "transaction has active cursors");
1158                 goto err;
1159         }
1160
1161         /* Check transaction's state. */
1162         td = txn->td;
1163
1164         /* Handle any operation specific checks. */
1165         switch (op) {
1166         case TXN_OP_DISCARD:
1167                 /*
1168                  * Since we're just tossing the per-process space; there are
1169                  * a lot of problems with the transaction that we can tolerate.
1170                  */
1171
1172                 /* Transaction is already been reused. */
1173                 if (txn->txnid != td->txnid)
1174                         return (0);
1175
1176                 /*
1177                  * What we've got had better be either a prepared or
1178                  * restored transaction.
1179                  */
1180                 if (td->status != TXN_PREPARED &&
1181                     !F_ISSET(td, TXN_DTL_RESTORED)) {
1182                         __db_errx(env, "not a restored transaction");
1183                         return (__env_panic(env, EINVAL));
1184                 }
1185
1186                 return (0);
1187         case TXN_OP_PREPARE:
1188                 if (txn->parent != NULL) {
1189                         /*
1190                          * This is not fatal, because you could imagine an
1191                          * application that simply prepares everybody because
1192                          * it doesn't distinguish between children and parents.
1193                          * I'm not arguing this is good, but I could imagine
1194                          * someone doing it.
1195                          */
1196                         __db_errx(env,
1197                             "Prepare disallowed on child transactions");
1198                         return (EINVAL);
1199                 }
1200                 break;
1201         case TXN_OP_ABORT:
1202         case TXN_OP_COMMIT:
1203         default:
1204                 break;
1205         }
1206
1207         switch (td->status) {
1208         case TXN_PREPARED:
1209                 if (op == TXN_OP_PREPARE) {
1210                         __db_errx(env, "transaction already prepared");
1211                         /*
1212                          * Txn_prepare doesn't blow away the user handle, so
1213                          * in this case, give the user the opportunity to
1214                          * abort or commit.
1215                          */
1216                         return (EINVAL);
1217                 }
1218                 break;
1219         case TXN_RUNNING:
1220                 break;
1221         case TXN_ABORTED:
1222         case TXN_COMMITTED:
1223         default:
1224                 __db_errx(env, "transaction already %s",
1225                     td->status == TXN_COMMITTED ? "committed" : "aborted");
1226                 goto err;
1227         }
1228
1229         return (0);
1230
1231 err:    /*
1232          * If there's a serious problem with the transaction, panic.  TXN
1233          * handles are dead by definition when we return, and if you use
1234          * a cursor you forgot to close, we have no idea what will happen.
1235          */
1236         return (__env_panic(env, EINVAL));
1237 }
1238
1239 /*
1240  * __txn_end --
1241  *      Internal transaction end routine.
1242  */
1243 static int
1244 __txn_end(txn, is_commit)
1245         DB_TXN *txn;
1246         int is_commit;
1247 {
1248         DB_LOCKREQ request;
1249         DB_TXNLOGREC *lr;
1250         DB_TXNMGR *mgr;
1251         DB_TXNREGION *region;
1252         ENV *env;
1253         TXN_DETAIL *ptd, *td;
1254         db_mutex_t mvcc_mtx;
1255         int do_closefiles, ret;
1256
1257         mgr = txn->mgrp;
1258         env = mgr->env;
1259         region = mgr->reginfo.primary;
1260         do_closefiles = 0;
1261
1262         /* Process commit events. */
1263         if ((ret = __txn_doevents(env,
1264             txn, is_commit ? TXN_COMMIT : TXN_ABORT, 0)) != 0)
1265                 return (__env_panic(env, ret));
1266
1267         /*
1268          * Release the locks.
1269          *
1270          * __txn_end cannot return an simple error, we MUST return
1271          * success/failure from commit or abort, ignoring any internal
1272          * errors.  So, we panic if something goes wrong.  We can't
1273          * deadlock here because we're not acquiring any new locks,
1274          * so DB_LOCK_DEADLOCK is just as fatal as any other error.
1275          */
1276         if (LOCKING_ON(env)) {
1277                 /* Allocate a locker for this restored txn if necessary. */
1278                 if (txn->locker == NULL &&
1279                     (ret = __lock_getlocker(env->lk_handle,
1280                     txn->txnid, 1, &txn->locker)) != 0)
1281                         return (__env_panic(env, ret));
1282                 request.op = txn->parent == NULL ||
1283                     is_commit == 0 ? DB_LOCK_PUT_ALL : DB_LOCK_INHERIT;
1284                 request.obj = NULL;
1285                 if ((ret = __lock_vec(env,
1286                     txn->locker, 0, &request, 1, NULL)) != 0)
1287                         return (__env_panic(env, ret));
1288         }
1289
1290         /* End the transaction. */
1291         td = txn->td;
1292         if (td->nlog_dbs != 0 && (ret = __txn_dref_fname(env, txn)) != 0)
1293                 return (__env_panic(env, ret));
1294
1295         if (td->mvcc_ref != 0 && IS_MAX_LSN(td->visible_lsn)) {
1296                 /*
1297                  * Some pages were dirtied but nothing was logged.  This can
1298                  * happen easily if we are aborting, but there are also cases
1299                  * in the compact code where pages are dirtied unconditionally
1300                  * and then we find out that there is no work to do.
1301                  *
1302                  * We need to make sure that the versions become visible to
1303                  * future transactions.  We need to set visible_lsn before
1304                  * setting td->status to ensure safe reads of visible_lsn in
1305                  * __memp_fget.
1306                  */
1307                 if ((ret = __log_current_lsn(env, &td->visible_lsn,
1308                     NULL, NULL)) != 0)
1309                         return (__env_panic(env, ret));
1310         }
1311
1312         TXN_SYSTEM_LOCK(env);
1313         td->status = is_commit ? TXN_COMMITTED : TXN_ABORTED;
1314         SH_TAILQ_REMOVE(&region->active_txn, td, links, __txn_detail);
1315         if (F_ISSET(td, TXN_DTL_RESTORED)) {
1316                 region->stat.st_nrestores--;
1317                 do_closefiles = region->stat.st_nrestores == 0;
1318         }
1319
1320         if (td->name != INVALID_ROFF) {
1321                 __env_alloc_free(&mgr->reginfo,
1322                     R_ADDR(&mgr->reginfo, td->name));
1323                 td->name = INVALID_ROFF;
1324         }
1325         if (td->nlog_slots != TXN_NSLOTS)
1326                 __env_alloc_free(&mgr->reginfo,
1327                     R_ADDR(&mgr->reginfo, td->log_dbs));
1328
1329         if (txn->parent != NULL) {
1330                 ptd = txn->parent->td;
1331                 SH_TAILQ_REMOVE(&ptd->kids, td, klinks, __txn_detail);
1332         } else if ((mvcc_mtx = td->mvcc_mtx) != MUTEX_INVALID) {
1333                 MUTEX_LOCK(env, mvcc_mtx);
1334                 if (td->mvcc_ref != 0) {
1335                         SH_TAILQ_INSERT_HEAD(&region->mvcc_txn,
1336                             td, links, __txn_detail);
1337
1338                         /*
1339                          * The transaction has been added to the list of
1340                          * committed snapshot transactions with active pages.
1341                          * It needs to be freed when the last page is evicted.
1342                          */
1343                         F_SET(td, TXN_DTL_SNAPSHOT);
1344 #ifdef HAVE_STATISTICS
1345                         if (++region->stat.st_nsnapshot >
1346                             region->stat.st_maxnsnapshot)
1347                                 region->stat.st_maxnsnapshot =
1348                                     region->stat.st_nsnapshot;
1349 #endif
1350                         td = NULL;
1351                 }
1352                 MUTEX_UNLOCK(env, mvcc_mtx);
1353                 if (td != NULL)
1354                         if ((ret = __mutex_free(env, &td->mvcc_mtx)) != 0)
1355                                 return (__env_panic(env, ret));
1356         }
1357
1358         if (td != NULL)
1359                 __env_alloc_free(&mgr->reginfo, td);
1360
1361 #ifdef HAVE_STATISTICS
1362         if (is_commit)
1363                 region->stat.st_ncommits++;
1364         else
1365                 region->stat.st_naborts++;
1366         --region->stat.st_nactive;
1367 #endif
1368
1369         TXN_SYSTEM_UNLOCK(env);
1370
1371         /*
1372          * The transaction cannot get more locks, remove its locker info,
1373          * if any.
1374          */
1375         if (LOCKING_ON(env) && (ret =
1376             __lock_freefamilylocker(env->lk_handle, txn->locker)) != 0)
1377                 return (__env_panic(env, ret));
1378         if (txn->parent != NULL)
1379                 TAILQ_REMOVE(&txn->parent->kids, txn, klinks);
1380
1381         /* Free the space. */
1382         while ((lr = STAILQ_FIRST(&txn->logs)) != NULL) {
1383                 STAILQ_REMOVE(&txn->logs, lr, __txn_logrec, links);
1384                 __os_free(env, lr);
1385         }
1386         if (txn->name != NULL) {
1387                 __os_free(env, txn->name);
1388                 txn->name = NULL;
1389         }
1390         if (F_ISSET(txn, TXN_MALLOC)) {
1391                 MUTEX_LOCK(env, mgr->mutex);
1392                 TAILQ_REMOVE(&mgr->txn_chain, txn, links);
1393                 MUTEX_UNLOCK(env, mgr->mutex);
1394
1395                 __os_free(env, txn);
1396         }
1397
1398         if (do_closefiles) {
1399                 /*
1400                  * Otherwise, we have resolved the last outstanding prepared
1401                  * txn and need to invalidate the fileids that were left
1402                  * open for those txns and then close them.
1403                  */
1404                 (void)__dbreg_invalidate_files(env, 1);
1405                 (void)__dbreg_close_files(env, 1);
1406                 if (IS_REP_MASTER(env))
1407                         F_CLR(env->rep_handle, DBREP_OPENFILES);
1408                 F_CLR(env->lg_handle, DBLOG_OPENFILES);
1409                 mgr->n_discards = 0;
1410                 (void)__txn_checkpoint(env, 0, 0,
1411                     DB_CKP_INTERNAL | DB_FORCE);
1412         }
1413
1414         return (0);
1415 }
1416
1417 static int
1418 __txn_dispatch_undo(env, txn, rdbt, key_lsn, txnlist)
1419         ENV *env;
1420         DB_TXN *txn;
1421         DBT *rdbt;
1422         DB_LSN *key_lsn;
1423         DB_TXNHEAD *txnlist;
1424 {
1425         int ret;
1426
1427         txnlist->td = txn->td;
1428         ret = __db_dispatch(env, &env->recover_dtab,
1429             rdbt, key_lsn, DB_TXN_ABORT, txnlist);
1430         if (ret == DB_SURPRISE_KID) {
1431                 F_SET(txn, TXN_CHILDCOMMIT);
1432                 ret = 0;
1433         }
1434         if (ret == 0 && F_ISSET(txn, TXN_CHILDCOMMIT) && IS_ZERO_LSN(*key_lsn))
1435                 ret = __db_txnlist_lsnget(env, txnlist, key_lsn, 0);
1436
1437         return (ret);
1438 }
1439
1440 /*
1441  * __txn_undo --
1442  *      Undo the transaction with id txnid.
1443  */
1444 static int
1445 __txn_undo(txn)
1446         DB_TXN *txn;
1447 {
1448         DBT rdbt;
1449         DB_LOGC *logc;
1450         DB_LSN key_lsn;
1451         DB_TXN *ptxn;
1452         DB_TXNHEAD *txnlist;
1453         DB_TXNLOGREC *lr;
1454         DB_TXNMGR *mgr;
1455         ENV *env;
1456         int ret, t_ret;
1457
1458         mgr = txn->mgrp;
1459         env = mgr->env;
1460         logc = NULL;
1461         txnlist = NULL;
1462         ret = 0;
1463
1464         if (!LOGGING_ON(env))
1465                 return (0);
1466
1467         /*
1468          * This is the simplest way to code this, but if the mallocs during
1469          * recovery turn out to be a performance issue, we can do the
1470          * allocation here and use DB_DBT_USERMEM.
1471          */
1472         memset(&rdbt, 0, sizeof(rdbt));
1473
1474         /*
1475          * Allocate a txnlist for children and aborted page allocs.
1476          * We need to associate the list with the maximal parent
1477          * so that aborted pages are recovered when that transaction
1478          * is committed or aborted.
1479          */
1480         for (ptxn = txn->parent; ptxn != NULL && ptxn->parent != NULL;)
1481                 ptxn = ptxn->parent;
1482
1483         if (ptxn != NULL && ptxn->txn_list != NULL)
1484                 txnlist = ptxn->txn_list;
1485         else if (txn->txn_list != NULL)
1486                 txnlist = txn->txn_list;
1487         else if ((ret = __db_txnlist_init(env,
1488             txn->thread_info, 0, 0, NULL, &txnlist)) != 0)
1489                 return (ret);
1490         else if (ptxn != NULL)
1491                 ptxn->txn_list = txnlist;
1492
1493         /*
1494          * Take log records from the linked list stored in the transaction,
1495          * then from the log.
1496          */
1497         STAILQ_FOREACH(lr, &txn->logs, links) {
1498                 rdbt.data = lr->data;
1499                 rdbt.size = 0;
1500                 LSN_NOT_LOGGED(key_lsn);
1501                 ret =
1502                     __txn_dispatch_undo(env, txn, &rdbt, &key_lsn, txnlist);
1503                 if (ret != 0) {
1504                         __db_err(env, ret,
1505                             "DB_TXN->abort: in-memory log undo failed");
1506                         goto err;
1507                 }
1508         }
1509
1510         key_lsn = ((TXN_DETAIL *)txn->td)->last_lsn;
1511
1512         if (!IS_ZERO_LSN(key_lsn) &&
1513              (ret = __log_cursor(env, &logc)) != 0)
1514                 goto err;
1515
1516         while (!IS_ZERO_LSN(key_lsn)) {
1517                 /*
1518                  * The dispatch routine returns the lsn of the record
1519                  * before the current one in the key_lsn argument.
1520                  */
1521                 if ((ret = __logc_get(logc, &key_lsn, &rdbt, DB_SET)) == 0) {
1522                         ret = __txn_dispatch_undo(env,
1523                             txn, &rdbt, &key_lsn, txnlist);
1524                 }
1525
1526                 if (ret != 0) {
1527                         __db_err(env, ret,
1528                     "DB_TXN->abort: log undo failed for LSN: %lu %lu",
1529                             (u_long)key_lsn.file, (u_long)key_lsn.offset);
1530                         goto err;
1531                 }
1532         }
1533
1534 err:    if (logc != NULL && (t_ret = __logc_close(logc)) != 0 && ret == 0)
1535                 ret = t_ret;
1536
1537         if (ptxn == NULL && txnlist != NULL)
1538                 __db_txnlist_end(env, txnlist);
1539         return (ret);
1540 }
1541
1542 /*
1543  * __txn_activekids --
1544  *      Return if this transaction has any active children.
1545  *
1546  * PUBLIC: int __txn_activekids __P((ENV *, u_int32_t, DB_TXN *));
1547  */
1548 int
1549 __txn_activekids(env, rectype, txn)
1550         ENV *env;
1551         u_int32_t rectype;
1552         DB_TXN *txn;
1553 {
1554         /*
1555          * On a child commit, we know that there are children (i.e., the
1556          * committing child at the least.  In that case, skip this check.
1557          */
1558         if (F_ISSET(txn, TXN_COMPENSATE) || rectype == DB___txn_child)
1559                 return (0);
1560
1561         if (TAILQ_FIRST(&txn->kids) != NULL) {
1562                 __db_errx(env, "Child transaction is active");
1563                 return (EPERM);
1564         }
1565         return (0);
1566 }
1567
1568 /*
1569  * __txn_force_abort --
1570  *      Force an abort record into the log if the commit record
1571  *      failed to get to disk.
1572  *
1573  * PUBLIC: int __txn_force_abort __P((ENV *, u_int8_t *));
1574  */
1575 int
1576 __txn_force_abort(env, buffer)
1577         ENV *env;
1578         u_int8_t *buffer;
1579 {
1580         DB_CIPHER *db_cipher;
1581         HDR hdr, *hdrp;
1582         u_int32_t offset, opcode, sum_len;
1583         u_int8_t *bp, *key, chksum[DB_MAC_KEY];
1584         size_t hdrsize, rec_len;
1585         int ret;
1586
1587         db_cipher = env->crypto_handle;
1588
1589         /*
1590          * This routine depends on the layout of HDR and the __txn_regop
1591          * record in txn.src.  We are passed the beginning of the commit
1592          * record in the log buffer and overwrite the commit with an abort
1593          * and recalculate the checksum.
1594          */
1595         hdrsize = CRYPTO_ON(env) ? HDR_CRYPTO_SZ : HDR_NORMAL_SZ;
1596
1597         hdrp = (HDR *)buffer;
1598         memcpy(&hdr.prev, buffer + SSZ(HDR, prev), sizeof(hdr.prev));
1599         memcpy(&hdr.len, buffer + SSZ(HDR, len), sizeof(hdr.len));
1600         rec_len = hdr.len - hdrsize;
1601
1602         offset = sizeof(u_int32_t) + sizeof(u_int32_t) + sizeof(DB_LSN);
1603         if (CRYPTO_ON(env)) {
1604                 key = db_cipher->mac_key;
1605                 sum_len = DB_MAC_KEY;
1606                 if ((ret = db_cipher->decrypt(env, db_cipher->data,
1607                     &hdrp->iv[0], buffer + hdrsize, rec_len)) != 0)
1608                         return (__env_panic(env, ret));
1609         } else {
1610                 key = NULL;
1611                 sum_len = sizeof(u_int32_t);
1612         }
1613         bp = buffer + hdrsize + offset;
1614         opcode = TXN_ABORT;
1615         memcpy(bp, &opcode, sizeof(opcode));
1616
1617         if (CRYPTO_ON(env) &&
1618             (ret = db_cipher->encrypt(env,
1619             db_cipher->data, &hdrp->iv[0], buffer + hdrsize, rec_len)) != 0)
1620                 return (__env_panic(env, ret));
1621
1622         __db_chksum(&hdr, buffer + hdrsize, rec_len, key, chksum);
1623         memcpy(buffer + SSZA(HDR, chksum), chksum, sum_len);
1624
1625         return (0);
1626 }
1627
1628 /*
1629  * __txn_preclose --
1630  *      Before we can close an environment, we need to check if we were in the
1631  *      middle of taking care of restored transactions.  If so, close the files
1632  *      we opened.
1633  *
1634  * PUBLIC: int __txn_preclose __P((ENV *));
1635  */
1636 int
1637 __txn_preclose(env)
1638         ENV *env;
1639 {
1640         DB_TXNMGR *mgr;
1641         DB_TXNREGION *region;
1642         int do_closefiles, ret;
1643
1644         mgr = env->tx_handle;
1645         region = mgr->reginfo.primary;
1646         do_closefiles = 0;
1647
1648         TXN_SYSTEM_LOCK(env);
1649         if (region != NULL &&
1650             region->stat.st_nrestores <= mgr->n_discards &&
1651             mgr->n_discards != 0)
1652                 do_closefiles = 1;
1653         TXN_SYSTEM_UNLOCK(env);
1654
1655         if (do_closefiles) {
1656                 /*
1657                  * Set the DBLOG_RECOVER flag while closing these files so they
1658                  * do not create additional log records that will confuse future
1659                  * recoveries.
1660                  */
1661                 F_SET(env->lg_handle, DBLOG_RECOVER);
1662                 ret = __dbreg_close_files(env, 0);
1663                 F_CLR(env->lg_handle, DBLOG_RECOVER);
1664         } else
1665                 ret = 0;
1666
1667         return (ret);
1668 }
1669
1670 /*
1671  * __txn_reset --
1672  *      Reset the last txnid to its minimum value, and log the reset.
1673  *
1674  * PUBLIC: int __txn_reset __P((ENV *));
1675  */
1676 int
1677 __txn_reset(env)
1678         ENV *env;
1679 {
1680         DB_LSN scrap;
1681         DB_TXNREGION *region;
1682
1683         region = env->tx_handle->reginfo.primary;
1684         region->last_txnid = TXN_MINIMUM;
1685
1686         DB_ASSERT(env, LOGGING_ON(env));
1687         return (__txn_recycle_log(env,
1688             NULL, &scrap, 0, TXN_MINIMUM, TXN_MAXIMUM));
1689 }
1690
1691 /*
1692  * txn_set_txn_lsnp --
1693  *      Set the pointer to the begin_lsn field if that field is zero.
1694  *      Set the pointer to the last_lsn field.
1695  */
1696 static void
1697 __txn_set_txn_lsnp(txn, blsnp, llsnp)
1698         DB_TXN *txn;
1699         DB_LSN **blsnp, **llsnp;
1700 {
1701         TXN_DETAIL *td;
1702
1703         td = txn->td;
1704         *llsnp = &td->last_lsn;
1705
1706         while (txn->parent != NULL)
1707                 txn = txn->parent;
1708
1709         td = txn->td;
1710         if (IS_ZERO_LSN(td->begin_lsn))
1711                 *blsnp = &td->begin_lsn;
1712 }