Skip to content
Snippets Groups Projects
Verified Commit 676a6506 authored by Nicolas Werner's avatar Nicolas Werner
Browse files

Speedup sending encrypted messages after metasync was reenabled

Calling fsync everytime we save to the db is slow, which is actually
fairly noticeable in some larger E2EE rooms. Speed that up slightly by
batching the olm session persisting.
parent ee1a2196
No related branches found
No related tags found
No related merge requests found
...@@ -912,6 +912,29 @@ Cache::getMegolmSessionData(const MegolmSessionIndex &index) ...@@ -912,6 +912,29 @@ Cache::getMegolmSessionData(const MegolmSessionIndex &index)
// OLM sessions. // OLM sessions.
// //
void
Cache::saveOlmSessions(std::vector<std::pair<std::string, mtx::crypto::OlmSessionPtr>> sessions,
uint64_t timestamp)
{
using namespace mtx::crypto;
auto txn = lmdb::txn::begin(env_);
for (const auto &[curve25519, session] : sessions) {
auto db = getOlmSessionsDb(txn, curve25519);
const auto pickled = pickle<SessionObject>(session.get(), pickle_secret_);
const auto session_id = mtx::crypto::session_id(session.get());
StoredOlmSession stored_session;
stored_session.pickled_session = pickled;
stored_session.last_message_ts = timestamp;
db.put(txn, session_id, nlohmann::json(stored_session).dump());
}
txn.commit();
}
void void
Cache::saveOlmSession(const std::string &curve25519, Cache::saveOlmSession(const std::string &curve25519,
mtx::crypto::OlmSessionPtr session, mtx::crypto::OlmSessionPtr session,
......
...@@ -277,6 +277,8 @@ public: ...@@ -277,6 +277,8 @@ public:
void saveOlmSession(const std::string &curve25519, void saveOlmSession(const std::string &curve25519,
mtx::crypto::OlmSessionPtr session, mtx::crypto::OlmSessionPtr session,
uint64_t timestamp); uint64_t timestamp);
void saveOlmSessions(std::vector<std::pair<std::string, mtx::crypto::OlmSessionPtr>> sessions,
uint64_t timestamp);
std::vector<std::string> getOlmSessions(const std::string &curve25519); std::vector<std::string> getOlmSessions(const std::string &curve25519);
std::optional<mtx::crypto::OlmSessionPtr> std::optional<mtx::crypto::OlmSessionPtr>
getOlmSession(const std::string &curve25519, const std::string &session_id); getOlmSession(const std::string &curve25519, const std::string &session_id);
......
...@@ -1299,78 +1299,83 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s ...@@ -1299,78 +1299,83 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s
auto our_curve = olm::client()->identity_keys().curve25519; auto our_curve = olm::client()->identity_keys().curve25519;
for (const auto &[user, devices] : targets) { {
auto deviceKeys = cache::client()->userKeys(user); auto currentTime = QDateTime::currentSecsSinceEpoch();
std::vector<std::pair<std::string, mtx::crypto::OlmSessionPtr>> sessionsToPersist;
// no keys for user, query them for (const auto &[user, devices] : targets) {
if (!deviceKeys) { auto deviceKeys = cache::client()->userKeys(user);
keysToQuery[user] = devices;
continue;
}
auto deviceTargets = devices; // no keys for user, query them
if (devices.empty()) { if (!deviceKeys) {
deviceTargets.clear(); keysToQuery[user] = devices;
deviceTargets.reserve(deviceKeys->device_keys.size()); continue;
for (const auto &[device, keys] : deviceKeys->device_keys) {
(void)keys;
deviceTargets.push_back(device);
} }
}
for (const auto &device : deviceTargets) { auto deviceTargets = devices;
if (!deviceKeys->device_keys.count(device)) { if (devices.empty()) {
keysToQuery[user] = {}; deviceTargets.clear();
break; deviceTargets.reserve(deviceKeys->device_keys.size());
for (const auto &[device, keys] : deviceKeys->device_keys) {
(void)keys;
deviceTargets.push_back(device);
}
} }
auto d = deviceKeys->device_keys.at(device); for (const auto &device : deviceTargets) {
if (!deviceKeys->device_keys.count(device)) {
keysToQuery[user] = {};
break;
}
if (!d.keys.count("curve25519:" + device) || !d.keys.count("ed25519:" + device)) { const auto &d = deviceKeys->device_keys.at(device);
nhlog::crypto()->warn("Skipping device {} since it has no keys!", device);
continue;
}
auto device_curve = d.keys.at("curve25519:" + device); if (!d.keys.count("curve25519:" + device) || !d.keys.count("ed25519:" + device)) {
if (device_curve == our_curve) { nhlog::crypto()->warn("Skipping device {} since it has no keys!", device);
nhlog::crypto()->warn("Skipping our own device, since sending " continue;
"ourselves olm messages makes no sense."); }
continue;
}
auto session = cache::getLatestOlmSession(device_curve); auto device_curve = d.keys.at("curve25519:" + device);
if (!session || force_new_session) { if (device_curve == our_curve) {
auto currentTime = QDateTime::currentSecsSinceEpoch(); nhlog::crypto()->warn("Skipping our own device, since sending "
if (rateLimit.value(QPair(user, device)) + 60 * 60 * 10 < currentTime) { "ourselves olm messages makes no sense.");
claims.one_time_keys[user][device] = mtx::crypto::SIGNED_CURVE25519; continue;
pks[user][device].ed25519 = d.keys.at("ed25519:" + device); }
pks[user][device].curve25519 = d.keys.at("curve25519:" + device);
rateLimit.insert(QPair(user, device), currentTime); auto session = cache::getLatestOlmSession(device_curve);
} else { if (!session || force_new_session) {
nhlog::crypto()->warn("Not creating new session with {}:{} " if (rateLimit.value(QPair(user, device)) + 60 * 60 * 10 < currentTime) {
"because of rate limit", claims.one_time_keys[user][device] = mtx::crypto::SIGNED_CURVE25519;
user, pks[user][device].ed25519 = d.keys.at("ed25519:" + device);
device); pks[user][device].curve25519 = d.keys.at("curve25519:" + device);
rateLimit.insert(QPair(user, device), currentTime);
} else {
nhlog::crypto()->warn("Not creating new session with {}:{} "
"because of rate limit",
user,
device);
}
continue;
} }
continue;
}
messages[mtx::identifiers::parse<mtx::identifiers::User>(user)][device] = messages[mtx::identifiers::parse<mtx::identifiers::User>(user)][device] =
olm::client() olm::client()
->create_olm_encrypted_content(session->get(), ->create_olm_encrypted_content(session->get(),
ev_json, ev_json,
UserId(user), UserId(user),
d.keys.at("ed25519:" + device), d.keys.at("ed25519:" + device),
device_curve) device_curve)
.get<mtx::events::msg::OlmEncrypted>(); .get<mtx::events::msg::OlmEncrypted>();
sessionsToPersist.emplace_back(d.keys.at("curve25519:" + device),
std::move(*session));
}
}
if (!sessionsToPersist.empty()) {
try { try {
nhlog::crypto()->debug("Updated olm session: {}", nhlog::crypto()->debug("Updated olm sessions: {}", sessionsToPersist.size());
mtx::crypto::session_id(session->get())); cache::client()->saveOlmSessions(std::move(sessionsToPersist), currentTime);
cache::saveOlmSession(d.keys.at("curve25519:" + device),
std::move(*session),
QDateTime::currentMSecsSinceEpoch());
} catch (const lmdb::error &e) { } catch (const lmdb::error &e) {
nhlog::db()->critical("failed to save outbound olm session: {}", e.what()); nhlog::db()->critical("failed to save outbound olm session: {}", e.what());
} catch (const mtx::crypto::olm_exception &e) { } catch (const mtx::crypto::olm_exception &e) {
...@@ -1395,6 +1400,9 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s ...@@ -1395,6 +1400,9 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s
mtx::http::RequestErr) { mtx::http::RequestErr) {
std::map<mtx::identifiers::User, std::map<std::string, mtx::events::msg::OlmEncrypted>> std::map<mtx::identifiers::User, std::map<std::string, mtx::events::msg::OlmEncrypted>>
messages; messages;
auto currentTime = QDateTime::currentSecsSinceEpoch();
std::vector<std::pair<std::string, mtx::crypto::OlmSessionPtr>> sessionsToPersist;
for (const auto &[user_id, retrieved_devices] : res.one_time_keys) { for (const auto &[user_id, retrieved_devices] : res.one_time_keys) {
nhlog::net()->debug("claimed keys for {}", user_id); nhlog::net()->debug("claimed keys for {}", user_id);
if (retrieved_devices.size() == 0) { if (retrieved_devices.size() == 0) {
...@@ -1440,21 +1448,24 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s ...@@ -1440,21 +1448,24 @@ send_encrypted_to_device_messages(const std::map<std::string, std::vector<std::s
session.get(), ev_json, UserId(user_id), sign_key, id_key) session.get(), ev_json, UserId(user_id), sign_key, id_key)
.get<mtx::events::msg::OlmEncrypted>(); .get<mtx::events::msg::OlmEncrypted>();
try { sessionsToPersist.emplace_back(id_key, std::move(session));
nhlog::crypto()->debug("Updated olm session: {}",
mtx::crypto::session_id(session.get()));
cache::saveOlmSession(
id_key, std::move(session), QDateTime::currentMSecsSinceEpoch());
} catch (const lmdb::error &e) {
nhlog::db()->critical("failed to save outbound olm session: {}", e.what());
} catch (const mtx::crypto::olm_exception &e) {
nhlog::crypto()->critical("failed to pickle outbound olm session: {}",
e.what());
}
} }
nhlog::net()->info("send_to_device: {}", user_id); nhlog::net()->info("send_to_device: {}", user_id);
} }
if (!sessionsToPersist.empty()) {
try {
nhlog::crypto()->debug("Updated (new) olm sessions: {}",
sessionsToPersist.size());
cache::client()->saveOlmSessions(std::move(sessionsToPersist), currentTime);
} catch (const lmdb::error &e) {
nhlog::db()->critical("failed to save outbound olm session: {}", e.what());
} catch (const mtx::crypto::olm_exception &e) {
nhlog::crypto()->critical("failed to pickle outbound olm session: {}",
e.what());
}
}
if (!messages.empty()) if (!messages.empty())
http::client()->send_to_device<mtx::events::msg::OlmEncrypted>( http::client()->send_to_device<mtx::events::msg::OlmEncrypted>(
http::client()->generate_txn_id(), messages, [](mtx::http::RequestErr err) { http::client()->generate_txn_id(), messages, [](mtx::http::RequestErr err) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment