Introduce in-memory transactions for sessions

This commit is contained in:
Fedor Indutny 2021-05-17 11:03:42 -07:00 committed by Scott Nonnenberg
parent 403b3c5fc6
commit 94d2c56ab9
12 changed files with 874 additions and 391 deletions

View file

@ -142,6 +142,7 @@ const dataInterface: ClientInterface = {
createOrUpdateSession,
createOrUpdateSessions,
commitSessionsAndUnprocessed,
getSessionById,
getSessionsById,
bulkAddSessions,
@ -767,6 +768,12 @@ async function createOrUpdateSession(data: SessionType) {
async function createOrUpdateSessions(array: Array<SessionType>) {
await channels.createOrUpdateSessions(array);
}
async function commitSessionsAndUnprocessed(options: {
sessions: Array<SessionType>;
unprocessed: Array<UnprocessedType>;
}) {
await channels.commitSessionsAndUnprocessed(options);
}
async function getSessionById(id: string) {
const session = await channels.getSessionById(id);
@ -1353,22 +1360,14 @@ async function getUnprocessedById(id: string) {
return channels.getUnprocessedById(id);
}
async function saveUnprocessed(
data: UnprocessedType,
{ forceSave }: { forceSave?: boolean } = {}
) {
const id = await channels.saveUnprocessed(_cleanData(data), { forceSave });
async function saveUnprocessed(data: UnprocessedType) {
const id = await channels.saveUnprocessed(_cleanData(data));
return id;
}
async function saveUnprocesseds(
arrayOfUnprocessed: Array<UnprocessedType>,
{ forceSave }: { forceSave?: boolean } = {}
) {
await channels.saveUnprocesseds(_cleanData(arrayOfUnprocessed), {
forceSave,
});
async function saveUnprocesseds(arrayOfUnprocessed: Array<UnprocessedType>) {
await channels.saveUnprocesseds(_cleanData(arrayOfUnprocessed));
}
async function updateUnprocessedAttempts(id: string, attempts: number) {

View file

@ -131,11 +131,11 @@ export type UnprocessedType = {
timestamp: number;
version: number;
attempts: number;
envelope: string;
envelope?: string;
source?: string;
sourceUuid?: string;
sourceDevice?: string;
sourceDevice?: number;
serverTimestamp?: number;
decrypted?: string;
};
@ -188,6 +188,10 @@ export type DataInterface = {
createOrUpdateSession: (data: SessionType) => Promise<void>;
createOrUpdateSessions: (array: Array<SessionType>) => Promise<void>;
commitSessionsAndUnprocessed(options: {
sessions: Array<SessionType>;
unprocessed: Array<UnprocessedType>;
}): Promise<void>;
getSessionById: (id: string) => Promise<SessionType | undefined>;
getSessionsById: (conversationId: string) => Promise<Array<SessionType>>;
bulkAddSessions: (array: Array<SessionType>) => Promise<void>;

View file

@ -133,6 +133,7 @@ const dataInterface: ServerInterface = {
createOrUpdateSession,
createOrUpdateSessions,
commitSessionsAndUnprocessed,
getSessionById,
getSessionsById,
bulkAddSessions,
@ -2217,6 +2218,26 @@ async function createOrUpdateSessions(
})();
}
async function commitSessionsAndUnprocessed({
sessions,
unprocessed,
}: {
sessions: Array<SessionType>;
unprocessed: Array<UnprocessedType>;
}): Promise<void> {
const db = getInstance();
db.transaction(() => {
for (const item of sessions) {
createOrUpdateSession(item);
}
for (const item of unprocessed) {
saveUnprocessedSync(item);
}
})();
}
async function getSessionById(id: string): Promise<SessionType | undefined> {
return getById(SESSIONS_TABLE, id);
}
@ -3948,82 +3969,79 @@ async function getTapToViewMessagesNeedingErase(): Promise<Array<MessageType>> {
return rows.map(row => jsonToObject(row.json));
}
function saveUnprocessedSync(
data: UnprocessedType,
{ forceSave }: { forceSave?: boolean } = {}
): string {
function saveUnprocessedSync(data: UnprocessedType): string {
const db = getInstance();
const { id, timestamp, version, attempts, envelope } = data;
const {
id,
timestamp,
version,
attempts,
envelope,
source,
sourceUuid,
sourceDevice,
serverTimestamp,
decrypted,
} = data;
if (!id) {
throw new Error('saveUnprocessed: id was falsey');
}
if (forceSave) {
prepare(
db,
`
INSERT INTO unprocessed (
id,
timestamp,
version,
attempts,
envelope
) values (
$id,
$timestamp,
$version,
$attempts,
$envelope
);
`
).run({
id,
timestamp,
version,
attempts,
envelope,
});
return id;
}
prepare(
db,
`
UPDATE unprocessed SET
timestamp = $timestamp,
version = $version,
attempts = $attempts,
envelope = $envelope
WHERE id = $id;
INSERT OR REPLACE INTO unprocessed (
id,
timestamp,
version,
attempts,
envelope,
source,
sourceUuid,
sourceDevice,
serverTimestamp,
decrypted
) values (
$id,
$timestamp,
$version,
$attempts,
$envelope,
$source,
$sourceUuid,
$sourceDevice,
$serverTimestamp,
$decrypted
);
`
).run({
id,
timestamp,
version,
attempts,
envelope,
envelope: envelope || null,
source: source || null,
sourceUuid: sourceUuid || null,
sourceDevice: sourceDevice || null,
serverTimestamp: serverTimestamp || null,
decrypted: decrypted || null,
});
return id;
}
async function saveUnprocessed(
data: UnprocessedType,
options: { forceSave?: boolean } = {}
): Promise<string> {
return saveUnprocessedSync(data, options);
async function saveUnprocessed(data: UnprocessedType): Promise<string> {
return saveUnprocessedSync(data);
}
async function saveUnprocesseds(
arrayOfUnprocessed: Array<UnprocessedType>,
{ forceSave }: { forceSave?: boolean } = {}
arrayOfUnprocessed: Array<UnprocessedType>
): Promise<void> {
const db = getInstance();
db.transaction(() => {
for (const unprocessed of arrayOfUnprocessed) {
assertSync(saveUnprocessedSync(unprocessed, { forceSave }));
assertSync(saveUnprocessedSync(unprocessed));
}
})();
}