From 275f5aa3cd3ebd7257586bc9ecbc48f0ea86a2ef Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Tue, 10 Dec 2019 11:07:44 -0800 Subject: [PATCH] ircd::m::room::head: Improve/cleanup generator related. --- matrix/room_head.cc | 186 +++++++++++++++++++++++++------------------- 1 file changed, 105 insertions(+), 81 deletions(-) diff --git a/matrix/room_head.cc b/matrix/room_head.cc index 6f6abf01b..77ed4bc12 100644 --- a/matrix/room_head.cc +++ b/matrix/room_head.cc @@ -8,12 +8,18 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. +namespace ircd::m +{ + static void append_v1(json::stack::array &, const event::id &); + static void append_v3(json::stack::array &, const event::id &); +} + IRCD_MODULE_EXPORT ircd::m::room::head::generate::generate(const mutable_buffer &buf, const m::room::head &head, const opts &opts) { - if(!head.room) + if(empty(buf)) return; json::stack out{buf}; @@ -42,37 +48,23 @@ ircd::m::room::head::generate::generate(json::stack::array &out, if(!head.room) return; - const m::event::id::closure &v1_ref{[&out] - (const auto &event_id) - { - json::stack::array prev{out}; - prev.append(event_id); - { - json::stack::object nilly{prev}; - json::stack::member willy - { - nilly, "", "" - }; - } - }}; - - const m::event::id::closure &v3_ref{[&out] - (const auto &event_id) - { - out.append(event_id); - }}; - + // Query the room version unless hinted in the opts char versionbuf[32]; const auto version { m::version(versionbuf, head.room, std::nothrow) }; + // The output format depends on the room version; we select an output + // function for the format here so we can abstractly call append(). const auto &append { - version == "1" || version == "2"? v1_ref : v3_ref + version == "1" || version == "2"? + append_v1: + append_v3 }; + // When the top_head option is given we query for that here const auto top_head { opts.need_top_head? @@ -80,89 +72,121 @@ ircd::m::room::head::generate::generate(json::stack::array &out, std::tuple{} }; - m::event::fetch event; - size_t limit{opts.limit}; + // Iterate the room head; starts with oldest events bool need_top_head{opts.need_top_head}; bool need_my_head{opts.need_my_head}; - head.for_each([&](const m::event::idx &event_idx, const m::event::id &event_id) + ssize_t limit(opts.limit); + head.for_each([&] + (const event::idx &event_idx, const event::id &event_id) { - if(!seek(event, event_idx, event_id, std::nothrow)) + // When using the need_my_head option, if we hit a head which + // originated from this server we mark that is no longer needed. + if(need_my_head && event::my(event_idx)) + need_my_head = false; + + // If we hit the top_head during the loop we can mark that satisfied. + if(need_top_head && event_id == std::get<0>(top_head)) + need_top_head = false; + + // Two reference slots are reserved to fulfill these features; the + // loop will iterate without appending anything else. + const ssize_t remain + { + limit - need_my_head - need_top_head + }; + + // Skip/continue the loop if all that remains are reserved slots. + if(remain <= 0) return true; - if(need_top_head) - if(event.event_id == std::get<0>(top_head)) - need_top_head = false; + // Add this head reference to result to output. + append(out, event_id); - const auto _append{[&]() -> bool + // Determine the depth for metrics + const int64_t depth { - if(need_my_head && my(event)) - need_my_head = false; + event_id == std::get<0>(top_head)? + std::get(top_head): + m::get(event_idx, "depth") + }; - append(event_id); - this->depth[0] = std::min(json::get<"depth"_>(event), this->depth[0]); - this->depth[1] = std::max(json::get<"depth"_>(event), this->depth[1]); - return --limit - need_top_head - need_my_head > 0; - }}; + // Indicate if this depth is highest or lowest of the set. + this->depth[0] = std::min(depth, this->depth[0]); + this->depth[1] = std::max(depth, this->depth[1]); - if(limit - need_top_head - need_my_head > 0) - { - if(need_my_head && my(event)) - need_my_head = false; - - return _append(); - } - - if(!need_my_head) - return false; - - if(my(event)) - return _append(); - else - return limit > 0; + // Continue loop until we're out of slots. + return --limit > 0; }); + // If the iteration did not provide us with the top_head and the opts + // require it, we add that here. if(need_top_head) { assert(limit > 0); - append(std::get<0>(top_head)); + append(out, std::get<0>(top_head)); this->depth[1] = std::get<1>(top_head); + need_top_head = false; --limit; } - if(!need_my_head || limit <= 0) - return; - - for(m::room::events it{head.room}; it; --it) - { - const bool my_sender + // If the iteration did not provide us with any heads from this origin + // and the opts require it, we find and add that here. + if(need_my_head) + for(m::room::events it{head.room}; it; --it) { - m::query(std::nothrow, event::idx{it}, "sender", false, [] - (const m::user::id &user_id) + if(!event::my(it.event_idx())) + continue; + + const auto event_id { - return m::my(user_id); - }) - }; + m::event_id(it.event_idx(), std::nothrow) + }; - if(!my_sender) - continue; + if(unlikely(!event_id)) + continue; - const auto event_id - { - m::event_id(event::idx{it}, std::nothrow) - }; + assert(limit > 0); + append(out, event_id); + const int64_t &depth(it.depth()); + this->depth[0] = std::min(depth, this->depth[0]); + this->depth[1] = std::max(depth, this->depth[1]); + need_my_head = false; + --limit; + break; + } - if(!event_id) - continue; + assert(limit >= 0); +} - assert(limit > 0); - append(event_id); - const int64_t &depth(it.depth()); - this->depth[0] = std::min(depth, this->depth[0]); - this->depth[1] = std::max(depth, this->depth[1]); - need_my_head = false; - --limit; - break; - } +void +ircd::m::append_v1(json::stack::array &out, + const event::id &event_id) +{ + json::stack::array prev + { + out + }; + + // [0] + prev.append(event_id); + + // [1] + json::stack::object nilly + { + prev + }; + + json::stack::member + { + nilly, "", "" + }; +} + +void +ircd::m::append_v3(json::stack::array &out, + const event::id &event_id) +{ + out.append(event_id); } size_t