0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 10:12:39 +01:00

ircd:Ⓜ️ Convert db column keys to binary integers over a continuous sequence space.

This commit is contained in:
Jason Volk 2018-04-17 19:14:39 -07:00
parent e6a80082c8
commit eefc7430bc
8 changed files with 809 additions and 330 deletions

View file

@ -27,10 +27,11 @@ namespace ircd::m::dbs
// Event metadata columns
extern db::column event_seq;
extern db::column state_node;
extern db::column event_idx;
extern db::index room_events;
extern db::index room_joined;
extern db::index room_state;
extern db::column state_node;
// Lowlevel util
string_view room_state_key(const mutable_buffer &out, const id::room &, const string_view &type, const string_view &state_key);
@ -41,14 +42,17 @@ namespace ircd::m::dbs
string_view room_joined_key(const mutable_buffer &out, const id::room &, const string_view &origin);
std::pair<string_view, string_view> room_joined_key(const string_view &amalgam);
string_view room_events_key(const mutable_buffer &out, const id::room &, const uint64_t &depth, const id::event &);
string_view room_events_key(const mutable_buffer &out, const id::room &, const uint64_t &depth, const event::idx &);
string_view room_events_key(const mutable_buffer &out, const id::room &, const uint64_t &depth);
std::pair<uint64_t, string_view> room_events_key(const string_view &amalgam);
std::pair<uint64_t, event::idx> room_events_key(const string_view &amalgam);
// Get the state root for an event (with as much information as you have)
string_view state_root(const mutable_buffer &out, const id::room &, const id::event &, const uint64_t &depth);
string_view state_root(const mutable_buffer &out, const id::room &, const id::event &);
string_view state_root(const mutable_buffer &out, const id::event &);
// [GET] the state root for an event (with as much information as you have)
string_view state_root(const mutable_buffer &out, const id::room &, const event::idx &, const uint64_t &depth);
string_view state_root(const mutable_buffer &out, const id::room &, const event::id &, const uint64_t &depth);
string_view state_root(const mutable_buffer &out, const id::room &, const event::idx &);
string_view state_root(const mutable_buffer &out, const id::room &, const event::id &);
string_view state_root(const mutable_buffer &out, const event::idx &);
string_view state_root(const mutable_buffer &out, const event::id &);
string_view state_root(const mutable_buffer &out, const event &);
// [SET (txn)] Basic write suite
@ -57,6 +61,7 @@ namespace ircd::m::dbs
struct ircd::m::dbs::write_opts
{
uint64_t idx {0};
string_view root_in;
mutable_buffer root_out;
db::op op {db::op::SET};
@ -97,9 +102,11 @@ namespace ircd::m::dbs::desc
//
// events sequence
extern const db::comparator events__event_seq__cmp;
extern const database::descriptor events__event_seq;
// events index
extern const database::descriptor events__event_idx;
// room events sequence
extern const db::prefix_transform events__room_events__pfx;
extern const db::comparator events__room_events__cmp;

View file

@ -84,8 +84,11 @@ struct ircd::m::event
// Common convenience aliases
using id = m::id::event;
using idx = uint64_t;
using closure = std::function<void (const event &)>;
using closure_bool = std::function<bool (const event &)>;
using closure_idx = std::function<void (const idx &)>;
using closure_idx_bool = std::function<bool (const idx &)>;
using closure_iov_mutable = std::function<void (json::iov &)>;
static constexpr size_t MAX_SIZE = 64_KiB;
@ -123,6 +126,7 @@ struct ircd::m::event
using super_type::tuple;
using super_type::operator=;
event(const idx &, const mutable_buffer &buf);
event(const id &, const mutable_buffer &buf);
event() = default;
};
@ -168,15 +172,27 @@ struct ircd::m::event::fetch
{
std::array<db::cell, event::size()> cell;
db::row row;
bool valid;
bool valid(const event::id &) const;
fetch(const event::id &, std::nothrow_t);
fetch(const event::id &);
public:
fetch(const idx &, std::nothrow_t);
fetch(const idx &);
fetch(const id &, std::nothrow_t);
fetch(const id &);
fetch();
friend bool seek(fetch &, const event::id &, std::nothrow_t);
friend void seek(fetch &, const event::id &);
static bool event_id(const idx &, std::nothrow_t, const id::closure &);
static void event_id(const idx &, const id::closure &);
static idx index(const id &, std::nothrow_t);
static idx index(const id &);
static idx index(const event &, std::nothrow_t);
static idx index(const event &);
friend bool seek(fetch &, const idx &, std::nothrow_t);
friend void seek(fetch &, const idx &);
friend bool seek(fetch &, const id &, std::nothrow_t);
friend void seek(fetch &, const id &);
};
/// Device to evaluate the conformity of an event object. This is an 'in vitro'

View file

@ -113,13 +113,17 @@ struct ircd::m::room
operator const id &() const;
// Convenience passthru to room::messages (linear query; newest first)
void for_each(const string_view &type, const event::id::closure_bool &) const;
bool for_each(const string_view &type, const event::closure_idx_bool &) const;
void for_each(const string_view &type, const event::closure_idx &) const;
bool for_each(const string_view &type, const event::id::closure_bool &) const;
void for_each(const string_view &type, const event::id::closure &) const;
void for_each(const string_view &type, const event::closure_bool &) const;
bool for_each(const string_view &type, const event::closure_bool &) const;
void for_each(const string_view &type, const event::closure &) const;
void for_each(const event::id::closure_bool &) const;
bool for_each(const event::closure_idx_bool &) const;
void for_each(const event::closure_idx &) const;
bool for_each(const event::id::closure_bool &) const;
void for_each(const event::id::closure &) const;
void for_each(const event::closure_bool &) const;
bool for_each(const event::closure_bool &) const;
void for_each(const event::closure &) const;
// Convenience passthru to room::state (logarithmic query)
@ -155,22 +159,22 @@ struct ircd::m::room
/// This interface has the form of an STL-style iterator over room messages
/// which are state and non-state events from all integrated timelines.
/// Moving the iterator is cheap, but the dereference operators fetch a
/// full event. One can iterate just event_id's by using event_id() instead
/// full event. One can iterate just event_idx's by using event_idx() instead
/// of the dereference operators.
///
struct ircd::m::room::messages
{
m::room room;
db::index::const_iterator it;
event::id _event_id;
event::idx _event_idx;
event::fetch _event;
public:
operator bool() const { return bool(it); }
bool operator!() const { return !it; }
const event::id &event_id();
operator const event::id &();
event::id::buf event_id(); // deprecated; will remove
const event::idx &event_idx();
const m::event &fetch(std::nothrow_t);
const m::event &fetch();
@ -218,17 +222,22 @@ struct ircd::m::room::state
// Iterate the state; for_each protocol
void for_each(const string_view &type, const keys &) const;
void for_each(const string_view &type, const event::closure_idx &) const;
void for_each(const string_view &type, const event::id::closure &) const;
void for_each(const string_view &type, const event::closure &) const;
void for_each(const event::closure_idx &) const;
void for_each(const event::id::closure &) const;
void for_each(const event::closure &) const;
// Iterate the state; test protocol
bool test(const string_view &type, const string_view &lower_bound, const event::closure_idx_bool &view) const;
bool test(const string_view &type, const string_view &lower_bound, const event::id::closure_bool &view) const;
bool test(const string_view &type, const string_view &lower_bound, const event::closure_bool &view) const;
bool test(const string_view &type, const keys_bool &view) const;
bool test(const string_view &type, const event::closure_idx_bool &view) const;
bool test(const string_view &type, const event::id::closure_bool &view) const;
bool test(const string_view &type, const event::closure_bool &view) const;
bool test(const event::closure_idx_bool &view) const;
bool test(const event::id::closure_bool &view) const;
bool test(const event::closure_bool &view) const;
@ -241,8 +250,10 @@ struct ircd::m::room::state
bool has(const string_view &type) const;
// Fetch a state event
bool get(std::nothrow_t, const string_view &type, const string_view &state_key, const event::closure_idx &) const;
bool get(std::nothrow_t, const string_view &type, const string_view &state_key, const event::id::closure &) const;
bool get(std::nothrow_t, const string_view &type, const string_view &state_key, const event::closure &) const;
void get(const string_view &type, const string_view &state_key, const event::closure_idx &) const;
void get(const string_view &type, const string_view &state_key, const event::id::closure &) const;
void get(const string_view &type, const string_view &state_key, const event::closure &) const;

View file

@ -33,15 +33,15 @@ namespace ircd::m::vm
namespace ircd::m::vm::events
{
using id_closure_bool = std::function<bool (const uint64_t &, const event::id &)>;
using idx_closure_bool = std::function<bool (const uint64_t &, const event::idx &)>;
using closure_bool = std::function<bool (const uint64_t &, const event &)>;
// counts up from start
bool for_each(const uint64_t &start, const id_closure_bool &);
bool for_each(const uint64_t &start, const idx_closure_bool &);
bool for_each(const uint64_t &start, const closure_bool &);
// -1 starts at newest event; counts down
bool rfor_each(const uint64_t &start, const id_closure_bool &);
bool rfor_each(const uint64_t &start, const idx_closure_bool &);
bool rfor_each(const uint64_t &start, const closure_bool &);
}

View file

@ -28,6 +28,11 @@ decltype(ircd::m::dbs::event_seq)
ircd::m::dbs::event_seq
{};
/// Linkage for a reference to the event_seq column.
decltype(ircd::m::dbs::event_idx)
ircd::m::dbs::event_idx
{};
/// Linkage for a reference to the state_node column.
decltype(ircd::m::dbs::state_node)
ircd::m::dbs::state_node
@ -73,6 +78,7 @@ ircd::m::dbs::init::init(std::string dbopts)
// Cache the columns for the metadata
event_seq = db::column{*events, desc::events__event_seq.name};
event_idx = db::column{*events, desc::events__event_idx.name};
state_node = db::column{*events, desc::events__state_node.name};
room_events = db::index{*events, desc::events__room_events.name};
room_joined = db::index{*events, desc::events__room_joined.name};
@ -112,9 +118,21 @@ ircd::m::dbs::write(db::txn &txn,
const event &event,
const write_opts &opts)
{
assert(opts.idx != 0);
db::txn::append
{
txn, at<"event_id"_>(event), event, event_column, opts.op
txn, dbs::event_idx,
{
db::op::SET,
at<"event_id"_>(event),
byte_view<string_view>(opts.idx)
}
};
db::txn::append
{
txn, byte_view<string_view>(opts.idx), event, event_column, opts.op
};
if(defined(json::get<"state_key"_>(event)))
@ -151,7 +169,7 @@ try
target_id, std::nothrow
};
if(unlikely(!target.valid(target_id)))
if(unlikely(!target.valid))
log::error
{
"Redaction from '%s' missing redaction target '%s'",
@ -230,10 +248,10 @@ ircd::m::dbs::_index__room_events(db::txn &txn,
const string_view &new_root)
{
const ctx::critical_assertion ca;
thread_local char buf[768];
thread_local char buf[256 + 1 + 8 + 8];
const string_view &key
{
room_events_key(buf, at<"room_id"_>(event), at<"depth"_>(event), at<"event_id"_>(event))
room_events_key(buf, at<"room_id"_>(event), at<"depth"_>(event), opts.idx)
};
db::txn::append
@ -321,9 +339,9 @@ ircd::m::dbs::_index__room_state(db::txn &txn,
room_state_key(buf, at<"room_id"_>(event), at<"type"_>(event), at<"state_key"_>(event))
};
const string_view &val
const string_view val
{
at<"event_id"_>(event)
byte_view<string_view>(opts.idx)
};
const db::op op
@ -354,6 +372,13 @@ ircd::m::dbs::state_root(const mutable_buffer &out,
ircd::string_view
ircd::m::dbs::state_root(const mutable_buffer &out,
const id::event &event_id)
{
return state_root(out, event::fetch::index(event_id));
}
ircd::string_view
ircd::m::dbs::state_root(const mutable_buffer &out,
const event::idx &event_idx)
{
static constexpr auto idx
{
@ -366,18 +391,27 @@ ircd::m::dbs::state_root(const mutable_buffer &out,
};
id::room::buf room_id;
column(event_id, [&room_id](const string_view &val)
column(byte_view<string_view>(event_idx), [&room_id]
(const string_view &val)
{
room_id = val;
});
return state_root(out, room_id, event_id);
return state_root(out, room_id, event_idx);
}
ircd::string_view
ircd::m::dbs::state_root(const mutable_buffer &out,
const id::room &room_id,
const id::event &event_id)
{
return state_root(out, room_id, event::fetch::index(event_id));
}
ircd::string_view
ircd::m::dbs::state_root(const mutable_buffer &out,
const id::room &room_id,
const event::idx &event_idx)
{
static constexpr auto idx
{
@ -390,13 +424,13 @@ ircd::m::dbs::state_root(const mutable_buffer &out,
};
uint64_t depth;
column(event_id, [&](const string_view &binary)
column(byte_view<string_view>(event_idx), [&depth]
(const string_view &binary)
{
assert(size(binary) == sizeof(depth));
depth = byte_view<uint64_t>(binary);
});
return state_root(out, room_id, event_id, depth);
return state_root(out, room_id, event_idx, depth);
}
ircd::string_view
@ -405,9 +439,18 @@ ircd::m::dbs::state_root(const mutable_buffer &out,
const id::event &event_id,
const uint64_t &depth)
{
char keybuf[768]; const auto key
return state_root(out, room_id, event::fetch::index(event_id), depth);
}
ircd::string_view
ircd::m::dbs::state_root(const mutable_buffer &out,
const id::room &room_id,
const event::idx &event_idx,
const uint64_t &depth)
{
char keybuf[256 + 1 + 8 + 8]; const auto key
{
room_events_key(keybuf, room_id, depth, event_id)
room_events_key(keybuf, room_id, depth, event_idx)
};
string_view ret;
@ -423,62 +466,6 @@ ircd::m::dbs::state_root(const mutable_buffer &out,
// Database descriptors
//
/// State nodes are pieces of the m::state:: b-tree. The key is the hash
/// of the value, which serves as the ID of the node when referenced in
/// the tree. see: m/state.h for details.
///
const ircd::database::descriptor
ircd::m::dbs::desc::events__state_node
{
// name
"_state_node",
// explanation
R"(### developer note:
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
},
// options
{},
// comparator
{},
// prefix transform
{},
// cache size
96_MiB, //TODO: conf
// cache size for compressed assets
24_MiB, //TODO: conf
};
const ircd::db::comparator
ircd::m::dbs::desc::events__event_seq__cmp
{
"_event_seq",
// less
[](const string_view &sa, const string_view &sb)
{
const byte_view<uint64_t> a{sa}, b{sb};
return a < b;
},
// equal
[](const string_view &sa, const string_view &sb)
{
const byte_view<uint64_t> a{sa}, b{sb};
return a == b;
},
};
const ircd::database::descriptor
ircd::m::dbs::desc::events__event_seq
{
@ -488,19 +475,23 @@ ircd::m::dbs::desc::events__event_seq
// explanation
R"(### developer note:
Sequence counter.
The key is an integer given by the m::vm. The value is the index number to
be used as the key to all the event data columns. At the time of this
comment these are actually the same thing.
)",
// typing (key, value)
{
typeid(uint64_t), typeid(ircd::string_view)
typeid(uint64_t), typeid(uint64_t)
},
// options
{},
// comparator
events__event_seq__cmp,
{},
// prefix transform
{},
@ -515,6 +506,44 @@ ircd::m::dbs::desc::events__event_seq
0, // no bloom filter because of possible comparator issues
};
const ircd::database::descriptor
ircd::m::dbs::desc::events__event_idx
{
// name
"_event_idx",
// explanation
R"(### developer note:
The key is an event_id and the value is the index number to be used as the
key to all the event data columns.
)",
// typing (key, value)
{
typeid(string_view), typeid(uint64_t)
},
// options
{},
// comparator
{},
// prefix transform
{},
// cache size
64_MiB, //TODO: conf
// cache size for compressed assets
16_MiB, //TODO: conf
// bloom filter bits
12,
};
/// Prefix transform for the events__room_events. The prefix here is a room_id
/// and the suffix is the depth+event_id concatenation.
/// for efficient sequences
@ -571,11 +600,11 @@ ircd::m::dbs::desc::events__room_events__cmp
if(pre[0] != pre[1])
return pre[0] < pre[1];
// After the prefix is the depth + event_id
// After the prefix is the depth + event_idx
const string_view post[2]
{
a.substr(size(pre[0])),
b.substr(size(pre[1])),
a.substr(sizes[0]),
b.substr(sizes[1]),
};
if(empty(post[0]))
@ -585,17 +614,10 @@ ircd::m::dbs::desc::events__room_events__cmp
return false;
// Now want just the depth...
const string_view depths[2]
const uint64_t depth[2]
{
between(post[0], "\0"_sv, "$"_sv),
between(post[1], "\0"_sv, "$"_sv),
};
// ...as machine words
const int64_t depth[2]
{
lex_cast<int64_t>(depths[0]),
lex_cast<int64_t>(depths[1]),
room_events_key(post[0]).first,
room_events_key(post[1]).first,
};
// Highest to lowest sort so highest is first
@ -608,10 +630,15 @@ ircd::m::dbs::room_events_key(const mutable_buffer &out_,
const id::room &room_id,
const uint64_t &depth)
{
const const_buffer depth_cb
{
reinterpret_cast<const char *>(&depth), sizeof(depth)
};
mutable_buffer out{out_};
consume(out, copy(out, room_id));
consume(out, copy(out, "\0"_sv));
consume(out, copy(out, lex_cast(depth)));
consume(out, copy(out, depth_cb));
return { data(out_), data(out) };
}
@ -619,39 +646,52 @@ ircd::string_view
ircd::m::dbs::room_events_key(const mutable_buffer &out_,
const id::room &room_id,
const uint64_t &depth,
const id::event &event_id)
const event::idx &event_idx)
{
const const_buffer depth_cb
{
reinterpret_cast<const char *>(&depth), sizeof(depth)
};
const const_buffer event_idx_cb
{
reinterpret_cast<const char *>(&event_idx), sizeof(event_idx)
};
mutable_buffer out{out_};
consume(out, copy(out, room_id));
consume(out, copy(out, "\0"_sv));
consume(out, copy(out, lex_cast(depth)));
consume(out, copy(out, event_id));
consume(out, copy(out, depth_cb));
consume(out, copy(out, event_idx_cb));
return { data(out_), data(out) };
}
std::pair<uint64_t, ircd::string_view>
std::pair<uint64_t, ircd::m::event::idx>
ircd::m::dbs::room_events_key(const string_view &amalgam)
{
const auto &key
assert(size(amalgam) == 1 + 8 + 8 || size(amalgam) == 1 + 8);
assert(amalgam.front() == '\0');
const uint64_t &depth
{
lstrip(amalgam, "\0"_sv)
*reinterpret_cast<const uint64_t *>(data(amalgam) + 1)
};
const auto &s
const event::idx &event_idx
{
split(key, "$"_sv)
size(amalgam) >= 1 + 8 + 8?
*reinterpret_cast<const uint64_t *>(data(amalgam) + 1 + 8):
0UL
};
return
{
lex_cast<uint64_t>(s.first),
{ end(s.first), end(s.second) }
};
// Make sure these are copied rather than ever returning references in
// a tuple because the chance the integers will be aligned is low.
return { depth, event_idx };
}
/// This column stores events in sequence in a room. Consider the following:
///
/// [room_id | depth + event_id => state_root]
/// [room_id | depth + event_idx => state_root]
///
/// The key is composed from three parts:
///
@ -661,17 +701,19 @@ ircd::m::dbs::room_events_key(const string_view &amalgam)
///
/// - `depth` is the ordering. Within the sequence, all elements are ordered by
/// depth from HIGHEST TO LOWEST. The sequence will start at the highest depth.
/// NOTE: Depth is a fixed 8 byte binary integer.
///
/// - `event_id` is the key suffix. This column serves to sequence all events
/// - `event_idx` is the key suffix. This column serves to sequence all events
/// within a room ordered by depth. There may be duplicate room_id|depth
/// prefixing but the event_id suffix gives the key total uniqueness.
/// prefixing but the event_idx suffix gives the key total uniqueness.
/// NOTE: event_idx is a fixed 8 byte binary integer.
///
/// The value is then used to store the node ID of the state tree root at this
/// event. Nodes of the state tree are stored in the state_node column. From
/// that root node the state of the room at the time of this event_id can be
/// queried.
///
/// There is one caveat here: we can't directly take a room_id and an event_id
/// There is one caveat here: we can't directly take a room_id and an event_idx
/// and make a trivial query to find the state root, since the depth number
/// gets in the way. Rather than creating yet another column without the depth,
/// for the time being, we pay the cost of an extra query to events_depth and
@ -693,7 +735,7 @@ ircd::m::dbs::desc::events__room_events
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(string_view), typeid(string_view)
},
// options
@ -801,7 +843,7 @@ ircd::m::dbs::desc::events__room_joined
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(string_view), typeid(uint64_t)
},
// options
@ -904,7 +946,7 @@ ircd::m::dbs::desc::events__room_state
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(string_view), typeid(uint64_t)
},
// options
@ -923,6 +965,42 @@ ircd::m::dbs::desc::events__room_state
32_MiB, //TODO: conf
};
/// State nodes are pieces of the m::state:: b-tree. The key is the hash
/// of the value, which serves as the ID of the node when referenced in
/// the tree. see: m/state.h for details.
///
const ircd::database::descriptor
ircd::m::dbs::desc::events__state_node
{
// name
"_state_node",
// explanation
R"(### developer note:
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
},
// options
{},
// comparator
{},
// prefix transform
{},
// cache size
96_MiB, //TODO: conf
// cache size for compressed assets
24_MiB, //TODO: conf
};
//
// Direct column descriptors
//
@ -943,12 +1021,12 @@ ircd::m::dbs::desc::events_event_id
MUST NOT exceed 255 bytes.
### developer note:
key is event_id. This is redundant data but we have to have it for now.
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -969,12 +1047,12 @@ ircd::m::dbs::desc::events_type
MUST NOT exceed 255 bytes.
### developer note:
key is event_id
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -995,12 +1073,12 @@ ircd::m::dbs::desc::events_content
Since events must not exceed 64 KiB the maximum size for the content is the remaining
space after all the other fields for the event are rendered.
key is event_id
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1014,13 +1092,13 @@ ircd::m::dbs::desc::events_redacts
R"(### protocol note:
### developer note:
key is event_id
key is event_idx number.
value is targeted event_id
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1040,12 +1118,12 @@ ircd::m::dbs::desc::events_room_id
MUST NOT exceed 255 bytes.
### developer note:
key is event_id
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1065,12 +1143,12 @@ ircd::m::dbs::desc::events_sender
MUST NOT exceed 255 bytes.
### developer note:
key is event_id
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1092,12 +1170,12 @@ ircd::m::dbs::desc::events_state_key
MUST NOT exceed 255 bytes.
### developer note:
key is event_id
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1114,12 +1192,12 @@ ircd::m::dbs::desc::events_origin
DNS name of homeserver that created this PDU
### developer note:
key is event_id
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1136,7 +1214,7 @@ ircd::m::dbs::desc::events_origin_server_ts
Timestamp in milliseconds on origin homeserver when this PDU was created.
### developer note:
key is event_id
key is event_idx number.
value is a machine integer (binary)
TODO: consider unsigned rather than time_t because of millisecond precision
@ -1145,7 +1223,7 @@ ircd::m::dbs::desc::events_origin_server_ts
// typing (key, value)
{
typeid(ircd::string_view), typeid(time_t)
typeid(uint64_t), typeid(time_t)
}
};
@ -1159,13 +1237,13 @@ ircd::m::dbs::desc::events_signatures
R"(### protocol note:
### developer note:
key is event_id
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1179,12 +1257,12 @@ ircd::m::dbs::desc::events_auth_events
R"(### protocol note:
### developer note:
key is event_id.
key is event_idx number..
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1198,12 +1276,12 @@ ircd::m::dbs::desc::events_depth
R"(### protocol note:
### developer note:
key is event_id value is long integer
key is event_idx number. value is long integer
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(int64_t)
typeid(uint64_t), typeid(int64_t)
}
};
@ -1217,12 +1295,12 @@ ircd::m::dbs::desc::events_hashes
R"(### protocol note:
### developer note:
key is event_id.
key is event_idx number..
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1236,12 +1314,12 @@ ircd::m::dbs::desc::events_membership
R"(### protocol note:
### developer note:
key is event_id.
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1255,12 +1333,12 @@ ircd::m::dbs::desc::events_prev_events
R"(### protocol note:
### developer note:
key is event_id.
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(string_view)
}
};
@ -1274,12 +1352,12 @@ ircd::m::dbs::desc::events_prev_state
R"(### protocol note:
### developer note:
key is event_id.
key is event_idx number.
)",
// typing (key, value)
{
typeid(ircd::string_view), typeid(ircd::string_view)
typeid(uint64_t), typeid(ircd::string_view)
}
};
@ -1290,9 +1368,9 @@ ircd::m::dbs::desc::events
{ "default" },
//
// These columns directly represent event fields indexed by event_id and
// the value is the actual event values. Some values may be JSON, like
// content.
// These columns directly represent event fields indexed by event_idx
// number and the value is the actual event values. Some values may be
// JSON, like content.
//
events_auth_events,
@ -1313,15 +1391,18 @@ ircd::m::dbs::desc::events
events_type,
//
// These columns are metadata composed from the event data. Specifically,
// they are designed for fast sequential iterations.
// These columns are metadata oriented around the event data.
//
// uint64_t => event_id
// Sequence of all events counted by the m::vm.
// uint64_t => uint64_t
// Sequence number to event_idx number counted by the m::vm.
events__event_seq,
// (room_id, (depth, event_id)) => (state_root)
// event_id => uint64_t
// Mapping of event_id to index number.
events__event_idx,
// (room_id, (depth, event_idx)) => (state_root)
// Sequence of all events for a room, ever.
events__room_events,
@ -1333,10 +1414,7 @@ ircd::m::dbs::desc::events
// Sequence of the PRESENT STATE of the room.
events__room_state,
//
// Other columns
//
// (state tree node id) => (state tree node)
// Mapping of state tree node id to node data.
events__state_node,
};

View file

@ -133,14 +133,9 @@ ircd::m::degree(const event::prev &prev)
bool
ircd::m::exists(const id::event &event_id)
{
static constexpr auto idx
{
json::indexof<event, "event_id"_>()
};
auto &column
{
dbs::event_column.at(idx)
dbs::event_idx
};
return has(column, event_id);
@ -503,24 +498,35 @@ ircd::m::event::max_size
ircd::m::event::event(const id &id,
const mutable_buffer &buf)
:event
{
fetch::index(id), buf
}
{
}
ircd::m::event::event(const idx &idx,
const mutable_buffer &buf)
{
assert(bool(dbs::events));
db::gopts opts;
opts.snapshot = database::snapshot{*dbs::events};
for(size_t i(0); i < dbs::event_column.size(); ++i)
{
const db::cell cell
{
dbs::event_column[i], id, opts
dbs::event_column[i], byte_view<string_view>{idx}, opts
};
db::assign(*this, cell, id);
db::assign(*this, cell, byte_view<string_view>{idx});
}
const json::object obj
{
string_view{data(buf), json::print(buf, *this)}
string_view
{
data(buf), json::print(buf, *this)
}
};
new (this) m::event(obj);
@ -1145,15 +1151,128 @@ ircd::m::seek(event::fetch &fetch,
const event::id &event_id,
std::nothrow_t)
{
db::seek(fetch.row, string_view{event_id});
if(!fetch.row.valid(event_id))
const event::idx &event_idx
{
event::fetch::index(event_id, std::nothrow)
};
return seek(fetch, event_idx, std::nothrow);
}
void
ircd::m::seek(event::fetch &fetch,
const event::idx &event_idx)
{
if(!seek(fetch, event_idx, std::nothrow))
throw m::NOT_FOUND
{
"%lu not found in database", event_idx
};
}
bool
ircd::m::seek(event::fetch &fetch,
const event::idx &event_idx,
std::nothrow_t)
{
const string_view &key
{
byte_view<string_view>(event_idx)
};
db::seek(fetch.row, key);
fetch.valid = fetch.row.valid(key);
if(!fetch.valid)
return false;
auto &event{static_cast<m::event &>(fetch)};
assign(event, fetch.row, event_id);
assign(event, fetch.row, key);
return true;
}
ircd::m::event::idx
ircd::m::event::fetch::index(const event &event)
{
return index(at<"event_id"_>(event));
}
ircd::m::event::idx
ircd::m::event::fetch::index(const event &event,
std::nothrow_t)
{
return index(at<"event_id"_>(event), std::nothrow);
}
ircd::m::event::idx
ircd::m::event::fetch::index(const id &event_id)
{
auto &column
{
dbs::event_idx
};
event::idx ret;
column(event_id, [&ret]
(const string_view &value)
{
ret = byte_view<event::idx>(value);
});
return ret;
}
ircd::m::event::idx
ircd::m::event::fetch::index(const id &event_id,
std::nothrow_t)
{
auto &column
{
dbs::event_idx
};
event::idx ret{0};
column(event_id, std::nothrow, [&ret]
(const string_view &value)
{
ret = byte_view<event::idx>(value);
});
return ret;
}
void
ircd::m::event::fetch::event_id(const idx &idx,
const id::closure &closure)
{
if(!event_id(idx, std::nothrow, closure))
throw m::NOT_FOUND
{
"%lu not found in database", idx
};
}
bool
ircd::m::event::fetch::event_id(const idx &idx,
std::nothrow_t,
const id::closure &closure)
{
static constexpr auto column_idx
{
json::indexof<event, "event_id"_>()
};
auto &column
{
dbs::event_column.at(column_idx)
};
return column(byte_view<string_view>{idx}, std::nothrow, [&closure]
(const string_view &value)
{
closure(value);
});
}
// db::row finds the layout of an event tuple because we pass this as a
// reference argument to its constructor, rather than making db::row into
// a template type.
@ -1166,44 +1285,64 @@ ircd::m::event::fetch::fetch()
{
*dbs::events, string_view{}, _dummy_event_, cell
}
,valid
{
false
}
{
}
/// Seek to event_id and populate this event from database.
/// Throws if event not in database.
ircd::m::event::fetch::fetch(const event::id &event_id)
:row
:fetch
{
*dbs::events, event_id, _dummy_event_, cell
index(event_id)
}
{
if(!row.valid(event_id))
throw m::NOT_FOUND
{
"%s not found in database", event_id
};
assign(*this, row, event_id);
}
/// Seek to event_id and populate this event from database.
/// Event is not populated if not found in database.
ircd::m::event::fetch::fetch(const event::id &event_id,
std::nothrow_t)
:row
:fetch
{
*dbs::events, event_id, _dummy_event_, cell
index(event_id, std::nothrow), std::nothrow
}
{
if(row.valid(event_id))
assign(*this, row, event_id);
}
bool
ircd::m::event::fetch::valid(const event::id &event_id)
const
/// Seek to event_idx and populate this event from database.
/// Throws if event not in database.
ircd::m::event::fetch::fetch(const event::idx &event_idx)
:fetch
{
return row.valid(event_id);
event_idx, std::nothrow
}
{
if(!valid)
throw m::NOT_FOUND
{
"idx %zu not found in database", event_idx
};
}
/// Seek to event_idx and populate this event from database.
/// Event is not populated if not found in database.
ircd::m::event::fetch::fetch(const event::idx &event_idx,
std::nothrow_t)
:row
{
*dbs::events, byte_view<string_view>{event_idx}, _dummy_event_, cell
}
,valid
{
row.valid(byte_view<string_view>{event_idx})
}
{
if(valid)
assign(*this, row, byte_view<string_view>{event_idx});
}
//

View file

@ -45,7 +45,10 @@ ircd::m::top(const id::room &room_id)
};
if(std::get<0>(ret) == -1)
throw m::NOT_FOUND{};
throw m::NOT_FOUND
{
"No head for room %s", string_view{room_id}
};
return ret;
}
@ -71,12 +74,20 @@ ircd::m::top(std::nothrow_t,
dbs::room_events_key(key)
};
const auto &depth{std::get<0>(part)};
const auto &event_id{std::get<1>(part)};
return
const int64_t &depth(std::get<0>(part));
std::tuple<int64_t, ircd::m::id::event::buf> ret
{
depth, event_id
depth, {}
};
const event::idx &event_idx{std::get<1>(part)};
event::fetch::event_id(event_idx, std::nothrow, [&ret]
(const event::id &event_id)
{
std::get<1>(ret) = event_id;
});
return ret;
}
bool
@ -207,59 +218,42 @@ void
ircd::m::room::for_each(const event::closure &closure)
const
{
for_each(event::closure_bool{[&closure]
(const event &event)
{
closure(event);
return true;
}});
for_each(string_view{}, closure);
}
void
bool
ircd::m::room::for_each(const event::closure_bool &closure)
const
{
event::fetch event;
for_each(event::id::closure_bool{[&closure, &event]
(const event::id &event_id)
{
if(!seek(event, event_id, std::nothrow))
return true;
return closure(event);
}});
return for_each(string_view{}, closure);
}
void
ircd::m::room::for_each(const event::id::closure &closure)
const
{
for_each(event::id::closure_bool{[&closure]
(const event::id &event_id)
{
closure(event_id);
return true;
}});
for_each(string_view{}, closure);
}
void
bool
ircd::m::room::for_each(const event::id::closure_bool &closure)
const
{
static constexpr auto idx
{
json::indexof<event, "type"_>()
};
return for_each(string_view{}, closure);
}
auto &column
{
dbs::event_column.at(idx)
};
void
ircd::m::room::for_each(const event::closure_idx &closure)
const
{
for_each(string_view{}, closure);
}
messages it{*this};
for(; it; --it)
if(!closure(it.event_id()))
break;
bool
ircd::m::room::for_each(const event::closure_idx_bool &closure)
const
{
return for_each(string_view{}, closure);
}
void
@ -275,16 +269,16 @@ const
}});
}
void
bool
ircd::m::room::for_each(const string_view &type,
const event::closure_bool &closure)
const
{
event::fetch event;
for_each(type, event::id::closure_bool{[&closure, &event]
(const event::id &event_id)
return for_each(type, event::closure_idx_bool{[&closure, &event]
(const event::idx &event_idx)
{
if(!seek(event, event_id, std::nothrow))
if(!seek(event, event_idx, std::nothrow))
return true;
return closure(event);
@ -304,10 +298,42 @@ const
}});
}
void
bool
ircd::m::room::for_each(const string_view &type,
const event::id::closure_bool &closure)
const
{
return for_each(type, event::closure_idx_bool{[&closure]
(const event::idx &idx)
{
bool ret{true};
event::fetch::event_id(idx, std::nothrow, [&ret, &closure]
(const event::id &event_id)
{
ret = closure(event_id);
});
return ret;
}});
}
void
ircd::m::room::for_each(const string_view &type,
const event::closure_idx &closure)
const
{
for_each(type, event::closure_idx_bool{[&closure]
(const event::idx &idx)
{
closure(idx);
return true;
}});
}
bool
ircd::m::room::for_each(const string_view &type,
const event::closure_idx_bool &closure)
const
{
static constexpr auto idx
{
@ -322,22 +348,29 @@ const
messages it{*this};
for(; it; --it)
{
const auto &event_id
const auto &event_idx
{
it.event_id()
it.event_idx()
};
bool match{false};
column(event_id, [&match, &type]
(const string_view &value)
bool match
{
match = value == type;
});
empty(type) // allow empty type to always match and bypass query
};
if(!match)
column(byte_view<string_view>(event_idx), std::nothrow, [&match, &type]
(const string_view &value)
{
match = value == type;
});
if(match)
if(!closure(event_id))
break;
if(!closure(event_idx))
return false;
}
return true;
}
//
@ -380,27 +413,27 @@ ircd::m::room::messages::seek()
bool
ircd::m::room::messages::seek(const event::id &event_id)
{
static constexpr auto idx
{
json::indexof<event, "depth"_>()
};
auto &column
{
dbs::event_column.at(idx)
dbs::event_column.at(json::indexof<event, "depth"_>())
};
const event::idx event_idx
{
event::fetch::index(event_id)
};
uint64_t depth;
column(event_id, [&](const string_view &binary)
column(byte_view<string_view>(event_idx), [&depth]
(const string_view &value)
{
assert(size(binary) == sizeof(depth));
depth = byte_view<uint64_t>(binary);
depth = byte_view<uint64_t>(value);
});
char buf[m::state::KEY_MAX_SZ];
const auto seek_key
{
dbs::room_events_key(buf, room.room_id, depth, event_id)
dbs::room_events_key(buf, room.room_id, depth, event_idx)
};
this->it = dbs::room_events.begin(seek_key);
@ -420,33 +453,40 @@ ircd::m::room::messages::seek(const uint64_t &depth)
return bool(*this);
}
ircd::m::room::messages::operator
const m::event::id &()
ircd::m::event::id::buf
ircd::m::room::messages::event_id()
{
return event_id();
event::id::buf ret;
event::fetch::event_id(this->event_idx(), [&ret]
(const event::id &event_id)
{
ret = event_id;
});
return ret;
}
const ircd::m::event::id &
ircd::m::room::messages::event_id()
const ircd::m::event::idx &
ircd::m::room::messages::event_idx()
{
assert(bool(*this));
const auto &key{it->first};
const auto part{dbs::room_events_key(key)};
_event_id = std::get<1>(part);
return _event_id;
_event_idx = std::get<1>(part);
return _event_idx;
}
const ircd::m::event &
ircd::m::room::messages::fetch()
{
m::seek(_event, event_id());
m::seek(_event, event_idx());
return _event;
}
const ircd::m::event &
ircd::m::room::messages::fetch(std::nothrow_t)
{
if(!m::seek(_event, event_id(), std::nothrow))
if(!m::seek(_event, event_idx(), std::nothrow))
_event = m::event::fetch{};
return _event;
@ -524,12 +564,12 @@ ircd::m::room::state::get(const string_view &type,
const event::closure &closure)
const
{
get(type, state_key, event::id::closure{[&closure]
(const event::id &event_id)
get(type, state_key, event::closure_idx{[&closure]
(const event::idx &event_idx)
{
const event::fetch event
{
event_id
event_idx
};
closure(event);
@ -549,9 +589,44 @@ const try
closure(unquote(event_id));
});
get(type, state_key, event::closure_idx{[&closure]
(const event::idx &idx)
{
event::fetch::event_id(idx, closure);
}});
}
catch(const db::not_found &e)
{
throw m::NOT_FOUND
{
"(%s,%s) in %s :%s",
type,
state_key,
string_view{room_id},
e.what()
};
}
void
ircd::m::room::state::get(const string_view &type,
const string_view &state_key,
const event::closure_idx &closure)
const try
{
if(root_id)
m::state::get(root_id, type, state_key, [&closure]
(const string_view &event_id)
{
closure(event::fetch::index(unquote(event_id)));
});
char key[768];
auto &column{dbs::room_state};
return column(dbs::room_state_key(key, room_id, type, state_key), closure);
column(dbs::room_state_key(key, room_id, type, state_key), [&closure]
(const string_view &value)
{
closure(byte_view<event::idx>(value));
});
}
catch(const db::not_found &e)
{
@ -572,12 +647,12 @@ ircd::m::room::state::get(std::nothrow_t,
const event::closure &closure)
const
{
return get(std::nothrow, type, state_key, event::id::closure{[&closure]
(const event::id &event_id)
return get(std::nothrow, type, state_key, event::closure_idx{[&closure]
(const event::idx &event_idx)
{
const event::fetch event
{
event_id
event_idx, std::nothrow
};
closure(event);
@ -598,9 +673,34 @@ const
closure(unquote(event_id));
});
return get(std::nothrow, type, state_key, event::closure_idx{[&closure]
(const event::idx &idx)
{
event::fetch::event_id(idx, std::nothrow, closure);
}});
}
bool
ircd::m::room::state::get(std::nothrow_t,
const string_view &type,
const string_view &state_key,
const event::closure_idx &closure)
const
{
if(root_id)
return m::state::get(std::nothrow, root_id, type, state_key, [&closure]
(const string_view &event_id)
{
return closure(event::fetch::index(unquote(event_id), std::nothrow));
});
char key[768];
auto &column{dbs::room_state};
return column(dbs::room_state_key(key, room_id, type, state_key), std::nothrow, closure);
return column(dbs::room_state_key(key, room_id, type, state_key), std::nothrow, [&closure]
(const string_view &value)
{
closure(byte_view<event::idx>(value));
});
}
bool
@ -672,10 +772,10 @@ ircd::m::room::state::test(const event::closure_bool &closure)
const
{
event::fetch event;
return test(event::id::closure_bool{[&event, &closure]
(const event::id &event_id)
return test(event::closure_idx_bool{[&event, &closure]
(const event::idx &event_idx)
{
if(seek(event, unquote(event_id), std::nothrow))
if(seek(event, event_idx, std::nothrow))
if(closure(event))
return true;
@ -694,9 +794,34 @@ const
return closure(unquote(event_id));
});
return test(event::closure_idx_bool{[&closure]
(const event::idx &idx)
{
bool ret{false};
event::fetch::event_id(idx, std::nothrow, [&ret, &closure]
(const event::id &id)
{
ret = closure(id);
});
return ret;
}});
}
bool
ircd::m::room::state::test(const event::closure_idx_bool &closure)
const
{
if(root_id)
return m::state::test(root_id, [&closure]
(const json::array &key, const string_view &event_id)
{
return closure(event::fetch::index(unquote(event_id), std::nothrow));
});
auto &column{dbs::room_state};
for(auto it{column.begin(room_id)}; bool(it); ++it)
if(closure(it->second))
if(closure(byte_view<event::idx>(it->second)))
return true;
return false;
@ -708,10 +833,10 @@ ircd::m::room::state::test(const string_view &type,
const
{
event::fetch event;
return test(type, event::id::closure_bool{[&event, &closure]
(const event::id &event_id)
return test(type, event::closure_idx_bool{[&event, &closure]
(const event::idx &event_idx)
{
if(seek(event, unquote(event_id), std::nothrow))
if(seek(event, event_idx, std::nothrow))
if(closure(event))
return true;
@ -731,6 +856,32 @@ const
return closure(unquote(event_id));
});
return test(type, event::closure_idx_bool{[&closure]
(const event::idx &idx)
{
bool ret{false};
event::fetch::event_id(idx, std::nothrow, [&ret, &closure]
(const event::id &id)
{
ret = closure(id);
});
return ret;
}});
}
bool
ircd::m::room::state::test(const string_view &type,
const event::closure_idx_bool &closure)
const
{
if(root_id)
return m::state::test(root_id, type, [&closure]
(const json::array &key, const string_view &event_id)
{
return closure(event::fetch::index(unquote(event_id), std::nothrow));
});
char keybuf[768];
const auto &key
{
@ -741,7 +892,7 @@ const
for(auto it{column.begin(key)}; bool(it); ++it)
if(std::get<0>(dbs::room_state_key(it->first)) == type)
{
if(closure(it->second))
if(closure(byte_view<event::idx>(it->second)))
return true;
}
else break;
@ -794,10 +945,10 @@ ircd::m::room::state::test(const string_view &type,
const
{
event::fetch event;
return test(type, state_key_lb, event::id::closure_bool{[&event, &closure]
(const event::id &event_id)
return test(type, state_key_lb, event::closure_idx_bool{[&event, &closure]
(const event::idx &event_idx)
{
if(seek(event, unquote(event_id), std::nothrow))
if(seek(event, event_idx, std::nothrow))
if(closure(event))
return true;
@ -818,6 +969,33 @@ const
return closure(unquote(event_id));
});
return test(type, state_key_lb, event::closure_idx_bool{[&closure]
(const event::idx &idx)
{
bool ret{false};
event::fetch::event_id(idx, std::nothrow, [&ret, &closure]
(const event::id &id)
{
ret = closure(id);
});
return ret;
}});
}
bool
ircd::m::room::state::test(const string_view &type,
const string_view &state_key_lb,
const event::closure_idx_bool &closure)
const
{
if(root_id)
return m::state::test(root_id, type, state_key_lb, [&closure]
(const json::array &key, const string_view &event_id)
{
return closure(event::fetch::index(unquote(event_id), std::nothrow));
});
char keybuf[768];
const auto &key
{
@ -828,7 +1006,7 @@ const
for(auto it{column.begin(key)}; bool(it); ++it)
if(std::get<0>(dbs::room_state_key(it->first)) == type)
{
if(closure(it->second))
if(closure(byte_view<event::idx>(it->second)))
return true;
}
else break;
@ -841,10 +1019,10 @@ ircd::m::room::state::for_each(const event::closure &closure)
const
{
event::fetch event;
for_each(event::id::closure{[&event, &closure]
(const event::id &event_id)
for_each(event::closure_idx{[&event, &closure]
(const event::idx &event_idx)
{
if(seek(event, event_id, std::nothrow))
if(seek(event, event_idx, std::nothrow))
closure(event);
}});
}
@ -860,9 +1038,27 @@ const
closure(unquote(event_id));
});
for_each(event::closure_idx{[&closure]
(const event::idx &idx)
{
event::fetch::event_id(idx, std::nothrow, closure);
}});
}
void
ircd::m::room::state::for_each(const event::closure_idx &closure)
const
{
if(root_id)
return m::state::for_each(root_id, [&closure]
(const json::array &key, const string_view &event_id)
{
closure(event::fetch::index(unquote(event_id), std::nothrow));
});
auto &column{dbs::room_state};
for(auto it{column.begin(room_id)}; bool(it); ++it)
closure(it->second);
closure(byte_view<event::idx>(it->second));
}
void
@ -871,10 +1067,10 @@ ircd::m::room::state::for_each(const string_view &type,
const
{
event::fetch event;
for_each(type, event::id::closure{[&event, &closure]
(const event::id &event_id)
for_each(type, event::closure_idx{[&event, &closure]
(const event::idx &event_idx)
{
if(seek(event, event_id, std::nothrow))
if(seek(event, event_idx, std::nothrow))
closure(event);
}});
}
@ -891,6 +1087,25 @@ const
closure(unquote(event_id));
});
for_each(type, event::closure_idx{[&closure]
(const event::idx &idx)
{
event::fetch::event_id(idx, std::nothrow, closure);
}});
}
void
ircd::m::room::state::for_each(const string_view &type,
const event::closure_idx &closure)
const
{
if(root_id)
return m::state::for_each(root_id, type, [&closure]
(const json::array &key, const string_view &event_id)
{
closure(event::fetch::index(unquote(event_id), std::nothrow));
});
char keybuf[768];
const auto &key
{
@ -900,7 +1115,7 @@ const
auto &column{dbs::room_state};
for(auto it{column.begin(key)}; bool(it); ++it)
if(std::get<0>(dbs::room_state_key(it->first)) == type)
closure(it->second);
closure(byte_view<event::idx>(it->second));
else
break;
}
@ -912,7 +1127,7 @@ const
{
if(root_id)
return m::state::for_each(root_id, type, [&closure]
(const json::array &key, const string_view &event_id)
(const json::array &key, const string_view &)
{
assert(size(key) >= 2);
closure(unquote(key.at(1)));

View file

@ -450,13 +450,18 @@ ircd::m::vm::_eval_pdu(eval &eval,
++vm::current_sequence
};
m::dbs::write_opts wopts;
wopts.present = opts.present;
wopts.history = opts.history;
wopts.idx = sequence_number;
db::txn::append
{
*eval.txn, dbs::event_seq,
{
db::op::SET,
byte_view<string_view>(sequence_number),
event_id
byte_view<string_view>(sequence_number),
}
};
@ -507,11 +512,8 @@ ircd::m::vm::_eval_pdu(eval &eval,
m::room room{room_id, head};
m::room::state state{room};
m::state::id_buffer new_root_buf;
m::dbs::write_opts wopts;
wopts.root_in = state.root_id;
wopts.root_out = new_root_buf;
wopts.present = opts.present;
wopts.history = opts.history;
const auto new_root
{
dbs::write(*eval.txn, event, wopts)
@ -520,10 +522,7 @@ ircd::m::vm::_eval_pdu(eval &eval,
else if(opts.write)
{
m::state::id_buffer new_root_buf;
m::dbs::write_opts wopts;
wopts.root_out = new_root_buf;
wopts.present = opts.present;
wopts.history = opts.history;
const auto new_root
{
dbs::write(*eval.txn, event, wopts)
@ -553,10 +552,10 @@ ircd::m::vm::events::rfor_each(const uint64_t &start,
const closure_bool &closure)
{
event::fetch event;
return rfor_each(start, id_closure_bool{[&event, &closure]
(const uint64_t &seq, const event::id &event_id)
return rfor_each(start, idx_closure_bool{[&event, &closure]
(const uint64_t &seq, const event::idx &event_idx)
{
if(!seek(event, event_id, std::nothrow))
if(!seek(event, event_idx, std::nothrow))
return true;
return closure(seq, event);
@ -565,7 +564,7 @@ ircd::m::vm::events::rfor_each(const uint64_t &start,
bool
ircd::m::vm::events::rfor_each(const uint64_t &start,
const id_closure_bool &closure)
const idx_closure_bool &closure)
{
auto &column
{
@ -575,7 +574,7 @@ ircd::m::vm::events::rfor_each(const uint64_t &start,
if(start == uint64_t(-1))
{
for(auto it(column.rbegin()); it; ++it)
if(!closure(byte_view<uint64_t>(it->first), it->second))
if(!closure(byte_view<uint64_t>(it->first), byte_view<event::idx>(it->second)))
return false;
return true;
@ -587,7 +586,7 @@ ircd::m::vm::events::rfor_each(const uint64_t &start,
};
for(; it; ++it)
if(!closure(byte_view<uint64_t>(it->first), it->second))
if(!closure(byte_view<uint64_t>(it->first), byte_view<event::idx>(it->second)))
return false;
return true;
@ -598,10 +597,10 @@ ircd::m::vm::events::for_each(const uint64_t &start,
const closure_bool &closure)
{
event::fetch event;
return for_each(start, id_closure_bool{[&event, &closure]
(const uint64_t &seq, const event::id &event_id)
return for_each(start, idx_closure_bool{[&event, &closure]
(const uint64_t &seq, const event::idx &event_idx)
{
if(!seek(event, event_id, std::nothrow))
if(!seek(event, event_idx, std::nothrow))
return true;
return closure(seq, event);
@ -610,7 +609,7 @@ ircd::m::vm::events::for_each(const uint64_t &start,
bool
ircd::m::vm::events::for_each(const uint64_t &start,
const id_closure_bool &closure)
const idx_closure_bool &closure)
{
auto &column
{
@ -625,7 +624,7 @@ ircd::m::vm::events::for_each(const uint64_t &start,
};
for(; it; ++it)
if(!closure(byte_view<uint64_t>(it->first), it->second))
if(!closure(byte_view<uint64_t>(it->first), byte_view<event::idx>(it->second)))
return false;
return true;
@ -650,14 +649,24 @@ ircd::m::vm::sequence(const eval &eval)
}
uint64_t
ircd::m::vm::last_sequence()
ircd::m::vm::last_sequence(id::event::buf &event_id)
{
id::event::buf event_id;
return last_sequence(event_id);
const auto &ret
{
last_sequence()
};
event::fetch::event_id(ret, std::nothrow, [&event_id]
(const event::id &event_id_)
{
event_id = event_id_;
});
return ret;
}
uint64_t
ircd::m::vm::last_sequence(id::event::buf &event_id)
ircd::m::vm::last_sequence()
{
auto &column
{
@ -677,8 +686,12 @@ ircd::m::vm::last_sequence(id::event::buf &event_id)
return 0;
}
event_id = it->second;
return byte_view<uint64_t>(it->first);
const auto &ret
{
byte_view<uint64_t>(it->first)
};
return ret;
}
ircd::string_view