diff --git a/include/ircd/m/event/fetch.h b/include/ircd/m/event/fetch.h index fd3379902..72a5a957e 100644 --- a/include/ircd/m/event/fetch.h +++ b/include/ircd/m/event/fetch.h @@ -11,15 +11,6 @@ #pragma once #define HAVE_IRCD_M_EVENT_FETCH_H -namespace ircd::m -{ - bool seek(event::fetch &, const event::idx &, std::nothrow_t); - void seek(event::fetch &, const event::idx &); - - bool seek(event::fetch &, const event::id &, std::nothrow_t); - void seek(event::fetch &, const event::id &); -} - struct ircd::m::event::fetch :event { @@ -31,6 +22,7 @@ struct ircd::m::event::fetch static const opts default_opts; std::array cell; + db::cell _json; db::row row; bool valid; @@ -45,11 +37,34 @@ struct ircd::m::event::fetch static void event_id(const idx &, const id::closure &); }; +namespace ircd::m +{ + bool seek(event::fetch &, const event::idx &, std::nothrow_t, const event::fetch::opts *const & = nullptr); + void seek(event::fetch &, const event::idx &, const event::fetch::opts *const & = nullptr); + + bool seek(event::fetch &, const event::id &, std::nothrow_t, const event::fetch::opts *const & = nullptr); + void seek(event::fetch &, const event::id &, const event::fetch::opts *const & = nullptr); +} + struct ircd::m::event::fetch::opts { + /// Event property selector event::keys keys; + + /// Database get options passthru db::gopts gopts; + /// Whether to allowing querying the event_json to populate the event if + /// it would be more efficient based on the keys being sought. Ex. If all + /// keys are being sought then we can make a single query to event_json + /// rather than a concurrent row query. This is enabled by default. + bool query_json_maybe {true}; + + /// Whether to force only querying for event_json to populate the event, + /// regardless of what keys are sought in the property selector. This is + /// not enabled by default. + bool query_json_only {false}; + opts(const event::keys &, const db::gopts & = {}); opts(const event::keys::selection &, const db::gopts & = {}); opts(const db::gopts &, const event::keys::selection & = {}); diff --git a/ircd/m/event.cc b/ircd/m/event.cc index 87e0bc57e..0e2fcc639 100644 --- a/ircd/m/event.cc +++ b/ircd/m/event.cc @@ -1384,6 +1384,11 @@ ircd::m::get(std::nothrow_t, const string_view &key, const event::fetch::view_closure &closure) { + const string_view &column_key + { + byte_view{event_idx} + }; + const auto &column_idx { json::indexof(key) @@ -1394,14 +1399,15 @@ ircd::m::get(std::nothrow_t, dbs::event_column.at(column_idx) }; - return column(byte_view{event_idx}, std::nothrow, closure); + return column(column_key, std::nothrow, closure); } void ircd::m::seek(event::fetch &fetch, - const event::id &event_id) + const event::id &event_id, + const event::fetch::opts *const &opts) { - if(!seek(fetch, event_id, std::nothrow)) + if(!seek(fetch, event_id, std::nothrow, opts)) throw m::NOT_FOUND { "%s not found in database", event_id @@ -1411,21 +1417,25 @@ ircd::m::seek(event::fetch &fetch, bool ircd::m::seek(event::fetch &fetch, const event::id &event_id, - std::nothrow_t) + std::nothrow_t, + const event::fetch::opts *const &opts) { const auto &event_idx { index(event_id, std::nothrow) }; - return seek(fetch, event_idx, std::nothrow); + return event_idx? + seek(fetch, event_idx, std::nothrow, opts): + false; } void ircd::m::seek(event::fetch &fetch, - const event::idx &event_idx) + const event::idx &event_idx, + const event::fetch::opts *const &opts) { - if(!seek(fetch, event_idx, std::nothrow)) + if(!seek(fetch, event_idx, std::nothrow, opts)) throw m::NOT_FOUND { "%lu not found in database", event_idx @@ -1435,21 +1445,68 @@ ircd::m::seek(event::fetch &fetch, bool ircd::m::seek(event::fetch &fetch, const event::idx &event_idx, - std::nothrow_t) + std::nothrow_t, + const event::fetch::opts *const &opts) { + auto &event + { + static_cast(fetch) + }; + const string_view &key { byte_view(event_idx) }; - db::seek(fetch.row, key); - fetch.valid = fetch.row.valid(key); - if(!fetch.valid) - return false; + const db::gopts &gopts + { + opts? + opts->gopts: + db::gopts{} + }; - auto &event{static_cast(fetch)}; - assign(event, fetch.row, key); - return true; + const bool query_json + { + opts && opts->query_json_only? + true: // User only wants to make the event_json query + + opts && !opts->query_json_maybe? + false: // User never wants to make the event_json query + + fetch.row.size() < fetch.cell.size()? + false: // User is making specific column queries + + fetch.row.size() == fetch.cell.size()? + true: // User is querying all columns + + false + }; + + if(query_json) + { + if((fetch.valid = fetch._json.load(key, gopts))) + event = m::event + { + fetch._json.val() + }; + + if(fetch.valid) + return fetch.valid; + + if(opts && opts->query_json_only) + return fetch.valid; + + // graceful fallback to row query if json query failed. + assert(!fetch.valid); + } + + if(!(fetch.valid = db::seek(fetch.row, key, gopts))) + return fetch.valid; + + if((fetch.valid = fetch.row.valid(key))) + assign(event, fetch.row, key); + + return fetch.valid; } ircd::m::event::idx @@ -1554,7 +1611,13 @@ ircd::m::event::fetch::event_id(const idx &idx, /// Seekless constructor. ircd::m::event::fetch::fetch(const opts *const &opts) -:row +:_json +{ + m::dbs::event_json, + string_view{}, + opts? opts->gopts : default_opts.gopts +} +,row { *dbs::events, string_view{}, @@ -1613,21 +1676,12 @@ ircd::m::event::fetch::fetch(const event::idx &event_idx, ircd::m::event::fetch::fetch(const event::idx &event_idx, std::nothrow_t, const opts *const &opts) -:row +:fetch { - *dbs::events, - byte_view{event_idx}, - opts? opts->keys : default_opts.keys, - cell, - opts? opts->gopts : default_opts.gopts -} -,valid -{ - row.valid(byte_view{event_idx}) + opts } { - if(valid) - assign(*this, row, byte_view{event_idx}); + seek(*this, event_idx, std::nothrow, opts); } //