Listing 3
template< class TDatabaseEnvironment >
class CTransaction
{
public:
inline explicit CTransaction
(
CTransaction< TDatabaseEnvironment > * pOptionalParent = 0,
u_int32_t Flags = 0
);
inline void Commit( u_int32_t CommitFlags = 0 );
inline void Abort();
// Destructor will abort transaction if Commit() or Abort()
// not explicitly called first.
inline ~CTransaction();
private:
CTransaction< TDatabaseEnvironment > * m_pOptionalParent;
DbTxn * m_pDbTxn;
// Disable copying and assignment.
CTransaction( const CTransaction & );
CTransaction & operator=( const CTransaction & );
// Transactions are normally scoped stack objects. However, there are
// times when we need to put them on the heap (held by auto_ptr or
// shared_ptr for for scoping)
// So we only disable array new and delete, not single new and delete.
static void * operator new[]( size_t nSize );
static void operator delete[]( void *pArray );
};
template< class TDatabaseEnvironment >
CTransaction< TDatabaseEnvironment >::CTransaction
(
CTransaction< CDatabaseEnvironment > * pOptionalParent,
u_int32_t Flags
)
:
m_pOptionalParent( pOptionalParent ),
m_pDbTxn( 0 )
{
DbTxn * pOptionalParentDbTxn = 0;
if ( m_pOptionalParent )
{
pOptionalParentDbTxn = m_pOptionalParent->GetDbTxn();
}
// We're using the C++ API so this throws if it fails.
TBerkeley DBEnv::Instance()->txn_begin
(
pOptionalParentDbTxn,
& m_pDbTxn,
TransactionFlags
);
}
template< class TDatabaseEnvironment >
CTransaction< TDatabaseEnvironment >::~CTransaction
{
try
{
// Call abort if not already called commit or abort.
if ( m_pDbTxn )
{
m_pDbTxn->abort();
}
}
catch ( ... )
{
// All destructors must be no-throw.
}
}
template< class CBerkeley DBEnv >
void CTransaction<CBerkeley DBEnv>::Commit( u_int32_t CommitFlags )
{
AssertPreCondition( "Not already commited or aborted", m_pDbTxn );
// commit may throw but we are never allowed to use the DbTxn again.
DbTxn * pDbTxn = m_pDbTxn;
m_pDbTxn = 0;
pDbTxn->commit( CommitFlags );
}
template< class TDatabaseEnvironment >
void CTransaction< TDatabaseEnvironment >::Abort()
{
AssertPreCondition( "Not already commited or aborted", m_pDbTxn );
// abort may throw but we are never allowed to use the DbTxn again.
DbTxn * pDbTxn = m_pDbTxn;
m_pDbTxn = 0;
pDbTxn->abort();
}