From 09d7377f81aeb8fde4aa1698e946457f03380d45 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 6 May 2013 12:05:39 +0200 Subject: Add support for object sections Sections are an optimization mechanism that allows the partitioning of data members of a persistent class into groups that can be separately loaded and/or updated. --- odb/validator.cxx | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 152 insertions(+), 4 deletions(-) (limited to 'odb/validator.cxx') diff --git a/odb/validator.cxx b/odb/validator.cxx index efe9236..080aaa4 100644 --- a/odb/validator.cxx +++ b/odb/validator.cxx @@ -4,11 +4,13 @@ #include +#include #include #include #include #include +#include #include #include @@ -110,6 +112,50 @@ namespace } } + // Make sure a member of a section is an immediate member of an object. + // The same for the section member itself. + // + if (!object (c)) + { + if (m.count ("section-member")) + { + os << m.file () << ":" << m.line () << ":" << m.column () << ": " << + "error: data member belonging to a section can only be a " << + "direct member of a persistent class" << endl; + valid_ = false; + } + + if (t.fq_name () == "::odb::section") + { + os << m.file () << ":" << m.line () << ":" << m.column () << ": " << + "error: section data member can only be a direct member of a " << + "persistent class" << endl; + valid_ = false; + } + } + + // Make sure the load and update pragmas are only specified on + // section members. + // + if (t.fq_name () != "::odb::section") + { + if (m.count ("section-load")) + { + location_t loc (m.get ("section-load-location")); + error (loc) << "'#pragma db load' can only be specified for " + "a section data member" << endl; + valid_ = false; + } + + if (m.count ("section-update")) + { + location_t loc (m.get ("section-update-location")); + error (loc) << "'#pragma db update' can only be specified for " + "a section data member" << endl; + valid_ = false; + } + } + // Resolve null overrides. // override_null (m); @@ -438,9 +484,16 @@ namespace if (id->count ("default")) { os << id->file () << ":" << id->line () << ":" << id->column () - << ": error: object id member cannot have default value" - << endl; + << ": error: object id member cannot have default value" << endl; + valid_ = false; + } + // Complain if an id member is in a section. + // + if (id->count ("section-member")) + { + os << id->file () << ":" << id->line () << ":" << id->column () + << ": error: object id member cannot be in a section" << endl; valid_ = false; } @@ -464,7 +517,7 @@ namespace // Make sure we have the class declared optimistic. // - if (&optimistic->scope () == &c && !c.count ("optimistic")) + if (&m.scope () == &c && !c.count ("optimistic")) { os << m.file () << ":" << m.line () << ":" << m.column () << ":" << " error: version data member in a class not declared " @@ -490,7 +543,7 @@ namespace // Make sure id and version members are in the same class. The // current architecture relies on that. // - if (id != 0 && &id->scope () != &optimistic->scope ()) + if (id != 0 && &id->scope () != &m.scope ()) { os << c.file () << ":" << c.line () << ":" << c.column () << ":" << " error: object id and version members are in different " @@ -519,6 +572,15 @@ namespace valid_ = false; } + // Complain if the version member is in a section. + // + if (m.count ("section-member")) + { + os << m.file () << ":" << m.line () << ":" << m.column () + << ": error: version member cannot be in a section" << endl; + valid_ = false; + } + // This takes care of also marking derived classes as optimistic. // c.set ("optimistic-member", optimistic); @@ -571,6 +633,28 @@ namespace if (poly_root != 0) c.set ("polymorphic-root", poly_root); + // Sectionable objects. + // + if (c.count ("sectionable")) + { + if (optimistic == 0) + { + location_t l (c.get ("sectionable-location")); + error (l) << "only optimistic class can be sectionable" << endl; + valid_ = false; + } + else if (&optimistic->scope () != &c && poly_root != &c) + { + location l (c.get ("sectionable-location")); + error (l) << "only optimistic class that declares the version " << + "data member or that is a root of a polymorphic hierarchy can " << + "be sectionable" << endl; + info (optimistic->location ()) << "version member is declared " << + "here" << endl; + valid_ = false; + } + } + // Update features set based on this object. // if (options.at_once () || class_file (c) == unit.file ()) @@ -878,6 +962,56 @@ namespace virtual void traverse_object (type& c) { + bool poly (polymorphic (c)); + + // Make sure we have no empty or pointless sections unless we + // are reuse-abstract or polymorphic. + // + if (!poly && !abstract (c)) + { + user_sections& uss (c.get ("user-sections")); + + for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) + { + user_section& s (*i); + + // Skip the special version update section (we always treat it + // as abstract in reuse inheritance). + // + if (s.special == user_section::special_version) + continue; + + semantics::data_member& m (*s.member); + location const& l (m.location ()); + + if (s.total == 0 && !s.containers) + { + error (l) << "empty section" << endl; + + if (&m.scope () != &c) + info (c.location ()) << "as seen in this non-abstract " << + "persistent class" << endl; + + valid_ = false; + continue; + } + + // Eager-loaded section with readonly members. + // + if (s.load == user_section::load_eager && s.update_empty ()) + { + error (l) << "eager-loaded section with readonly members is " << + "pointless" << endl; + + if (&m.scope () != &c) + info (c.location ()) << "as seen in this non-abstract " << + "persistent class" << endl; + + valid_ = false; + } + } + } + if (semantics::data_member* id = id_member (c)) { semantics::type& t (utype (*id)); @@ -937,6 +1071,20 @@ namespace } } } + else + { + // Make sure an object without id has no sections. + // + user_sections& uss (c.get ("user-sections")); + + if (!uss.empty ()) + { + semantics::data_member& m (*uss.front ().member); + os << m.file () << ":" << m.line () << ":" << m.column () + << ": error: object without id cannot have sections" << endl; + valid_ = false; + } + } } virtual void -- cgit v1.1