Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r83152 - in sandbox/transaction/boost/transact: . detail
From: strasser_at_[hidden]
Date: 2013-02-25 11:23:55


Author: stefans
Date: 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
New Revision: 83152
URL: http://svn.boost.org/trac/boost/changeset/83152

Log:
updated logging subsystem

Added:
   sandbox/transaction/boost/transact/detail/file_iterator.hpp (contents, props changed)
Removed:
   sandbox/transaction/boost/transact/char_archive.hpp
Properties modified:
   sandbox/transaction/boost/transact/archive.hpp (contents, props changed)
   sandbox/transaction/boost/transact/array_extension.hpp (contents, props changed)
   sandbox/transaction/boost/transact/default_tag.hpp (props changed)
   sandbox/transaction/boost/transact/object_access.hpp (contents, props changed)
Text files modified:
   sandbox/transaction/boost/transact/archive.hpp | 45 +-
   sandbox/transaction/boost/transact/array_extension.hpp | 64 ++-
   sandbox/transaction/boost/transact/basic_transaction.hpp | 14
   sandbox/transaction/boost/transact/detail/aligning_file.hpp | 13
   sandbox/transaction/boost/transact/detail/buffering_file.hpp | 49 ++-
   sandbox/transaction/boost/transact/detail/config.hpp | 6
   sandbox/transaction/boost/transact/detail/embedded_vector.hpp | 31 +
   sandbox/transaction/boost/transact/detail/file.hpp | 82 +++-
   sandbox/transaction/boost/transact/detail/filebuf_file.hpp | 22 +
   sandbox/transaction/boost/transact/detail/sectorizing_file.hpp | 10
   sandbox/transaction/boost/transact/detail/syncing_file.hpp | 59 ++-
   sandbox/transaction/boost/transact/log.hpp | 616 +++++++++++++++++++++++----------------
   sandbox/transaction/boost/transact/object_access.hpp | 13
   13 files changed, 629 insertions(+), 395 deletions(-)

Modified: sandbox/transaction/boost/transact/archive.hpp
==============================================================================
--- sandbox/transaction/boost/transact/archive.hpp (original)
+++ sandbox/transaction/boost/transact/archive.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Stefan Strasser 2010.
+// Copyright Stefan Strasser 2010 - 2013.
 // 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)
@@ -12,8 +12,6 @@
 #include <boost/ref.hpp>
 #include <boost/assert.hpp>
 #include <boost/mpl/bool.hpp>
-#include <boost/serialization/is_bitwise_serializable.hpp>
-#include <boost/serialization/wrapper.hpp>
 #include <boost/archive/archive_exception.hpp>
 #include <boost/transact/array_extension.hpp>
 #include <iterator>
@@ -27,6 +25,7 @@
 #include <boost/archive/basic_binary_oarchive.hpp>
 #include <boost/archive/impl/basic_binary_iarchive.ipp>
 #include <boost/archive/impl/basic_binary_oarchive.ipp>
+#include <boost/serialization/wrapper.hpp>
 #include <string>
 
 #endif
@@ -220,16 +219,16 @@
     explicit basic_char_oarchive(OutputIterator const &out) : out(out){}
     template<class Size>
     void save_binary(void const *vdata,Size size){
- this->save_binary(static_cast<char const *>(vdata),size,typename array_extension<OutputIterator>::type());
+ this->save_binary(static_cast<char const *>(vdata),size,typename has_array_extension<OutputIterator>::type());
     }
 private:
     template<class Size>
     void save_binary(char const *data,Size size,mpl::true_){
- this->out.assign(data,size);
+ this->out=this->out.insert(data,size);
     }
     template<class Size>
     void save_binary(char const *data,Size size,mpl::false_){
- std::copy(data,data+size,this->out);
+ this->out=std::copy(data,data+size,this->out);
     }
 
     OutputIterator out;
@@ -240,34 +239,43 @@
 public:
     basic_char_iarchive(InputIterator const &begin,InputIterator const &end)
         : in(begin), end(end){
- BOOST_ASSERT(end - begin >= 0);
     }
     template<class Size>
     void load_binary(void *vdata,Size size){
         char *data=static_cast<char *>(vdata);
+ this->load_binary(data,size,typename has_array_extension<InputIterator>::type());
+ }
+private:
+ template<class Size>
+ void load_binary(char *data,Size size,mpl::true_ arrayex){
+ this->in=this->in.extract(data,size);
+ }
+ template<class Size>
+ void load_binary(char *data,Size size,mpl::false_ arrayex){
         this->load_binary(
             data,
             size,
+ arrayex,
             typename std::iterator_traits<InputIterator>::iterator_category(),
- typename continuous_values<InputIterator>::type()
- );
+ typename has_contiguous_values<InputIterator>::type()
+ );
     }
-private:
     template<class Size>
- void load_binary(char *data,Size size,std::random_access_iterator_tag,mpl::true_ contvals){
- if(std::size_t(this->end - this->in) < size) throw archive::archive_exception(archive::archive_exception::stream_error);
+ void load_binary(char *data,Size size,mpl::false_ arrayex,std::random_access_iterator_tag,mpl::true_ contvals){
+ if(std::size_t(this->end - this->in) < size) throw archive::archive_exception(archive::archive_exception::input_stream_error);
         std::memcpy(data,&*this->in,size);
         this->in+=size;
     }
     template<class Size>
- void load_binary(char *data,Size size,std::random_access_iterator_tag,mpl::false_ contvals){
- if(std::size_t(this->end - this->in) < size) throw archive::archive_exception(archive::archive_exception::stream_error);
+ void load_binary(char *data,Size size,mpl::false_ arrayex,std::random_access_iterator_tag,mpl::false_ contvals){
+ //FIXME:
+ if(std::size_t(this->end - this->in) < size) throw archive::archive_exception(archive::archive_exception::input_stream_error);
         std::copy(data,data+size,this->in);
     }
     template<class Size,class Category>
- void load_binary(char *data,Size size,Category,mpl::false_ contvals){
+ void load_binary(char *data,Size size,mpl::false_ arrayex,Category,mpl::false_ contvals){
         for(std::size_t c=0;c<size;++c){
- if(this->in == this->end) throw archive::archive_exception(archive::archive_exception::stream_error);
+ if(this->in == this->end) throw archive::archive_exception(archive::archive_exception::input_stream_error);
             *data++=*this->in++;
         }
     }
@@ -331,7 +339,7 @@
             data,
             size,
             typename std::iterator_traits<InputIterator>::iterator_category(),
- typename continuous_values<InputIterator>::type()
+ typename has_contiguous_values<InputIterator>::type()
         );
     }
     void save(std::type_info const *type){
@@ -352,7 +360,8 @@
     }
     template<class Size>
     void save_binary(char const *data,Size size,std::random_access_iterator_tag,mpl::false_ contvals){
- if((std::size_t(this->end - this->in) < size) || (!std::equal(data,data+size,this->in))) this->equal_=false;
+ //FIXME: invalid iterator:
+ if((std::size_t(this->end - this->in) < size) || (!std::equal(data,data+size,this->in))) this->equal_=false;
         else this->in+=size;
     }
     template<class Size,class Category>

Modified: sandbox/transaction/boost/transact/array_extension.hpp
==============================================================================
--- sandbox/transaction/boost/transact/array_extension.hpp (original)
+++ sandbox/transaction/boost/transact/array_extension.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Stefan Strasser 2010.
+// Copyright Stefan Strasser 2010 - 2013.
 // 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)
@@ -13,57 +13,65 @@
 namespace transact{
 
 template<class T>
-struct array_extension : mpl::false_{};
+struct has_array_extension : mpl::false_{};
 
 template<class T>
-struct continuous_values : mpl::false_{};
+struct has_contiguous_values : mpl::false_{};
 
 template<class T>
-struct continuous_values<T *> : mpl::true_{};
+struct has_contiguous_values<T *> : mpl::true_{};
 
 
 template<typename Vector>
 class vector_back_insert_iterator
- : public std::iterator<std::output_iterator_tag,void,void,void,void>{
+ : public std::iterator<std::output_iterator_tag,typename Vector::value_type,typename Vector::difference_type,typename Vector::pointer_type,typename Vector::reference_type>{
 public:
     typedef Vector container_type;
- explicit vector_back_insert_iterator(Vector &vec) : vec(vec){}
+ explicit vector_back_insert_iterator(Vector &vec) : vec(&vec){}
     vector_back_insert_iterator &operator=(typename Vector::const_reference v){
- this->vec.push_back(v);
+ this->vec->push_back(v);
         return *this;
     }
- template<class Size>
- vector_back_insert_iterator &assign(typename Vector::const_pointer data,Size size){
- this->assign(data,size,typename array_extension<Vector>::type(),typename is_pod<typename Vector::value_type>::type());
- return *this;
+ template<class InputIterator,class Size>
+ vector_back_insert_iterator &insert(InputIterator input,Size size){
+ this->insert(input,size,typename has_array_extension<Vector>::type());
+ return *this;
     }
     vector_back_insert_iterator &operator*(){ return *this; }
     vector_back_insert_iterator &operator++(){ return *this; }
     vector_back_insert_iterator operator++(int){ return *this; }
 private:
- template<class Size,bool Pod>
- void assign(typename Vector::const_pointer data,Size size,mpl::true_ array,mpl::bool_<Pod>){
- this->vec.push_back(data,size);
- }
- template<class Size>
- void assign(typename Vector::const_pointer data,Size size,mpl::false_ array,mpl::true_ pod){
- std::size_t const oldsize=this->vec.size();
- this->vec.resize(oldsize + size);
- std::memcpy(&this->vec[oldsize],data,size * sizeof(typename Vector::value_type));
- }
- template<class Size>
- void assign(typename Vector::const_pointer data,Size size,mpl::false_ array,mpl::false_ pod){
- std::size_t const oldsize=this->vec.size();
- this->vec.resize(oldsize + size);
- std::copy(data,data+size,this->vec.begin()+oldsize);
+ template<class InputIterator,class Size>
+ void insert(InputIterator input,Size size,mpl::true_ arrayex){
+ this->vec->push_back(input,size);
+ }
+ template<class InputIterator,class Size>
+ void insert(InputIterator input,Size size,mpl::false_ arrayex){
+ this->insert(input,size,arrayex,
+ mpl::bool_<has_contiguous_values<InputIterator>::value
+ && is_pod<typename Vector::value_type>::value>());
+ }
+
+ template<class InputIterator,class Size>
+ void insert(InputIterator input,Size size,mpl::false_ arrayex,mpl::true_ contigpod){
+ std::size_t const oldsize=this->vec->size();
+ this->vec->resize(oldsize + size);
+ std::memcpy(&(*this->vec)[oldsize],&*input,size * sizeof(typename Vector::value_type));
+ }
+ template<class InputIterator,class Size>
+ void insert(InputIterator input,Size size,mpl::false_ arrayex,mpl::false_ contigpod){
+ this->vec->reserve(this->vec->size() + size);
+ for(std::size_t c=0;c<size;++c){
+ this->vec->push_back(*input++);
+ }
     }
 
- Vector &vec;
+ Vector *vec;
 };
 
 
 template<class Vector>
-struct array_extension<vector_back_insert_iterator<Vector> > : mpl::true_{};
+struct has_array_extension<vector_back_insert_iterator<Vector> > : mpl::true_{};
 
 
 

Modified: sandbox/transaction/boost/transact/basic_transaction.hpp
==============================================================================
--- sandbox/transaction/boost/transact/basic_transaction.hpp (original)
+++ sandbox/transaction/boost/transact/basic_transaction.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Stefan Strasser 2009 - 2010.
+// Copyright Stefan Strasser 2009 - 2013.
 // 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)
@@ -142,22 +142,29 @@
         boost::transact::basic_transaction<TXMGR> ___tx; \
         while(true){ \
             try{ \
+ // call ___tx.commit() at the end of this scope unless an exception is thrown: \
                 boost::transact::detail::commit_on_destruction<TXMGR> ___commit(___tx); \
                 try{ \
                     do{ \
- ___control=1; \
+ ___control=1; \
+ // force the following user code to be exactly one statement or {} \
                         if(false);else
 
 #define BOOST_TRANSACT_BASIC_RETRY(TXMGR) \
+ // if this point is reached, the user code above neither used \
+ // "break" nor "continue". exit while-loop with ___control==0 \
                         ___control=0; \
                         break; \
+ // if this point is reached, the user code above used "continue". \
+ // commit the transaction but record the user intent by ___control==2 \
                     }while((___control=2),false); \
+ break; \
                 }catch(...){ \
                     ___commit.nullify(); \
                     throw; \
                 } \
- break; \
             }catch(boost::transact::isolation_exception &___i){ \
+ // transaction must be repeated: \
                 ___i.unwind<TXMGR>(); \
                 ___tx.restart(); \
                 do{ \
@@ -172,6 +179,7 @@
             } \
         }; \
         BOOST_ASSERT(___control == 0); \
+ // force the use of a semicolon: \
     }void()
 
 #define BOOST_TRANSACT_BASIC_END_RETRY_IN_LOOP(TXMGR) \

Deleted: sandbox/transaction/boost/transact/char_archive.hpp
==============================================================================
--- sandbox/transaction/boost/transact/char_archive.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
+++ (empty file)
@@ -1,116 +0,0 @@
-// 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_CHAR_ARCHIVE_HPP
-#define BOOST_TRANSACT_CHAR_ARCHIVE_HPP
-
-#include <boost/mpl/bool.hpp>
-#include <boost/mpl/size_t.hpp>
-#include <boost/serialization/is_bitwise_serializable.hpp>
-#include <boost/archive/archive_exception.hpp>
-#include <boost/static_assert.hpp>
-#include <boost/type_traits/is_same.hpp>
-#include <boost/transact/array_extension.hpp>
-#include <algorithm>
-#include <iterator>
-#include <typeinfo>
-#include <cstring>
-
-namespace boost{
-namespace transact{
-
-template<class OutputIterator>
-class char_oarchive{
-public:
- typedef mpl::true_ is_saving;
- typedef mpl::false_ is_loading;
- explicit char_oarchive(OutputIterator const &out) : out(out){}
- template<class Size>
- void save_binary(void const *vdata,Size size){
- this->save_binary(static_cast<char const *>(vdata),size,typename array_extension<OutputIterator>::type());
- }
- template<class T>
- char_oarchive &operator<<(T const &t){
- BOOST_STATIC_ASSERT(serialization::is_bitwise_serializable<T>::value);
- this->save_binary(&t,mpl::size_t<sizeof(T)>());
- return *this;
- }
- template<class T>
- char_oarchive &operator&(T const &t){
- return this->operator<<(t);
- }
-private:
- template<class Size>
- void save_binary(char const *data,Size size,mpl::true_){
- this->out.assign(data,size);
- }
- template<class Size>
- void save_binary(char const *data,Size size,mpl::false_){
- std::copy(data,data+size,this->out);
- }
-
- OutputIterator out;
-};
-
-template<class InputIterator>
-class char_iarchive{
-public:
- typedef mpl::false_ is_saving;
- typedef mpl::true_ is_loading;
- //TODO optimization: array extract extension
- char_iarchive(InputIterator const &begin,InputIterator const &end)
- : in(begin), end(end){}
- template<class Size>
- void load_binary(void *vdata,Size size){
- char *data=static_cast<char *>(vdata);
- this->load_binary(
- data,
- size,
- typename std::iterator_traits<InputIterator>::iterator_category(),
- typename continuous_values<InputIterator>::type()
- );
- }
- template<class T>
- char_iarchive &operator >>(T &t){
- BOOST_STATIC_ASSERT(serialization::is_bitwise_serializable<T>::value);
- this->load_binary(&t,mpl::size_t<sizeof(T)>());
- return *this;
- }
- template<class T>
- char_iarchive &operator &(T &t){
- return this->operator>>(t);
- }
-private:
- BOOST_STATIC_ASSERT((is_same<typename std::iterator_traits<InputIterator>::value_type,char>::value));
- template<class Size>
- void load_binary(char *data,Size size,std::random_access_iterator_tag,mpl::true_ contvals){
- if(this->in + size > this->end) throw archive::archive_exception(archive::archive_exception::stream_error);
- std::memcpy(data,&*this->in,size);
- this->in+=size;
- }
- template<class Size>
- void load_binary(char *data,Size size,std::random_access_iterator_tag,mpl::false_ contvals){
- if(this->in + size > this->end) throw archive::archive_exception(archive::archive_exception::stream_error);
- std::copy(data,data+size,this->in);
- }
- template<class Size,class Category>
- void load_binary(char *data,Size size,Category,mpl::false_ contvals){
- for(std::size_t c=0;c<size;++c){
- if(this->in == this->end) throw archive::archive_exception(archive::archive_exception::stream_error);
- *data++=*this->in++;
- }
- }
-
- InputIterator in;
- InputIterator end;
-};
-
-
-}
-}
-
-
-#endif

Modified: sandbox/transaction/boost/transact/detail/aligning_file.hpp
==============================================================================
--- sandbox/transaction/boost/transact/detail/aligning_file.hpp (original)
+++ sandbox/transaction/boost/transact/detail/aligning_file.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Stefan Strasser 2009 - 2010.
+// Copyright Stefan Strasser 2009 - 2013.
 // 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)
@@ -27,7 +27,7 @@
 
 //does. the inserted 1536 bytes of garbage even need to be synced.
 
-//TODO optimization: not tested on windows.
+//TODO optimization: not performance tested on windows.
 
 template<class Base>
 class aligning_seq_ofile{
@@ -51,6 +51,15 @@
         if(this->sectors <= max_sectors) return this->base.position() + this->sectors * sector_size;
         else return this->base.position();
     }
+ void close(){
+ this->flush_buffer();
+ this->sectors=0;
+ this->base.close();
+ }
+ void reopen(std::string const &name){
+ BOOST_ASSERT(this->sectors==0);
+ this->base.reopen(name);
+ }
     void flush(){
         BOOST_ASSERT(this->base.position() % sector_size == 0);
         if(this->sectors > 1 && this->sectors <= max_sectors){

Modified: sandbox/transaction/boost/transact/detail/buffering_file.hpp
==============================================================================
--- sandbox/transaction/boost/transact/detail/buffering_file.hpp (original)
+++ sandbox/transaction/boost/transact/detail/buffering_file.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Stefan Strasser 2009 - 2010.
+// Copyright Stefan Strasser 2009 - 2013.
 // Copyright Bob Walters 2010
 // Distributed under the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE_1_0.txt or copy at
@@ -52,7 +52,7 @@
 class buffering_seq_ofile{
 public:
     typedef typename Base::size_type size_type;
- static const bool direct_io = Base::has_direct_io;
+ static const bool has_direct_io = Base::has_direct_io;
         
     explicit buffering_seq_ofile(std::string const &name)
         : base(name)
@@ -72,6 +72,14 @@
         this->flush_buffer();
         this->base.flush();
     }
+ void close(){
+ this->flush_buffer();
+ this->base.close();
+ }
+ void reopen(std::string const &name){
+ BOOST_ASSERT(this->size==0);
+ this->base.reopen(name);
+ }
     void sync(){
         //don't flush buffer! caller is responsible to call flush() inside a mutex lock.
         this->base.sync();
@@ -88,25 +96,25 @@
 private:
     void write_overflow(void const *data,std::size_t s){
         BOOST_ASSERT(this->size + s > Capacity);
- if (direct_io) {
- while (this->size + s > Capacity) {
- std::size_t write=Capacity - this->size;
- std::memcpy(this->buffer.data+this->size,data,write);
- this->size=Capacity;
- this->flush_buffer();
- data = static_cast<char const *>(data)+write;
- s-=write;
- }
- if (s) {
- this->write(data,s);
- }
- }else if(this->size == 0){
+ if (has_direct_io) {
+ while (this->size + s > Capacity) {
+ std::size_t write=Capacity - this->size;
+ std::memcpy(this->buffer.data+this->size,data,write);
+ this->size=Capacity;
+ this->flush_full_buffer();
+ data = static_cast<char const *>(data)+write;
+ s-=write;
+ }
+ if (s) { //FIXME ???
+ this->write(data,s);
+ }
+ }else if(this->size == 0){
             this->base.write(data,s);
         }else{
             std::size_t write=Capacity - this->size;
             std::memcpy(this->buffer.data+this->size,data,write);
             this->size=Capacity;
- this->flush_buffer();
+ this->flush_full_buffer();
             this->write(static_cast<char const *>(data)+write,s-write);
         }
     }
@@ -116,10 +124,15 @@
             this->size=0;
         }
     }
+ void flush_full_buffer(){
+ BOOST_ASSERT(this->size == Capacity);
+ this->base.write(this->buffer.data,mpl::size_t<Capacity>());
+ this->size=0;
+ }
 
     Base base;
- ofile_buffer<Capacity,direct_io> buffer;
- std::size_t size;
+ ofile_buffer<Capacity,has_direct_io> buffer;
+ std::size_t size;
 };
 
 

Modified: sandbox/transaction/boost/transact/detail/config.hpp
==============================================================================
--- sandbox/transaction/boost/transact/detail/config.hpp (original)
+++ sandbox/transaction/boost/transact/detail/config.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Stefan Strasser 2010.
+// Copyright Stefan Strasser 2010 2013.
 // 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)
@@ -8,6 +8,10 @@
 
 #include <boost/config.hpp>
 
+//work around a bug in MSVC that doesn't allow the template keyword
+//to be used in call to template operators.
+//see boost list thread:
+//"[boost] [config] explicit call of operator templates / msvc bugworkaround"
 #ifdef BOOST_MSVC
 #define BOOST_NESTED_OPERATOR_TEMPLATE
 #else

Modified: sandbox/transaction/boost/transact/detail/embedded_vector.hpp
==============================================================================
--- sandbox/transaction/boost/transact/detail/embedded_vector.hpp (original)
+++ sandbox/transaction/boost/transact/detail/embedded_vector.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -115,15 +115,15 @@
     //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){
+ template<class InputIterator,class Size>
+ void push_back(InputIterator 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:
+ //don't need to be copyconstructible using this: FIXME use c++11
     template<class InPlaceFactory>
     void push_back(InPlaceFactory const &fac){
         this->reserve_add(mpl::size_t<1>());
@@ -165,20 +165,23 @@
             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 InputIterator,class Size>
+ static void copy_construct_n(T *dest,InputIterator src,Size n){
+ copy_construct_n(
+ dest,src,n,
+ mpl::bool_<is_pod<T>::value && has_contiguous_values<InputIterator>::value>()
+ );
+ }
+ template<class InputIterator,class Size>
+ static void copy_construct_n(T *dest,InputIterator 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,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){
+ template<class InputIterator,class Size>
+ static void copy_construct_n(T *dest,InputIterator src,Size n,false_type pod){
         std::size_t c;
         try{
             for(c=0;c<n;++c){
- new (dest+c) T(src[c]);
+ new (dest+c) T(*src++);
             }
         }catch(...){
             destruct(dest,dest+c);
@@ -243,7 +246,7 @@
 }
 
 template<class T,std::size_t EmbeddedSize,bool Expand>
-struct array_extension<detail::embedded_vector<T,EmbeddedSize,Expand> > : mpl::true_{};
+struct has_array_extension<detail::embedded_vector<T,EmbeddedSize,Expand> > : mpl::true_{};
 
 }
 }

Modified: sandbox/transaction/boost/transact/detail/file.hpp
==============================================================================
--- sandbox/transaction/boost/transact/detail/file.hpp (original)
+++ sandbox/transaction/boost/transact/detail/file.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Bob Walters 2010
+// Copyright Stefan Strasser 2010 - 2013
 // 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)
@@ -11,9 +11,11 @@
 
 namespace boost{
 namespace transact{
-namespace detail{
 
 struct eof_exception : io_failure{};
+
+
+namespace detail{
 
 
 #ifdef _WIN32
@@ -68,7 +70,7 @@
                         throw_io_failure("CreateFileA");
                 
                 //make sure the directory entry has reached the disk:
- std::string dirname=filesystem::system_complete(name).parent_path().external_directory_string();
+ std::string dirname=filesystem::system_complete(name).parent_path().native();
 
                 creation_flags = OPEN_EXISTING;
                 flags = FILE_FLAG_BACKUP_SEMANTICS;
@@ -88,6 +90,9 @@
                         CloseHandle(this->filedes);
         }
         
+ void close(); //TODO
+ void reopen(std::string const &name); //TODO
+
         void seek(size_type const &s) {
                 LARGE_INTEGER loc;
                 loc.QuadPart = s;
@@ -101,7 +106,7 @@
                         throw_io_failure("WriteFile");
                 return (size_type)written;
         }
-
+ void flush(){}
         void sync() {
                 if (!direct_io && FlushFileBuffers(this->filedes) == 0)
                         throw_io_failure("FlushFileBuffers");
@@ -117,6 +122,8 @@
 #error no POSIX synchronized IO available
 #endif
 
+
+
 // low-level ofile for Linux/Unix
 template <bool direct_io = false> // ignored on Posix API.
 class ofile {
@@ -124,29 +131,15 @@
         typedef unsigned int size_type;
         static const bool has_direct_io = direct_io;
 
- int filedes;
         
- ofile(std::string const &name) : 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();
- }
+ ofile(std::string const &name) : filedes(-1),name(name){
+ this->open_();
+ this->sync_directory();
         }
         
         ~ofile() {
- if(this->filedes != -1) ::close(this->filedes);
- }
+ this->close();
+ }
         
         void seek(size_type const &s) {
                 if(::lseek(this->filedes,s,SEEK_SET) != off_t(s)) throw io_failure();
@@ -156,7 +149,7 @@
                 if(::write(this->filedes,data,size) != ssize_t(size)) throw io_failure();
                 return size;
         }
-
+ void flush(){}
         void sync() {
 #ifdef linux
                 if(::fdatasync(this->filedes) != 0) throw io_failure();
@@ -164,6 +157,47 @@
                 if(::fsync(this->filedes) != 0) throw io_failure();
 #endif
         }
+ void close(){
+ if(this->filedes != -1){
+ if(::close(this->filedes) != 0) throw io_failure();
+ }
+ this->filedes=-1;
+ }
+ void reopen(std::string const &newname){
+ BOOST_ASSERT(this->filedes == -1);
+ filesystem::remove(this->name);
+ this->name=newname;
+ this->open_();
+ sync_directory();
+ }
+ void rename(std::string const &newname){
+ BOOST_ASSERT(this->filedes == -1);
+ filesystem::rename(this->name,newname);
+ this->name=newname;
+ this->open_(0); //do not truncate file!
+ sync_directory();
+ }
+private:
+ void sync_directory(){
+ //TODO optimization: directory entries are synced even if syncing is turning off,
+ //which is not passed to ofile
+ std::string dirname=filesystem::path(this->name).parent_path().native();
+ 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();
+ }
+ void open_(int flags=O_CREAT | O_TRUNC){
+ flags|=O_WRONLY;
+#ifdef linux
+ flags|=O_NOATIME;
+#endif
+ this->filedes=open(this->name.c_str(),flags,S_IRUSR | S_IWUSR);
+ if(this->filedes==-1) throw io_failure();
+ }
+ int filedes;
+ std::string name;
 };
 
 #endif

Added: sandbox/transaction/boost/transact/detail/file_iterator.hpp
==============================================================================
--- (empty file)
+++ sandbox/transaction/boost/transact/detail/file_iterator.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -0,0 +1,100 @@
+// Copyright Stefan Strasser 2013
+// 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_FILE_ITERATOR_HPP
+#define BOOST_TRANSACT_DETAIL_FILE_ITERATOR_HPP
+
+
+#include <iterator>
+#include <boost/mpl/bool.hpp>
+#include <boost/transact/array_extension.hpp>
+#include <boost/type_traits/is_pod.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/optional/optional.hpp>
+
+
+namespace boost{
+namespace transact{
+namespace detail{
+
+template<typename File>
+class file_output_iterator
+ : public std::iterator<std::output_iterator_tag,char>{
+public:
+ typedef File file_type;
+ explicit file_output_iterator(File &file) : file(&file){}
+ file_output_iterator &operator=(char v){
+ this->file->write(&v,mpl::size_t<sizeof(char)>());
+ return *this;
+ }
+ template<class InputIterator,class Size>
+ file_output_iterator &insert(InputIterator input,Size size){
+ this->insert(input,size,typename has_contiguous_values<InputIterator>::type());
+ return *this;
+ }
+ file_output_iterator &operator*(){ return *this; }
+ file_output_iterator &operator++(){ return *this; }
+ file_output_iterator operator++(int);
+private:
+ template<class InputIterator,class Size>
+ void insert(InputIterator input,Size size,mpl::true_ contig){
+ this->file->write(&*input,size);
+ }
+ template<class InputIterator,class Size>
+ void insert(InputIterator input,Size size,mpl::false_ contig){
+ for(std::size_t c=0;c<size;++c){
+ this->file->write(&*input,mpl::size_t<sizeof(char)>());
+ ++input;
+ }
+ }
+
+ File *file;
+};
+
+template<class File>
+class file_input_iterator
+ : std::iterator<std::forward_iterator_tag,char>{
+public:
+ typedef File file_type;
+ file_input_iterator() : file(0){} //eof iterator
+ explicit file_input_iterator(File &file) : file(&file){}
+ char operator*() const;
+ file_input_iterator &operator++();
+ file_input_iterator operator++(int);
+ bool operator==(file_input_iterator const &other) const;
+ bool operator!=(file_input_iterator const &other) const;
+ template<class OutputIterator,class Size>
+ file_input_iterator &extract(OutputIterator output,Size size){
+ this->extract(output,size,typename has_contiguous_values<OutputIterator>::type());
+ return *this;
+ }
+private:
+ template<class OutputIterator,class Size>
+ void extract(OutputIterator output,Size size,mpl::true_ contig){
+ this->file->read(&*output,size);
+ }
+ template<class OutputIterator,class Size>
+ void extract(OutputIterator output,Size size,mpl::false_ contig){
+ for(std::size_t c=0;c<size;++c){
+ this->file->read(&*output,mpl::size_t<sizeof(char)>());
+ ++output;
+ }
+ }
+ File *file;
+};
+
+
+}
+
+template<class File>
+struct has_array_extension<detail::file_output_iterator<File> > : mpl::true_{};
+template<class File>
+struct has_array_extension<detail::file_input_iterator<File> > : mpl::true_{};
+
+
+}
+}
+
+#endif

Modified: sandbox/transaction/boost/transact/detail/filebuf_file.hpp
==============================================================================
--- sandbox/transaction/boost/transact/detail/filebuf_file.hpp (original)
+++ sandbox/transaction/boost/transact/detail/filebuf_file.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Stefan Strasser 2009 - 2010.
+// Copyright Stefan Strasser 2009 - 2013.
 // 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)
@@ -10,6 +10,7 @@
 #include <fstream>
 #include <string>
 #include <boost/mpl/size_t.hpp>
+#include <boost/filesystem.hpp>
 #include <boost/transact/exception.hpp>
 #include <boost/transact/detail/file.hpp>
 
@@ -25,8 +26,9 @@
 class filebuf_seq_ofile{
 public:
     typedef unsigned int 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();
+ static bool const has_direct_io=false;
+ explicit filebuf_seq_ofile(std::string const &name) : pos(0),name(name){
+ this->open();
     }
     void write(void const *data,mpl::size_t<1>){
         if(this->buf.sputc(*static_cast<char const *>(data)) == EOF) throw io_failure();
@@ -44,9 +46,23 @@
     void sync(){
         throw unsupported_operation();
     }
+ void close(){
+ if(!this->buf.close()) throw io_failure();
+ }
+ void reopen(std::string const &newname){
+ BOOST_ASSERT(!this->buf.is_open());
+ filesystem::remove(this->name);
+ this->name=newname;
+ this->open();
+ }
 private:
+ void open(){
+ if(!this->buf.open(this->name.c_str(),std::ios::out | std::ios::binary)) throw io_failure();
+ this->pos=0;
+ }
     std::filebuf buf;
     size_type pos;
+ std::string name;
 };
 
 class filebuf_seq_ifile{

Modified: sandbox/transaction/boost/transact/detail/sectorizing_file.hpp
==============================================================================
--- sandbox/transaction/boost/transact/detail/sectorizing_file.hpp (original)
+++ sandbox/transaction/boost/transact/detail/sectorizing_file.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Stefan Strasser 2009 - 2010.
+// Copyright Stefan Strasser 2009 - 2013.
 // 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)
@@ -50,6 +50,14 @@
 #endif
         }
     }
+ void close(){
+ this->flush_buffer();
+ this->base.close();
+ }
+ void reopen(std::string const &name){
+ BOOST_ASSERT(this->size==0);
+ this->base.reopen(name);
+ }
 private:
     static std::size_t const sector_size=512;
     static std::size_t const max_size=sector_size-2;

Modified: sandbox/transaction/boost/transact/detail/syncing_file.hpp
==============================================================================
--- sandbox/transaction/boost/transact/detail/syncing_file.hpp (original)
+++ sandbox/transaction/boost/transact/detail/syncing_file.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,4 +1,4 @@
-// Copyright Stefan Strasser 2009 - 2010
+// Copyright Stefan Strasser 2009 - 2013
 // Copyright Bob Walters 2010
 // Distributed under the Boost Software License, Version 1.0.
 // (See accompanying file LICENSE_1_0.txt or copy at
@@ -21,7 +21,10 @@
 namespace transact{
 namespace detail{
 
+static std::size_t const file_write_ahead_size=10*1024*1024;
+static std::size_t const file_page_size=4096;
 
+
 template <class Base>
 class syncing_seq_ofile{
 public:
@@ -31,13 +34,13 @@
     explicit syncing_seq_ofile(std::string const &name)
                 : pos(0)
                 , base(name){
- this->write_ahead(0,write_ahead_size);
+ this->write_ahead(0,file_write_ahead_size);
                 }
     void write(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
+ size_type const s=this->pos % file_write_ahead_size;
+ if(s + size >= file_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 + file_write_ahead_size;
+ size_type end=start+((s + size)/file_write_ahead_size) * file_write_ahead_size; //usually == start + file_write_ahead_size, but "size" can theoretically span a whole file_write_ahead_size
                         BOOST_ASSERT(end > start);
                         this->write_ahead(start,end);
                 }
@@ -47,33 +50,47 @@
                 if(ret != std::size_t(size)) throw io_failure();
         }
     size_type position() const{ return this->pos; }
- void flush() {}
+ void flush(){
+ base.flush();
+ }
     void sync() {
- base.sync();
- }
+ base.sync();
+ }
+ void close(){
+ //do not actually close, just make sure contents are on disk. no call to base.close()!
+ this->flush();
+ this->sync(); //TODO opimize sync in lock?
+ this->pos=0;
+ }
+ void reopen(std::string const &name){
+ BOOST_ASSERT(this->pos==0);
+ //file is still open, invalidate file for reuse BEFORE renaming:
+ this->write_ahead(0,file_write_ahead_size);
+ this->base.close();
+ this->base.rename(name); //rename, not reopen! by writing ahead the file is effectively truncated
+ }
 private:
     size_type pos;
         Base base;
 
     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);
- BOOST_STATIC_ASSERT(write_ahead_size % page_size == 0);
+ BOOST_ASSERT(start % file_write_ahead_size == 0);
+ BOOST_ASSERT(end % file_write_ahead_size == 0);
+ BOOST_STATIC_ASSERT(file_write_ahead_size % file_page_size == 0);
         base.seek(start);
- for(size_type off=start;off < end;off+=page_size){
- base.write(empty_page.data,page_size);
+ for(size_type off=start;off < end;off+=file_page_size){
+ base.write(empty_page.data,file_page_size);
         }
- base.sync();
- base.seek(this->pos);
+ this->flush();
+ this->sync();
+ base.seek(this->pos);
     }
 
- static std::size_t const write_ahead_size=10*1024*1024;
- static std::size_t const page_size=4096;
 
- struct empty_page_type : public ofile_buffer<page_size,has_direct_io> {
- typedef ofile_buffer<page_size,has_direct_io> base_buffer;
+ struct empty_page_type : public ofile_buffer<file_page_size,has_direct_io> {
+ typedef ofile_buffer<file_page_size,has_direct_io> base_buffer;
         empty_page_type() : base_buffer() {
- std::memset(base_buffer::data,0,page_size);
+ std::memset(base_buffer::data,0,file_page_size);
         }
     };
         

Modified: sandbox/transaction/boost/transact/log.hpp
==============================================================================
--- sandbox/transaction/boost/transact/log.hpp (original)
+++ sandbox/transaction/boost/transact/log.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -1,39 +1,44 @@
-// Copyright Stefan Strasser 2009 - 2010.
+// Copyright Stefan Strasser 2009 - 2013.
 // 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)
 
 
+
+//TODO: rolling log files are always started at .1 currently.
+//is persistent needs a header in the log file the old logs can't be deleted
+//until a new one is created, so the log needs to start at .<old+1>
+//better solution is to don't use a header for this purpose but safe this info in
+//an extra file by persistent
+
 #ifndef BOOST_TRANSACT_LOG_HEADER_HPP
 #define BOOST_TRANSACT_LOG_HEADER_HPP
 
-#include <cstring>
-#include <string>
-#include <algorithm>
+#include <vector>
 #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 <algorithm>
+#include <boost/integer.hpp>
+#include <boost/optional/optional.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/filesystem.hpp>
+#include <boost/mpl/size.hpp>
+#include <boost/mpl/deref.hpp>
+#include <boost/mpl/next.hpp>
+#include <boost/mpl/begin.hpp>
+#include <boost/mpl/integral_c.hpp>
+#include <boost/mpl/at.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/eval_if.hpp>
+#include <boost/type_traits/is_same.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>
-
+#include <boost/transact/detail/file.hpp>
+#include <boost/transact/detail/file_iterator.hpp>
+#include <boost/transact/archive.hpp>
 
 namespace boost{
 namespace transact{
@@ -45,16 +50,16 @@
 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();
+ std::string filename=fs::path(name).filename().native();
+ fs::path dir=fs::path(name).parent_path();
         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();
+ std::string foundfilename=it->path().filename().native();
             if(foundfilename.substr(0,filename.length()+1) != filename+".") continue;
             std::string nrstring=foundfilename.substr(filename.length()+1);
- unsigned int nr;
+ unsigned int nr=0;
             try{ nr=lexical_cast<unsigned int>(nrstring); } catch(...){ continue; }
             *out++=nr;
         }
@@ -62,6 +67,8 @@
         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);
@@ -70,289 +77,374 @@
 
 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))){}
+namespace detail{
+
+template<class Entries>
+struct log_id_type{
+ typedef typename boost::uint_value_t<mpl::size<Entries>::value>::least type;
+};
+
+template<class Iterator,class Entry,class Id>
+struct log_entry_id_iterator{
+ typedef typename mpl::eval_if<
+ is_same<typename mpl::deref<Iterator>::type,Entry>,
+ Id,
+ log_entry_id_iterator<
+ typename mpl::next<Iterator>::type,
+ Entry,
+ mpl::integral_c<typename Id::value_type,Id::value+1>
+ >
+ >::type type;
+};
+
+//don't use mpl::distance, so Entries can be a ForwardSequence
+template<class Entries,class Entry>
+struct log_entry_id : log_entry_id_iterator<
+ typename mpl::begin<Entries>::type,
+ Entry,
+ mpl::integral_c<typename log_id_type<Entries>::type,1>
+ >::type{};
+}
 
- //Archive interface
+template<class Entries,class File>
+class olog{
+public:
+ typedef typename detail::log_id_type<Entries>::type id_type;
+ explicit olog(File &file) : file(file){}
     template<class T>
- olog_files &operator<<(T const &t){
- this->file->save(t);
+ olog &operator<<(T const &t){
+ typedef detail::file_output_iterator<File> it_type;
+ it_type it(this->file);
+ char_oarchive<it_type> archive(it);
+ archive << detail::log_entry_id<Entries,T>::type::value;
+ archive << 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;
-
+protected:
+ File &file;
+};
 
- bool overflow() const{
- return (!this->rolling())
- && (this->file->position() > this->max_log_size + this->header_size);
+namespace detail{
+
+template<class Archive,class Entries,class F>
+class ilog_dispatcher{
+ typedef typename detail::log_id_type<Entries>::type id_type;
+public:
+ ilog_dispatcher(){
+ this->init<0>(mpl::false_());
     }
-
- 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 operator()(id_type id,Archive &ar,F const &f) const{
+ if(id <= 0 || id > mpl::size<Entries>::value) throw io_failure();
+ (*this->functions[id-1])(ar,f);
     }
-
- 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;
+private:
+ template<id_type Id>
+ void init(mpl::false_){
+ this->functions[Id]=&dispatch<typename mpl::at_c<Entries,Id>::type>;
+ this->init<Id+1>(mpl::bool_<(Id+1 == mpl::size<Entries>::value)>());
     }
-
- void flush(){
- this->file->flush();
+ template<id_type Id>
+ void init(mpl::true_){}
+ template<class T>
+ static void dispatch(Archive &ar,F const &f){
+ T t; //FIXME requires log entries to be default constructible
+ ar >> t;
+ f(t);
     }
- void sync(){
- this->file->sync();
+ typedef void (*function_type)(Archive &,F const &f);
+ function_type functions[mpl::size<Entries>::value];
+};
+
+
+}
+
+template<class Entries,class File>
+class ilog{
+public:
+ typedef typename detail::log_id_type<Entries>::type id_type;
+ explicit ilog(File &file) : file(file){}
+ template<class F>
+ ilog &operator>>(F const &f){
+ typedef detail::file_input_iterator<File> it_type;
+ typedef char_iarchive<it_type> archive_type;
+ static detail::ilog_dispatcher<archive_type,Entries,F> const dispatch;
+
+ it_type it(this->file);
+ archive_type archive(it,it_type());
+ id_type id=0;
+ archive >> id;
+ dispatch(id,archive,f);
+ return *this;
     }
 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()
+ File &file;
 };
 
-template<bool Sync>
-class otransaction_log_files : public olog_files<Sync>{
-private:
+template<class Entries,class RollingLogfile,class Id=unsigned int>
+class transaction_olog
+ : public olog<Entries,RollingLogfile>{
+ typedef olog<Entries,RollingLogfile> base_type;
     struct detail{
- typedef unsigned int transaction;
+ struct null_header{};
     };
 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){}
-
+ typedef Id id_type;
+ transaction_olog(RollingLogfile &file,std::size_t max_log_size=100*1024*1024)
+ : base_type(file)
+ , max_log_size(max_log_size)
+ , next_tx(1)
+ , open_txs(0)
+ , rolled_txs(0)
+ , roll_cutoff(0){
+
+ }
+ Id begin_transaction(){
+ return this->begin_transaction(detail::null_header());
+ }
     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;
+ Id begin_transaction(Header const &header){
+ Id tx=this->next_tx++;
+ if(!this->rolling() && this->file.position() >= this->max_log_size){
+ //don't roll a second time until all transactions started in the old log
+ //are closed, RollingLogfile only guarantees a minimum of 2 existing files
+ this->file.roll();
+ this->roll_cutoff=tx;
+ BOOST_ASSERT(this->rolled_txs==0);
+ this->rolled_txs=this->open_txs;
+ this->open_txs=0;
+ this->write_header(header);
+ }
+ BOOST_ASSERT(!this->rolling() || tx >= this->roll_cutoff);
+ ++this->open_txs;
+ return tx;
     }
- void end_transaction(transaction tx){
+ void end_transaction(Id 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;
- }
+ BOOST_ASSERT(this->rolled_txs > 0);
+ --this->rolled_txs;
+ //if rolled_txs is now 0 all transactions started in the old, rolled, log have
+ //successfully ended. rolling() now returns false, removing the old log file
+ //and thus another log roll is safe from now on
+ }else{
+ BOOST_ASSERT(this->open_txs > 0);
+ --this->open_txs;
+ }
     }
+ bool rolling() const{ return this->rolled_txs > 0; }
 private:
- transaction next_tx;
- std::size_t open_transactions;
- std::size_t rolled_transactions;
- transaction roll_cutoff;
+ void write_header(detail::null_header const &){}
+ template<class Header>
+ void write_header(Header const &header){
+ typedef detail::file_output_iterator<RollingLogfile> it_type;
+ it_type it(this->file);
+ char_oarchive<it_type> archive(it);
+ archive << detail::log_entry_id<Entries,Header>::type::value;
+ archive << header;
+ }
+
+ std::size_t const max_log_size;
+ Id next_tx;
+ std::size_t open_txs, rolled_txs;
+ Id roll_cutoff;
 };
 
+namespace detail{
+
+
 template<bool Sync>
-class ilog_files{
+struct ologfile_type{
+ typedef typename mpl::if_c<
+ Sync,
+ detail::sectorizing_seq_ofile<
+ detail::aligning_seq_ofile<
+ detail::buffering_seq_ofile<
+ detail::syncing_seq_ofile<
+ detail::ofile<false> //FIXME argument. why is this a parameter?
+ >,
+ 8192
+ >
+ >
+ >,
+ detail::buffering_seq_ofile<
+ detail::filebuf_seq_ofile,
+ 8192
+ >
+ >::type type;
+};
+
+template<bool Sync>
+struct ilogfile_type{
+ typedef typename mpl::if_c<
+ Sync,
+ detail::sectorizing_seq_ifile<
+ detail::filebuf_seq_ifile
+ >,
+ detail::filebuf_seq_ifile
+ >::type type;
+};
+
+
+}
+
+template<bool Sync>
+class ologfile : public detail::ologfile_type<Sync>::type{
+ typedef typename detail::ologfile_type<Sync>::type base_type;
 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;
+ explicit ologfile(std::string const &name) : base_type(name){}
+};
+
+template<bool Sync>
+class ilogfile : public detail::ilogfile_type<Sync>::type{
+ typedef typename detail::ilogfile_type<Sync>::type base_type;
+public:
+ explicit ilogfile(std::string const &name) : base_type(name){}
+};
+
+namespace detail{
+
+template<class File>
+class rolling_ologfile_base{
+public:
+ typedef typename File::size_type size_type;
+ explicit rolling_ologfile_base(std::string const &name)
+ : name(name)
+ , logid(1){
+ this->files[0]=in_place(this->name+".1");
+ this->active_=&this->files[0];
     }
- 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);
+ void write(void const *data,Size s){
+ this->active()->write(data,s);
     }
- 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();
- }
+ void flush(){
+ this->active()->flush();
     }
-private:
- typedef std::set<unsigned int> log_ids_type;
- log_ids_type log_ids;
- log_ids_type::const_iterator current;
+ void sync(){
+ this->active()->sync();
+ }
+ typename File::size_type position() const{ return this->active()->position(); }
+protected:
+ optional<File> &active(){
+ return *this->active_;
+ }
+ optional<File> const &active() const{
+ return *this->active_;
+ }
+ optional<File> &inactive(){
+ return this->active_ == &this->files[0] ? this->files[1] : this->files[0];
+ }
+
     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;
+ unsigned int logid;
+ optional<File> files[2];
+ optional<File> *active_;
 };
 
 }
 
-template<class Entries,bool Sync>
-class olog{
-private:
- typedef typename detail::invert_vector<Entries>::type ids;
+template<class File>
+class rolling_ologfile
+ : public detail::rolling_ologfile_base<File>{
+ typedef detail::rolling_ologfile_base<File> base_type;
 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;
+ explicit rolling_ologfile(std::string const &name)
+ : base_type(name){}
+ void roll(){
+ //close old log to cause write exceptions, which would be ignored when destructing:
+ //TODO optimization close() flushes/syncs the old logfile. one could also keep the old
+ //log open until an explicit request to flush/sync the log causes all log files
+ //to flush/sync
+ this->active()->close();
+ //use 2 optional<>s because the new file must be fully constructed to replace the old one.
+ //if construction fails there must be a valid old log file in this->active, and files
+ //are not swap()able:
+ optional<File> &newlog=this->inactive();
+ BOOST_ASSERT(!newlog);
+ newlog=in_place(this->name+'.'+lexical_cast<std::string>(this->logid+1));
+ this->active_=&newlog; ++this->logid;
+ this->inactive().reset();
     }
+};
 
- 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;
+template<class File>
+class alternating_ologfile
+ : public detail::rolling_ologfile_base<File>{
+ typedef detail::rolling_ologfile_base<File> base_type;
+public:
+ explicit alternating_ologfile(std::string const &name)
+ : base_type(name){}
+ void roll(){
+ this->active()->close();
+ optional<File> &newlog=this->inactive();
+ std::string const newname=this->name+'.'+lexical_cast<std::string>(this->logid+1);
+ if(!newlog) newlog=in_place(newname);
+ else newlog->reopen(newname);
+ this->active_=&newlog; ++this->logid;
     }
- 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);
+};
+
+template<class File>
+class rolling_ilogfile{
+public:
+ typedef typename File::size_type size_type;
+ explicit rolling_ilogfile(std::string const &name)
+ : name(name){
+ detail::get_existing_log_ids(std::back_inserter(this->ids),this->name);
+ std::sort(this->ids.begin(),this->ids.end());
+
+ //must be a contiguous sequence of files:
+ for(ids_type::const_iterator next=this->ids.begin();next!=this->ids.end();){
+ ids_type::const_iterator it=next++;
+ if(next != this->log_ids.end() && (*it != *next-1)) throw io_failure();
         }
- typedef mpl::true_ is_saving;
- typedef mpl::false_ is_loading;
- private:
- olog &log;
- };
+
+ this->current=this->ids.begin();
+ this->open();
+ }
+ template<class Size>
+ void read(void *data,Size s){
+ if(!this->file) throw eof_exception();
+ try{
+ this->file->read(data,s);
+ }catch(eof_exception &){
+ //eof means nothing was read, otherwise io_exception is thrown. retry in next file
+ ++this->current;
+ this->open();
+ this->read(data,s);
+ }
+ }
+ void remove(){
+ for(ids_type::const_iterator it=this->ids.begin();it!=this->ids.end();++it){
+ filesystem::remove(this->name+'.'+lexical_cast<std::string>(*it));
+ }
+ }
 private:
- olog_files<Sync> &files;
- id_type id_offset;
+ void open(){
+ this->file.reset();
+ if(this->current != this->ids.end()){
+ this->file=in_place(this->name+'.'+lexical_cast<std::string>(*this->current));
+ }
+ }
+ std::string const name;
+ optional<File> file;
+ typedef std::vector<unsigned int> ids_type;
+ ids_type ids;
+ ids_type::const_iterator current;
 };
 
+
+
+
+/*
+ *
+ * old class (needs rewrite) that buffers log writes so the log itself only needs to be locked
+ * on flush. useful only when 2 logs are interlaced into the same file?
+
 template<class Log,class Lockable,std::size_t Size>
 class olog_buffer{
 public:
@@ -426,7 +518,9 @@
     detail::embedded_vector<char,Size,false> buffer;
 };
 
+*/
 
+
 }
 }
 

Modified: sandbox/transaction/boost/transact/object_access.hpp
==============================================================================
--- sandbox/transaction/boost/transact/object_access.hpp (original)
+++ sandbox/transaction/boost/transact/object_access.hpp 2013-02-25 11:23:51 EST (Mon, 25 Feb 2013)
@@ -24,6 +24,7 @@
 
 #include <boost/serialization/serialization.hpp>
 #include <boost/serialization/version.hpp>
+#include <boost/archive/impl/archive_serializer_map.ipp>
 
 #endif
 
@@ -238,11 +239,21 @@
 
 
 template<class Archive,class T>
+void serialize(Archive &ar,T &t,mpl::true_ saving){
+ archive::save(ar.serialization_archive(),t);
+}
+template<class Archive,class T>
+void serialize(Archive &ar,T &t,mpl::false_ saving){
+ archive::load(ar.serialization_archive(),t);
+}
+
+
+template<class Archive,class T>
 void serialize(Archive &ar,T &t,constructed_tag){
 #ifdef NO_BOOST_SERIALIZATION
     sizeof(boost_serialization_required<T>);
 #else
- serialization::serialize_adl(ar.serialization_archive(),t,serialization::version<T>::value);
+ detail::serialize(ar,t,typename Archive::is_saving());
 #endif
 }
 


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