diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2011-03-22 16:22:06 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2011-03-22 16:22:06 +0200 |
commit | be5909a7fc240c007bb0128353d493af947a8749 (patch) | |
tree | 84f4e6488adcde96e5e41a691c191035da6e92c1 | |
parent | 878a448f86ddd60e5eb7778e88edd965003ea480 (diff) |
Add object and container statement caches
-rw-r--r-- | odb/sqlite/container-statements.hxx | 179 | ||||
-rw-r--r-- | odb/sqlite/container-statements.txx | 36 | ||||
-rw-r--r-- | odb/sqlite/makefile | 1 | ||||
-rw-r--r-- | odb/sqlite/object-statements.cxx | 17 | ||||
-rw-r--r-- | odb/sqlite/object-statements.hxx | 333 | ||||
-rw-r--r-- | odb/sqlite/object-statements.ixx | 54 | ||||
-rw-r--r-- | odb/sqlite/object-statements.txx | 77 | ||||
-rw-r--r-- | odb/sqlite/statement-cache.hxx | 10 |
8 files changed, 697 insertions, 10 deletions
diff --git a/odb/sqlite/container-statements.hxx b/odb/sqlite/container-statements.hxx new file mode 100644 index 0000000..a114990 --- /dev/null +++ b/odb/sqlite/container-statements.hxx @@ -0,0 +1,179 @@ +// file : odb/sqlite/container-statements.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_CONTAINER_STATEMENTS_HXX +#define ODB_SQLITE_CONTAINER_STATEMENTS_HXX + +#include <odb/pre.hxx> + +#include <odb/forward.hxx> +#include <odb/traits.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/binding.hxx> +#include <odb/sqlite/statement.hxx> +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class connection; + + // Template argument is the generated container traits type. + // + template <typename T> + class container_statements + { + public: + typedef T traits; + + typedef typename traits::id_image_type id_image_type; + typedef typename traits::data_image_type data_image_type; + typedef typename traits::cond_image_type cond_image_type; + + typedef typename traits::functions_type functions_type; + + typedef sqlite::insert_statement insert_statement_type; + typedef sqlite::select_statement select_statement_type; + typedef sqlite::delete_statement delete_statement_type; + + typedef sqlite::connection connection_type; + + container_statements (connection_type&); + + connection_type& + connection () + { + return conn_; + } + + // Functions. + // + functions_type& + functions () + { + return functions_; + } + + // Id image (external). + // + id_image_type& + id_image () + { + return *id_image_; + } + + void + id_image (id_image_type& i) + { + id_image_ = &i; + } + + // Condition image. + // + cond_image_type& + cond_image () + { + return cond_image_; + } + + binding& + cond_image_binding () + { + return cond_image_binding_; + } + + // Data image. + // + data_image_type& + data_image () + { + return data_image_; + } + + binding& + data_image_binding () + { + return data_image_binding_; + } + + bool* + data_image_truncated () + { + return data_image_truncation_; + } + + // + // Statements. + // + + insert_statement_type& + insert_one_statement () + { + if (insert_one_ == 0) + insert_one_.reset ( + new (details::shared) insert_statement_type ( + conn_, traits::insert_one_statement, data_image_binding_)); + + return *insert_one_; + } + + select_statement_type& + select_all_statement () + { + if (select_all_ == 0) + select_all_.reset ( + new (details::shared) select_statement_type ( + conn_, + traits::select_all_statement, + cond_image_binding_, + data_image_binding_)); + + return *select_all_; + } + + delete_statement_type& + delete_all_statement () + { + if (delete_all_ == 0) + delete_all_.reset ( + new (details::shared) delete_statement_type ( + conn_, traits::delete_all_statement, cond_image_binding_)); + + return *delete_all_; + } + + private: + container_statements (const container_statements&); + container_statements& operator= (const container_statements&); + + private: + connection_type& conn_; + functions_type functions_; + + id_image_type* id_image_; + + cond_image_type cond_image_; + binding cond_image_binding_; + bind cond_image_bind_[traits::cond_column_count]; + + data_image_type data_image_; + binding data_image_binding_; + bind data_image_bind_[traits::data_column_count]; + bool data_image_truncated_[traits::data_column_count]; + + details::shared_ptr<insert_statement_type> insert_one_; + details::shared_ptr<select_statement_type> select_all_; + details::shared_ptr<delete_statement_type> delete_all_; + }; + } +} + +#include <odb/sqlite/container-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_CONTAINER_STATEMENTS_HXX diff --git a/odb/sqlite/container-statements.txx b/odb/sqlite/container-statements.txx new file mode 100644 index 0000000..23466df --- /dev/null +++ b/odb/sqlite/container-statements.txx @@ -0,0 +1,36 @@ +// file : odb/sqlite/container-statements.txx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cstddef> // std::size_t +#include <cstring> // std::memset + +namespace odb +{ + namespace sqlite + { + // container_statements + // + + template <typename T> + container_statements<T>:: + container_statements (connection_type& conn) + : conn_ (conn), + functions_ (this, + &traits::insert_one, + &traits::load_all, + &traits::delete_all), + id_image_ (0), + cond_image_binding_ (cond_image_bind_, traits::cond_column_count), + data_image_binding_ (data_image_bind_, traits::data_column_count) + { + std::memset (cond_image_bind_, 0, sizeof (cond_image_bind_)); + std::memset (data_image_bind_, 0, sizeof (data_image_bind_)); + std::memset (data_image_truncated_, 0, sizeof (data_image_truncated_)); + + for (std::size_t i (0); i < traits::data_column_count; ++i) + data_image_bind_[i].truncated = data_image_truncated_ + i; + } + } +} diff --git a/odb/sqlite/makefile b/odb/sqlite/makefile index f46587f..3cc9d3c 100644 --- a/odb/sqlite/makefile +++ b/odb/sqlite/makefile @@ -11,6 +11,7 @@ connection-factory.cxx \ database.cxx \ error.cxx \ exceptions.cxx \ +object-statements.cxx \ statement-cache.cxx \ statement.cxx \ traits.cxx \ diff --git a/odb/sqlite/object-statements.cxx b/odb/sqlite/object-statements.cxx new file mode 100644 index 0000000..fd3df50 --- /dev/null +++ b/odb/sqlite/object-statements.cxx @@ -0,0 +1,17 @@ +// file : odb/sqlite/object-statements.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/sqlite/object-statements.hxx> + +namespace odb +{ + namespace sqlite + { + object_statements_base:: + ~object_statements_base () + { + } + } +} diff --git a/odb/sqlite/object-statements.hxx b/odb/sqlite/object-statements.hxx new file mode 100644 index 0000000..73f3162 --- /dev/null +++ b/odb/sqlite/object-statements.hxx @@ -0,0 +1,333 @@ +// file : odb/sqlite/object-statements.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_OBJECT_STATEMENTS_HXX +#define ODB_SQLITE_OBJECT_STATEMENTS_HXX + +#include <odb/pre.hxx> + +#include <vector> +#include <cassert> + +#include <odb/forward.hxx> +#include <odb/traits.hxx> +#include <odb/cache-traits.hxx> +#include <odb/details/shared-ptr.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/binding.hxx> +#include <odb/sqlite/statement.hxx> +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class connection; + + class LIBODB_SQLITE_EXPORT object_statements_base: + public details::shared_base + { + public: + typedef sqlite::connection connection_type; + + connection_type& + connection () + { + return conn_; + } + + // Locking. + // + void + lock () + { + assert (!locked_); + locked_ = true; + } + + void + unlock () + { + assert (locked_); + locked_ = false; + } + + bool + locked () const + { + return locked_; + } + + public: + virtual + ~object_statements_base (); + + protected: + object_statements_base (connection_type& conn) + : conn_ (conn), locked_ (false) + { + } + + protected: + connection_type& conn_; + bool locked_; + }; + + template <typename T> + class object_statements: public object_statements_base + { + public: + typedef T object_type; + typedef odb::object_traits<object_type> object_traits; + typedef typename object_traits::id_type id_type; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::image_type image_type; + typedef typename object_traits::id_image_type id_image_type; + + typedef pointer_cache_traits<pointer_type> object_cache_traits; + + typedef + typename object_traits::container_statement_cache_type + container_statement_cache_type; + + typedef sqlite::insert_statement persist_statement_type; + typedef sqlite::select_statement find_statement_type; + typedef sqlite::update_statement update_statement_type; + typedef sqlite::delete_statement erase_statement_type; + + // Automatic lock. + // + struct auto_lock + { + // Lock the statements unless they are already locked in which + // case subsequent calls to locked() will return false. + // + auto_lock (object_statements&); + + // Unlock the statemens if we are holding the lock and clear + // the delayed loads. This should only happen in case an + // exception is thrown. In normal circumstances, the user + // should call unlock() explicitly. + // + ~auto_lock (); + + // Return true if this auto_lock instance holds the lock. + // + bool + locked () const; + + // Unlock the statemens. + // + void + unlock (); + + private: + auto_lock (const auto_lock&); + auto_lock& operator= (const auto_lock&); + + private: + object_statements& s_; + bool locked_; + }; + + // + // + object_statements (connection_type&); + + // Delayed loading. + // + void + delay_load (const id_type& id, + object_type& obj, + const typename object_cache_traits::position_type& p) + { + delayed_.push_back (delayed_load (id, obj, p)); + } + + void + load_delayed () + { + assert (locked ()); + + if (!delayed_.empty ()) + load_delayed_ (); + } + + void + clear_delayed () + { + if (!delayed_.empty ()) + clear_delayed_ (); + } + + // Object image. + // + image_type& + image () + { + return image_; + } + + binding& + in_image_binding () + { + return in_image_binding_; + } + + binding& + out_image_binding () + { + return out_image_binding_; + } + + bool* + out_image_truncated () + { + return out_image_truncated_; + } + + // Object id image. + // + id_image_type& + id_image () + { + return id_image_; + } + + binding& + id_image_binding () + { + return id_image_binding_; + } + + // Statements. + // + persist_statement_type& + persist_statement () + { + if (persist_ == 0) + persist_.reset ( + new (details::shared) persist_statement_type ( + conn_, object_traits::persist_statement, in_image_binding_)); + + return *persist_; + } + + find_statement_type& + find_statement () + { + if (find_ == 0) + find_.reset ( + new (details::shared) find_statement_type ( + conn_, + object_traits::find_statement, + id_image_binding_, + out_image_binding_)); + + return *find_; + } + + update_statement_type& + update_statement () + { + if (update_ == 0) + update_.reset ( + new (details::shared) update_statement_type ( + conn_, + object_traits::update_statement, + id_image_binding_, + in_image_binding_)); + + return *update_; + } + + erase_statement_type& + erase_statement () + { + if (erase_ == 0) + erase_.reset ( + new (details::shared) erase_statement_type ( + conn_, + object_traits::erase_statement, + id_image_binding_)); + + return *erase_; + } + + // Container statement cache. + // + container_statement_cache_type& + container_statment_cache () + { + return container_statement_cache_; + } + + private: + object_statements (const object_statements&); + object_statements& operator= (const object_statements&); + + private: + void + load_delayed_ (); + + void + clear_delayed_ (); + + private: + container_statement_cache_type container_statement_cache_; + + image_type image_; + + // In (send) binding. The last element is the id parameter. + // + binding in_image_binding_; + bind in_image_bind_[object_traits::in_column_count + 1]; + + // Out (receive) binding. + // + binding out_image_binding_; + bind out_image_bind_[object_traits::out_column_count]; + bool out_image_truncated_[object_traits::out_column_count]; + + // Id image binding (only in). + // + id_image_type id_image_; + binding id_image_binding_; + + details::shared_ptr<persist_statement_type> persist_; + details::shared_ptr<find_statement_type> find_; + details::shared_ptr<update_statement_type> update_; + details::shared_ptr<erase_statement_type> erase_; + + // Delayed loading. + // + struct delayed_load + { + typedef typename object_cache_traits::position_type position_type; + + delayed_load () {} + delayed_load (const id_type& i, object_type& o, const position_type& p) + : id (i), obj (&o), pos (p) + { + } + + id_type id; + object_type* obj; + position_type pos; + }; + + typedef std::vector<delayed_load> delayed_loads; + delayed_loads delayed_; + }; + } +} + +#include <odb/sqlite/object-statements.ixx> +#include <odb/sqlite/object-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_OBJECT_STATEMENTS_HXX diff --git a/odb/sqlite/object-statements.ixx b/odb/sqlite/object-statements.ixx new file mode 100644 index 0000000..e1ae3ef --- /dev/null +++ b/odb/sqlite/object-statements.ixx @@ -0,0 +1,54 @@ +// file : odb/sqlite/object-statements.ixx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace sqlite + { + // + // auto_lock + // + template <typename T> + inline object_statements<T>::auto_lock:: + auto_lock (object_statements& s) + : s_ (s) + { + if (!s_.locked ()) + { + s_.lock (); + locked_ = true; + } + else + locked_ = false; + } + + template <typename T> + inline object_statements<T>::auto_lock:: + ~auto_lock () + { + if (locked_) + { + s_.unlock (); + s_.clear_delayed (); + } + } + + template <typename T> + inline bool object_statements<T>::auto_lock:: + locked () const + { + return locked_; + } + + template <typename T> + inline void object_statements<T>::auto_lock:: + unlock () + { + assert (locked_); + s_.unlock (); + locked_ = false; + } + } +} diff --git a/odb/sqlite/object-statements.txx b/odb/sqlite/object-statements.txx new file mode 100644 index 0000000..88b99e8 --- /dev/null +++ b/odb/sqlite/object-statements.txx @@ -0,0 +1,77 @@ +// file : odb/sqlite/object-statements.txx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cstddef> // std::size_t +#include <cstring> // std::memset + +#include <odb/session.hxx> +#include <odb/exceptions.hxx> + +#include <odb/sqlite/connection.hxx> + +namespace odb +{ + namespace sqlite + { + template <typename T> + object_statements<T>:: + object_statements (connection_type& conn) + : object_statements_base (conn), + container_statement_cache_ (conn), + in_image_binding_ (in_image_bind_, object_traits::in_column_count), + out_image_binding_ (out_image_bind_, object_traits::out_column_count), + id_image_binding_ (in_image_bind_ + object_traits::in_column_count, 1) + { + std::memset (in_image_bind_, 0, sizeof (in_image_bind_)); + std::memset (out_image_bind_, 0, sizeof (out_image_bind_)); + std::memset (out_image_truncated_, 0, sizeof (out_image_truncated_)); + + for (std::size_t i (0); i < object_traits::out_column_count; ++i) + out_image_bind_[i].truncated = out_image_truncated_ + i; + } + + template <typename T> + void object_statements<T>:: + load_delayed_ () + { + // We should be careful here: the delayed vector can change + // from under us as a result of a recursive load. + // + database& db (connection ().database ()); + + while (!delayed_.empty ()) + { + delayed_load l (delayed_.back ()); + typename object_cache_traits::insert_guard g (l.pos); + delayed_.pop_back (); + + if (!object_traits::find_ (*this, l.id)) + throw object_not_persistent (); + + object_traits::init (*l.obj, image (), db); + object_traits::load_ (*this, *l.obj); // Load containers, etc. + g.release (); + } + } + + template <typename T> + void object_statements<T>:: + clear_delayed_ () + { + // Remove the objects from the session cache. + // + if (session::has_current ()) + { + for (typename delayed_loads::iterator i (delayed_.begin ()), + e (delayed_.end ()); i != e; ++i) + { + object_cache_traits::erase (i->pos); + } + } + + delayed_.clear (); + } + } +} diff --git a/odb/sqlite/statement-cache.hxx b/odb/sqlite/statement-cache.hxx index 9ef446d..1b3d4b2 100644 --- a/odb/sqlite/statement-cache.hxx +++ b/odb/sqlite/statement-cache.hxx @@ -17,10 +17,7 @@ #include <odb/sqlite/version.hxx> #include <odb/sqlite/statement.hxx> -/* #include <odb/sqlite/object-statements.hxx> -*/ - #include <odb/sqlite/details/export.hxx> namespace odb @@ -52,8 +49,6 @@ namespace odb return *rollback_; } -/* - @@ template <typename T> object_statements<T>& find () @@ -69,14 +64,11 @@ namespace odb map_.insert (map::value_type (&typeid (T), p)); return *p; } -*/ private: - /* typedef std::map<const std::type_info*, details::shared_ptr<object_statements_base>, details::type_info_comparator> map; - */ connection& conn_; @@ -84,9 +76,7 @@ namespace odb details::shared_ptr<simple_statement> commit_; details::shared_ptr<simple_statement> rollback_; - /* map map_; - */ }; } } |