1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12
13#include "db_cxx.h"
14#include "dbinc/cxx_int.h"
15
16#include "dbinc/txn.h"
17
18// Helper macro for simple methods that pass through to the
19// underlying C method. It may return an error or raise an exception.
20// Note this macro expects that input _argspec is an argument
21// list element (e.g., "char *arg") and that _arglist is the arguments
22// that should be passed through to the C method (e.g., "(db, arg)")
23//
24#define	DBTXN_METHOD(_name, _delete, _argspec, _arglist)		   \
25int DbTxn::_name _argspec						   \
26{									   \
27	int ret;							   \
28	DB_TXN *txn = unwrap(this);					   \
29	DbEnv *dbenv = DbEnv::get_DbEnv(txn->mgrp->env->dbenv);		   \
30									   \
31	ret = txn->_name _arglist;					   \
32	/* Weird, but safe if we don't access this again. */		   \
33	if (_delete) {							   \
34		/* Can't do this in the destructor. */			   \
35		if (parent_txn_ != NULL)				   \
36			parent_txn_->remove_child_txn(this);		   \
37		delete this;						   \
38	}								   \
39	if (!DB_RETOK_STD(ret))						   \
40		DB_ERROR(dbenv, "DbTxn::" # _name, ret, ON_ERROR_UNKNOWN); \
41	return (ret);							   \
42}
43
44// private constructor, never called but needed by some C++ linkers
45DbTxn::DbTxn(DbTxn *ptxn)
46:	imp_(0)
47{
48	TAILQ_INIT(&children);
49	memset(&child_entry, 0, sizeof(child_entry));
50	parent_txn_ = ptxn;
51	if (parent_txn_ != NULL)
52		parent_txn_->add_child_txn(this);
53}
54
55DbTxn::DbTxn(DB_TXN *txn, DbTxn *ptxn)
56:	imp_(txn)
57{
58	txn->api_internal = this;
59	TAILQ_INIT(&children);
60	memset(&child_entry, 0, sizeof(child_entry));
61	parent_txn_ = ptxn;
62	if (parent_txn_ != NULL)
63		parent_txn_->add_child_txn(this);
64}
65
66DbTxn::~DbTxn()
67{
68	DbTxn *txn, *pnext;
69
70	for(txn = TAILQ_FIRST(&children); txn != NULL;) {
71		pnext = TAILQ_NEXT(txn, child_entry);
72		delete txn;
73		txn = pnext;
74	}
75}
76
77DBTXN_METHOD(abort, 1, (), (txn))
78DBTXN_METHOD(commit, 1, (u_int32_t flags), (txn, flags))
79DBTXN_METHOD(discard, 1, (u_int32_t flags), (txn, flags))
80
81void DbTxn::remove_child_txn(DbTxn *kid)
82{
83	TAILQ_REMOVE(&children, kid, child_entry);
84	kid->set_parent(NULL);
85}
86
87void DbTxn::add_child_txn(DbTxn *kid)
88{
89	TAILQ_INSERT_HEAD(&children, kid, child_entry);
90	kid->set_parent(this);
91}
92
93u_int32_t DbTxn::id()
94{
95	DB_TXN *txn;
96
97	txn = unwrap(this);
98	return (txn->id(txn));		// no error
99}
100
101DBTXN_METHOD(get_name, 0, (const char **namep), (txn, namep))
102DBTXN_METHOD(prepare, 0, (u_int8_t *gid), (txn, gid))
103DBTXN_METHOD(set_name, 0, (const char *name), (txn, name))
104DBTXN_METHOD(set_timeout, 0, (db_timeout_t timeout, u_int32_t flags),
105    (txn, timeout, flags))
106
107// static method
108DbTxn *DbTxn::wrap_DB_TXN(DB_TXN *txn)
109{
110	DbTxn *wrapped_txn = get_DbTxn(txn);
111	// txn may have a valid parent transaction, but here we don't care.
112	// We maintain parent-kid relationship in DbTxn only to make sure
113	// unresolved kids of DbTxn objects are deleted.
114	return (wrapped_txn != NULL) ?  wrapped_txn : new DbTxn(txn, NULL);
115}
116