Cache SQL statements used during startup

This commit is contained in:
Fedor Indutny 2021-04-05 16:13:21 -07:00 committed by Josh Perez
parent 7ae25590e6
commit b9248e04ed

View file

@ -11,7 +11,7 @@
import { join } from 'path'; import { join } from 'path';
import mkdirp from 'mkdirp'; import mkdirp from 'mkdirp';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
import SQL, { Database } from 'better-sqlite3'; import SQL, { Database, Statement } from 'better-sqlite3';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
import { import {
@ -214,6 +214,26 @@ const dataInterface: ServerInterface = {
}; };
export default dataInterface; export default dataInterface;
type DatabaseQueryCache = Map<string, Statement<any[]>>;
const statementCache = new WeakMap<Database, DatabaseQueryCache>();
function prepare(db: Database, query: string): Statement<Query> {
let dbCache = statementCache.get(db);
if (!dbCache) {
dbCache = new Map();
statementCache.set(db, dbCache);
}
let result = dbCache.get(query);
if (!result) {
result = db.prepare(query);
dbCache.set(query, result);
}
return result;
}
function objectToJSON(data: any) { function objectToJSON(data: any) {
return JSON.stringify(data); return JSON.stringify(data);
} }
@ -1756,7 +1776,8 @@ async function createOrUpdateSession(data: SessionType): Promise<void> {
); );
} }
db.prepare<Query>( prepare(
db,
` `
INSERT OR REPLACE INTO sessions ( INSERT OR REPLACE INTO sessions (
id, id,
@ -2071,7 +2092,8 @@ async function updateConversation(data: ConversationType): Promise<void> {
? members.join(' ') ? members.join(' ')
: null; : null;
db.prepare<Query>( prepare(
db,
` `
UPDATE conversations SET UPDATE conversations SET
json = $json, json = $json,
@ -2407,7 +2429,8 @@ async function saveMessage(
}; };
if (id && !forceSave) { if (id && !forceSave) {
db.prepare<Query>( prepare(
db,
` `
UPDATE messages SET UPDATE messages SET
id = $id, id = $id,
@ -2467,7 +2490,8 @@ async function saveMessage(
id, id,
}); });
db.prepare<Query>( prepare(
db,
` `
INSERT INTO messages ( INSERT INTO messages (
id, id,
@ -2624,21 +2648,20 @@ async function getMessageBySender({
sent_at: number; sent_at: number;
}): Promise<Array<MessageType>> { }): Promise<Array<MessageType>> {
const db = getInstance(); const db = getInstance();
const rows: JSONRows = db const rows: JSONRows = prepare(
.prepare<Query>( db,
` `
SELECT json FROM messages WHERE SELECT json FROM messages WHERE
(source = $source OR sourceUuid = $sourceUuid) AND (source = $source OR sourceUuid = $sourceUuid) AND
sourceDevice = $sourceDevice AND sourceDevice = $sourceDevice AND
sent_at = $sent_at; sent_at = $sent_at;
` `
) ).all({
.all({ source,
source, sourceUuid,
sourceUuid, sourceDevice,
sourceDevice, sent_at,
sent_at, });
});
return rows.map(row => jsonToObject(row.json)); return rows.map(row => jsonToObject(row.json));
} }
@ -3154,7 +3177,8 @@ async function saveUnprocessed(
} }
if (forceSave) { if (forceSave) {
db.prepare<Query>( prepare(
db,
` `
INSERT INTO unprocessed ( INSERT INTO unprocessed (
id, id,
@ -3181,7 +3205,8 @@ async function saveUnprocessed(
return id; return id;
} }
db.prepare<Query>( prepare(
db,
` `
UPDATE unprocessed SET UPDATE unprocessed SET
timestamp = $timestamp, timestamp = $timestamp,
@ -3237,7 +3262,8 @@ async function updateUnprocessedWithData(
const db = getInstance(); const db = getInstance();
const { source, sourceUuid, sourceDevice, serverTimestamp, decrypted } = data; const { source, sourceUuid, sourceDevice, serverTimestamp, decrypted } = data;
db.prepare<Query>( prepare(
db,
` `
UPDATE unprocessed SET UPDATE unprocessed SET
source = $source, source = $source,
@ -3311,7 +3337,7 @@ async function removeUnprocessed(id: string | Array<string>): Promise<void> {
const db = getInstance(); const db = getInstance();
if (!Array.isArray(id)) { if (!Array.isArray(id)) {
db.prepare<Query>('DELETE FROM unprocessed WHERE id = id;').run({ id }); prepare(db, 'DELETE FROM unprocessed WHERE id = id;').run({ id });
return; return;
} }