|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r60906 - in sandbox/transaction: boost/transact libs/transact libs/transact/build libs/transact/doc libs/transact/doc/html libs/transact/example libs/transact/src libs/transact/test libs/transaction
From: strasser_at_[hidden]
Date: 2010-03-28 17:46:33
Author: stefans
Date: 2010-03-28 17:46:32 EDT (Sun, 28 Mar 2010)
New Revision: 60906
URL: http://svn.boost.org/trac/boost/changeset/60906
Log:
- transaction restart service
- fixed behaviour of isolation_exception::unwind()
- fixed basic_transaction behaviour wrt transaction binding according to the new macros
- changed basic_transaction_manager defaults to non-lazy transaction starts
- active transaction -> current transaction
Added:
sandbox/transaction/boost/transact/resource_manager.hpp (contents, props changed)
sandbox/transaction/libs/transact/
sandbox/transaction/libs/transact/build/
sandbox/transaction/libs/transact/doc/
sandbox/transaction/libs/transact/doc/html/
sandbox/transaction/libs/transact/example/
sandbox/transaction/libs/transact/src/
sandbox/transaction/libs/transact/test/
sandbox/transaction/libs/transact/test/transaction_stack_unwind.cpp (contents, props changed)
Removed:
sandbox/transaction/libs/transaction/
Text files modified:
sandbox/transaction/boost/transact/basic_transaction.hpp | 58 ++------
sandbox/transaction/boost/transact/basic_transaction_manager.hpp | 246 ++++++++++++++++++++++-----------------
sandbox/transaction/boost/transact/exception.hpp | 38 +++--
sandbox/transaction/boost/transact/simple_transaction_manager.hpp | 108 ++++++++++------
4 files changed, 243 insertions(+), 207 deletions(-)
Modified: sandbox/transaction/boost/transact/basic_transaction.hpp
==============================================================================
--- sandbox/transaction/boost/transact/basic_transaction.hpp (original)
+++ sandbox/transaction/boost/transact/basic_transaction.hpp 2010-03-28 17:46:32 EDT (Sun, 28 Mar 2010)
@@ -25,15 +25,15 @@
class basic_transaction : noncopyable{
public:
/// Binds the new transaction to this thread.
- /// If there already is an active transaction, the new transaction will be a nested transaction
- /// of the active transaction.
+ /// If there already is an current transaction, the new transaction will be a nested transaction
+ /// of the current transaction.
///
/// Throws: \c no_transaction_manager, \c io_failure, \c thread_resource_error,
/// resource-specific exceptions
/// thrown by resource managers beginning local transactions.
/// \brief Constructs a basic_transaction, beginning a new transaction scope
explicit basic_transaction()
- : parent(TxMgr::has_active_transaction() ? &TxMgr::active_transaction() : 0)
+ : parent(TxMgr::has_current_transaction() ? &TxMgr::current_transaction() : 0)
, tx(TxMgr::begin_transaction())
, done(false){
TxMgr::bind_transaction(this->tx);
@@ -54,52 +54,29 @@
#endif
}
}
- try{
- this->pop();
- }catch(...){
-#ifndef NDEBUG
- std::cerr << "ignored exception" << std::endl;
-#endif
- }
+ //bind_ and unbind_transaction can throw thread_resource_error.
+ //in the unlikely case it is actually thrown, it is not ignored, even though this is a destructor.
+ //if the current transaction cannot be bound correctly all following transactional operations are invalid.
+ //abort() is preferrable to that.
+ if(this->parent) TxMgr::bind_transaction(*this->parent);
+ else TxMgr::unbind_transaction();
}
- /// If this is a nested transaction, sets the active transaction to the parent transaction.
- /// If this is a root transaction, resets the active transaction.
- ///
/// Throws: \c isolation_exception, \c io_failure, \c thread_resource_error,
/// resource-specific exceptions thrown by resource managers committing local
/// transactions.
/// \brief Commits the transaction.
void commit(){
this->done=true;
- try{
- TxMgr::commit_transaction(this->tx);
- }catch(...){
- this->pop();
- throw;
- }
- }
- /// \cond
- void commit_(){
- this->commit();
+ TxMgr::commit_transaction(this->tx);
}
- /// \endcond
- /// If this is a nested transaction, sets the active transaction to the parent transaction.
- /// If this is a root transaction, resets the active transaction.
- ///
/// Throws: \c io_failure, \c thread_resource_error, resource-specific exceptions
/// thrown by resource managers rolling back transactions.
/// \brief Unwinds all changes made during this transaction.
void rollback(){
this->done=true;
- try{
- TxMgr::rollback_transaction(this->tx);
- }catch(...){
- this->pop();
- throw;
- }
- this->pop();
+ TxMgr::rollback_transaction(this->tx);
}
/// Throws: thread_resource_error
@@ -111,21 +88,18 @@
/// Throws: thread_resource_error
/// \brief If the current thread is bound to this transaction, unbinds it
void unbind(){
- if(TxMgr::has_active_transaction() &&
- &TxMgr::active_transaction() == &this->tx){
+ if(TxMgr::has_current_transaction() &&
+ &TxMgr::current_transaction() == &this->tx){
TxMgr::unbind_transaction();
}
}
- void restart(){}
+ void restart(){
+ TxMgr::restart_transaction(this->tx);
+ }
/// \cond
private:
- void pop(){
- if(this->parent) TxMgr::bind_transaction(*this->parent);
- else TxMgr::unbind_transaction();
- }
-
typename TxMgr::transaction *parent;
typename TxMgr::transaction tx;
bool done;
Modified: sandbox/transaction/boost/transact/basic_transaction_manager.hpp
==============================================================================
--- sandbox/transaction/boost/transact/basic_transaction_manager.hpp (original)
+++ sandbox/transaction/boost/transact/basic_transaction_manager.hpp 2010-03-28 17:46:32 EDT (Sun, 28 Mar 2010)
@@ -12,6 +12,7 @@
#include <boost/transact/detail/mutex.hpp>
#include <boost/transact/exception.hpp>
#include <boost/transact/detail/static_tss.hpp>
+#include <boost/transact/resource_manager.hpp>
#include <boost/type_traits/add_pointer.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/as_vector.hpp>
@@ -54,14 +55,6 @@
struct get_tag{
typedef typename Resource::tag type;
};
-template<class Resources>
-struct default_lazy_resources{
- typedef typename mpl::if_c<
- mpl::size<Resources>::value==1,
- mpl::empty_sequence,
- typename mpl::transform<Resources,get_tag<mpl::_1> >::type
- >::type type;
-};
template<class State,class F>
struct runtime_folder{
@@ -96,101 +89,107 @@
/// access of the resource transaction. This can be beneficial when 2 or more
/// resource managers are used but not every resource is accessed in a global
/// transaction.
-/// By default, all resource transactions
-/// are started lazily, unless there is only one resource manager used.
/// \brief A transaction manager
template<
class Resources,
bool Threads=true,
bool TThreads=true,
- class Lazy=typename detail::default_lazy_resources<Resources>::type
+ class Lazy=mpl::empty_sequence
>
class basic_transaction_manager : noncopyable{
/// \cond
BOOST_STATIC_ASSERT(Threads || !TThreads);
+public:
+ class transaction;
private:
- struct detail{
- typedef typename mpl::transform<
- Resources,
- transact::detail::get_tag<mpl::_1>
- >::type resource_tags;
+ typedef typename mpl::transform<
+ Resources,
+ transact::detail::get_tag<mpl::_1>
+ >::type resource_tags;
- template<class Resource>
- struct make_resource_pair{
- typedef mpl::pair<typename Resource::tag,Resource> type;
- };
- typedef typename mpl::fold<
- Resources,
- mpl::map0<>,
- mpl::insert<mpl::_1,make_resource_pair<mpl::_2> >
- >::type resource_types_by_tag;
+ template<class Resource>
+ struct make_resource_pair{
+ typedef mpl::pair<typename Resource::tag,Resource> type;
+ };
+ typedef typename mpl::fold<
+ Resources,
+ mpl::map0<>,
+ mpl::insert<mpl::_1,make_resource_pair<mpl::_2> >
+ >::type resource_types_by_tag;
+
+ template<class Tag>
+ struct resource_type{
+ typedef typename mpl::at<resource_types_by_tag,Tag>::type type;
+ };
+
+ class transaction_construct_t{
+ explicit transaction_construct_t(transaction *parent)
+ : parent(parent){}
+ friend class basic_transaction_manager;
+ transaction *parent;
+ };
+
+ struct currenttx_tag{};
+ typedef transact::detail::static_thread_specific_ptr<
+ transaction,
+ currenttx_tag,
+ Threads> currenttx;
+ template<class Resource>
+ struct get_services{
+ typedef typename Resource::services type;
+ };
+ struct detail{ //for QuickBook
+ typedef typename basic_transaction_manager::transaction_construct_t transaction_construct_t;
template<class Tag>
struct resource_type{
- typedef typename mpl::at<resource_types_by_tag,Tag>::type type;
- };
-
- template<class Resource>
- struct get_services{
- typedef typename Resource::services type;
+ typedef typename basic_transaction_manager::template resource_type<Tag>::type type;
};
- template<class Service>
+ template<class ServiceTag>
struct default_resource{
typedef typename mpl::deref<
typename mpl::find_if<
Resources,
- mpl::contains<get_services<mpl::_1>,Service>
+ mpl::contains<get_services<mpl::_1>,ServiceTag>
>::type
>::type::tag type;
};
+ };
- class transaction;
- class transaction_construct_t{
- explicit transaction_construct_t(transaction *parent)
- : parent(parent){}
- friend class basic_transaction_manager;
- transaction *parent;
- };
-
- class transaction : noncopyable{
- public:
- explicit transaction(transaction_construct_t const &c) : parent(c.parent){
- mpl::for_each<resource_tags>(beginner(*this));
- }
- private:
- friend class basic_transaction_manager;
-
- template<class Resource>
- struct make_resource_transaction_pair{
- typedef fusion::pair<typename Resource::tag,optional<typename Resource::transaction> > type;
- };
- typedef typename fusion::result_of::as_map<
- typename mpl::transform<
- Resources,
- make_resource_transaction_pair<mpl::_1>
- >::type
- >::type resource_transactions_type;
- resource_transactions_type resource_transactions;
-
- transaction * const parent;
+ /// \endcond
+public:
+ class transaction : noncopyable{
+ /// \cond
+ public:
+ explicit transaction(transaction_construct_t const &c) : parent(c.parent){
+ mpl::for_each<resource_tags>(beginner(*this));
+ }
+ private:
+ friend class basic_transaction_manager;
- typedef typename mpl::if_c<
- TThreads,
- transact::detail::mutex_type,
- transact::detail::null_lockable
- >::type mutex_type;
-
- mutex_type mutex;
+ template<class Resource>
+ struct make_resource_transaction_pair{
+ typedef fusion::pair<typename Resource::tag,optional<typename Resource::transaction> > type;
};
- };
- struct activetx_tag{};
- typedef transact::detail::static_thread_specific_ptr<
- typename detail::transaction,
- activetx_tag,
- Threads> activetx;
+ typedef typename fusion::result_of::as_map<
+ typename mpl::transform<
+ Resources,
+ make_resource_transaction_pair<mpl::_1>
+ >::type
+ >::type resource_transactions_type;
+ resource_transactions_type resource_transactions;
+
+ transaction * const parent;
+
+ typedef typename mpl::if_c<
+ TThreads,
+ transact::detail::mutex_type,
+ transact::detail::null_lockable
+ >::type mutex_type;
+
+ mutex_type mutex;
/// \endcond
-public:
- typedef typename detail::transaction transaction;
+ };
typedef Resources resource_types;
template<class ServiceTag>
struct default_resource{
@@ -218,61 +217,64 @@
}
template<class Tag>
- static typename detail::resource_type<Tag>::type &resource(Tag tag=Tag()){
- typename detail::resource_type<Tag>::type *res
+ static typename detail::template resource_type<Tag>::type &resource(Tag tag=Tag()){
+ typename resource_type<Tag>::type *res
=fusion::at_key<Tag>(resources);
if(res) return *res;
else throw resource_error();
}
template<class Tag>
- static typename detail::resource_type<Tag>::type::transaction &
+ static typename detail::template resource_type<Tag>::type::transaction &
resource_transaction(transaction &tx,Tag tag=Tag()){
return resource_transaction(tx,tag,typename mpl::contains<Lazy,Tag>());
}
static typename detail::transaction_construct_t begin_transaction(){
- return typename detail::transaction_construct_t(activetx::get());
+ return transaction_construct_t(currenttx::get());
}
static void commit_transaction(transaction &tx){
- typedef typename detail::resource_tags tags;
bind_transaction(tx);
//call finish_transaction until all transactions return false
- while(transact::detail::runtime_fold<tags>(false,finisher(tx)));
+ while(transact::detail::runtime_fold<resource_tags>(false,finisher(tx)));
- mpl::for_each<tags>(preparer<false>(tx)); //prepare transient two-phase transactions
+ mpl::for_each<resource_tags>(preparer<false>(tx)); //prepare transient two-phase transactions
//count persistent transactions and transactions that only support one-phase commit:
- std::size_t pers=transact::detail::runtime_fold<tags>(0,persistent_counter(tx));
+ std::size_t pers=transact::detail::runtime_fold<resource_tags>(0,persistent_counter(tx));
if(pers > 1){
- mpl::for_each<tags>(preparer<true>(tx)); //prepare persistent transactions
+ mpl::for_each<resource_tags>(preparer<true>(tx)); //prepare persistent transactions
//TODO write commit message to log
- mpl::for_each<tags>(committer<true>(tx)); //commit persistent transactions
+ mpl::for_each<resource_tags>(committer<true>(tx)); //commit persistent transactions
}else{
- mpl::for_each<tags>(committer<true>(tx)); //commit persistent transaction unprepared
+ mpl::for_each<resource_tags>(committer<true>(tx)); //commit persistent transaction unprepared
}
- mpl::for_each<tags>(committer<false>(tx)); //commit transient two-phase transactions
+ mpl::for_each<resource_tags>(committer<false>(tx)); //commit transient two-phase transactions
}
static void rollback_transaction(transaction &tx){
bind_transaction(tx);
- mpl::for_each<detail::resource_tags>(rollbacker(tx));
+ mpl::for_each<resource_tags>(rollbacker(tx));
+ }
+
+ static void restart_transaction(transaction &tx){
+ mpl::for_each<resource_tags>(restarter(tx));
}
static void bind_transaction(transaction &tx){
- activetx::reset(&tx);
+ currenttx::reset(&tx);
}
static void unbind_transaction(){
- activetx::reset(0);
+ currenttx::reset(0);
}
- static transaction &active_transaction(){
- if(transaction *tx=activetx::get()) return *tx;
- else throw no_active_transaction();
+ static transaction ¤t_transaction(){
+ if(transaction *tx=currenttx::get()) return *tx;
+ else throw no_transaction();
}
- static bool has_active_transaction(){
- return activetx::get() ? true : false;
+ static bool has_current_transaction(){
+ return currenttx::get() ? true : false;
}
/// \cond
@@ -281,7 +283,7 @@
explicit persistent_counter(transaction &tx) : tx(tx){}
template<class Tag>
std::size_t operator()(std::size_t c,Tag){
- typedef typename detail::resource_type<Tag>::type res_type;
+ typedef typename resource_type<Tag>::type res_type;
if(is_persistent<res_type>::type::value){
if(fusion::at_key<Tag>(tx.resource_transactions)){
return c+1;
@@ -296,7 +298,7 @@
explicit finisher(transaction &tx) : tx(tx){}
template<class Tag>
bool operator()(bool repeat,Tag tag){
- typedef typename detail::resource_type<Tag>::type res_type;
+ typedef typename resource_type<Tag>::type res_type;
optional<typename res_type::transaction> &rtx=
fusion::at_key<Tag>(tx.resource_transactions);
if(rtx){
@@ -320,7 +322,7 @@
void begin(Tag,mpl::true_ lazy){}
template<class Tag>
void begin(Tag,mpl::false_ lazy){
- typedef typename detail::resource_type<Tag>::type res_type;
+ typedef typename resource_type<Tag>::type res_type;
res_type *rmgr=fusion::at_key<Tag>(resources);
if(rmgr){
optional<typename res_type::transaction> &rtx=
@@ -336,9 +338,9 @@
transaction &tx;
};
template<class Tag>
- static typename detail::resource_type<Tag>::type::transaction &
+ static typename detail::template resource_type<Tag>::type::transaction &
resource_transaction(transaction &tx,Tag tag,mpl::true_ lazy){
- typedef typename detail::resource_type<Tag>::type res_type;
+ typedef typename resource_type<Tag>::type res_type;
optional<typename res_type::transaction> &rtx=
fusion::at_key<Tag>(tx.resource_transactions);
@@ -362,9 +364,9 @@
return *rtx;
}
template<class Tag>
- static typename detail::resource_type<Tag>::type::transaction &
+ static typename detail::template resource_type<Tag>::type::transaction &
resource_transaction(transaction &tx,Tag tag,mpl::false_ lazy){
- typedef typename detail::resource_type<Tag>::type res_type;
+ typedef typename resource_type<Tag>::type res_type;
optional<typename res_type::transaction> &rtx=
fusion::at_key<Tag>(tx.resource_transactions);
BOOST_ASSERT(rtx);
@@ -384,7 +386,7 @@
explicit committer(transaction &tx) : tx(tx){}
template<class Tag>
void operator()(Tag){
- typedef typename detail::resource_type<Tag>::type res_type;
+ typedef typename resource_type<Tag>::type res_type;
if(Persistent == is_persistent<res_type>::type::value){
optional<typename res_type::transaction> &rtx=
fusion::at_key<Tag>(tx.resource_transactions);
@@ -403,9 +405,9 @@
explicit preparer(transaction &tx) : tx(tx){}
template<class Tag>
void operator()(Tag){
- typedef typename detail::resource_type<Tag>::type res_type;
+ typedef typename resource_type<Tag>::type res_type;
if(Persistent == is_persistent<res_type>::type::value){
- typedef typename detail::resource_type<Tag>::type res_type;
+ typedef typename resource_type<Tag>::type res_type;
optional<typename res_type::transaction> &rtx=
fusion::at_key<Tag>(tx.resource_transactions);
if(rtx){
@@ -432,16 +434,44 @@
explicit rollbacker(transaction &tx) : tx(tx){}
template<class Tag>
void operator()(Tag){
- typedef typename detail::resource_type<Tag>::type res_type;
+ typedef typename resource_type<Tag>::type res_type;
+ optional<typename res_type::transaction> &rtx=
+ fusion::at_key<Tag>(tx.resource_transactions);
+ if(rtx){
+ res_type *res=fusion::at_key<Tag>(resources);
+ BOOST_ASSERT(res);
+ res->rollback_transaction(*rtx);
+ }
+ }
+ private:
+ transaction &tx;
+ };
+ struct restarter{
+ explicit restarter(transaction &tx) : tx(tx){}
+ template<class Tag>
+ void operator()(Tag){
+ typedef typename resource_type<Tag>::type res_type;
optional<typename res_type::transaction> &rtx=
fusion::at_key<Tag>(tx.resource_transactions);
if(rtx){
res_type *res=fusion::at_key<Tag>(resources);
BOOST_ASSERT(res);
+ this->operator()(*res,rtx,typename mpl::contains<typename res_type::services,transaction_restart_service_tag>::type());
res->rollback_transaction(*rtx);
}
}
private:
+ template<class Resource>
+ void operator()(Resource &res,optional<typename Resource::transaction> &rtx,mpl::true_ service){
+ res.restart_transaction(*rtx);
+ }
+ template<class Resource>
+ void operator()(Resource &res,optional<typename Resource::transaction> &rtx,mpl::false_ service){
+ rtx=none;
+ beginner begin(this->tx);
+ begin(typename Resource::tag()); //TODO optimization: looked up twice. esp. with stateful tags.
+ }
+
transaction &tx;
};
template<class Resource>
Modified: sandbox/transaction/boost/transact/exception.hpp
==============================================================================
--- sandbox/transaction/boost/transact/exception.hpp (original)
+++ sandbox/transaction/boost/transact/exception.hpp 2010-03-28 17:46:32 EDT (Sun, 28 Mar 2010)
@@ -7,7 +7,7 @@
#ifndef BOOST_TRANSACT_EXCEPTION_HEADER_HPP
#define BOOST_TRANSACT_EXCEPTION_HEADER_HPP
-#include <stdexcept>
+#include <exception>
#include <boost/mpl/begin.hpp>
#include <boost/mpl/end.hpp>
#include <boost/mpl/next.hpp>
@@ -27,8 +27,9 @@
///\brief Indicates that an internal operation reading from/writing to files failed.
struct io_failure : transact::exception{};
-///\brief Indicates that this operation required an active transaction but there was no active transaction bound for this thread.
-struct no_active_transaction : transact::exception{};
+///\brief Indicates that this operation required a transaction but there was no transaction bound to this thread, or that the operation
+///required an active transaction but the transaction bound to this thread was inactive.
+struct no_transaction : transact::exception{};
///\brief Indicates an error with regard to connecting a resource to a transaction manager
struct resource_error : transact::exception{};
@@ -78,13 +79,14 @@
///\c isolation_exception is an abstract base class. The derived class
///\c resource_isolation_exception can be used to throw this exception.
struct isolation_exception : transact::exception{
- ///Rethrows the exception if the active transaction is a nested transaction but the isolation exception was caused by a parent transaction of it.
+ ///Rethrows the exception if the current transaction is a nested transaction but the isolation exception was caused by a parent transaction of it,
+ ///or if the isolation_exception was caused independently of a transaction.
+ ///\pre TxMgr::current_transaction() must be a rolled back transaction
template<class TxMgr>
void unwind() const{ //pseudo-virtual
detail::isolation_unwind_visitor<TxMgr,typename mpl::begin<typename TxMgr::resource_types>::type> visit;
visit(*this);
}
- virtual ~isolation_exception()throw (){}
protected:
isolation_exception(){}
};
@@ -97,22 +99,26 @@
template<class ResMgr>
struct resource_isolation_exception : isolation_exception{
///\brief Constructs a resource_isolation_exception
- ///\param unwind_to A pointer to the transaction that ought to be active when
- ///unwind() returns. Must be a transaction on the nested transaction
- ///stack. If 0, unwind() rethrows the exception until all transactions
- ///including the root transaction are destroyed.
- explicit resource_isolation_exception(typename ResMgr::transaction *unwind_to)
- : to(unwind_to){}
+ resource_isolation_exception() : retry(0){}
+
+ ///\brief Constructs a resource_isolation_exception
+ ///\param retry The transaction that caused the isolation_exception and ought to be repeated.
+ ///Must be a transaction on the nested transaction stack.
+ explicit resource_isolation_exception(typename ResMgr::transaction &retry)
+ : retry(&retry){}
+
+ ///Throws: thread_resource_error. no_transaction if \c retry was not on the nested transaction stack or it was removed before unwind() was called.
///\brief Equivalent to <tt>isolation_exception::unwind<TxMgr>()</tt>
+ ///\pre TxMgr::current_transaction() must be a rolled back transaction
template<class TxMgr>
void unwind() const{ //pseudo-virtual
- if(this->to){
- typename ResMgr::transaction &tx=TxMgr::resource_transaction(TxMgr::active_transaction(),typename ResMgr::tag());
- if(&tx != this->to) throw;
- }else if(TxMgr::has_active_transaction()) throw;
+ if(this->retry){
+ typename ResMgr::transaction ¤ttx=TxMgr::resource_transaction(TxMgr::current_transaction(),typename ResMgr::tag());
+ if(this->retry != ¤ttx) throw;
+ }else throw;
}
private:
- typename ResMgr::transaction *to;
+ typename ResMgr::transaction *retry;
};
}
Added: sandbox/transaction/boost/transact/resource_manager.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/resource_manager.hpp 2010-03-28 17:46:32 EDT (Sun, 28 Mar 2010)
@@ -0,0 +1,19 @@
+// Copyright Stefan Strasser 2010.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+
+#ifndef BOOST_TRANSACT_RESOURCE_MANAGER_HPP
+#define BOOST_TRANSACT_RESOURCE_MANAGER_HPP
+
+namespace boost{
+namespace transact{
+
+struct transaction_restart_service_tag{};
+
+}
+}
+
+
+#endif
Modified: sandbox/transaction/boost/transact/simple_transaction_manager.hpp
==============================================================================
--- sandbox/transaction/boost/transact/simple_transaction_manager.hpp (original)
+++ sandbox/transaction/boost/transact/simple_transaction_manager.hpp 2010-03-28 17:46:32 EDT (Sun, 28 Mar 2010)
@@ -8,11 +8,14 @@
#define BOOST_TRANSACT_SIMPLE_TRANSACTION_MANAGER_HEADER_HPP
#include <boost/mpl/vector.hpp>
+#include <boost/mpl/contains.hpp>
+#include <boost/mpl/bool.hpp>
#include <boost/utility/in_place_factory.hpp>
#include <boost/optional/optional.hpp>
#include <boost/transact/exception.hpp>
#include <boost/noncopyable.hpp>
#include <boost/transact/detail/static_tss.hpp>
+#include <boost/transact/resource_manager.hpp>
namespace boost{
namespace transact{
@@ -27,44 +30,48 @@
// \brief A transaction manager that only supports one resource manager.
template<class Resource,bool Threads=true>
class simple_transaction_manager : noncopyable{
+public:
+ class transaction;
private:
- struct detail{
- class transaction;
- class transaction_construct_t{
- explicit transaction_construct_t(transaction *parent)
- : parent(parent){}
- friend class simple_transaction_manager;
- friend class transaction;
- transaction *parent;
- };
-
- class transaction : noncopyable{
- public:
- explicit transaction(transaction_construct_t const &c)
- : parent(c.parent){
- if(res){
- if(this->parent){
- this->rtx=in_place(res->begin_nested_transaction(*this->parent->rtx));
- }else{
- this->rtx=in_place(res->begin_root_transaction());
- }
- }
- }
- private:
- friend class simple_transaction_manager;
- optional<typename Resource::transaction> rtx;
- transaction * const parent;
- };
+ class transaction_construct_t{
+ explicit transaction_construct_t(transaction *parent)
+ : parent(parent){}
+ friend class simple_transaction_manager;
+ friend class transaction;
+ transaction *parent;
};
- struct activetx_tag{};
+ struct currenttx_tag{};
typedef transact::detail::static_thread_specific_ptr<
- typename detail::transaction,
- activetx_tag,
- Threads> activetx;
+ transaction,
+ currenttx_tag,
+ Threads> currenttx;
+
+ struct detail{ //for QuickBook
+ typedef typename simple_transaction_manager::transaction_construct_t transaction_construct_t;
+ };
/// \endcond
public:
- typedef typename detail::transaction transaction;
- typedef mpl::vector<Resource> resource_types;
+ class transaction : noncopyable{
+ /// \cond
+ public:
+ explicit transaction(transaction_construct_t const &c)
+ : parent(c.parent){
+ if(res){
+ if(this->parent){
+ BOOST_ASSERT(this->parent->rtx);
+ this->rtx=in_place(res->begin_nested_transaction(*this->parent->rtx));
+ }else{
+ this->rtx=in_place(res->begin_root_transaction());
+ }
+ }
+ }
+ private:
+ friend class simple_transaction_manager;
+ optional<typename Resource::transaction> rtx;
+ transaction * const parent;
+ /// \endcond
+ };
+ typedef mpl::vector1<Resource> resource_types;
template<class ServiceTag>
struct default_resource{
typedef typename Resource::tag type;
@@ -96,7 +103,7 @@
}
static typename detail::transaction_construct_t begin_transaction(){
- return typename detail::transaction_construct_t(activetx::get());
+ return transaction_construct_t(currenttx::get());
}
static void commit_transaction(transaction &tx){
@@ -116,22 +123,41 @@
}
}
+ static void restart_transaction(transaction &tx){
+ if(res){
+ BOOST_ASSERT(tx.rtx);
+ restart_transaction(tx,typename mpl::contains<typename Resource::services,transaction_restart_service_tag>::type());
+ }
+ }
+
static void bind_transaction(transaction &tx){
- activetx::reset(&tx);
+ currenttx::reset(&tx);
}
static void unbind_transaction(){
- activetx::reset(0);
+ currenttx::reset(0);
}
- static transaction &active_transaction(){
- if(transaction *tx=activetx::get()) return *tx;
- else throw no_active_transaction();
+ static transaction ¤t_transaction(){
+ if(transaction *tx=currenttx::get()) return *tx;
+ else throw no_transaction();
}
- static bool has_active_transaction(){
- return activetx::get() ? true : false;
+ static bool has_current_transaction(){
+ return currenttx::get() ? true : false;
}
/// \cond
private:
+ static void restart_transaction(transaction &tx,mpl::true_ service){
+ res->restart_transaction(*tx.rtx);
+ }
+ static void restart_transaction(transaction &tx,mpl::false_ service){
+ if(tx.parent){
+ BOOST_ASSERT(tx.parent->rtx);
+ tx.rtx=in_place(res->begin_nested_transaction(*tx.parent->rtx));
+ }else{
+ tx.rtx=in_place(res->begin_root_transaction());
+ }
+ }
+
static Resource *res;
/// \endcond
};
Added: sandbox/transaction/libs/transact/test/transaction_stack_unwind.cpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/libs/transact/test/transaction_stack_unwind.cpp 2010-03-28 17:46:32 EDT (Sun, 28 Mar 2010)
@@ -0,0 +1,65 @@
+#include <boost/transact/simple_transaction_manager.hpp>
+#include <boost/mpl/empty_sequence.hpp>
+#include <boost/assert.hpp>
+
+using namespace boost;
+using namespace transact;
+
+struct my_rm{
+ typedef int transaction;
+ typedef mpl::empty_sequence services;
+ struct tag{};
+ transaction begin_root_transaction(){ return 0; }
+ transaction begin_nested_transaction(transaction){ return 0; }
+ void commit_transaction(transaction){}
+ bool finish_transaction(transaction){ return false; }
+ void rollback_transaction(transaction){}
+};
+
+
+typedef simple_transaction_manager<my_rm> my_tm;
+#define BOOST_TRANSACT_CONFIGURATION my_tm
+
+#include <boost/transact/language.hpp>
+
+
+int test(int contextnr){
+ my_tm::transaction *txs[5];
+ int retried=-1;
+ begin_transaction{
+ txs[0]=&my_tm::current_transaction();
+ begin_transaction{
+ txs[1]=&my_tm::current_transaction();
+ begin_transaction{
+ txs[2]=&my_tm::current_transaction();
+ begin_transaction{
+ txs[3]=&my_tm::current_transaction();
+ begin_transaction{
+ txs[4]=&my_tm::current_transaction();
+ my_rm::transaction &rtx=my_tm::resource_transaction(*txs[contextnr]);
+ throw resource_isolation_exception<my_rm>(rtx);
+ }retry{
+ return 4;
+ }end_retry;
+ }retry{
+ return 3;
+ }end_retry;
+ }retry{
+ return 2;
+ }end_retry;
+ }retry{
+ return 1;
+ }end_retry;
+ }retry{
+ return 0;
+ }end_retry;
+}
+
+
+int main(){
+ my_rm rm;
+ my_tm::connect_resource(rm);
+ for(int c=0;c<5;++c){
+ BOOST_ASSERT( test(c) == c );
+ }
+}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk