ssb: Faster loads around the profile page. An experiment with caching SQL queries, and make one query just plain faster.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 8m53s

This commit is contained in:
2025-11-16 14:20:26 -05:00
parent aea4a14a62
commit 35f374047a
3 changed files with 44 additions and 11 deletions

View File

@@ -2,6 +2,7 @@ import * as tfrpc from '/tfrpc.js';
let g_database;
let g_hash;
let g_sql_cache = {};
tfrpc.register(async function localStorageGet(key) {
return app.localStorageGet(key);
@@ -51,14 +52,38 @@ tfrpc.register(async function connect(token) {
tfrpc.register(async function closeConnection(id) {
await ssb.closeConnection(id);
});
tfrpc.register(async function query(sql, args) {
tfrpc.register(async function query(sql, args, options) {
let start = new Date();
let result = [];
await ssb.sqlAsync(sql, args, function callback(row) {
result.push(row);
});
let key = options?.cacheable ? JSON.stringify([sql, args]) : undefined;
let entry = key ? g_sql_cache[key] : undefined;
const k_ideal_count = 64;
if (entry) {
result = entry.result;
} else {
await ssb.sqlAsync(sql, args, function callback(row) {
result.push(row);
});
if (key) {
g_sql_cache[key] = {
result: result,
time: new Date().valueOf(),
};
if (Object.keys(g_sql_cache).length > k_ideal_count * 2) {
let aged = Object.entries(g_sql_cache).map(([k, v]) => [v.time, k]);
aged.sort();
for (let i = 0; i < aged.length / 2; i++) {
delete g_sql_cache[aged[i][1]];
}
}
}
}
let end = new Date();
print((end - start) / 1000, sql.replaceAll(/\s+/g, ' ').trim());
print(
(end - start) / 1000,
entry ? 'from cache' : 'from db',
sql.replaceAll(/\s+/g, ' ').trim()
);
return result;
});
tfrpc.register(async function appendMessage(id, message) {

View File

@@ -37,16 +37,22 @@ class TfProfileElement extends LitElement {
this.following = undefined;
this.blocking = undefined;
let latest = (
await tfrpc.rpc.query('SELECT MAX(rowid) AS latest FROM messages')
)[0].latest;
let result = await tfrpc.rpc.query(
`
SELECT json_extract(content, '$.following') AS following
FROM messages WHERE author = ? AND
json_extract(content, '$.type') = 'contact' AND
json_extract(content, '$.contact') = ? AND
following IS NOT NULL
following IS NOT NULL AND
messages.rowid <= ?
ORDER BY sequence DESC LIMIT 1
`,
[this.whoami, this.id]
[this.whoami, this.id, latest],
{cacheable: true}
);
this.following = result?.[0]?.following ?? false;
result = await tfrpc.rpc.query(
@@ -55,10 +61,12 @@ class TfProfileElement extends LitElement {
FROM messages WHERE author = ? AND
json_extract(content, '$.type') = 'contact' AND
json_extract(content, '$.contact') = ? AND
blocking IS NOT NULL
blocking IS NOT NULL AND
messages.rowid <= ?
ORDER BY sequence DESC LIMIT 1
`,
[this.whoami, this.id]
[this.whoami, this.id, latest],
{cacheable: true}
);
this.blocking = result?.[0]?.blocking ?? false;
}
@@ -238,7 +246,7 @@ class TfProfileElement extends LitElement {
let profile = this.users[this.id] || {};
tfrpc.rpc
.query(
`SELECT SUM(LENGTH(content)) AS size, MAX(sequence) AS sequence FROM messages WHERE author = ?`,
`SELECT size AS size, max_sequence AS sequence FROM messages_stats WHERE author = ?`,
[this.id]
)
.then(function (result) {