Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r59594 - in sandbox/transaction/boost: transact transact/detail transaction
From: strasser_at_[hidden]
Date: 2010-02-09 08:33:37


Author: stefans
Date: 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
New Revision: 59594
URL: http://svn.boost.org/trac/boost/changeset/59594

Log:
initial
Added:
   sandbox/transaction/boost/transact/
   sandbox/transaction/boost/transact/atomic.hpp (contents, props changed)
   sandbox/transaction/boost/transact/basic_atomic.hpp (contents, props changed)
   sandbox/transaction/boost/transact/basic_transaction.hpp (contents, props changed)
   sandbox/transaction/boost/transact/basic_transaction_manager.hpp (contents, props changed)
   sandbox/transaction/boost/transact/detail/
   sandbox/transaction/boost/transact/detail/aligning_file.hpp (contents, props changed)
   sandbox/transaction/boost/transact/detail/buffering_file.hpp (contents, props changed)
   sandbox/transaction/boost/transact/detail/embedded_vector.hpp (contents, props changed)
   sandbox/transaction/boost/transact/detail/filebuf_file.hpp (contents, props changed)
   sandbox/transaction/boost/transact/detail/mutex.hpp (contents, props changed)
   sandbox/transaction/boost/transact/detail/sectorizing_file.hpp (contents, props changed)
   sandbox/transaction/boost/transact/detail/static_tss.hpp (contents, props changed)
   sandbox/transaction/boost/transact/detail/syncing_file.hpp (contents, props changed)
   sandbox/transaction/boost/transact/exception.hpp (contents, props changed)
   sandbox/transaction/boost/transact/log.hpp (contents, props changed)
   sandbox/transaction/boost/transact/simple_transaction_manager.hpp (contents, props changed)
   sandbox/transaction/boost/transact/transaction.hpp (contents, props changed)
   sandbox/transaction/boost/transact/transaction_manager.hpp (contents, props changed)
Removed:
   sandbox/transaction/boost/transaction/

Added: sandbox/transaction/boost/transact/atomic.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/atomic.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,16 @@
+#ifndef BOOST_TRANSACT_ATOMIC_HPP
+#define BOOST_TRANSACT_ATOMIC_HPP
+
+#include <boost/transact/basic_atomic.hpp>
+#include <boost/transact/transaction_manager.hpp>
+
+/// \brief An alias of BOOST_TRANSACT_BASIC_ATOMIC using the default transaction manager
+#define BOOST_TRANSACT_ATOMIC \
+ BOOST_TRANSACT_BASIC_ATOMIC(boost::transact::transaction_manager)
+
+/// \brief An alias of BOOST_TRANSACT_BASIC_COMMIT using the default transaction manager
+#define BOOST_TRANSACT_COMMIT() \
+ BOOST_TRANSACT_BASIC_COMMIT(boost::transact::transaction_manager)
+
+
+#endif

Added: sandbox/transaction/boost/transact/basic_atomic.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/basic_atomic.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,49 @@
+#include <boost/transact/basic_transaction.hpp>
+
+#ifndef BOOST_TRANSACT_BASIC_ATOMIC_HPP
+#define BOOST_TRANSACT_BASIC_ATOMIC_HPP
+
+/// \brief Begins a new transaction scope.
+///
+/// BOOST_TRANSACT_BASIC_ATOMIC and BOOST_TRANSACT_BASIC_COMMIT provide a simple syntax for
+/// concurrent transactions.
+///
+/// When used together the macros
+/// expand to a transaction scope that gets repeatedly executed until the transaction
+/// is successfully committed without conflicting with another transaction.
+///
+/// Example: \code
+/// #define atomic BOOST_TRANSACT_ATOMIC
+/// #define commit BOOST_TRANSACT_COMMIT
+///
+/// do atomic{
+/// ...
+/// }commit();
+/// \endcode expands to code equivalent to \code
+/// do{
+/// try{
+/// transaction tx;
+/// ...
+/// tx.commit();
+/// }catch(isolation_exception &i){
+/// i.unwind<transaction_manager>();
+/// continue;
+/// }
+/// }while(false); \endcode
+#define BOOST_TRANSACT_BASIC_ATOMIC(TXMGR) \
+ { \
+ try{ \
+ boost::transact::basic_transaction<TXMGR> ___tx;
+
+/// Ends a transaction scope.
+/// See BOOST_TRANSACT_BASIC_ATOMIC for a detailed description.
+#define BOOST_TRANSACT_BASIC_COMMIT(TXMGR) \
+ } \
+ ___tx.commit_(); \
+ }catch(boost::transact::isolation_exception &i){ \
+ i.unwind<TXMGR>(); \
+ continue; \
+ } \
+ }while(false);
+
+#endif

Added: sandbox/transaction/boost/transact/basic_transaction.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/basic_transaction.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,139 @@
+// Copyright Stefan Strasser 2009 - 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_BASIC_TRANSACTION_HEADER_HPP
+#define BOOST_TRANSACT_BASIC_TRANSACTION_HEADER_HPP
+
+#include <boost/noncopyable.hpp>
+
+namespace boost{
+namespace transact{
+
+/// Begins a transaction on construction, and rolls it back on destruction if it is
+/// still active.
+///
+/// Template parameters:
+/// \li \c TxMgr The transaction manager
+/// \brief A transaction scope
+template<class TxMgr>
+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.
+ ///
+ /// 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)
+ , tx(TxMgr::begin_transaction())
+ , done(false){
+ TxMgr::bind_transaction(this->tx);
+ }
+
+ /// The transaction is rolled back if it is still active. Exceptions
+ /// caused by rolling back the transaction are ignored.
+ ///
+ /// Throws: Nothing
+ /// \brief Destructs the basic_transaction object
+ ~basic_transaction(){
+ if(!this->done){
+ try{
+ TxMgr::rollback_transaction(this->tx);
+ }catch(...){
+#ifndef NDEBUG
+ std::cerr << "ignored exception" << std::endl;
+#endif
+ }
+ }
+ try{
+ this->pop();
+ }catch(...){
+#ifndef NDEBUG
+ std::cerr << "ignored exception" << std::endl;
+#endif
+ }
+ }
+
+ /// 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();
+ }
+ /// \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();
+ }
+
+ /// Throws: thread_resource_error
+ /// \brief Binds the current thread to this transaction
+ void bind(){
+ TxMgr::bind_transaction(this->tx);
+ }
+
+ /// 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){
+ TxMgr::unbind_transaction();
+ }
+ }
+
+ /// \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;
+ /// \endcond
+};
+
+
+}
+}
+
+
+
+
+
+
+#endif
\ No newline at end of file

Added: sandbox/transaction/boost/transact/basic_transaction_manager.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/basic_transaction_manager.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,479 @@
+// Copyright Stefan Strasser 2009 - 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_BASIC_TRANSACTION_MANAGER_HEADER_HPP
+#define BOOST_TRANSACT_BASIC_TRANSACTION_MANAGER_HEADER_HPP
+
+#include <boost/thread/locks.hpp>
+#include <boost/thread/tss.hpp>
+#include <boost/transact/detail/mutex.hpp>
+#include <boost/transact/exception.hpp>
+#include <boost/transact/detail/static_tss.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>
+#include <boost/fusion/include/at.hpp>
+#include <boost/fusion/include/vector.hpp>
+#include <boost/fusion/include/is_sequence.hpp>
+#include <boost/utility/in_place_factory.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/transform.hpp>
+#include <boost/mpl/size.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/at.hpp>
+#include <boost/mpl/is_sequence.hpp>
+#include <boost/mpl/map.hpp>
+#include <boost/mpl/range_c.hpp>
+#include <boost/mpl/for_each.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/empty_sequence.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/deref.hpp>
+#include <boost/mpl/find.hpp>
+#include <boost/mpl/find_if.hpp>
+#include <boost/mpl/contains.hpp>
+#include <boost/mpl/distance.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/fusion/include/pair.hpp>
+#include <boost/fusion/include/as_map.hpp>
+#include <boost/fusion/include/at_key.hpp>
+#include <boost/mpl/map.hpp>
+#include <boost/mpl/insert.hpp>
+
+
+namespace boost{
+namespace transact{
+
+namespace detail{
+
+template<class Resource>
+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{
+ explicit runtime_folder(State &state,F &f)
+ : state(state),f(f){}
+ template<class U>
+ void operator()(U x){
+ state=f(state,x);
+ }
+private:
+ State &state;
+ F &f;
+};
+
+template<class Sequence,class State,class F>
+State runtime_fold(State state,F f){
+ mpl::for_each<Sequence>(runtime_folder<State,F>(state,f));
+ return state;
+}
+
+}
+
+/// Model of TransactionManager. Only members that are not part of that concept are documented here.
+///
+/// Template parameters:
+/// \li \c Resources A MPL Sequence containing the types of the resource managers used.
+/// \li \c Threads \c true if multiple threads are used to access this transaction manager.
+/// \li \c TThreads \c true if multiple threads are used to access the same transaction. Can be \c false if multiple threads are used to access the transaction manager, but not to access the same transaction.
+/// \li \c Lazy A MPL Sequence of resource tags of those resource managers whose transactions
+/// ought to be started lazily, i.e. the local transaction of the resource manager
+/// is not started when the global transaction is started but on first
+/// 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 basic_transaction_manager : noncopyable{
+/// \cond
+ BOOST_STATIC_ASSERT(Threads || !TThreads);
+private:
+ struct detail{
+ typedef typename mpl::if_<
+ mpl::is_sequence<Resources>,
+ Resources,
+ mpl::vector1<Resources>
+ >::type resource_types;
+
+ typedef typename mpl::transform<
+ typename detail::resource_types,
+ 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<
+ resource_types,
+ 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;
+ };
+
+ template<class Resource>
+ struct get_services{
+ typedef typename Resource::services type;
+ };
+ template<class Service>
+ struct default_resource{
+ typedef typename mpl::deref<
+ typename mpl::find_if<
+ resource_types,
+ mpl::contains<get_services<mpl::_1>,Service>
+ >::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<
+ resource_types,
+ 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_mutex
+ >::type mutex_type;
+
+ mutex_type mutex;
+ };
+ };
+ struct activetx_tag{};
+ typedef transact::detail::static_thread_specific_ptr<
+ typename detail::transaction,
+ activetx_tag,
+ Threads> activetx;
+ /// \endcond
+public:
+ typedef typename detail::transaction transaction;
+ typedef typename detail::resource_types resource_types;
+ template<class ServiceTag>
+ struct default_resource{
+ typedef typename detail::template default_resource<ServiceTag>::type type;
+ };
+
+ /// A basic_transaction_manager constructed using this constructor
+ /// is not able to commit transactions that involve two or more persistent
+ /// resource managers, i.e. that require a two phase commit protocol.
+ /// \brief Constructs a basic_transaction_manager
+ basic_transaction_manager(){}
+
+ /// TODO doc, not part of the concept
+ template<class Resource>
+ static void connect_resource(Resource &newres){
+ Resource *&res=fusion::at_key<typename Resource::tag>(resources);
+ if(res) throw resource_error();
+ res=&newres;
+ }
+
+ /// TODO doc, not part of the concept
+ template<class ResourceTag>
+ static void disconnect_resource(ResourceTag tag=ResourceTag()){
+ fusion::at<ResourceTag>(resources)=0;
+ }
+
+ template<class Tag>
+ static typename detail::resource_type<Tag>::type &resource(Tag tag=Tag()){
+ typename detail::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 &
+ 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());
+ }
+
+ 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)));
+
+ mpl::for_each<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));
+ if(pers > 1){
+ mpl::for_each<tags>(preparer<true>(tx)); //prepare persistent transactions
+ //TODO write commit message to log
+ mpl::for_each<tags>(committer<true>(tx)); //commit persistent transactions
+ }else{
+ mpl::for_each<tags>(committer<true>(tx)); //commit persistent transaction unprepared
+ }
+ mpl::for_each<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));
+ }
+
+ static void bind_transaction(transaction &tx){
+ activetx::reset(&tx);
+ }
+ static void unbind_transaction(){
+ activetx::reset(0);
+ }
+
+ static transaction &active_transaction(){
+ if(transaction *tx=activetx::get()) return *tx;
+ else throw no_active_transaction();
+ }
+ static bool has_active_transaction(){
+ return activetx::get() ? true : false;
+ }
+
+ /// \cond
+private:
+ struct persistent_counter{
+ 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;
+ if(is_persistent<res_type>::type::value){
+ if(fusion::at_key<Tag>(tx.resource_transactions)){
+ return c+1;
+ }
+ }
+ return c;
+ }
+ private:
+ transaction &tx;
+ };
+ struct finisher{
+ explicit finisher(transaction &tx) : tx(tx){}
+ template<class Tag>
+ bool operator()(bool repeat,Tag tag){
+ typedef typename detail::resource_type<Tag>::type res_type;
+ optional<typename res_type::transaction> &rtx=
+ fusion::at_key<Tag>(tx.resource_transactions);
+ if(rtx){
+ res_type *rmgr=fusion::at_key<Tag>(resources);
+ BOOST_ASSERT(rmgr);
+ return rmgr->finish_transaction(*rtx) || repeat;
+ }
+ return repeat;
+ }
+ private:
+ transaction &tx;
+ };
+ struct beginner{
+ explicit beginner(transaction &tx) : tx(tx){}
+ template<class Tag>
+ void operator()(Tag tag){
+ this->begin(tag,typename mpl::contains<Lazy,Tag>::type());
+ }
+ private:
+ template<class Tag>
+ void begin(Tag,mpl::true_ lazy){}
+ template<class Tag>
+ void begin(Tag,mpl::false_ lazy){
+ typedef typename detail::resource_type<Tag>::type res_type;
+ res_type *rmgr=fusion::at_key<Tag>(resources);
+ if(rmgr){
+ optional<typename res_type::transaction> &rtx=
+ fusion::at_key<Tag>(tx.resource_transactions);
+ BOOST_ASSERT(!rtx);
+ if(tx.parent){
+ typename res_type::transaction &parentrtx=
+ resource_transaction<Tag>(*tx.parent);
+ rtx=in_place(rmgr->begin_nested_transaction(parentrtx));
+ }else rtx=in_place(rmgr->begin_root_transaction());
+ }
+ }
+ transaction &tx;
+ };
+ template<class Tag>
+ static typename detail::resource_type<Tag>::type::transaction &
+ resource_transaction(transaction &tx,Tag tag,mpl::true_ lazy){
+ typedef typename detail::resource_type<Tag>::type res_type;
+ optional<typename res_type::transaction> &rtx=
+ fusion::at_key<Tag>(tx.resource_transactions);
+
+ lock_guard<typename transaction::mutex_type> l(tx.mutex);
+ if(!rtx){
+ res_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 res_type::transaction &parentrtx=resource_transaction<Tag>(*tx.parent);
+ rtx=in_place(res.begin_nested_transaction(parentrtx));
+ }else{
+ rtx=in_place(res.begin_root_transaction());
+ }
+ }
+ return *rtx;
+ }
+ template<class Tag>
+ static typename detail::resource_type<Tag>::type::transaction &
+ resource_transaction(transaction &tx,Tag tag,mpl::false_ lazy){
+ typedef typename detail::resource_type<Tag>::type res_type;
+ optional<typename res_type::transaction> &rtx=
+ fusion::at_key<Tag>(tx.resource_transactions);
+ BOOST_ASSERT(rtx);
+ return *rtx;
+ }
+ template<class Resource>
+ struct is_persistent{
+ typedef mpl::true_ type; //FIXME
+ };
+ template<class Resource>
+ struct is_two_phase{
+ typedef mpl::false_ type; //FIXME
+ };
+
+ template<bool Persistent>
+ struct committer{
+ explicit committer(transaction &tx) : tx(tx){}
+ template<class Tag>
+ void operator()(Tag){
+ typedef typename detail::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);
+ if(rtx){
+ res_type *res=fusion::at_key<Tag>(resources);
+ BOOST_ASSERT(res);
+ res->commit_transaction(*rtx);
+ }
+ }
+ }
+ private:
+ transaction &tx;
+ };
+ template<bool Persistent>
+ struct preparer{
+ explicit preparer(transaction &tx) : tx(tx){}
+ template<class Tag>
+ void operator()(Tag){
+ typedef typename detail::resource_type<Tag>::type res_type;
+ if(Persistent == is_persistent<res_type>::type::value){
+ typedef typename detail::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->prepare(*res,*rtx,typename is_two_phase<res_type>::type());
+ }
+ }
+ }
+ private:
+ template<class Resource>
+ void prepare(Resource &res,typename Resource::transaction &rtx,mpl::true_){
+ res.prepare_transaction(rtx);
+ }
+ template<class Resource>
+ void prepare(Resource &res,typename Resource::transaction &rtx,mpl::false_){
+ //a resource that does not support two-phase-commit was used
+ //together with other persistent resources
+ throw unsupported_exception();
+ }
+ transaction &tx;
+ };
+ struct rollbacker{
+ explicit rollbacker(transaction &tx) : tx(tx){}
+ template<class Tag>
+ void operator()(Tag){
+ typedef typename detail::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;
+ };
+ template<class Resource>
+ struct make_resource_ptr_pair{
+ typedef fusion::pair<typename Resource::tag,Resource *> type;
+ };
+ typedef typename fusion::result_of::as_map<
+ typename mpl::transform<
+ resource_types,
+ make_resource_ptr_pair<mpl::_1>
+ >::type
+ >::type resources_type;
+ static resources_type resources;
+
+ /// \endcond
+};
+
+template<class Res,bool Thr,bool TThr,class Lazy>
+typename basic_transaction_manager<Res,Thr,TThr,Lazy>::resources_type
+basic_transaction_manager<Res,Thr,TThr,Lazy>::resources;
+
+}
+}
+
+
+
+#endif
\ No newline at end of file

Added: sandbox/transaction/boost/transact/detail/aligning_file.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/detail/aligning_file.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,135 @@
+// Copyright Stefan Strasser 2009 - 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_DETAIL_ALIGNING_FILE_HPP
+#define BOOST_TRANSACT_DETAIL_ALIGNING_FILE_HPP
+
+#include <boost/mpl/size_t.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/assert.hpp>
+#include <cstring>
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+//linux needs sync intervals up to 4096 bytes to be aligned,
+//e.g., starting at position 0, and | representing a sync:
+
+//512 | 2048 | ...
+
+//does not result in sequential writing performance, instead:
+
+//512 | [1536] | 2048 | ...
+
+//does. the inserted 1536 bytes of garbage even need to be synced.
+
+//TODO optimization: not tested on windows.
+
+template<class Base>
+class aligning_seq_ofile{
+public:
+ typedef typename Base::size_type size_type;
+private:
+ static std::size_t const sector_size=512;
+ static std::size_t const max_alignment=4096;
+ static std::size_t const max_sectors=max_alignment / sector_size / 2;
+public:
+ explicit aligning_seq_ofile(std::string const &name)
+ : base(name)
+ , sectors(0){}
+ void save_binary(void const *data,mpl::size_t<sector_size> size){
+ if(this->sectors < max_sectors){
+ std::memcpy(this->buffer + this->sectors * sector_size,data,size);
+ ++this->sectors;
+ }else this->save_overflow(data);
+ }
+ size_type position() const{
+ if(this->sectors <= max_sectors) return this->base.position() + this->sectors * sector_size;
+ else return this->base.position();
+ }
+ void flush(){
+ BOOST_ASSERT(this->base.position() % sector_size == 0);
+ if(this->sectors > 1 && this->sectors <= max_sectors){
+ BOOST_STATIC_ASSERT(max_sectors == 4);
+ this->align((this->sectors == 3 ? 4 : this->sectors) * sector_size);
+ }
+ this->flush_buffer();
+ this->sectors=0;
+ this->base.flush();
+ }
+ void sync(){
+ this->base.sync();
+ }
+ ~aligning_seq_ofile(){
+ try{
+ this->flush_buffer();
+ }catch(...){
+#ifndef NDEBUG
+ std::cerr << "ignored exception" << std::endl;
+#endif
+ }
+ }
+private:
+ void save_overflow(void const *data){
+ BOOST_ASSERT(this->sectors >= max_sectors);
+ if(this->sectors == max_sectors){
+ this->align(max_alignment);
+ this->flush_buffer();
+ this->sectors=max_sectors+1;
+ }
+ this->base.save_binary(data,sector_size);
+ }
+
+ void flush_buffer(){
+ if(this->sectors > 0 && this->sectors <= max_sectors){
+ this->base.save_binary(this->buffer,this->sectors * sector_size);
+ }
+ }
+ void align(std::size_t alignment){
+ BOOST_ASSERT(this->base.position() % sector_size == 0);
+ std::size_t mod=this->base.position() % alignment;
+ if(mod != 0){
+ std::size_t write=alignment - mod;
+ BOOST_ASSERT(write <= empty_sectors_t::size && write % sector_size == 0);
+ this->base.save_binary(empty_sectors.data,write);
+ this->base.flush();
+ //this sync is unnecessary from a data-consistency viewpoint.
+ //but it is required to keep linux is sequential writing.
+ this->base.sync(); //TODO optimization: sync inside mutex lock
+ }
+ }
+
+ Base base;
+ unsigned char buffer[max_sectors * sector_size];
+ std::size_t sectors;
+
+ struct empty_sectors_t{
+ empty_sectors_t(){
+ for(std::size_t c=0;c<sectors;++c) clear_sector(this->data + c*sector_size);
+ }
+ static std::size_t const size=max_alignment - sector_size;
+ static std::size_t const sectors = size / sector_size;
+ unsigned char data[size];
+ static void clear_sector(char *sec){
+ sec[0]=0x80;
+ sec[sector_size-1]=0x80;
+ }
+ };
+ static empty_sectors_t empty_sectors;
+};
+
+template<class Base>
+typename aligning_seq_ofile<Base>::empty_sectors_t aligning_seq_ofile<Base>::empty_sectors;
+
+
+}
+}
+}
+
+
+
+#endif

Added: sandbox/transaction/boost/transact/detail/buffering_file.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/detail/buffering_file.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,89 @@
+// Copyright Stefan Strasser 2009 - 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_DETAIL_BUFFERING_FILE_HPP
+#define BOOST_TRANSACT_DETAIL_BUFFERING_FILE_HPP
+
+#include <boost/mpl/size_t.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/assert.hpp>
+#include <cstring>
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+template<class Base,std::size_t Capacity>
+class buffering_seq_ofile{
+public:
+ typedef typename Base::size_type size_type;
+ explicit buffering_seq_ofile(std::string const &name)
+ : base(name)
+ , size(0){}
+ template<class Size>
+ void save_binary(void const *data,Size s){
+ if(this->size + s <= Capacity){
+ std::memcpy(this->buffer+this->size,data,s);
+ this->size+=s;
+ }else this->save_overflow(data,s);
+ }
+ template<class T>
+ void save(T const &t){
+ this->save_binary(&t,mpl::size_t<sizeof(T)>());
+ }
+ size_type position() const{
+ return this->base.position() + this->size;
+ }
+ void flush(){
+ this->flush_buffer();
+ this->base.flush();
+ }
+ void sync(){
+ //don't flush buffer! caller is responsible to call flush() inside a mutex lock.
+ this->base.sync();
+ }
+ ~buffering_seq_ofile(){
+ try{
+ this->flush_buffer();
+ }catch(...){
+#ifndef NDEBUG
+ std::cerr << "ignored exception" << std::endl;
+#endif
+ }
+ }
+private:
+ void save_overflow(void const *data,std::size_t s){
+ BOOST_ASSERT(this->size + s > Capacity);
+ if(this->size == 0){
+ this->base.save_binary(data,s);
+ }else{
+ std::size_t write=Capacity - this->size;
+ std::memcpy(this->buffer+this->size,data,write);
+ this->size=Capacity;
+ this->flush_buffer();
+ this->save_binary(static_cast<char const *>(data)+write,s-write);
+ }
+ }
+ void flush_buffer(){
+ if(this->size > 0){
+ this->base.save_binary(this->buffer,this->size);
+ this->size=0;
+ }
+ }
+
+ Base base;
+ char buffer[Capacity];
+ std::size_t size;
+};
+
+
+}
+}
+}
+
+
+
+#endif

Added: sandbox/transaction/boost/transact/detail/embedded_vector.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/detail/embedded_vector.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,239 @@
+#ifndef BOOST_TRANSACT_DETAIL_EMBEDDED_VECTOR_HEADER_HPP
+#define BOOST_TRANSACT_DETAIL_EMBEDDED_VECTOR_HEADER_HPP
+
+#include <iterator>
+#include <algorithm>
+#include <cstring>
+#include <boost/utility/in_place_factory.hpp>
+#include <boost/type_traits/is_pod.hpp>
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+template<class T,std::size_t EmbeddedSize,bool Expand=true>
+class embedded_vector{
+public:
+ typedef T &reference;
+ typedef T const &const_reference;
+ typedef T *iterator;
+ typedef T const *const_iterator;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef T *pointer;
+ typedef T const *const_pointer;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ embedded_vector()
+ : begin_(emb_data())
+ , end_(emb_data())
+ , end_storage(emb_data() + EmbeddedSize){}
+
+ embedded_vector(size_type n,T const &value=T());
+ template<class InputIterator>
+ embedded_vector(InputIterator begin,InputIterator end);
+ embedded_vector(embedded_vector const &);
+ ~embedded_vector(){
+ destruct(this->begin(),this->end());
+ if(Expand){
+ if(this->begin() != this->emb_data()){
+ ::operator delete(this->begin_);
+ }
+ }else BOOST_ASSERT(this->begin() == this->emb_data());
+ }
+
+ embedded_vector &operator=(embedded_vector const &);
+
+ iterator begin(){ return this->begin_; }
+ const_iterator begin() const{ return this->begin_; }
+ iterator end(){ return this->end_; }
+ const_iterator end() const{ return this->end_; }
+ reverse_iterator rbegin(){ return reverse_iterator(this->end()); }
+ const_reverse_iterator rbegin() const{ return const_reverse_iterator(this->end()); }
+ reverse_iterator rend(){ return reverse_iterator(this->begin()); }
+ const_reverse_iterator rend() const{ return const_reverse_iterator(this->begin()); }
+ size_type size() const{
+ return this->end() - this->begin();
+ }
+ size_type max_size() const{
+ if(Expand) return size_type(-1);
+ else return EmbeddedSize;
+ }
+ void resize(size_type s,T const &c=T()){
+ this->reserve(s);
+ if(s > this->size()) copy_construct(this->end(),this->begin()+s,c);
+ else destruct(this->begin()+s,this->end());
+ this->end_=this->begin_+s;
+ }
+ size_type capacity() const{
+ return this->end_storage - this->begin_;
+ }
+ bool empty() const{
+ return this->begin() == this->end();
+ }
+ void reserve(size_type mincap){
+ this->reserve(mincap,mpl::bool_<Expand>());
+ }
+ reference operator[](size_type n){
+ BOOST_ASSERT(n < this->size());
+ return *(this->begin() + n);
+ }
+ const_reference operator[](size_type n) const{
+ BOOST_ASSERT(n < this->size());
+ return *(this->begin() + n);
+ }
+ reference at(size_type);
+ const_reference at(size_type) const;
+
+ reference front(){ return *this->begin(); }
+ const_reference front() const{ return *this->begin(); }
+ reference back(){ return *this->rbegin(); }
+ const_reference back() const{ return *this->rbegin(); }
+
+ template<class InputIterator>
+ void assign(InputIterator begin,InputIterator end);
+ void assign(size_type n,T const &u);
+
+ void push_back(T const &x){
+ this->reserve_add(mpl::size_t<1>());
+ new (this->end_) T(x);
+ ++this->end_;
+ }
+
+ //extension to efficiently insert arrays.
+ //insert(this->end(), ...) is not the same thing. even though the end() == end()
+ //comparison can be optimized away if inlined, size must be statically known to get
+ //an intrinsic memcpy for PODs.
+ template<class Size>
+ void push_back(T const *src,Size size){
+ this->reserve_add(size);
+ copy_construct_n(this->end_,src,size);
+ this->end_+=size;
+ }
+
+ //extension to in-place construct a new element. elements of vectors with Expand==false
+ //don't need to be copyconstructible using this:
+ template<class InPlaceFactory>
+ void push_back(InPlaceFactory const &fac){
+ this->reserve_add(mpl::size_t<1>());
+ fac.template apply<T>(this->end_);
+ ++this->end_;
+ }
+
+ void pop_back();
+ iterator insert(iterator position,T const &x);
+ void insert(iterator position,size_type n,T const &x);
+ template<class InputIterator>
+ void insert(iterator position,InputIterator first,InputIterator last);
+ iterator erase(iterator position);
+ iterator erase(iterator begin,iterator end);
+ void swap(embedded_vector &);
+ void clear(){
+ destruct(this->begin(),this->end());
+ this->end_=this->begin();
+ }
+private:
+ static void copy_construct(T *dest,T const *begin,T const *end){
+ copy_construct_n(dest,begin,std::size_t(end-begin));
+ }
+ static void copy_construct(T *begin,T *end,T const &x){
+ static bool const usememset=boost::is_pod<T>::value && sizeof(T) == 1;
+ copy_construct(begin,end,x,mpl::bool_<usememset>());
+ }
+ static void copy_construct(T *begin,T *end,T const &x,mpl::true_ usememset){
+ std::memset(begin,x,end-begin);
+ }
+ static void copy_construct(T *begin,T *end,T const &x,mpl::false_ usememset){
+ T *it;
+ try{
+ for(it=begin;it != end;++it){
+ new (it) T(x);
+ }
+ }catch(...){
+ destruct(begin,it);
+ throw;
+ }
+ }
+ template<class Size>
+ static void copy_construct_n(T *dest,T const *src,Size n){
+ copy_construct_n(dest,src,n,typename is_pod<T>::type());
+ }
+ template<class Size>
+ static void copy_construct_n(T *dest,T const *src,Size n,true_type pod){
+ std::memcpy(dest,src,sizeof(T)*std::size_t(n));
+ }
+ template<class Size>
+ static void copy_construct_n(T *dest,T const *src,Size n,false_type pod){
+ std::size_t c;
+ try{
+ for(c=0;c<n;++c){
+ new (dest+c) T(src[c]);
+ }
+ }catch(...){
+ destruct(dest,dest+c);
+ throw;
+ }
+ }
+ static void destruct(T const *begin,T const *end){
+ destruct(begin,end,typename is_pod<T>::type());
+ }
+ static void destruct(T const *begin,T const *end,true_type pod){}
+ static void destruct(T const *begin,T const *end,false_type pod){
+ for(T const *it=begin;it != end;++it){
+ it->~T(); //nothrow
+ }
+ }
+ //equivalent to reserve(size() + s)
+ template<class Size>
+ void reserve_add(Size s){
+ this->reserve_add(s,mpl::bool_<Expand>());
+ }
+ template<class Size>
+ void reserve_add(Size s,mpl::true_ expand){
+ if(this->end_ + s > this->end_storage) this->reallocate(this->size()+s);
+ }
+ template<class Size>
+ void reserve_add(Size s,mpl::false_ expand){
+ BOOST_ASSERT(this->capacity() >= this->size() + s);
+ }
+
+ void reserve(size_type mincap,mpl::true_ expand){
+ if(this->capacity() < mincap) this->reallocate(mincap);
+ }
+ void reserve(size_type mincap,mpl::false_ expand){
+ BOOST_ASSERT(this->capacity() >= mincap);
+ }
+ void reallocate(size_type mincap){
+ BOOST_ASSERT(mincap > this->capacity());
+ size_type newcap=this->capacity() * 2;
+ if(newcap < mincap) newcap=mincap;
+ void *newdata=::operator new(newcap * sizeof(T));
+ T *newbegin=reinterpret_cast<T *>(newdata);
+ try{
+ copy_construct(newbegin,this->begin(),this->end());
+ destruct(this->begin(),this->end());
+ }catch(...){ ::operator delete(newdata); throw; }
+ this->end_=newbegin + this->size();
+ this->end_storage=newbegin + newcap;
+ ::operator delete(this->begin_);
+ this->begin_=newbegin;
+ }
+ T *emb_data(){
+ return reinterpret_cast<T *>(this->emb_data_);
+ }
+
+ char emb_data_[sizeof(T)*EmbeddedSize];
+ T *begin_; //TODO optimization: begin_ and end_storage are not needed if Expand==false
+ T *end_;
+ T *end_storage;
+};
+
+
+}
+}
+}
+
+
+#endif

Added: sandbox/transaction/boost/transact/detail/filebuf_file.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/detail/filebuf_file.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,92 @@
+// Copyright Stefan Strasser 2009 - 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_DETAIL_FILEBUF_FILE_HPP
+#define BOOST_TRANSACT_DETAIL_FILEBUF_FILE_HPP
+
+#include <fstream>
+#include <string>
+#include <boost/mpl/size_t.hpp>
+#include <boost/transact/exception.hpp>
+
+#pragma warning(push)
+#pragma warning(disable:4996)
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+class filebuf_seq_ofile{
+public:
+ typedef unsigned long long size_type;
+ explicit filebuf_seq_ofile(std::string const &name) : pos(0){
+ if(!this->buf.open(name.c_str(),std::ios::out | std::ios::binary)) throw io_failure();
+ }
+ void save_binary(void const *data,mpl::size_t<1>){
+ if(this->buf.sputc(*static_cast<char const *>(data)) == EOF) throw io_failure();
+ ++this->pos;
+ }
+ void save_binary(void const *data,std::size_t size){
+ std::streamsize ret=this->buf.sputn(static_cast<char const *>(data),std::streamsize(size));
+ this->pos+=ret;
+ if(ret != std::streamsize(size)) throw io_failure();
+ }
+ template<class T>
+ void save(T const &t){
+ this->save_binary(&t,mpl::size_t<sizeof(T)>());
+ }
+ size_type position() const{ return this->pos; }
+ void flush(){
+ if(this->buf.pubsync() != 0) throw io_failure();
+ }
+ void sync(){
+ throw unsupported_exception();
+ }
+private:
+ std::filebuf buf;
+ size_type pos;
+};
+
+class filebuf_seq_ifile{
+public:
+ typedef unsigned long long size_type;
+ explicit filebuf_seq_ifile(std::string const &name) : pos(0){
+ if(!this->buf.open(name.c_str(),std::ios::in | std::ios::binary)) throw io_failure();
+ }
+ void load_binary(void *dataptr,mpl::size_t<1>){
+ char &data=*static_cast<char *>(dataptr);
+ int ret=this->buf.sbumpc();
+ if(ret == EOF) throw eof_exception();
+ ++this->pos;
+ data=ret;
+ }
+ void load_binary(void *data,std::size_t size){
+ std::streamsize ret=this->buf.sgetn(static_cast<char *>(data),std::streamsize(size));
+ this->pos+=ret;
+ if(ret != std::streamsize(size)){
+ if(ret == 0) throw eof_exception();
+ else throw io_failure();
+ }
+ }
+ template<class T>
+ void load(T &t){
+ this->load_binary(&t,mpl::size_t<sizeof(T)>());
+ }
+ size_type position() const{ return this->pos; }
+private:
+ std::filebuf buf;
+ size_type pos;
+};
+
+
+
+}
+}
+}
+
+#pragma warning(pop)
+
+#endif

Added: sandbox/transaction/boost/transact/detail/mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/detail/mutex.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,93 @@
+// 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_DETAIL_MUTEX_HPP
+#define BOOST_TRANSACT_DETAIL_MUTEX_HPP
+
+#include <boost/thread/mutex.hpp>
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+struct null_mutex{
+ void lock(){}
+ bool try_lock(){ return true; }
+ void unlock(){}
+};
+
+}
+}
+}
+
+
+
+#ifdef BOOST_ATOMIC
+#include <boost/atomic.hpp>
+#include <boost/assert.hpp>
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+class combined_mutex{
+public:
+ combined_mutex() : count(-1){
+ this->smutex.lock();
+ }
+ void lock(){
+ int old=this->count.fetch_add(1,boost::memory_order_acquire);
+ if(old >= 0){
+ try{
+ this->smutex.lock();
+ }catch(...){
+ --this->count;
+ throw;
+ }
+ }
+ }
+ void unlock(){
+ unsigned int old=this->count.fetch_sub(1,boost::memory_order_release);
+ BOOST_ASSERT(old >= 0);
+ if(old > 0) this->smutex.unlock();
+ }
+ ~combined_mutex(){
+ BOOST_ASSERT(this->count.load() == -1);
+ this->smutex.unlock();
+ }
+private:
+ boost::mutex smutex;
+ boost::atomic<int> count;
+};
+
+
+typedef combined_mutex mutex_type;
+
+
+}
+}
+}
+
+#else
+
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+typedef boost::mutex mutex_type;
+
+}
+}
+}
+
+
+#endif
+
+
+
+
+#endif
+

Added: sandbox/transaction/boost/transact/detail/sectorizing_file.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/detail/sectorizing_file.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,166 @@
+// Copyright Stefan Strasser 2009 - 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_DETAIL_SECTORIZING_FILE_HPP
+#define BOOST_TRANSACT_DETAIL_SECTORIZING_FILE_HPP
+
+#include <boost/mpl/size_t.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/assert.hpp>
+#include <cstring>
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+template<class Base>
+class sectorizing_seq_ofile{
+public:
+ typedef typename Base::size_type size_type;
+ explicit sectorizing_seq_ofile(std::string const &name)
+ : base(name)
+ , size(0){}
+ template<class Size>
+ void save_binary(void const *data,Size s){
+ if(this->size + s <= max_size){
+ std::memcpy(this->buffer(this->size),data,s);
+ this->size+=s;
+ }else this->save_overflow(data,s);
+ }
+ template<class T>
+ void save(T const &t){
+ this->save_binary(&t,mpl::size_t<sizeof(T)>());
+ }
+ size_type position() const{
+ return this->base.position() + this->size + 1;
+ }
+ void flush(){
+ this->flush_buffer();
+ this->base.flush();
+ }
+ void sync(){
+ this->base.sync();
+ }
+ ~sectorizing_seq_ofile(){
+ try{
+ this->flush_buffer();
+ }catch(...){
+#ifndef NDEBUG
+ std::cerr << "ignored exception" << std::endl;
+#endif
+ }
+ }
+private:
+ static std::size_t const sector_size=512;
+ static std::size_t const max_size=sector_size-2;
+
+ void save_overflow(void const *data,std::size_t s){
+ BOOST_ASSERT(this->size + s > max_size);
+
+ std::size_t write=max_size-this->size;
+ std::memcpy(this->buffer(this->size),data,write); this->size=max_size;
+ std::size_t left=s - write;
+ char const *cdata=static_cast<char const *>(data)+write;
+ while(left > 0){
+ this->flush_buffer(); BOOST_ASSERT(this->size == 0);
+ if(left <= max_size) write=left;
+ else write=max_size;
+ std::memcpy(this->buffer(this->size),cdata,write); this->size+=write;
+ left-=write; cdata+=write;
+ }
+ }
+ void flush_buffer(){
+ if(this->size > 0){
+ BOOST_STATIC_ASSERT(max_size < (1 << 14));
+ BOOST_ASSERT(this->size <= max_size);
+ this->buffer_[0]=this->size | 0x80;
+ this->buffer_[sector_size-1]=(this->size >> 7) | 0x80;
+ this->base.save_binary(this->buffer_,mpl::size_t<sector_size>());
+ this->size=0;
+ }
+ }
+
+ char *buffer(std::size_t i){ return this->buffer_+i+1; }
+
+ Base base;
+ char buffer_[sector_size];
+ std::size_t size;
+};
+
+
+template<class Base>
+class sectorizing_seq_ifile{
+public:
+ typedef typename Base::size_type size_type;
+ explicit sectorizing_seq_ifile(std::string const &name)
+ : base(name)
+ , pos(0)
+ , size(0){}
+ template<class Size>
+ void load_binary(void *data,Size s){
+ if(this->size == 0 || this->pos == this->size) this->load_sector();
+ if(this->pos + s <= this->size){
+ std::memcpy(data,this->buffer(this->pos),s);
+ this->pos+=s;
+ }else{
+ try{
+ std::size_t read=this->size - this->pos;
+ BOOST_ASSERT(read > 0);
+ std::memcpy(data,this->buffer(this->pos),read); this->pos+=read;
+ std::size_t left=s - read;
+ char *cdata=static_cast<char *>(data)+read;
+ while(left > 0){
+ this->load_sector();
+ if(left <= this->size) read=left; else read=this->size;
+ std::memcpy(cdata,this->buffer(this->pos),read); this->pos+=read;
+ left-=read; cdata+=read;
+ }
+ }catch(eof_exception &){
+ //at least some data was read, real EOFs are thrown above
+ throw io_failure();
+ }
+ }
+ }
+ template<class T>
+ void load(T &t){
+ this->load_binary(&t,mpl::size_t<sizeof(T)>());
+ }
+ size_type position() const;
+private:
+ void load_sector(){
+ BOOST_ASSERT(this->pos == this->size);
+ do{
+ this->base.load_binary(this->buffer_,mpl::size_t<sector_size>());
+ if(this->buffer_[0] == 0 || this->buffer_[sector_size-1] == 0) throw eof_exception();
+ this->size=((this->buffer_[sector_size-1] & 0x7f) << 7) | (this->buffer_[0] & 0x7f);
+ if(this->size > max_size) throw io_failure();
+ }while(this->size == 0);
+ this->pos=0;
+ }
+
+
+ char *buffer(std::size_t p){
+ return this->buffer_+p+data_begin;
+ }
+
+ static std::size_t const sector_size=512;
+ static std::size_t const data_begin=1;
+ static std::size_t const data_end=sector_size-1;
+ static std::size_t const max_size=data_end-data_begin;
+
+ Base base;
+ char buffer_[sector_size];
+ std::size_t pos;
+ std::size_t size;
+};
+
+
+}
+}
+}
+
+
+#endif

Added: sandbox/transaction/boost/transact/detail/static_tss.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/detail/static_tss.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,79 @@
+// 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_DETAIL_STATIC_TSS_HPP
+#define BOOST_TRANSACT_DETAIL_STATIC_TSS_HPP
+
+#include <boost/noncopyable.hpp>
+#include <boost/thread/tss.hpp>
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+template<class T,class Tag,bool Threads=true>
+class static_thread_specific_ptr;
+
+
+template<class T,class Tag>
+class static_thread_specific_ptr<T,Tag,true> : noncopyable{
+private:
+ static_thread_specific_ptr();
+public:
+
+#if defined(__GNUG__)
+ static void reset(T *p=0){ ptr=p; }
+ static T *get(){ return ptr; }
+private:
+ static __thread T *ptr;
+};
+
+template<class T,class Tag>
+__thread T *static_thread_specific_ptr<T,Tag,true>::ptr(0);
+
+#elif defined(BOOST_MSVC)
+ static void reset(T *p=0){ ptr=p; }
+ static T *get(){ return ptr; }
+private:
+ static __declspec(thread) T *ptr;
+};
+
+template<class T,class Tag>
+__declspec(thread) T *static_thread_specific_ptr<T,Tag,true>::ptr(0);
+
+
+#else
+ static void reset(T *p=0){ ptr.reset(p); }
+ static T *get(){ return ptr.get(); }
+private:
+ static thread_specific_ptr<T> ptr;
+};
+
+template<class T,class Tag>
+thread_specific_ptr<T> static_thread_specific_ptr<T,Tag,true>::ptr(0); //null deleter
+
+#endif
+
+template<class T,class Tag>
+class static_thread_specific_ptr<T,Tag,false> : noncopyable{
+private:
+ static_thread_specific_ptr();
+public:
+ static void reset(T *p=0){ ptr=p; }
+ static T *get(){ return ptr; }
+private:
+ static T *ptr;
+};
+
+template<class T,class Tag>
+T *static_thread_specific_ptr<T,Tag,false>::ptr(0);
+
+}
+}
+}
+
+
+#endif

Added: sandbox/transaction/boost/transact/detail/syncing_file.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/detail/syncing_file.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,145 @@
+// Copyright Stefan Strasser 2009 - 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_DETAIL_SYNCING_FILE_HPP
+#define BOOST_TRANSACT_DETAIL_SYNCING_FILE_HPP
+
+#include <string>
+#include <cstring>
+#include <boost/filesystem.hpp>
+#include <boost/mpl/size_t.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+
+#ifdef WIN32
+
+//TODO
+
+#else
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifndef _POSIX_SYNCHRONIZED_IO
+#error no POSIX synchronized IO available
+#endif
+
+#ifndef _LARGEFILE64_SOURCE
+#error need POSIX Large File Support extension
+#endif
+
+#endif
+
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+class syncing_seq_ofile{
+public:
+ typedef unsigned long long size_type;
+ explicit syncing_seq_ofile(std::string const &name);
+ void save_binary(void const *data,std::size_t size);
+ template<class T>
+ void save(T const &t){
+ this->save_binary(&t,mpl::size_t<sizeof(T)>());
+ }
+ size_type position() const{ return this->pos; }
+ void flush();
+ void sync();
+private:
+ size_type pos;
+#ifdef WIN32
+#else
+public:
+ ~syncing_seq_ofile(){
+ if(this->filedes != -1) ::close(this->filedes);
+ }
+private:
+ void write_ahead(size_type const &s){
+ BOOST_ASSERT(s % write_ahead_size == 0);
+ if(this->pos != s){
+ if(::lseek64(this->filedes,s,SEEK_SET) != off64_t(s)) throw io_failure();
+ }
+ char data[write_page_size]; memset(data,0,write_page_size);
+ BOOST_STATIC_ASSERT(write_ahead_size % write_page_size == 0);
+ for(std::size_t c=0;c<write_ahead_size / write_page_size;++c){
+ if(::write(this->filedes,data,write_page_size) != ssize_t(write_page_size)) throw io_failure();
+ }
+ if(::fsync(this->filedes) != 0) throw io_failure();
+ if(::lseek64(this->filedes,this->pos,SEEK_SET) != off64_t(this->pos)) throw io_failure();
+ }
+ void write_ahead(size_type const &start,size_type const &end){
+ BOOST_ASSERT(start % write_ahead_size == 0);
+ BOOST_ASSERT(end % write_ahead_size == 0);
+ for(size_type off=start;off < end;off+=write_ahead_size) this->write_ahead(off);
+ }
+
+ static std::size_t const write_ahead_size=10*1024*1024;
+ static std::size_t const write_page_size=4096;
+
+ int filedes;
+#endif
+};
+
+#ifdef WIN32
+#else
+
+inline syncing_seq_ofile::syncing_seq_ofile(std::string const &name)
+ : pos(0)
+ , filedes(-1){
+ int flags=O_CREAT | O_WRONLY;
+#ifdef linux
+ flags|=O_NOATIME;
+#endif
+ this->filedes=::open(name.c_str(),flags,S_IRUSR | S_IWUSR);
+ if(this->filedes==-1) throw io_failure();
+ { //make sure the directory entry has reached the disk:
+ std::string dirname=filesystem::path(name).directory_string();
+ if(dirname.empty()) dirname=".";
+ int dirfd=::open(dirname.c_str(),O_RDONLY);
+ if(dirfd==-1) throw io_failure();
+ int ret=::fsync(dirfd);
+ if(::close(dirfd) != 0 || ret != 0) throw io_failure();
+ }
+ this->write_ahead(0);
+}
+
+void syncing_seq_ofile::save_binary(void const *data,std::size_t size){
+ size_type const s=this->pos % write_ahead_size;
+ if(s + size >= write_ahead_size){ //there must be at least one 0 at the and, so also write ahead if this is equal.
+ size_type start=this->pos - s + write_ahead_size;
+ size_type end=start+((s + size)/write_ahead_size) * write_ahead_size; //usually == start + write_ahead_size, but "size" can theoretically span a whole write_ahead_size
+ BOOST_ASSERT(end > start);
+ this->write_ahead(start,end);
+ }
+
+ ssize_t ret=::write(this->filedes,data,size);
+ if(ret > 0) this->pos+=ret;
+ if(ret != ssize_t(size)) throw io_failure();
+}
+
+
+inline void syncing_seq_ofile::flush(){}
+inline void syncing_seq_ofile::sync(){
+#ifdef linux
+ if(::fdatasync(this->filedes) != 0) throw io_failure();
+#else //multiple sources say fdatasync is not safe on other systems
+ if(::fsync(this->filedes) != 0) throw io_failure();
+#endif
+}
+
+
+#endif
+
+}
+}
+}
+
+
+
+#endif

Added: sandbox/transaction/boost/transact/exception.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/exception.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,129 @@
+// Copyright Stefan Strasser 2009 - 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_EXCEPTION_HEADER_HPP
+#define BOOST_TRANSACT_EXCEPTION_HEADER_HPP
+
+#include <stdexcept>
+#include <boost/mpl/begin.hpp>
+#include <boost/mpl/end.hpp>
+#include <boost/mpl/next.hpp>
+#include <boost/mpl/deref.hpp>
+#include <boost/assert.hpp>
+
+
+namespace boost{
+namespace transact{
+
+///\brief Exception base class.
+struct exception : std::exception{};
+
+///\brief Indicates that a persistent resource recovery failed.
+struct recovery_failure : transact::exception{};
+
+///\brief Indicates that an internal operation reading from/writing to files failed.
+struct io_failure : transact::exception{};
+
+namespace detail{
+
+struct eof_exception : io_failure{};
+
+}
+
+///\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 an error with regard to connecting a resource to a transaction manager
+struct resource_error : transact::exception{};
+
+///\brief Indicates that no transaction manager was constructed.
+struct no_transaction_manager : transact::exception{};
+
+///\brief Indicates that this operation is not supported by this implementation
+struct unsupported_exception : transact::exception{};
+
+struct isolation_exception;
+template<class ResMgr>
+struct resource_isolation_exception;
+
+namespace detail{
+
+//this used so that resource managers can throw isolation exceptions
+//without knowing the type of the transaction manager. as a result,
+//the type of the transaction manager is only known to isolation_exception::unwind(),
+//which makes it a function template, i.e. not a virtual function. to still be able to call
+//the correct unwind() function of the derived class the resource managers are iterated.
+
+template<class TxMgr,class Iterator>
+struct isolation_unwind_visitor{
+ void operator()(isolation_exception const &iso){
+ typedef typename mpl::deref<Iterator>::type resource_type;
+ if(resource_isolation_exception<resource_type> const *viso=dynamic_cast<resource_isolation_exception<resource_type> const *>(&iso)){
+ viso->template unwind<TxMgr>();
+ }else{
+ isolation_unwind_visitor<TxMgr,typename mpl::next<Iterator>::type> visit;
+ visit(iso);
+ }
+ }
+};
+
+template<class TxMgr>
+struct isolation_unwind_visitor<TxMgr,typename mpl::end<typename TxMgr::resource_types>::type>{
+ void operator()(isolation_exception const &){
+ BOOST_ASSERT(false);
+ }
+};
+
+}
+
+///\brief Indicates that the operation conflicted with another transaction.
+///
+///\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.
+ 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(){}
+protected:
+ isolation_exception(){}
+};
+
+
+///´\brief Indicates that the operation conflicted with another transaction.
+///
+///The base class \c isolation_exception should be used to catch this exception,
+///in order to catch isolation exceptions of all resource managers.
+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){}
+ ///\brief Equivalent to <tt>isolation_exception::unwind<TxMgr>()</tt>
+ 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;
+ }
+private:
+ typename ResMgr::transaction *to;
+};
+
+}
+}
+
+
+
+#endif

Added: sandbox/transaction/boost/transact/log.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/log.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,435 @@
+// Copyright Stefan Strasser 2009 - 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_LOG_HEADER_HPP
+#define BOOST_TRANSACT_LOG_HEADER_HPP
+
+#include <cstring>
+#include <string>
+#include <algorithm>
+#include <iterator>
+#include <set>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/map.hpp>
+#include <boost/mpl/fold.hpp>
+#include <boost/mpl/insert.hpp>
+#include <boost/mpl/pair.hpp>
+#include <boost/mpl/at.hpp>
+#include <boost/mpl/size_t.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/optional.hpp>
+#include <boost/assert.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/utility/in_place_factory.hpp>
+#include <boost/transact/detail/sectorizing_file.hpp>
+#include <boost/transact/detail/aligning_file.hpp>
+#include <boost/transact/detail/buffering_file.hpp>
+#include <boost/transact/detail/syncing_file.hpp>
+#include <boost/transact/detail/filebuf_file.hpp>
+#include <boost/transact/detail/embedded_vector.hpp>
+
+
+namespace boost{
+namespace transact{
+
+
+namespace detail{
+
+template<class OutputIterator>
+static void get_existing_log_ids(OutputIterator out,std::string const &name){
+ namespace fs=boost::filesystem;
+ try{
+ fs::path dir=fs::path(name).remove_filename();
+ std::string filename=fs::path(name).filename();
+ fs::directory_iterator it;
+ if(dir.empty()) it=fs::directory_iterator(".");
+ else it=fs::directory_iterator(dir);
+ for(;it != fs::directory_iterator();++it){
+ std::string foundfilename=it->path().filename();
+ if(foundfilename.substr(0,filename.length()+1) != filename+".") continue;
+ std::string nrstring=foundfilename.substr(filename.length()+1);
+ unsigned int nr;
+ try{ nr=lexical_cast<unsigned int>(nrstring); } catch(...){ continue; }
+ *out++=nr;
+ }
+ }catch(...){
+ throw io_failure();
+ }
+}
+static unsigned int get_next_log_id(std::string const &name){
+ std::vector<unsigned int> ids;
+ get_existing_log_ids(std::back_inserter(ids),name);
+ return ids.empty() ? 1 : *std::max_element(ids.begin(),ids.end())+1;
+}
+
+static std::string get_log_filename(std::string const &name,unsigned int l){
+ return name+'.'+lexical_cast<std::string>(l);
+}
+
+}
+
+
+template<bool Sync>
+class olog_files{
+public:
+ olog_files(std::string const &name,unsigned int max_log_size)
+ : log_id(detail::get_next_log_id(name))
+ , rolling_(false)
+ , max_log_size(max_log_size)
+ , header_size(0)
+ , name(name)
+ , file(new file_type(detail::get_log_filename(name,log_id))){}
+
+ //Archive interface
+ template<class T>
+ olog_files &operator<<(T const &t){
+ this->file->save(t);
+ return *this;
+ }
+ template<class T>
+ olog_files &operator&(T const &t){ return this->operator<<(t); }
+ template<class Size>
+ void save_binary(void const *data,Size size){
+ this->file->save_binary(data,size);
+ }
+ typedef mpl::true_ is_saving;
+ typedef mpl::false_ is_loading;
+
+
+ bool overflow() const{
+ return (!this->rolling())
+ && (this->file->position() > this->max_log_size + this->header_size);
+ }
+
+
+ bool rolling() const{ return this->rolling_; }
+ template<class Header>
+ void begin_roll(Header header){
+ BOOST_ASSERT(!this->rolling());
+ this->rolling_=true;
+ try{
+ //first construct the new log and then replace it. if construction
+ //of new log file fails, there must still be a valid file in this->file
+ //for other threads:
+ this->file.reset(new file_type(detail::get_log_filename(this->name,this->log_id+1)));
+ ++this->log_id;
+ header();
+ this->header_size=this->file->position();
+ }catch(...){
+ this->rolling_=false;
+ throw;
+ }
+ }
+
+ void commit_roll(){
+ BOOST_ASSERT(this->rolling_);
+ this->flush();
+ this->sync(); //TODO optimization: outside of lock
+ //TODO optimization: don't remove, but invalidate and rename to the next log. increases
+ //performance of writing ahead if the file is already fully "allocated".
+
+ try{
+ filesystem::remove(detail::get_log_filename(this->name,this->log_id-1));
+ }catch(...){
+ throw io_failure();
+ }
+ this->rolling_=false;
+ }
+
+ void flush(){
+ this->file->flush();
+ }
+ void sync(){
+ this->file->sync();
+ }
+private:
+ typedef typename mpl::if_c<
+ Sync,
+ detail::sectorizing_seq_ofile<
+ detail::aligning_seq_ofile<
+ detail::buffering_seq_ofile<
+ detail::syncing_seq_ofile,
+ 8192
+ >
+ >
+ >,
+ detail::buffering_seq_ofile<
+ detail::filebuf_seq_ofile,
+ 8192
+ >
+ >::type file_type;
+
+ unsigned int log_id;
+ bool rolling_;
+ typename file_type::size_type max_log_size;
+ typename file_type::size_type header_size;
+ std::string const name;
+ scoped_ptr<file_type> file; //no optional. see begin_roll()
+};
+
+template<bool Sync>
+class otransaction_log_files : public olog_files<Sync>{
+private:
+ struct detail{
+ typedef unsigned int transaction;
+ };
+public:
+ typedef typename detail::transaction transaction;
+ otransaction_log_files(std::string const &name,std::size_t max_log_size)
+ : olog_files<Sync>(name,max_log_size)
+ , next_tx(1)
+ , open_transactions(0)
+ , rolled_transactions(0)
+ , roll_cutoff(0){}
+
+ template<class Header>
+ typename detail::transaction begin_transaction(Header header){
+ transaction tx=this->next_tx++;
+ if(this->overflow()){
+ this->begin_roll(header);
+ this->roll_cutoff=tx;
+ BOOST_ASSERT(this->rolled_transactions==0);
+ this->rolled_transactions=this->open_transactions;
+ this->open_transactions=0;
+ }
+ BOOST_ASSERT(!this->rolling() || tx >= this->roll_cutoff);
+ ++this->open_transactions;
+ return tx;
+ }
+ void end_transaction(transaction tx){
+ if(this->rolling() && tx < this->roll_cutoff){
+ BOOST_ASSERT(this->rolled_transactions > 0);
+ --this->rolled_transactions;
+ if(this->rolled_transactions==0){
+ //all transactions that were begun in the old, rolled, log have ended.
+ this->commit_roll();
+ }
+ }else{
+ BOOST_ASSERT(this->open_transactions > 0);
+ --this->open_transactions;
+ }
+ }
+private:
+ transaction next_tx;
+ std::size_t open_transactions;
+ std::size_t rolled_transactions;
+ transaction roll_cutoff;
+};
+
+template<bool Sync>
+class ilog_files{
+public:
+ explicit ilog_files(std::string const &name) : name(name){
+ detail::get_existing_log_ids(std::inserter(this->log_ids,this->log_ids.begin()),name);
+ this->current=this->log_ids.begin();
+
+ //although the current implementation of log rolling only produces a maximum of
+ //2 logs at a time, an aborted recovery may have created another log. work through all of them.
+
+ for(log_ids_type::const_iterator next=this->log_ids.begin();next!=this->log_ids.end();){
+ log_ids_type::const_iterator it=next++;
+ if(next != this->log_ids.end() && (*it != *next-1)) throw io_failure();
+ }
+
+ if(this->current != this->log_ids.end()){
+ this->file=in_place(detail::get_log_filename(this->name,*this->current));
+ }
+ }
+ //Archive interface
+ template<class T>
+ ilog_files &operator>>(T const &t){
+ this->file->load(t);
+ return *this;
+ }
+ template<class T>
+ ilog_files &operator&(T const &t){ return this->operator>>(t); }
+ template<class Size>
+ void load_binary(void *data,Size size){
+ this->file->load_binary(data,size);
+ }
+ typedef mpl::true_ is_saving;
+ typedef mpl::false_ is_loading;
+ void remove(){
+ try{
+ for(log_ids_type::const_iterator it=this->log_ids.begin();it != this->log_ids.end();++it){
+ filesystem::remove(detail::get_log_filename(this->name,*it));
+ //FIXME sync directory entry. the delete of an older log
+ //must have reached disk before a newer log is deleted.
+ }
+ }catch(...){
+ throw io_failure();
+ }
+ }
+private:
+ typedef std::set<unsigned int> log_ids_type;
+ log_ids_type log_ids;
+ log_ids_type::const_iterator current;
+ std::string const name;
+ typedef typename mpl::if_c<
+ Sync,
+ detail::sectorizing_seq_ifile<detail::filebuf_seq_ifile>,
+ detail::filebuf_seq_ifile
+ >::type file_type;
+ optional<file_type> file;
+};
+
+namespace detail{
+
+template<class Entry,class State>
+struct make_entry_pair{
+ typedef mpl::pair<
+ Entry,
+ typename mpl::size<State>::type
+ > type;
+};
+
+template<class Vector>
+struct invert_vector{
+ typedef typename mpl::fold<
+ Vector,
+ mpl::map0<>,
+ mpl::insert<
+ mpl::_1,
+ make_entry_pair<
+ mpl::_2,
+ mpl::_1
+ >
+ >
+ >::type type;
+};
+
+}
+
+template<class Entries,bool Sync>
+class olog{
+private:
+ typedef typename detail::invert_vector<Entries>::type ids;
+public:
+ typedef unsigned char id_type;
+ explicit olog(olog_files<Sync> &files)
+ : files(files)
+ , id_offset(0){}
+
+ template<class T>
+ id_type id() const{
+ return mpl::at<ids,T>::type::value + this->id_offset;
+ }
+
+ template<class T>
+ olog &operator<<(T const &t){
+ id_type const tid=this->id<T>();
+ static std::size_t const size=sizeof(tid) + sizeof(t);
+ unsigned char data[size];
+ std::memcpy(data,&tid,sizeof(tid));
+ std::memcpy(data+sizeof(tid),&t,sizeof(t));
+ this->files.save_binary(data,mpl::size_t<size>());
+ return *this;
+ }
+ struct archive{
+ explicit archive(olog &log) : log(log){}
+ template<class T>
+ archive &operator<<(T const &t){
+ this->log.files << t;
+ return *this;
+ }
+ template<class T>
+ archive &operator&(T const &t){ return this->operator<<(t); }
+ template<class Size>
+ void save_binary(void const *data,Size size){
+ this->log.files.save_binary(data,size);
+ }
+ typedef mpl::true_ is_saving;
+ typedef mpl::false_ is_loading;
+ private:
+ olog &log;
+ };
+private:
+ olog_files<Sync> &files;
+ id_type id_offset;
+};
+
+template<class Log,class Lockable,std::size_t Size>
+class olog_buffer{
+public:
+ typedef typename Log::id_type id_type;
+ olog_buffer(Log &log,Lockable &lockable)
+ : log(log), lockable(lockable){}
+ template<class T>
+ olog &operator<<(T const &t){
+ static std::size_t const size=sizeof(id_type) + sizeof(T);
+ BOOST_STATIC_ASSERT(size <= Size);
+ id_type const id=this->log.template id<T>();
+
+ if(this->buffer.size() + size > this->buffer.max_size()) this->flush();
+ this->buffer.push_back(reinterpret_cast<char const *>(&id),mpl::size_t<sizeof(id_type)>());
+ this->buffer.push_back(reinterpret_cast<char const *>(&t),mpl::size_t<sizeof(T)>());
+ return *this;
+ }
+ struct archive{
+ explicit archive(olog_buffer &log) : log(log){}
+ template<class T>
+ archive &operator<<(T const &t){
+ this->save_binary(&t,mpl::size_t<sizeof(T)>());
+ return *this;
+ }
+ template<class T>
+ archive &operator&(T const &t){ return this->operator<<(t); }
+ template<class S>
+ void save_binary(void const *data,S size){
+ if(this->log.buffer.size() + size > this->log.buffer.max_size()){
+ if(size > Size){
+ this->log.flush_and_write(data,size);
+ return;
+ }else{
+ this->log.flush();
+ }
+ }
+ this->log.buffer.push_back(static_cast<char const *>(data),size);
+ }
+ typedef mpl::true_ is_saving;
+ typedef mpl::false_ is_loading;
+ private:
+ olog_buffer &log;
+ };
+private:
+ friend struct archive;
+
+ void flush(){
+ if(!this->buffer.empty()){
+ typename Log::archive ar(this->log);
+ {
+ lock_guard<Lockable> l(this->lockable);
+ ar.save_binary(&this->buffer[0],this->buffer.size());
+ }
+ this->buffer.clear();
+ }
+ }
+ template<class S>
+ void flush_and_write(void const *data,S size){
+ typename Log::archive ar(this->log);
+ lock_guard<Lockable> l(this->lockable);
+ if(!this->buffer.empty()){
+ ar.save_binary(&this->buffer[0],this->buffer.size());
+ this->buffer.clear();
+ }
+ ar.save_binary(data,size);
+ }
+
+
+ Log &log;
+ Lockable &lockable;
+ detail::embedded_vector<char,Size,false> buffer;
+};
+
+
+}
+}
+
+#endif
+

Added: sandbox/transaction/boost/transact/simple_transaction_manager.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/simple_transaction_manager.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,145 @@
+// 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_SIMPLE_TRANSACTION_MANAGER_HEADER_HPP
+#define BOOST_TRANSACT_SIMPLE_TRANSACTION_MANAGER_HEADER_HPP
+
+#include <boost/mpl/vector.hpp>
+#include <boost/utility/in_place_factory.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/transact/exception.hpp>
+
+namespace boost{
+namespace transact{
+
+/// Model of TransactionManager. Only members that are not part of that concept are documented here.
+///
+/// Equivalent to <tt>basic_transaction_manager<mpl::vector<Resource>,Threads></tt>.
+///
+/// Template parameters:
+/// \li \c Resource The type of the resource manager used.
+/// \li \c Threads \c true if multiple threads are used to access this transaction manager.
+// \brief A transaction manager that only supports one resource manager.
+template<class Resource,bool Threads=true>
+class simple_transaction_manager : noncopyable{
+private:
+ struct detail{
+ class transaction;
+ class transaction_construct_t{
+ explicit transaction_construct_t(transaction *parent)
+ : parent(parent){}
+ friend class simple_transaction_manager;
+ 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;
+ };
+ };
+ struct activetx_tag{};
+ typedef transact::detail::static_thread_specific_ptr<
+ typename detail::transaction,
+ activetx_tag,
+ Threads> activetx;
+ /// \endcond
+public:
+ typedef typename detail::transaction transaction;
+ typedef mpl::vector<Resource> resource_types;
+ template<class ServiceTag>
+ struct default_resource{
+ typedef typename Resource::tag type;
+ };
+
+ /// \brief Constructs a simple_transaction_manager
+ simple_transaction_manager(){}
+
+ /// TODO doc, not part of the concept
+ static void connect_resource(Resource &newres){
+ if(res) throw resource_error();
+ res=&newres;
+ }
+
+ /// TODO doc, not part of the concept
+ static void disconnect_resource(typename Resource::tag tag=typename Resource::tag()){
+ res=0;
+ }
+
+ static Resource &resource(typename Resource::tag tag=typename Resource::tag()){
+ if(res) return *res;
+ else throw resource_error();
+ }
+
+ static typename Resource::transaction &
+ resource_transaction(transaction &tx,typename Resource::tag tag=typename Resource::tag()){
+ if(tx.rtx) return *tx.rtx;
+ else throw resource_error();
+ }
+
+ static typename detail::transaction_construct_t begin_transaction(){
+ return typename detail::transaction_construct_t(activetx::get());
+ }
+
+ static void commit_transaction(transaction &tx){
+ bind_transaction(tx);
+ if(res){
+ BOOST_ASSERT(tx.rtx);
+ res->finish_transaction(*tx.rtx);
+ res->commit_transaction(*tx.rtx);
+ }
+ }
+
+ static void rollback_transaction(transaction &tx){
+ bind_transaction(tx);
+ if(res){
+ BOOST_ASSERT(tx.rtx);
+ res->rollback_transaction(*tx.rtx);
+ }
+ }
+
+ static void bind_transaction(transaction &tx){
+ activetx::reset(&tx);
+ }
+ static void unbind_transaction(){
+ activetx::reset(0);
+ }
+ static transaction &active_transaction(){
+ if(transaction *tx=activetx::get()) return *tx;
+ else throw no_active_transaction();
+ }
+ static bool has_active_transaction(){
+ return activetx::get() ? true : false;
+ }
+
+ /// \cond
+private:
+ static Resource *res;
+ /// \endcond
+};
+
+template<class Res,bool Thr>
+Res *simple_transaction_manager<Res,Thr>::res=0;
+
+
+}
+}
+
+
+
+#endif
\ No newline at end of file

Added: sandbox/transaction/boost/transact/transaction.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/transaction.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,25 @@
+// Copyright Stefan Strasser 2009 - 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_TRANSACTION_HEADER_HPP
+#define BOOST_TRANSACT_TRANSACTION_HEADER_HPP
+
+#include <boost/transact/basic_transaction.hpp>
+#include <boost/transact/transaction_manager.hpp>
+
+
+namespace boost{
+namespace transact{
+
+/// \brief An alias of \c basic_transaction using the default transaction manager
+typedef basic_transaction<transaction_manager> transaction;
+
+
+}
+}
+
+
+#endif
\ No newline at end of file

Added: sandbox/transaction/boost/transact/transaction_manager.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/transaction_manager.hpp 2010-02-09 08:33:35 EST (Tue, 09 Feb 2010)
@@ -0,0 +1,25 @@
+// Copyright Stefan Strasser 2009 - 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_TRANSACTION_MANAGER_HPP
+#define BOOST_TRANSACT_TRANSACTION_MANAGER_HPP
+
+
+#ifndef BOOST_TRANSACT_CONFIGURATION
+#error BOOST_TRANSACT_CONFIGURATION not defined
+#endif
+
+namespace boost{
+namespace transact{
+
+/// \brief An alias of the configured transaction manager
+typedef BOOST_TRANSACT_CONFIGURATION transaction_manager;
+
+
+}
+}
+
+#endif
\ No newline at end of file


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