|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r59230 - sandbox/transaction/dev
From: strasser_at_[hidden]
Date: 2010-01-22 14:32:32
Author: stefans
Date: 2010-01-22 14:32:31 EST (Fri, 22 Jan 2010)
New Revision: 59230
URL: http://svn.boost.org/trac/boost/changeset/59230
Log:
- made all public members of basic_transaction_manager static
- added connect_resource, disconnect_resource
- moved control over "transaction stack", i.e. binding to the parent transaction on commit/rollback
from basic_transaction_manager to basic_transaction
- use thread_specific_ptr<transaction> with a null cleanup function instead of
thread_specific_ptr<transaction *> with default cleanup
- thread local storage instead of thread_specific_ptr for GCC and MSVC
Text files modified:
sandbox/transaction/dev/basic_transaction.hpp | 32 +++--
sandbox/transaction/dev/basic_transaction_manager.hpp | 220 ++++++++++++++++++---------------------
sandbox/transaction/dev/exception.hpp | 22 ++--
3 files changed, 136 insertions(+), 138 deletions(-)
Modified: sandbox/transaction/dev/basic_transaction.hpp
==============================================================================
--- sandbox/transaction/dev/basic_transaction.hpp (original)
+++ sandbox/transaction/dev/basic_transaction.hpp 2010-01-22 14:32:31 EST (Fri, 22 Jan 2010)
@@ -28,10 +28,10 @@
/// Throws: \c no_active_transaction_manager, \c finalize_error, \c io_failure, \c thread_resource_error
/// \brief Constructs a basic_transaction, beginning a new transaction scope
explicit basic_transaction()
- : manager(TxMgr::active())
- , tx(manager.begin_transaction())
+ : parent(TxMgr::has_active_transaction() ? &TxMgr::active_transaction() : 0)
+ , tx(TxMgr::begin_transaction())
, done(false){
- this->manager.bind_transaction(this->tx);
+ TxMgr::bind_transaction(this->tx);
}
/// The transaction is rolled back if it was not yet committed.
@@ -39,9 +39,10 @@
/// Throws: Nothing
/// \brief Destructs the basic_transaction object
~basic_transaction(){
+ this->pop();
if(!this->done){
try{
- this->manager.rollback_transaction(this->tx);
+ TxMgr::rollback_transaction(this->tx);
}catch(...){
#ifndef NDEBUG
std::cerr << "ignored exception" << std::endl;
@@ -57,8 +58,9 @@
/// \c archive_exception, \c io_failure, \c thread_resource_error, any exception thrown by the following user-supplied functions: \c T::T(), \c serialize(), \c save(), \c load(), \c construct(), \c equal(), \c finalize()
/// \brief Commits the transaction.
void commit(){
+ this->pop();
this->done=true;
- this->manager.commit_transaction(this->tx);
+ TxMgr::commit_transaction(this->tx);
}
/// If this is a nested transaction, sets the active transaction to the parent transaction.
@@ -67,28 +69,36 @@
/// Throws: \c io_failure, \c thread_resource_error
/// \brief Unwinds all changes made during this transaction.
void rollback(){
+ this->pop();
this->done=true;
- this->manager.rollback_transaction(this->tx);
+ TxMgr::rollback_transaction(this->tx);
}
/// Throws: Nothing
/// \brief Binds the current thread to this transaction
void bind(){
- this->manager.bind_transaction(this->tx);
+ TxMgr::bind_transaction(this->tx);
}
/// Throws: Nothing
/// \brief If the current thread is bound to this transaction, unbinds it
void unbind(){
- if(this->manager.has_active_transaction() &&
- &this->manager.active_transaction() == &this->tx){
- this->manager.unbind_transaction();
+ if(TxMgr::has_active_transaction() &&
+ &TxMgr::active_transaction() == &this->tx){
+ TxMgr::unbind_transaction();
}
}
/// \cond
private:
- TxMgr &manager;
+ void pop(){
+ if(TxMgr::has_active_transaction() && &TxMgr::active_transaction() == &this->tx){
+ if(this->parent) TxMgr::bind_transaction(*this->parent);
+ else TxMgr::unbind_transaction();
+ }
+ }
+
+ typename TxMgr::transaction *parent;
typename TxMgr::transaction tx;
bool done;
/// \endcond
Modified: sandbox/transaction/dev/basic_transaction_manager.hpp
==============================================================================
--- sandbox/transaction/dev/basic_transaction_manager.hpp (original)
+++ sandbox/transaction/dev/basic_transaction_manager.hpp 2010-01-22 14:32:31 EST (Fri, 22 Jan 2010)
@@ -15,7 +15,7 @@
#include <boost/persistent/detail/utility.hpp>
#include <boost/persistent/detail/null_mutex.hpp>
#include <boost/persistent/detail/mutex.hpp>
-#include <boost/type_traits/add_reference.hpp>
+#include <boost/type_traits/add_pointer.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/count_if.hpp>
@@ -71,8 +71,8 @@
>::type
>::type::tag type;
};
- typedef typename mpl::transform<resource_types,add_reference<mpl::_1> >::type resource_references;
- typedef typename fusion::result_of::as_vector<resource_references>::type resources_tuple;
+ typedef typename mpl::transform<resource_types,add_pointer<mpl::_1> >::type resource_pointers;
+ typedef typename fusion::result_of::as_vector<resource_pointers>::type resources_tuple;
class transaction;
class transaction_construct_t{
@@ -105,6 +105,7 @@
mutex_type mutex;
};
};
+ basic_transaction_manager();
/// \endcond
public:
typedef typename detail::transaction transaction;
@@ -114,37 +115,34 @@
typedef typename detail::template default_resource<ServiceTag>::type type;
};
- /// This constructor is only available if this transaction manager uses only one
- /// resource manager.
- ///
- /// Throws: Nothing
- /// \brief Constructs a basic_transaction_manager using the passed resource manager
- /// \param resource The resource manager
- explicit basic_transaction_manager(typename mpl::front<resource_types>::type &resource)
- : resources(ref(resource))
- , activetx(){
- BOOST_STATIC_ASSERT(mpl::size<resource_types>::value==1);
- this->bind();
- }
-
- /// Throws: Nothing
- /// \brief Constructs a basic_transaction_manager using the passed resource managers
- /// \param resources A Boost.Fusion Sequence of non-const references to the resource
- /// managers. For example, fusion::vector<res1_type &,res2_type &>
- explicit basic_transaction_manager(typename detail::resources_tuple const &resources)
- : resources(resources)
- , activetx(){
- this->bind();
+ /// TODO doc, not part of the concept
+ template<class Resource>
+ static void connect_resource(Resource &newres){
+ typedef typename Resource::tag tag;
+ typedef typename persistent::detail::index_by_tag<resource_types,tag>::type index;
+ Resource *&res=fusion::at<index>(resources);
+ if(res) persistent::detail::throw_(resource_error());
+ res=&newres;
+ }
+
+ /// TODO doc, not part of the concept
+ template<class ResourceTag>
+ static void disconnect_resource(ResourceTag tag=ResourceTag()){
+ typedef typename persistent::detail::index_by_tag<resource_types,ResourceTag>::type index;
+ fusion::at<index>(resources)=0;
}
template<class Tag>
- typename persistent::detail::type_by_tag<resource_types,Tag>::type &resource(Tag tag=Tag()){
+ static typename persistent::detail::type_by_tag<resource_types,Tag>::type &resource(Tag tag=Tag()){
+ typedef typename persistent::detail::type_by_tag<resource_types,Tag>::type resource_type;
typedef typename persistent::detail::index_by_tag<resource_types,Tag>::type index;
- return fusion::at<index>(this->resources);
+ resource_type *res=fusion::at<index>(resources);
+ if(res) return *res;
+ else persistent::detail::throw_(resource_error());
}
template<class Tag>
- typename persistent::detail::type_by_tag<resource_types,Tag>::type::transaction &
+ static typename persistent::detail::type_by_tag<resource_types,Tag>::type::transaction &
resource_transaction(transaction &tx,Tag tag=Tag()){
typedef typename persistent::detail::type_by_tag<resource_types,Tag>::type resource_type;
typedef typename persistent::detail::index_by_tag<resource_types,Tag>::type index;
@@ -157,93 +155,66 @@
//manager is the only one, or according to user configuration.
lock_guard<typename transaction::mutex_type> l(tx.mutex);
if(!rtx){
- resource_type &resource=fusion::at<index>(this->resources);
+ resource_type &res=resource(tag);
if(tx.parent){
//TODO optimization: if 10 nested transactions were created in one resource manager,
//and then a second resource manager is called for the first time in the innermost
//transaction, 10 nested transactions are created in the second resource manager,
//even though it would be enough to create one transaction
//that gets committed only when the outermost global transaction is committed.
+ //(or is moved to the parent on commit instead of performing an actual commit?)
- typename resource_type::transaction &parentrtx=this->resource_transaction<Tag>(*tx.parent);
- rtx=in_place(resource.begin_nested_transaction(parentrtx));
+ typename resource_type::transaction &parentrtx=resource_transaction<Tag>(*tx.parent);
+ rtx=in_place(res.begin_nested_transaction(parentrtx));
}else{
- rtx=in_place(resource.begin_root_transaction());
+ rtx=in_place(res.begin_root_transaction());
}
}
return *rtx;
}
- typename detail::transaction_construct_t begin_transaction(){
- if(this->has_active_transaction()) return typename detail::transaction_construct_t(&this->active_transaction());
- else return typename detail::transaction_construct_t(0);
- }
-
- void commit_transaction(transaction &tx){
- this->bind_transaction(tx);
-
- try{
- std::size_t nr=fusion::count_if(tx.resource_transactions,is());
- if(nr > 0){
- if(nr == 1){
- //FIXME the local transaction commit might access other resource managers
- //(e.g. for reference counting). that can start another resource transaction
- //and a two-phase-commit must take place.
- //finish-phase must be introduced to make sure the commit itself doesn't
- //access other resource managers
- this->for_each_transaction(tx,committer());
- }else{
- persistent::detail::throw_(unsupported_exception()); //TODO distributed transaction
- }
- }
- }catch(...){ //commit_transaction is called exactly once, even if something goes wrong. unbind transaction:
- if(tx.parent) this->bind_transaction(*tx.parent);
- else this->unbind_transaction();
- throw;
- }
- if(tx.parent) this->bind_transaction(*tx.parent);
- else this->unbind_transaction();
+ static typename detail::transaction_construct_t begin_transaction(){
+ return typename detail::transaction_construct_t(active_transaction(mpl::bool_<Threads>()));
}
- void rollback_transaction(transaction &tx){
- this->bind_transaction(tx);
+ static void commit_transaction(transaction &tx){
+ bind_transaction(tx);
- try{ this->for_each_transaction(tx,rollbacker()); }
- catch(...){
- if(tx.parent) this->bind_transaction(*tx.parent);
- else this->unbind_transaction();
- throw;
+ std::size_t nr=fusion::count_if(tx.resource_transactions,is());
+ if(nr > 0){
+ if(nr == 1){
+ //FIXME the local transaction commit might access other resource managers
+ //(e.g. for reference counting). that can start another resource transaction
+ //and a two-phase-commit must take place.
+ //finish-phase must be introduced to make sure the commit itself doesn't
+ //access other resource managers
+ for_each_transaction(tx,committer());
+ }else{
+ persistent::detail::throw_(unsupported_exception()); //TODO distributed transaction
+ }
}
-
- if(tx.parent) this->bind_transaction(*tx.parent);
- else this->unbind_transaction();
}
- void bind_transaction(transaction &tx){
- this->active_transaction(&tx,mpl::bool_<Threads>());
- }
- void unbind_transaction(){
- this->active_transaction(0,mpl::bool_<Threads>());
+ static void rollback_transaction(transaction &tx){
+ bind_transaction(tx);
+
+ for_each_transaction(tx,rollbacker());
}
- transaction &active_transaction() const{
- if(transaction *tx=this->active_transaction(mpl::bool_<Threads>())) return *tx;
- else persistent::detail::throw_(no_active_transaction());
+ static void bind_transaction(transaction &tx){
+ active_transaction(&tx,mpl::bool_<Threads>());
}
- bool has_active_transaction() const{
- return this->active_transaction(mpl::bool_<Threads>()) ? true : false;
+ static void unbind_transaction(){
+ active_transaction(0,mpl::bool_<Threads>());
}
- static bool has_active(){
- return active_;
+ static transaction &active_transaction(){
+ if(transaction *tx=active_transaction(mpl::bool_<Threads>())) return *tx;
+ else persistent::detail::throw_(no_active_transaction());
}
-
- static basic_transaction_manager &active(){
- if(active_) return *active_;
- else persistent::detail::throw_(no_active_transaction_manager());
+ static bool has_active_transaction(){
+ return active_transaction(mpl::bool_<Threads>()) ? true : false;
}
- void bind(){ active_=this; }
- static void unbind(){ active_=0; }
/// \cond
private:
@@ -266,53 +237,70 @@
};
template<class F>
struct for_each_helper{
- explicit for_each_helper(basic_transaction_manager *this_,transaction &tx,F const &f) : this_(this_),tx(tx),f(f){}
+ explicit for_each_helper(transaction &tx,F const &f) : tx(tx),f(f){}
template<class U>
void operator()(U) const{
typedef typename mpl::at<resource_types,U>::type resource_type;
optional<typename resource_type::transaction> &rtx=fusion::at<U>(tx.resource_transactions);
if(rtx){
- resource_type &rmgr=fusion::at<U>(this_->resources);
- f(rmgr,*rtx);
+ resource_type *rmgr=fusion::at<U>(resources);
+ BOOST_ASSERT(rmgr);
+ f(*rmgr,*rtx);
}
}
private:
- basic_transaction_manager *this_;
transaction &tx;
F f;
};
template<class F>
- void for_each_transaction(transaction &tx,F const &f){
+ static void for_each_transaction(transaction &tx,F const &f){
static unsigned int const size=mpl::size<resource_types>::type::value;
typedef mpl::range_c<unsigned int,0,size> range;
- mpl::for_each<range>(for_each_helper<F>(this,tx,f));
- }
- void active_transaction(transaction *newtx,mpl::true_){
- if(transaction **tx=this->activetx.get()) *tx=newtx;
- else this->activetx.reset(new transaction *(newtx));
- }
- void active_transaction(transaction *newtx,mpl::false_){
- this->activetx=newtx;
- }
- transaction *active_transaction(mpl::true_) const{
- if(transaction **tx=this->activetx.get()){
- if(*tx) return *tx;
- }
- return 0;
- }
- transaction *active_transaction(mpl::false_) const{
- return this->activetx;
+ mpl::for_each<range>(for_each_helper<F>(tx,f));
}
+#if defined(__GNUG__) || defined(BOOST_MSVC)
+ template<class T>
+ static void active_transaction(transaction *newtx,T){ activetx=newtx; }
+ template<class T>
+ static transaction *active_transaction(T){ return activetx; }
+ typedef transaction *activetx_type;
+ #ifdef BOOST_MSVC
+ static __declspec(thread) transaction *activetx; //TODO MSVC untested
+ #else
+ static __thread transaction *activetx;
+ #endif
+#else
+ static void active_transaction(transaction *newtx,mpl::true_){ activetx.reset(newtx); }
+ static void active_transaction(transaction *newtx,mpl::false_){ activetx=newtx; }
+ static transaction *active_transaction(mpl::true_){ return activetx.get(); }
+ static transaction *active_transaction(mpl::false_){ return activetx; }
+ typedef typename mpl::if_c<
+ Threads,
+ thread_specific_ptr<transaction>,
+ transaction *>::type activetx_type;
+ activetx_type activetx;
+#endif
- typename detail::resources_tuple const resources;
- //TODO optimization: use thread local variable instead of thread_specific_ptr
- typename mpl::if_c<Threads,thread_specific_ptr<transaction *>,transaction *>::type activetx;
- static basic_transaction_manager *active_;
+
+ typedef typename detail::resources_tuple resources_type;
+ static resources_type resources;
/// \endcond
};
-template<class Resources,bool Threads,bool TThreads>
-basic_transaction_manager<Resources,Threads,TThreads> *basic_transaction_manager<Resources,Threads,TThreads>::active_=0;
+template<class Res,bool Thr,bool TThr>
+typename basic_transaction_manager<Res,Thr,TThr>::resources_type
+basic_transaction_manager<Res,Thr,TThr>::resources;
+
+template<class Res,bool Thr,bool TThr>
+#if defined(__GNUG__)
+__thread
+#elif defined(BOOST_MSVC)
+__declspec(thread)
+#endif
+typename basic_transaction_manager<Res,Thr,TThr>::activetx_type
+basic_transaction_manager<Res,Thr,TThr>::activetx(0); //the 0-argument either initializes
+//the pointer to 0, or passes a 0 cleanup function to the thread_specific_ptr constructor.
+
}
}
Modified: sandbox/transaction/dev/exception.hpp
==============================================================================
--- sandbox/transaction/dev/exception.hpp (original)
+++ sandbox/transaction/dev/exception.hpp 2010-01-22 14:32:31 EST (Fri, 22 Jan 2010)
@@ -43,8 +43,8 @@
///Indicates that the operation required an active transaction but there was no active transaction set for this thread.
struct no_active_transaction : persistent::exception{};
-///Indicates that the operation required an active transaction manager but there is none set.
-struct no_active_transaction_manager : persistent::exception{};
+///TODO doc
+struct resource_error : persistent::exception{};
///Indicates that the operation is not supported by this implementation
struct unsupported_exception : persistent::exception{};
@@ -58,20 +58,20 @@
template<class TxMgr,class Iterator>
struct isolation_unwind_visitor{
- void operator()(TxMgr &txmgr,isolation_exception const &iso){
+ void operator()(isolation_exception const &iso){
typedef typename mpl::deref<Iterator>::type resource_type;
if(visolation_exception<resource_type> const *viso=dynamic_cast<visolation_exception<resource_type> const *>(&iso)){
- viso->unwind(txmgr);
+ viso->template unwind<TxMgr>();
}else{
isolation_unwind_visitor<TxMgr,typename mpl::next<Iterator>::type> visit;
- visit(txmgr,iso);
+ visit(iso);
}
}
};
template<class TxMgr>
struct isolation_unwind_visitor<TxMgr,typename mpl::end<typename TxMgr::resource_types>::type>{
- void operator()(TxMgr &,isolation_exception const &){
+ void operator()(isolation_exception const &){
BOOST_ASSERT(false);
}
};
@@ -82,9 +82,9 @@
struct isolation_exception : persistent::exception{
///Rethrows the exception if the active transaction is a nested transaction but the isolation exception was caused by a parent transaction of it.
template<class TxMgr>
- void unwind(TxMgr &txmgr=TxMgr::active()) const{ //pseudo-virtual
+ void unwind() const{ //pseudo-virtual
detail::isolation_unwind_visitor<TxMgr,typename mpl::begin<typename TxMgr::resource_types>::type> visit;
- visit(txmgr,*this);
+ visit(*this);
}
};
@@ -95,11 +95,11 @@
struct visolation_exception : isolation_exception{
visolation_exception(typename ResMgr::transaction *unwind_to) : to(unwind_to){}
template<class TxMgr>
- void unwind(TxMgr &txmgr) const{ //pseudo-virtual
+ void unwind() const{ //pseudo-virtual
if(this->to){
- typename ResMgr::transaction &tx=txmgr.template resource_transaction<typename ResMgr::tag>(txmgr.active_transaction());
+ typename ResMgr::transaction &tx=TxMgr::template resource_transaction<typename ResMgr::tag>(TxMgr::active_transaction());
if(&tx != this->to) throw;
- }else if(txmgr.has_active_transaction()) throw;
+ }else if(TxMgr::has_active_transaction()) throw;
}
private:
typename ResMgr::transaction *to;
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