From 1586cc2c76b2ce7845fd3f60d789a772c4958e4a Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 11 Nov 2014 10:19:22 +0200 Subject: Complete initial bulk erase() implementation --- odb/database.hxx | 8 +++++ odb/database.ixx | 43 +++++++++++++++++------- odb/database.txx | 66 +++++++++++++++++++++++++++++++++---- odb/exceptions.cxx | 76 ++++++++++++++++++++++++++++-------------- odb/exceptions.hxx | 97 +++++++++++++++++++++++++++++++++++++----------------- 5 files changed, 218 insertions(+), 72 deletions(-) diff --git a/odb/database.hxx b/odb/database.hxx index d399209..f4a3d36 100644 --- a/odb/database.hxx +++ b/odb/database.hxx @@ -566,6 +566,14 @@ namespace odb void erase_ (const typename object_traits::pointer_type&); + template + void + erase_id_ (I, I); + + template + void + erase_object_ (I, I); + template typename object_traits::pointer_type query_one_ (const Q&); diff --git a/odb/database.ixx b/odb/database.ixx index 9a9b892..a17e90a 100644 --- a/odb/database.ixx +++ b/odb/database.ixx @@ -7,56 +7,68 @@ #include #include +#include namespace odb { template - struct object_pointer_p + struct object_pointer_traits { typedef details::meta::no result_type; typedef T object_type; + static const T& get_ref (const T& x) {return x;} }; template - struct object_pointer_p + struct object_pointer_traits { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const T* p) {return *p;} }; template - struct object_pointer_p + struct object_pointer_traits { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const T* p) {return *p;} }; template class P> - struct object_pointer_p > + struct object_pointer_traits > { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const P& p) { + return pointer_traits >::get_ref (p);} }; template class P> - struct object_pointer_p > + struct object_pointer_traits > { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const P& p) { + return pointer_traits >::get_ref (p);} }; template class P> - struct object_pointer_p > + struct object_pointer_traits > { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const P& p) { + return pointer_traits >::get_ref (p);} }; template class P> - struct object_pointer_p > + struct object_pointer_traits > { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const P& p) { + return pointer_traits >::get_ref (p);} }; inline database:: @@ -477,7 +489,14 @@ namespace odb inline void database:: erase (I idb, I ide) { - erase_ (idb, ide); + erase_id_ (idb, ide); + } + + template + inline void database:: + erase (I ob, I oe) + { + erase_object_ (ob, oe); } template @@ -698,13 +717,13 @@ namespace odb #else // Assume iterator is just a pointer. // - typedef typename object_pointer_p::object_type value_type; + typedef typename object_pointer_traits::object_type value_type; #endif - typedef object_pointer_p test; + typedef object_pointer_traits opt; - persist_ ( - b, e, typename test::result_type ()); + persist_ ( + b, e, typename opt::result_type ()); } template diff --git a/odb/database.txx b/odb/database.txx index 8003345..943f31c 100644 --- a/odb/database.txx +++ b/odb/database.txx @@ -86,7 +86,7 @@ namespace odb while (b != e) { std::size_t n (0); - T* a[object_traits::batch]; + object_type* a[object_traits::batch]; for (; b != e && n < object_traits::batch; ++n) a[n] = &(*b++); @@ -159,13 +159,13 @@ namespace odb typedef object_traits_impl object_traits; - multiple_exceptions mex; + multiple_exceptions mex (typeid (object_already_persistent)); try { while (b != e) { std::size_t n (0); - T* a[object_traits::batch]; + object_type* a[object_traits::batch]; details::pointer_copy p[object_traits::batch]; for (; b != e && n < object_traits::batch; ++n) @@ -279,9 +279,9 @@ namespace odb throw section_not_in_object (); } - template + template void database:: - erase_ (I b, I e) + erase_id_ (I b, I e) { // T is explicitly specified by the caller, so assume it is object type. // @@ -289,7 +289,7 @@ namespace odb typedef object_traits_impl object_traits; typedef typename object_traits::id_type id_type; - multiple_exceptions mex; + multiple_exceptions mex (typeid (object_not_persistent)); try { while (b != e) @@ -323,6 +323,60 @@ namespace odb } } + template + void database:: + erase_object_ (I b, I e) + { + // Sun CC with non-standard STL does not have iterator_traits. + // +#ifndef _RWSTD_NO_CLASS_PARTIAL_SPEC + typedef typename std::iterator_traits::value_type value_type; +#else + // Assume iterator is just a pointer. + // + typedef typename object_pointer_traits::object_type value_type; +#endif + + // object_pointer_traits::object_type can be const. + // + typedef object_pointer_traits opt; + + typedef + typename object_traits::object_type + object_type; + + typedef object_traits_impl object_traits; + + multiple_exceptions mex (typeid (object_not_persistent)); + try + { + while (b != e) + { + std::size_t n (0); + const object_type* a[object_traits::batch]; + + for (; b != e && n < object_traits::batch; ++n) + a[n] = &opt::get_ref (*b++); + + object_traits::erase (*this, a, n, &mex); + + if (mex.fatal ()) + break; + + mex.delta (n); + } + } + catch (const odb::exception& ex) + { + mex.insert (ex, true); + } + + if (!mex.empty ()) + { + mex.prepare (); + throw mex; + } + } template struct database::query_ diff --git a/odb/exceptions.cxx b/odb/exceptions.cxx index 6b9a531..ca9e84c 100644 --- a/odb/exceptions.cxx +++ b/odb/exceptions.cxx @@ -4,6 +4,7 @@ #include // std::strlen #include +#include #include @@ -256,7 +257,7 @@ namespace odb } unknown_schema:: - unknown_schema (const std::string& name) + unknown_schema (const string& name) : name_ (name) { what_ = "unknown database schema '"; @@ -338,31 +339,31 @@ namespace odb ~multiple_exceptions () throw () {} void multiple_exceptions:: - insert (size_t p, const odb::exception& e, bool fatal) + insert (size_t p, bool maybe, const odb::exception& e, bool fatal) { - if (const multiple_exceptions* me = - dynamic_cast (&e)) - { - // Multipe exceptions in the batch. Splice them in. - // - for (iterator i (me->begin ()); i != me->end (); ++i) - set_.insert ( - value_type (delta_ + i->position (), i->exception_ptr ())); + details::shared_ptr pe; - fatal_ = fatal_ || me->fatal () || fatal; - } + if (common_exception_ti_ != typeid (e)) + pe.reset (e.clone ()); else { - set_.insert (value_type (delta_ + p, e)); - fatal_ = fatal_ || fatal; + if (common_exception_ == 0) + common_exception_.reset (e.clone ()); + + pe = common_exception_; } + + set_.insert (value_type (delta_ + p, maybe, pe)); + fatal_ = fatal_ || fatal; } - const odb::exception* multiple_exceptions:: + const multiple_exceptions::value_type* multiple_exceptions:: lookup (size_t p) const { - iterator i (set_.find (value_type (p + delta_))); - return i == set_.end () ? 0 : &i->exception (); + p += delta_; // Called while populating multiple_exceptions. + + iterator i (set_.find (value_type (p))); + return i == set_.end () ? 0 : &*i; } void multiple_exceptions:: @@ -370,22 +371,49 @@ namespace odb { current_ = 0; delta_ = 0; + common_exception_.reset (); ostringstream os; os << "multiple exceptions, " << attempted_ << " element" << (attempted_ != 1 ? "s" : "") << " attempted, " - << size () << " failed" + << failed () << " failed" << (fatal_ ? ", fatal" : "") << ":"; bool nl (true); - for (iterator i (begin ()); i != end (); ++i) + for (iterator i (begin ()); i != end ();) { - const char* w (i->exception ().what ()); - - os << (nl ? "\n" : "") - << '[' << i->position () << "] " << w; - + size_t p (i->position ()); + const odb::exception& e (i->exception ()); + + os << (nl ? "\n" : ""); + + if (!i->maybe ()) + { + os << '[' << p << ']'; + ++i; + } + else + { + // In this case we will normally have a large number of maybe + // failures in a row (usually the whole batch). So let's try + // to represent them all as a single range. + // + size_t n (0); + for (++i; i != end () && i->maybe (); ++i) + { + assert (&e == &i->exception ()); // The same common exception. + n++; + } + + if (n == 0) + os << '[' << p << ']'; + else + os << '[' << p << '-' << (p + n) << "] (some)"; + } + + const char* w (e.what ()); + os << ' ' << w; nl = (w[strlen (w) - 1] != '\n'); } diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx index e8ee227..fbf960d 100644 --- a/odb/exceptions.hxx +++ b/odb/exceptions.hxx @@ -9,7 +9,8 @@ #include #include -#include // std::size_t +#include // std::size_t +#include #include // schema_version, odb::core #include @@ -290,25 +291,33 @@ namespace odb { struct LIBODB_EXPORT value_type { - value_type (std::size_t p, const odb::exception& e) - : p_ (p), e_ (e.clone ()) {} - - value_type (std::size_t p, details::shared_ptr e) - : p_ (p), e_ (e) {} - std::size_t position () const {return p_;} + // If true, then this means that some positions in the batch have + // triggered the exception but it is not possible, due to the + // limitations of the underlying database API, to discern exactly + // which ones. As a result, all the positions in the batch are + // marked as "maybe failed". + // + bool + maybe () const {return m_;} + const odb::exception& exception () const {return *e_;} + // Implementation details. + // public: - value_type (std::size_t p): p_ (p) {} // "Key" for set lookup. + value_type (std::size_t p, + bool maybe, + details::shared_ptr e) + : m_ (maybe), p_ (p), e_ (e) {} - details::shared_ptr - exception_ptr () const {return e_;} + value_type (std::size_t p): p_ (p) {} // "Key" for set lookup. private: + bool m_; std::size_t p_; details::shared_ptr e_; }; @@ -339,24 +348,32 @@ namespace odb // Lookup. // public: - const odb::exception* + // Return NULL if the element at this position has no exception. Note + // that the returned value is value_type* and not odb::exception* in + // order to provide access to maybe(); see value_type::maybe() for + // details. + // + const value_type* operator[] (std::size_t p) const { return set_.empty () ? 0 : lookup (p); } - // Size and direct set access. + // Severity, failed and attempt counts. // public: + // Return the number of elements for which the operation has been + // attempted. + // std::size_t - size () const {return set_.size ();} - - const set_type& - set () const {return set_;} + attempted () const {return attempted_;} - // Severity and attempts. + // Return the number of positions for which the operation has failed. + // Note that this count includes the maybe failed positions. // - public: + std::size_t + failed () const {return set_.size ();} + // If fatal() returns true, then (some of) the exceptions were fatal. // In this case, even for elements that were processed but did not // cause the exception, no attempts were made to complete the bulk @@ -378,12 +395,6 @@ namespace odb void fatal (bool f) {fatal_ = fatal_ || f;} - // Return the number of elements for which the operation has been - // attempted. - // - std::size_t - attempted () const {return attempted_;} - // odb::exception interface. // public: @@ -393,11 +404,25 @@ namespace odb virtual multiple_exceptions* clone () const; + // Direct set access. + // + public: + const set_type& + set () const {return set_;} + // Implementation details. // public: ~multiple_exceptions () throw (); - multiple_exceptions (): fatal_ (false), delta_ (0), current_ (0) {} + + // All instances of the common exception must be equal since we are + // going to create and share just one. + // + multiple_exceptions (const std::type_info& common_exception_ti) + : common_exception_ti_ (common_exception_ti), + fatal_ (false), + delta_ (0), + current_ (0) {} // Set the attempted count as (delta + n). // @@ -419,7 +444,16 @@ namespace odb current (std::size_t c) {current_ = c;} void - insert (std::size_t p, const odb::exception& e, bool fatal = false); + insert (std::size_t p, + bool maybe, + const odb::exception& e, + bool fatal = false); + + void + insert (std::size_t p, const odb::exception& e, bool fatal = false) + { + insert (p, false, e, fatal); + } void insert (const odb::exception& e, bool fatal = false) @@ -434,15 +468,18 @@ namespace odb prepare (); private: - const odb::exception* - lookup (std::size_t) const; + const value_type* + lookup (std::size_t p) const; private: + const std::type_info& common_exception_ti_; + details::shared_ptr common_exception_; + set_type set_; bool fatal_; std::size_t attempted_; - std::size_t delta_; // Position of the batch. - std::size_t current_; // Position in the batch. + std::size_t delta_; // Position of the batch. + std::size_t current_; // Position in the batch. std::string what_; }; -- cgit v1.1