From 856a438b33184959b64864f1afdf5a6a2fd6b0d2 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 16 Jan 2013 16:31:29 +0200 Subject: Make session cache management functions static, add notifications --- common/session/custom/driver.cxx | 20 ++++++++- common/session/custom/session.cxx | 23 +++------- common/session/custom/session.hxx | 64 ++++++++++++++++++--------- common/session/custom/session.txx | 92 +++++++++++++++++++++++++++------------ 4 files changed, 131 insertions(+), 68 deletions(-) (limited to 'common/session/custom') diff --git a/common/session/custom/driver.cxx b/common/session/custom/driver.cxx index 1ec7cbb..0a58ea5 100644 --- a/common/session/custom/driver.cxx +++ b/common/session/custom/driver.cxx @@ -145,10 +145,10 @@ main (int argc, char* argv[]) transaction t (db->begin ()); tracer.count = 0; t.tracer (tracer); - s.flush (*db); // Flush all the changes. + s.flush (*db); assert (tracer.count == 2); t.commit (); - s.mark (); // Mark all the changed objects as unchanged. + s.mark (); } { @@ -159,6 +159,22 @@ main (int argc, char* argv[]) assert (tracer.count == 0); t.commit (); } + + // Explicit update. + // + cs->symbol ("CS"); + st->symbol ("ST"); + + { + transaction t (db->begin ()); + db->update (cs); + tracer.count = 0; + t.tracer (tracer); + s.flush (*db); + assert (tracer.count == 1); + t.commit (); + s.mark (); + } } catch (const odb::exception& e) { diff --git a/common/session/custom/session.cxx b/common/session/custom/session.cxx index b50493f..f8cd102 100644 --- a/common/session/custom/session.cxx +++ b/common/session/custom/session.cxx @@ -6,33 +6,20 @@ #include "session.hxx" -static session* current_; // Use TLS in multi-threaded applications. +session* session::current; session:: session () { - assert (current_ == 0); - current_ = this; + assert (current == 0); + current = this; } session:: ~session () { - assert (current_ == this); - current_ = 0; -} - -bool session:: -has_current () -{ - return current_ != 0; -} - -session& session:: -current () -{ - assert (current_ != 0); - return *current_; + assert (current == this); + current = 0; } void session:: diff --git a/common/session/custom/session.hxx b/common/session/custom/session.hxx index bb60a4b..3b1789a 100644 --- a/common/session/custom/session.hxx +++ b/common/session/custom/session.hxx @@ -26,14 +26,13 @@ private: session (const session&); session& operator= (const session&); - // Current session interface. + // Session for the current thread. This can be implemented in pretty + // much any way that makes sense to the application. It can be a global + // session as we have here. In multi-threaded applications we could use + // TLS instead. // public: - static bool - has_current (); - - static session& - current (); + static session* current; // Change tracking interface. // @@ -61,23 +60,30 @@ private: mark () = 0; }; + enum object_state + { + tracking, // Tracking any modifications by storing the original copy. + changed, // Known to be changed. + flushed // Flushed but not yet committed/rolled back. + }; + template - struct object_state + struct object_data { typedef typename odb::object_traits::pointer_type pointer_type; explicit - object_state (pointer_type o): obj (o), flushed_ (false) {} + object_data (pointer_type o): obj (o), state (tracking) {} pointer_type obj; pointer_type orig; - bool flushed_; + object_state state; }; template struct object_map: object_map_base, std::map::id_type, - object_state > + object_data > { virtual void flush (odb::database&); @@ -95,37 +101,53 @@ public: typedef object_map map; typedef typename map::iterator iterator; - position () {} + position (): map_ (0) {} position (map& m, const iterator& p): map_ (&m), pos_ (p) {} map* map_; iterator pos_; }; + // Cache management. + // template - position + static position insert (odb::database&, const typename odb::object_traits::id_type&, const typename odb::object_traits::pointer_type&); template + static typename odb::object_traits::pointer_type + find (odb::database&, const typename odb::object_traits::id_type&); + + template + static void + erase (const position& p) + { + if (p.map_ != 0) + p.map_->erase (p.pos_); + } + + // Notifications. + // + template static void - initialize (const position&); + persist (const position& p) + { + load (p); + } template - typename odb::object_traits::pointer_type - find (odb::database&, const typename odb::object_traits::id_type&) const; + static void + load (const position&); template - void - erase (odb::database&, const typename odb::object_traits::id_type&); + static void + update (odb::database&, const T&); template static void - erase (const position& p) - { - p.map_->erase (p.pos_); - } + erase (odb::database&, const typename odb::object_traits::id_type&); private: typedef std::map object_traits; - std::shared_ptr& pm (map_[&typeid (T)]); + if (current == 0) + return position (); // No session, return empty position. + + std::shared_ptr& pm (current->map_[&typeid (T)]); if (!pm) pm.reset (new object_map); object_map& m (static_cast&> (*pm)); - typename object_map::value_type vt (id, object_state (obj)); + typename object_map::value_type vt (id, object_data (obj)); std::pair::iterator, bool> r (m.insert (vt)); // We shall never try to re-insert the same object into the cache. @@ -30,11 +33,37 @@ insert (odb::database&, } template +typename odb::object_traits::pointer_type session:: +find (odb::database&, const typename odb::object_traits::id_type& id) +{ + typedef typename odb::object_traits::pointer_type pointer_type; + + if (current == 0) + return pointer_type (); // No session, return NULL pointer. + + type_map::const_iterator ti (current->map_.find (&typeid (T))); + + if (ti == current->map_.end ()) + return pointer_type (); + + const object_map& m (static_cast&> (*ti->second)); + typename object_map::const_iterator oi (m.find (id)); + + if (oi == m.end ()) + return pointer_type (); + + return oi->second.obj; +} + +template void session:: -initialize (const position& p) +load (const position& p) { typedef typename odb::object_traits::pointer_type pointer_type; + if (p.map_ == 0) + return; // Empty position. + // Make a copy for change tracking. If our object model had a // polymorphic hierarchy, then we would have had to use a // virtual function-based mechanism (e.g., clone()) instead of @@ -45,32 +74,45 @@ initialize (const position& p) } template -typename odb::object_traits::pointer_type session:: -find (odb::database&, const typename odb::object_traits::id_type& id) const +void session:: +update (odb::database&, const T& obj) { - typedef typename odb::object_traits::pointer_type pointer_type; + typedef odb::object_traits object_traits; + typedef typename object_traits::pointer_type pointer_type; - type_map::const_iterator ti (map_.find (&typeid (T))); + if (current == 0) + return; // No session. - if (ti == map_.end ()) - return pointer_type (); + // User explicitly updated the object by calling database::update(). + // Change the state to flushed and reset the original copy (we are + // still tracking changes after the update). + // + type_map::iterator ti (current->map_.find (&typeid (T))); - const object_map& m (static_cast&> (*ti->second)); - typename object_map::const_iterator oi (m.find (id)); + if (ti == current->map_.end ()) + return; // This object is not in the session. + + object_map& m (static_cast&> (*ti->second)); + typename object_map::iterator oi (m.find (object_traits::id (obj))); if (oi == m.end ()) - return pointer_type (); + return; // This object is not in the session. - return oi->second.obj; + object_data& d (oi->second); + d.orig = pointer_type (new T (*d.obj)); + d.state = flushed; } template void session:: erase (odb::database&, const typename odb::object_traits::id_type& id) { - type_map::iterator ti (map_.find (&typeid (T))); + if (current == 0) + return; // No session. - if (ti == map_.end ()) + type_map::iterator ti (current->map_.find (&typeid (T))); + + if (ti == current->map_.end ()) return; object_map& m (static_cast&> (*ti->second)); @@ -82,7 +124,7 @@ erase (odb::database&, const typename odb::object_traits::id_type& id) m.erase (oi); if (m.empty ()) - map_.erase (ti); + current->map_.erase (ti); } template @@ -92,13 +134,10 @@ flush (odb::database& db) for (typename object_map::iterator i (this->begin ()), e (this->end ()); i != e; ++i) { - const T& obj (*i->second.obj); + object_data& d (i->second); - if (obj.changed (*i->second.orig)) - { - db.update (obj); - i->second.flushed_ = true; - } + if (d.state == changed || d.obj->changed (*d.orig)) + db.update (d.obj); // State changed by the update() notification. } } @@ -109,10 +148,9 @@ mark () for (typename object_map::iterator i (this->begin ()), e (this->end ()); i != e; ++i) { - if (i->second.flushed_) - { - i->second.orig.reset (new T (*i->second.obj)); - i->second.flushed_ = false; - } + object_data& d (i->second); + + if (d.state == flushed) + d.state = tracking; } } -- cgit v1.1