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