Boost logo

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 &current_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 &currenttx=TxMgr::resource_transaction(TxMgr::current_transaction(),typename ResMgr::tag());
+ if(this->retry != &currenttx) 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 &current_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