Speedup startup by caching last message timestamp

The cache is only approximate, i.e. it doesn't skip edits and similar,
but this might be good enough? Also no migration right now.

Speeds up startup by about 5x on my system.

Half the startup time is now loading the powerlevels for each room. We
can probably lazily load those too in the future.
This commit is contained in:
Nicolas Werner 2022-06-15 02:13:17 +02:00
parent 6e1fec1e63
commit ef9ebe3fd3
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
5 changed files with 95 additions and 23 deletions

View file

@ -1570,6 +1570,47 @@ Cache::updateState(const std::string &room, const mtx::responses::StateEvents &s
txn.commit();
}
namespace {
template<typename T>
auto
isMessage(const mtx::events::RoomEvent<T> &e)
-> std::enable_if_t<std::is_same<decltype(e.content.msgtype), std::string>::value, bool>
{
return true;
}
template<typename T>
auto
isMessage(const mtx::events::Event<T> &)
{
return false;
}
template<typename T>
auto
isMessage(const mtx::events::EncryptedEvent<T> &)
{
return true;
}
auto
isMessage(const mtx::events::RoomEvent<mtx::events::msg::CallInvite> &)
{
return true;
}
auto
isMessage(const mtx::events::RoomEvent<mtx::events::msg::CallAnswer> &)
{
return true;
}
auto
isMessage(const mtx::events::RoomEvent<mtx::events::msg::CallHangUp> &)
{
return true;
}
}
void
Cache::saveState(const mtx::responses::Sync &res)
{
@ -1623,6 +1664,25 @@ Cache::saveState(const mtx::responses::Sync &res)
saveTimelineMessages(txn, eventsDb, room.first, room.second.timeline);
RoomInfo updatedInfo;
{
// retrieve the old tags and modification ts
std::string_view data;
if (roomsDb_.get(txn, room.first, data)) {
try {
RoomInfo tmp = json::parse(std::string_view(data.data(), data.size()));
updatedInfo.tags = std::move(tmp.tags);
updatedInfo.approximate_last_modification_ts =
tmp.approximate_last_modification_ts;
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse room info: room_id ({}), {}: {}",
room.first,
std::string(data.data(), data.size()),
e.what());
}
}
}
updatedInfo.name = getRoomName(txn, statesdb, membersdb).toStdString();
updatedInfo.topic = getRoomTopic(txn, statesdb).toStdString();
updatedInfo.avatar_url = getRoomAvatarUrl(txn, statesdb, membersdb).toStdString();
@ -1666,7 +1726,6 @@ Cache::saveState(const mtx::responses::Sync &res)
rooms_with_space_updates.insert(room.first);
}
bool has_new_tags = false;
// Process the account_data associated with this room
if (!room.second.account_data.events.empty()) {
auto accountDataDb = getAccountDataDb(txn, room.first);
@ -1691,7 +1750,8 @@ Cache::saveState(const mtx::responses::Sync &res)
// for tag events
if (std::holds_alternative<AccountDataEvent<account_data::Tags>>(evt)) {
auto tags_evt = std::get<AccountDataEvent<account_data::Tags>>(evt);
has_new_tags = true;
updatedInfo.tags.clear();
for (const auto &tag : tags_evt.content.tags) {
updatedInfo.tags.push_back(tag.first);
}
@ -1704,20 +1764,12 @@ Cache::saveState(const mtx::responses::Sync &res)
}
}
}
if (!has_new_tags) {
// retrieve the old tags, they haven't changed
std::string_view data;
if (roomsDb_.get(txn, room.first, data)) {
try {
RoomInfo tmp = json::parse(std::string_view(data.data(), data.size()));
updatedInfo.tags = tmp.tags;
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse room info: room_id ({}), {}: {}",
room.first,
std::string(data.data(), data.size()),
e.what());
}
}
for (const auto &e : room.second.timeline.events) {
if (!std::visit([](const auto &e) -> bool { return isMessage(e); }, e))
continue;
updatedInfo.approximate_last_modification_ts =
mtx::accessors::origin_server_ts(e).toMSecsSinceEpoch();
}
roomsDb_.put(txn, room.first, json(updatedInfo).dump());
@ -4709,6 +4761,8 @@ to_json(json &j, const RoomInfo &info)
j["join_rule"] = info.join_rule;
j["guest_access"] = info.guest_access;
j["app_l_ts"] = info.approximate_last_modification_ts;
j["notification_count"] = info.notification_count;
j["highlight_count"] = info.highlight_count;
@ -4732,6 +4786,8 @@ from_json(const json &j, RoomInfo &info)
info.join_rule = j.at("join_rule");
info.guest_access = j.at("guest_access");
info.approximate_last_modification_ts = j.value("app_l_ts", 0);
info.notification_count = j.value("notification_count", 0);
info.highlight_count = j.value("highlight_count", 0);