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/relational/pgsql/context.cxx | 46 +++++++---- odb/relational/pgsql/context.hxx | 2 +- odb/relational/pgsql/header.cxx | 48 +++++++++++- odb/relational/pgsql/source.cxx | 163 ++++++++++++++++++++++++++++++--------- 4 files changed, 200 insertions(+), 59 deletions(-) (limited to 'odb/relational/pgsql') diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx index 3d71144..947c6bd 100644 --- a/odb/relational/pgsql/context.cxx +++ b/odb/relational/pgsql/context.cxx @@ -114,8 +114,8 @@ namespace relational { struct has_grow: traversal::class_ { - has_grow (bool& r) - : r_ (r) + has_grow (bool& r, user_section* s) + : r_ (r), section_ (s) { *this >> inherits_ >> *this; } @@ -128,7 +128,7 @@ namespace relational if (!(context::object (c) || context::composite (c))) return; - if (c.count ("pgsql-grow")) + if (section_ == 0 && c.count ("pgsql-grow")) r_ = c.get ("pgsql-grow"); else { @@ -139,29 +139,41 @@ namespace relational if (!r_) names (c); - c.set ("pgsql-grow", r_); + if (section_ == 0) + c.set ("pgsql-grow", r_); } } private: bool& r_; + user_section* section_; traversal::inherits inherits_; }; struct has_grow_member: member_base { has_grow_member (bool& r, + user_section* section = 0, semantics::type* type = 0, string const& key_prefix = string ()) - : relational::member_base (type, string (), key_prefix), + : relational::member_base (type, string (), key_prefix, section), r_ (r) { } + virtual bool + pre (member_info& mi) + { + return (section_ == 0 && !separate_load (mi.m)) || + (section_ != 0 && *section_ == section (mi.m)); + } + virtual void traverse_composite (member_info& mi) { // By calling grow() instead of recursing, we reset any overrides. + // We also don't pass section since they don't apply inside + // composites. // r_ = r_ || context::grow (dynamic_cast (mi.t)); } @@ -189,22 +201,15 @@ namespace relational }; } - string const& context:: - convert_expr (string const& sqlt, semantics::data_member& m, bool to) - { - sql_type const& t (parse_sql_type (sqlt, m)); - return to ? t.to : t.from; - } - bool context:: - grow_impl (semantics::class_& c) + grow_impl (semantics::class_& c, user_section* section) { - if (c.count ("pgsql-grow")) + if (section == 0 && c.count ("pgsql-grow")) return c.get ("pgsql-grow"); bool r (false); - has_grow ct (r); - has_grow_member mt (r); + has_grow ct (r, section); + has_grow_member mt (r, section); traversal::names names; ct >> names >> mt; ct.traverse (c); @@ -224,11 +229,18 @@ namespace relational grow_impl (semantics::data_member& m, semantics::type& t, string const& kp) { bool r (false); - has_grow_member mt (r, &t, kp); + has_grow_member mt (r, 0, &t, kp); mt.traverse (m); return r; } + string const& context:: + convert_expr (string const& sqlt, semantics::data_member& m, bool to) + { + sql_type const& t (parse_sql_type (sqlt, m)); + return to ? t.to : t.from; + } + string context:: database_type_impl (semantics::type& t, semantics::names* hint, diff --git a/odb/relational/pgsql/context.hxx b/odb/relational/pgsql/context.hxx index d06e932..b7ec873 100644 --- a/odb/relational/pgsql/context.hxx +++ b/odb/relational/pgsql/context.hxx @@ -103,7 +103,7 @@ namespace relational convert_expr (string const&, semantics::data_member&, bool); virtual bool - grow_impl (semantics::class_&); + grow_impl (semantics::class_&, user_section*); virtual bool grow_impl (semantics::data_member&); diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx index b924a42..a23ec9e 100644 --- a/odb/relational/pgsql/header.cxx +++ b/odb/relational/pgsql/header.cxx @@ -36,6 +36,9 @@ namespace relational column_count_type const& cc (column_count (c)); + size_t update_columns ( + cc.total - cc.id - cc.inverse - cc.readonly - cc.separate_update); + // Statement names. // os << "static const char persist_statement_name[];"; @@ -51,7 +54,7 @@ namespace relational if (poly && !poly_derived) os << "static const char find_discriminator_statement_name[];"; - if (cc.total != cc.id + cc.inverse + cc.readonly) + if (update_columns != 0) os << "static const char update_statement_name[];"; os << "static const char erase_statement_name[];"; @@ -76,7 +79,7 @@ namespace relational { os << "static const unsigned int find_statement_types[];"; - if (cc.total != cc.id + cc.inverse + cc.readonly) + if (update_columns != 0) os << "static const unsigned int update_statement_types[];"; if (optimistic != 0) @@ -125,8 +128,7 @@ namespace relational // Container statement types. // - os << "static const unsigned int select_types[];" - << "static const unsigned int insert_types[];"; + os << "static const unsigned int insert_types[];"; if (smart) os << "static const unsigned int update_types[];" @@ -137,6 +139,44 @@ namespace relational }; entry container_traits_; + struct section_traits: relational::section_traits, context + { + section_traits (base const& x): base (x) {} + + virtual void + section_public_extra_post (user_section& s) + { + semantics::class_* poly_root (polymorphic (c_)); + bool poly (poly_root != 0); + + if (!poly && (abstract (c_) || + s.special == user_section::special_version)) + return; + + bool load (s.total != 0 && s.separate_load ()); + bool load_opt (s.optimistic () && s.separate_load ()); + + bool update (s.total != s.inverse + s.readonly); // Always separate. + bool update_opt (s.optimistic () && (s.readwrite_containers || poly)); + + // Statement names. + // + if (load || load_opt) + os << "static const char select_name[];" + << endl; + + if (update || update_opt) + os << "static const char update_name[];" + << endl; + + // Statement types. + // + if (update || update_opt) + os << "static const unsigned int update_types[];"; + } + }; + entry section_traits_; + struct image_member: relational::image_member, member_base { image_member (base const& x) diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx index ceda512..d5fe8fd 100644 --- a/odb/relational/pgsql/source.cxx +++ b/odb/relational/pgsql/source.cxx @@ -98,11 +98,28 @@ namespace relational struct statement_oids: object_columns_base, context { - statement_oids (statement_kind sk, bool first = true) - : object_columns_base (first), sk_ (sk) + statement_oids (statement_kind sk, + bool first = true, + object_section* section = 0) + : object_columns_base (first, column_prefix (), section), sk_ (sk) { } + virtual bool + section_test (data_member_path const& mp) + { + object_section& s (section (mp)); + + // Include eager loaded members into the main section for + // SELECT statements. + // + return section_ == 0 || + *section_ == s || + (sk_ == statement_select && + *section_ == main_section && + !s.separate_load ()); + } + virtual void traverse_pointer (semantics::data_member& m, semantics::class_& c) { @@ -265,6 +282,17 @@ namespace relational if (container (mi)) return false; + if (section_ != 0 && *section_ != section (mi.m)) + return false; + + if (var_override_.empty ()) + { + // Ignore separately loaded members. + // + if (section_ == 0 && separate_load (mi.m)) + return false; + } + // Ignore polymorphic id references; they are not returned by // the select statement. // @@ -641,8 +669,12 @@ namespace relational semantics::data_member* id (id_member (c)); semantics::data_member* optimistic (context::optimistic (c)); + column_count_type const& cc (column_count (c)); + size_t update_columns ( + cc.total - cc.id - cc.inverse - cc.readonly - cc.separate_update); + string const& n (class_fq_name (c)); string const& fn (flat_name (n)); string traits ("access::object_traits_impl< " + n + ", id_pgsql >"); @@ -684,7 +716,7 @@ namespace relational strlit (fn + "_find_discriminator") << ";" << endl; - if (cc.total != cc.id + cc.inverse + cc.readonly) + if (update_columns != 0) os << "const char " << traits << "::" << endl << "update_statement_name[] = " << strlit (fn + "_update") << ";" @@ -745,7 +777,7 @@ namespace relational << "find_statement_types[] =" << "{"; - statement_oids st (statement_select); + statement_oids st (statement_select, true); st.traverse (*id); os << "};"; @@ -753,19 +785,21 @@ namespace relational // update_statement_types. // - if (id != 0 && cc.total != cc.id + cc.inverse + cc.readonly) + if (id != 0 && update_columns != 0) { os << "const unsigned int " << traits << "::" << endl << "update_statement_types[] =" << "{"; { - statement_oids st (statement_update); + statement_oids st (statement_update, true, &main_section); st.traverse (c); } + // Not the same as update_columns. + // bool first (cc.total == cc.id + cc.inverse + cc.readonly + - cc.optimistic_managed); + cc.separate_update + cc.optimistic_managed); statement_oids st (statement_where, first); st.traverse (*id); @@ -791,11 +825,13 @@ namespace relational } virtual void - container_cache_extra_args (bool used) + extra_statement_cache_extra_args (bool c, bool s) { + bool u (c || s); + os << "," << endl - << db << "::native_binding&" << (used ? " idn" : "") << "," << endl - << "const unsigned int*" << (used ? " idt" : ""); + << db << "::native_binding&" << (u ? " idn" : "") << "," << endl + << "const unsigned int*" << (u ? " idt" : ""); } virtual void @@ -916,33 +952,6 @@ namespace relational semantics::type& vt (container_vt (t)); semantics::type& idt (container_idt (m)); - // select statement types. - // - { - os << "const unsigned int " << scope << "::" << endl - << "select_types[] =" - << "{"; - - statement_oids so (statement_where); - - if (inv) - { - // many(i)-to-many - // - if (container (*inv_m)) - so.traverse (*inv_m, idt, "value", "value"); - - // many(i)-to-one - // - else - so.traverse (*inv_m); - } - else - so.traverse (m, idt, "id", "object_id"); - - os << "};"; - } - // insert statement types. // { @@ -1065,6 +1074,74 @@ namespace relational }; entry container_traits_; + struct section_traits : relational::section_traits, context + { + section_traits (base const& x): base (x) {} + + virtual void + section_extra (user_section& s) + { + semantics::class_* poly_root (polymorphic (c_)); + bool poly (poly_root != 0); + + if (!poly && (abstract (c_) || + s.special == user_section::special_version)) + return; + + semantics::data_member* opt (optimistic (c_)); + + bool load (s.total != 0 && s.separate_load ()); + bool load_opt (s.optimistic () && s.separate_load ()); + + bool update (s.total != s.inverse + s.readonly); // Always separate. + bool update_opt (s.optimistic () && (s.readwrite_containers || poly)); + + string name (public_name (*s.member)); + string scope (scope_ + "::" + name + "_traits"); + + // Statment names. + // + + // Prefix object name to avoid conflicts with inherited member + // statement names. + // + string fn (flat_name (class_fq_name (c_) + "_" + name)); + + if (load || load_opt) + os << "const char " << scope << "::" << endl + << "select_name[] = " << strlit (fn + "_select") << ";" + << endl; + + if (update || update_opt) + os << "const char " << scope << "::" << endl + << "update_name[] = " << strlit (fn + "_update") << ";" + << endl; + + // Statement types. + // + if (update || update_opt) + { + os << "const unsigned int " << scope << "::" << endl + << "update_types[] =" + << "{"; + + { + statement_oids st (statement_update, true, &s); + st.traverse (c_); + } + + statement_oids st (statement_where, !update); + st.traverse (*id_member (c_)); + + if (s.optimistic ()) // Note: not update_opt. + st.traverse (*opt); + + os << "};"; + } + } + }; + entry section_traits_; + struct container_cache_init_members: relational::container_cache_init_members { @@ -1078,6 +1155,18 @@ namespace relational }; entry container_cache_init_members_; + struct section_cache_init_members: + relational::section_cache_init_members + { + section_cache_init_members (base const& x): base (x) {} + + virtual void + extra_members () + { + os << ", idn, idt"; + } + }; + entry section_cache_init_members_; } } } -- cgit v1.1