0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 18:22:50 +01:00

ircd:Ⓜ️:room::events: Split nested interfaces into headers/units.

This commit is contained in:
Jason Volk 2023-02-16 20:41:09 -08:00
parent edab741e9f
commit 47f670b7a2
10 changed files with 546 additions and 485 deletions

View file

@ -11,33 +11,6 @@
#pragma once
#define HAVE_IRCD_M_ROOM_EVENTS_H
// The "viewport" is comprised of events starting from the tophead (most recent
// in room timeline) and covering about ~20 events leading up to that. Note
// that this is a completely ad hoc and configurable server value. Events in
// the viewport must be eval'ed and synced to clients in the order they will
// be displayed. Events not in the viewport are not /synced to clients and any
// client request provides event ordering: thus older events (backfills, etc)
// can be eval'ed without this constraint.
//
// The "sounding" is the depth of the first gap. In any attempt to trace
// the room timeline from the tophead to the m.room.create event: the sounding
// is the [highest number] depth preventing that.
//
// The "twain" marks the depth at the end of the first gap; the server is in
// possession of one or more events again at the twain.
//
// The "hazard" is the depth of the first gap starting from the m.room.create
// event toward the tophead. In any attempt to trace the room timeline with
// an increasing depth, the hazard is the next gap to frontfill.
namespace ircd::m
{
std::pair<int64_t, event::idx> viewport(const room &);
std::pair<int64_t, event::idx> sounding(const room &); // Last missing (one)
std::pair<int64_t, event::idx> twain(const room &);
std::pair<int64_t, event::idx> hazard(const room &); // First missing (one)
}
/// Interface to room events
///
/// This interface has the form of an STL-style iterator over room events
@ -49,8 +22,8 @@ namespace ircd::m
struct ircd::m::room::events
{
struct sounding;
struct horizon;
struct missing;
struct horizon;
static conf::item<ssize_t> viewport_size;
@ -121,77 +94,3 @@ struct ircd::m::room::events
static size_t count(const m::room &, const event::idx_range &);
static size_t count(const event::idx_range &);
};
/// Find missing room events. This is a breadth-first iteration of missing
/// references from the tophead (or at the event provided in the room arg)
///
/// The closure is invoked with the first argument being the event_id unknown
/// to the server, followed by the depth and event::idx of the event making the
/// reference.
///
struct ircd::m::room::events::missing
{
using closure = std::function<bool (const event::id &, const uint64_t &, const event::idx &)>;
m::room room;
private:
bool _each(m::room::events &, const closure &) const;
public:
bool rfor_each(const pair<int64_t> &depth, const closure &) const;
bool for_each(const pair<int64_t> &depth, const closure &) const;
bool for_each(const closure &) const;
size_t count() const;
missing() = default;
missing(const m::room &room)
:room{room}
{}
};
/// Find gaps in the room's events. A gap is where this server has no events
/// at a certain depth. This is a path-finding diagnostic interface, useful to
/// understand what areas of the timeline have not been acquired by the server
/// to calculate backfill requests, etc. This interface is depth-first oriented,
/// rather than the breadth-first room::events::missing interface.
///
struct ircd::m::room::events::sounding
{
using range = std::pair<int64_t, int64_t>;
using closure = std::function<bool (const range &, const event::idx &)>;
m::room room;
public:
bool for_each(const closure &) const;
bool rfor_each(const closure &) const;
sounding() = default;
sounding(const m::room &room)
:room{room}
{}
};
/// Find missing room events. This is an interface to the event-horizon for
/// this room. The event horizon is keyed by event_id and the value is the
/// event::idx of the event referencing it. There can be multiple entries for
/// an event_id. The closure is also invoked with the depth of the referencer.
///
struct ircd::m::room::events::horizon
{
using closure = std::function<bool (const event::id &, const uint64_t &, const event::idx &)>;
m::room room;
public:
bool for_each(const closure &) const;
size_t count() const;
size_t rebuild();
horizon() = default;
horizon(const m::room &room)
:room{room}
{}
};

View file

@ -0,0 +1,35 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2023 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_M_ROOM_EVENTS_HORIZON_H
/// Find missing room events. This is an interface to the event-horizon for
/// this room. The event horizon is keyed by event_id and the value is the
/// event::idx of the event referencing it. There can be multiple entries for
/// an event_id. The closure is also invoked with the depth of the referencer.
///
struct ircd::m::room::events::horizon
{
using closure = std::function<bool (const event::id &, const uint64_t &, const event::idx &)>;
m::room room;
public:
bool for_each(const closure &) const;
size_t count() const;
size_t rebuild();
horizon() = default;
horizon(const m::room &room)
:room{room}
{}
};

View file

@ -0,0 +1,40 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2023 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_M_ROOM_EVENTS_MISSING_H
/// Find missing room events. This is a breadth-first iteration of missing
/// references from the tophead (or at the event provided in the room arg)
///
/// The closure is invoked with the first argument being the event_id unknown
/// to the server, followed by the depth and event::idx of the event making the
/// reference.
///
struct ircd::m::room::events::missing
{
using closure = std::function<bool (const event::id &, const uint64_t &, const event::idx &)>;
m::room room;
private:
bool _each(m::room::events &, const closure &) const;
public:
bool rfor_each(const pair<int64_t> &depth, const closure &) const;
bool for_each(const pair<int64_t> &depth, const closure &) const;
bool for_each(const closure &) const;
size_t count() const;
missing() = default;
missing(const m::room &room)
:room{room}
{}
};

View file

@ -0,0 +1,62 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2023 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_M_ROOM_EVENTS_SOUNDING_H
// The "viewport" is comprised of events starting from the tophead (most recent
// in room timeline) and covering about ~20 events leading up to that. Note
// that this is a completely ad hoc and configurable server value. Events in
// the viewport must be eval'ed and synced to clients in the order they will
// be displayed. Events not in the viewport are not /synced to clients and any
// client request provides event ordering: thus older events (backfills, etc)
// can be eval'ed without this constraint.
//
// The "sounding" is the depth of the first gap. In any attempt to trace
// the room timeline from the tophead to the m.room.create event: the sounding
// is the [highest number] depth preventing that.
//
// The "twain" marks the depth at the end of the first gap; the server is in
// possession of one or more events again at the twain.
//
// The "hazard" is the depth of the first gap starting from the m.room.create
// event toward the tophead. In any attempt to trace the room timeline with
// an increasing depth, the hazard is the next gap to frontfill.
namespace ircd::m
{
std::pair<int64_t, event::idx> viewport(const room &);
std::pair<int64_t, event::idx> sounding(const room &); // Last missing (one)
std::pair<int64_t, event::idx> twain(const room &);
std::pair<int64_t, event::idx> hazard(const room &); // First missing (one)
}
/// Find gaps in the room's events. A gap is where this server has no events
/// at a certain depth. This is a path-finding diagnostic interface, useful to
/// understand what areas of the timeline have not been acquired by the server
/// to calculate backfill requests, etc. This interface is depth-first oriented,
/// rather than the breadth-first room::missing interface.
///
struct ircd::m::room::events::sounding
{
using range = std::pair<int64_t, int64_t>;
using closure = std::function<bool (const range &, const event::idx &)>;
m::room room;
public:
bool for_each(const closure &) const;
bool rfor_each(const closure &) const;
sounding() = default;
sounding(const m::room &room)
:room{room}
{}
};

View file

@ -189,6 +189,9 @@ struct ircd::m::room
};
#include "events.h"
#include "events_sounding.h"
#include "events_missing.h"
#include "events_horizon.h"
#include "state.h"
#include "state_space.h"
#include "state_history.h"

View file

@ -109,6 +109,9 @@ libircd_matrix_la_SOURCES += room_aliases.cc
libircd_matrix_la_SOURCES += room_bootstrap.cc
libircd_matrix_la_SOURCES += room_create.cc
libircd_matrix_la_SOURCES += room_events.cc
libircd_matrix_la_SOURCES += room_events_sounding.cc
libircd_matrix_la_SOURCES += room_events_missing.cc
libircd_matrix_la_SOURCES += room_events_horizon.cc
libircd_matrix_la_SOURCES += room_head.cc
libircd_matrix_la_SOURCES += room_head_fetch.cc
libircd_matrix_la_SOURCES += room_state_fetch.cc

View file

@ -15,103 +15,6 @@ ircd::m::room::events::viewport_size
{ "default", 96L },
};
std::pair<int64_t, ircd::m::event::idx>
ircd::m::viewport(const room &room)
{
std::pair<int64_t, m::event::idx> ret
{
-1, 0
};
m::room::events it
{
room
};
const ssize_t &max
{
room::events::viewport_size
};
for(auto i(0); it && i < max; --it, ++i)
{
ret.first = it.depth();
ret.second = it.event_idx();
}
return ret;
}
std::pair<int64_t, ircd::m::event::idx>
ircd::m::twain(const room &room)
{
std::pair<int64_t, m::event::idx> ret
{
-1, 0
};
const room::events::sounding s
{
room
};
s.rfor_each([&ret]
(const auto &range, const auto &event_idx) noexcept
{
ret.first = range.first - 1;
return false;
});
return ret;
}
std::pair<int64_t, ircd::m::event::idx>
ircd::m::sounding(const room &room)
{
std::pair<int64_t, m::event::idx> ret
{
-1, 0
};
const room::events::sounding s
{
room
};
s.rfor_each([&ret]
(const auto &range, const auto &event_idx) noexcept
{
ret.first = range.second;
ret.second = event_idx;
return false;
});
return ret;
}
std::pair<int64_t, ircd::m::event::idx>
ircd::m::hazard(const room &room)
{
std::pair<int64_t, m::event::idx> ret
{
0, 0
};
const room::events::sounding s
{
room
};
s.for_each([&ret]
(const auto &range, const auto &event_idx) noexcept
{
ret.first = range.first;
return false;
});
return ret;
}
//
// room::events
//
@ -436,289 +339,3 @@ const
return std::get<0>(part);
}
//
// room::events::missing
//
size_t
ircd::m::room::events::missing::count()
const
{
size_t ret{0};
for_each([&ret]
(const auto &event_id, const auto &depth, const auto &event_idx) noexcept
{
++ret;
return true;
});
return ret;
}
bool
ircd::m::room::events::missing::for_each(const closure &closure)
const
{
return for_each({0L, 0L}, closure);
}
bool
ircd::m::room::events::missing::for_each(const pair<int64_t> &depth,
const closure &closure)
const
{
room::events it
{
room, uint64_t(depth.first)
};
for(; it; ++it)
{
if(depth.second && int64_t(it.depth()) > depth.second)
break;
if(!_each(it, closure))
return false;
}
return true;
}
bool
ircd::m::room::events::missing::rfor_each(const pair<int64_t> &depth,
const closure &closure)
const
{
room::events it
{
room, depth.second?: -1UL
};
for(; it; --it)
{
if(depth.second && int64_t(it.depth()) > depth.second)
continue;
if(int64_t(it.depth()) < depth.first)
break;
if(!_each(it, closure))
return false;
}
return true;
}
bool
ircd::m::room::events::missing::_each(m::room::events &it,
const closure &closure)
const
{
const m::event event
{
*it
};
const event::prev prev
{
event
};
event::idx idx_buf[event::prev::MAX];
const auto idx
{
prev.idxs(idx_buf)
};
for(size_t i(0); i < idx.size(); ++i)
{
if(idx[i])
continue;
if(!closure(prev.prev_event(i), it.depth(), it.event_idx()))
return false;
}
return true;
}
//
// room::events::sounding
//
bool
ircd::m::room::events::sounding::rfor_each(const closure &closure)
const
{
const int64_t depth
{
room.event_id?
m::get(std::nothrow, m::index(std::nothrow, room.event_id), "depth", -1L):
-1L
};
room::events it
{
room, uint64_t(depth)
};
if(!it)
return true;
event::idx idx{0};
for(sounding::range range{0L, it.depth()}; it; --it)
{
range.first = it.depth();
if(range.first == range.second)
{
idx = it.event_idx();
continue;
}
--range.second;
if(range.first == range.second)
{
idx = it.event_idx();
continue;
}
if(!closure({range.first+1, range.second+1}, idx))
return false;
range.second = range.first;
}
return true;
}
bool
ircd::m::room::events::sounding::for_each(const closure &closure)
const
{
const int64_t depth
{
room.event_id?
m::get(std::nothrow, m::index(std::nothrow, room.event_id), "depth", 0L):
0L
};
room::events it
{
room, uint64_t(depth)
};
for(sounding::range range{depth, 0L}; it; ++it)
{
range.second = it.depth();
if(range.first == range.second)
continue;
++range.first;
if(range.first == range.second)
continue;
if(!closure(range, it.event_idx()))
return false;
range.first = range.second;
}
return true;
}
//
// room::events::horizon
//
//TODO: XXX remove fwd decl
namespace ircd::m::dbs
{
void _index_event_horizon(db::txn &, const event &, const opts &, const m::event::id &);
}
size_t
ircd::m::room::events::horizon::rebuild()
{
m::dbs::opts opts;
opts.appendix.reset();
opts.appendix.set(dbs::appendix::EVENT_HORIZON);
db::txn txn
{
*dbs::events
};
size_t ret(0);
m::room::events it
{
room
};
for(; it; --it)
{
const m::event &event{*it};
const event::prev prev_events{event};
opts.event_idx = it.event_idx();
m::for_each(prev_events, [&]
(const m::event::id &event_id)
{
if(m::exists(event_id))
return true;
m::dbs::_index_event_horizon(txn, event, opts, event_id);
++ret;
return true;
});
}
txn();
return ret;
}
size_t
ircd::m::room::events::horizon::count()
const
{
size_t ret{0};
for_each([&ret]
(const auto &event_id, const auto &depth, const auto &event_idx) noexcept
{
++ret;
return true;
});
return ret;
}
bool
ircd::m::room::events::horizon::for_each(const closure &closure)
const
{
const std::function<bool (const string_view &)> in_room
{
[this](const string_view &room_id) noexcept
{
return room_id == this->room.room_id;
}
};
return event::horizon::for_every([&in_room, &closure]
(const event::id &event_id, const event::idx &event_idx)
{
if(!m::query(event_idx, "room_id", false, in_room))
return true;
if(m::exists(event_id))
return true;
uint64_t depth;
if(!m::get(event_idx, "depth", depth))
return true;
if(!closure(event_id, depth, event_idx))
return false;
return true;
});
}

View file

@ -0,0 +1,101 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2023 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
//TODO: XXX remove fwd decl
namespace ircd::m::dbs
{
void _index_event_horizon(db::txn &, const event &, const opts &, const m::event::id &);
}
size_t
ircd::m::room::events::horizon::rebuild()
{
m::dbs::opts opts;
opts.appendix.reset();
opts.appendix.set(dbs::appendix::EVENT_HORIZON);
db::txn txn
{
*dbs::events
};
size_t ret(0);
m::room::events it
{
room
};
for(; it; --it)
{
const m::event &event{*it};
const event::prev prev_events{event};
opts.event_idx = it.event_idx();
m::for_each(prev_events, [&]
(const m::event::id &event_id)
{
if(m::exists(event_id))
return true;
m::dbs::_index_event_horizon(txn, event, opts, event_id);
++ret;
return true;
});
}
txn();
return ret;
}
size_t
ircd::m::room::events::horizon::count()
const
{
size_t ret{0};
for_each([&ret]
(const auto &event_id, const auto &depth, const auto &event_idx) noexcept
{
++ret;
return true;
});
return ret;
}
bool
ircd::m::room::events::horizon::for_each(const closure &closure)
const
{
const std::function<bool (const string_view &)> in_room
{
[this](const string_view &room_id) noexcept
{
return room_id == this->room.room_id;
}
};
return event::horizon::for_every([&in_room, &closure]
(const event::id &event_id, const event::idx &event_idx)
{
if(!m::query(event_idx, "room_id", false, in_room))
return true;
if(m::exists(event_id))
return true;
uint64_t depth;
if(!m::get(event_idx, "depth", depth))
return true;
if(!closure(event_id, depth, event_idx))
return false;
return true;
});
}

View file

@ -0,0 +1,111 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2023 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
size_t
ircd::m::room::events::missing::count()
const
{
size_t ret{0};
for_each([&ret]
(const auto &event_id, const auto &depth, const auto &event_idx) noexcept
{
++ret;
return true;
});
return ret;
}
bool
ircd::m::room::events::missing::for_each(const closure &closure)
const
{
return for_each({0L, 0L}, closure);
}
bool
ircd::m::room::events::missing::for_each(const pair<int64_t> &depth,
const closure &closure)
const
{
room::events it
{
room, uint64_t(depth.first)
};
for(; it; ++it)
{
if(depth.second && int64_t(it.depth()) > depth.second)
break;
if(!_each(it, closure))
return false;
}
return true;
}
bool
ircd::m::room::events::missing::rfor_each(const pair<int64_t> &depth,
const closure &closure)
const
{
room::events it
{
room, depth.second?: -1UL
};
for(; it; --it)
{
if(depth.second && int64_t(it.depth()) > depth.second)
continue;
if(int64_t(it.depth()) < depth.first)
break;
if(!_each(it, closure))
return false;
}
return true;
}
bool
ircd::m::room::events::missing::_each(m::room::events &it,
const closure &closure)
const
{
const m::event event
{
*it
};
const event::prev prev
{
event
};
event::idx idx_buf[event::prev::MAX];
const auto idx
{
prev.idxs(idx_buf)
};
for(size_t i(0); i < idx.size(); ++i)
{
if(idx[i])
continue;
if(!closure(prev.prev_event(i), it.depth(), it.event_idx()))
return false;
}
return true;
}

View file

@ -0,0 +1,190 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2023 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
std::pair<int64_t, ircd::m::event::idx>
ircd::m::viewport(const room &room)
{
std::pair<int64_t, m::event::idx> ret
{
-1, 0
};
m::room::events it
{
room
};
const ssize_t &max
{
room::events::viewport_size
};
for(auto i(0); it && i < max; --it, ++i)
{
ret.first = it.depth();
ret.second = it.event_idx();
}
return ret;
}
std::pair<int64_t, ircd::m::event::idx>
ircd::m::twain(const room &room)
{
std::pair<int64_t, m::event::idx> ret
{
-1, 0
};
const room::events::sounding s
{
room
};
s.rfor_each([&ret]
(const auto &range, const auto &event_idx) noexcept
{
ret.first = range.first - 1;
return false;
});
return ret;
}
std::pair<int64_t, ircd::m::event::idx>
ircd::m::sounding(const room &room)
{
std::pair<int64_t, m::event::idx> ret
{
-1, 0
};
const room::events::sounding s
{
room
};
s.rfor_each([&ret]
(const auto &range, const auto &event_idx) noexcept
{
ret.first = range.second;
ret.second = event_idx;
return false;
});
return ret;
}
std::pair<int64_t, ircd::m::event::idx>
ircd::m::hazard(const room &room)
{
std::pair<int64_t, m::event::idx> ret
{
0, 0
};
const room::events::sounding s
{
room
};
s.for_each([&ret]
(const auto &range, const auto &event_idx) noexcept
{
ret.first = range.first;
return false;
});
return ret;
}
//
// room::events::sounding
//
bool
ircd::m::room::events::sounding::rfor_each(const closure &closure)
const
{
const int64_t depth
{
room.event_id?
m::get(std::nothrow, m::index(std::nothrow, room.event_id), "depth", -1L):
-1L
};
room::events it
{
room, uint64_t(depth)
};
if(!it)
return true;
event::idx idx{0};
for(sounding::range range{0L, it.depth()}; it; --it)
{
range.first = it.depth();
if(range.first == range.second)
{
idx = it.event_idx();
continue;
}
--range.second;
if(range.first == range.second)
{
idx = it.event_idx();
continue;
}
if(!closure({range.first+1, range.second+1}, idx))
return false;
range.second = range.first;
}
return true;
}
bool
ircd::m::room::events::sounding::for_each(const closure &closure)
const
{
const int64_t depth
{
room.event_id?
m::get(std::nothrow, m::index(std::nothrow, room.event_id), "depth", 0L):
0L
};
room::events it
{
room, uint64_t(depth)
};
for(sounding::range range{depth, 0L}; it; ++it)
{
range.second = it.depth();
if(range.first == range.second)
continue;
++range.first;
if(range.first == range.second)
continue;
if(!closure(range, it.event_idx()))
return false;
range.first = range.second;
}
return true;
}