Skip to content

Commit

Permalink
SQL: Batch save, using transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
benbucksch committed Nov 28, 2024
1 parent 65c8fc3 commit e40cc57
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 22 deletions.
24 changes: 5 additions & 19 deletions app/logic/Mail/IMAP/IMAPFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,29 +373,15 @@ export class IMAPFolder extends Folder {

/** Save headers of newly discovered emails */
protected async saveNewMsgs(msgs: Collection<IMAPEMail>) {
// Saving message headers is so slow and expensive
// that it drags down the whole app.
// It's far faster to re-download the headers from the server.
// Disable it for now, until we can save faster, e.g. as batches.
// Saving message headers is slow and expensive,
// and it drags down the whole app.
// It's faster to re-download the headers from the server.
// Disable saving only message headers for now.
// We will still save the completely downloaded emails, in
// `downloadMessages()` -> `msg.saveCompleteMessage()`
return;
await this.saveNewMsgsDirectly(msgs);
this.saveNewMsgsDirectly(msgs)
.catch(this.account.errorCallback);
}

protected async saveNewMsgsDirectly(msgs: Collection<IMAPEMail>) {
let startTime = Date.now();
for (let email of msgs) {
try {
if (email.subject) {
await this.storage.saveMessage(email);
}
} catch (ex) {
this.account.errorCallback(ex);
}
}
await this.storage.saveMessages(msgs);
let saveTime = Date.now() - startTime;
console.log(" Saved", msgs.length, "msgs in", saveTime, "ms =", saveTime / msgs.length, "ms/msg");
}
Expand Down
1 change: 1 addition & 0 deletions app/logic/Mail/MailAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ export interface MailAccountStorage {
readMessageWritableProps(email: EMail): Promise<void>;
readMessageBody(email: EMail): Promise<void>;
saveMessage(email: EMail): Promise<void>;
saveMessages(emails: Collection<EMail>): Promise<void>;
saveMessageWritableProps(email: EMail): Promise<void>;
saveMessageTags(email: EMail): Promise<void>;
deleteMessage(email: EMail): Promise<void>;
Expand Down
24 changes: 22 additions & 2 deletions app/logic/Mail/SQL/SQLEMail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import { Attachment, ContentDisposition } from "../Attachment";
import { getTagByName, Tag } from "../Tag";
import { JSONEMail } from "../JSON/JSONEMail";
import { getDatabase } from "./SQLDatabase";
import { assert, fileExtensionForMIMEType } from "../../util/util";
import { ArrayColl } from "svelte-collections";
import { sanitize } from "../../../../lib/util/sanitizeDatatypes";
import { Lock } from "../../util/Lock";
import { assert, fileExtensionForMIMEType } from "../../util/util";
import { ArrayColl, Collection } from "svelte-collections";
import sql from "../../../../lib/rs-sqlite";

export class SQLEMail {
Expand Down Expand Up @@ -212,6 +213,25 @@ export class SQLEMail {
)`);
}

protected static transactionLock = new Lock();

static async saveMultiple(emails: Collection<EMail>) {
let lock = await this.transactionLock.lock();
try {
await (await getDatabase()).run(sql`BEGIN TRANSACTION`);
for (let email of emails) {
if (!email.subject) {
continue;
}
await this.save(email);
}
await (await getDatabase()).run(sql`END TRANSACTION`);
} finally {
lock.release();
}
}


static async read(dbID: number, email: EMail, row?: any, recipientRows?: any[], attachmentRows?: any[], tagRows?: any[]): Promise<EMail> {
if (!row) {
// <copied to="readAll()" />
Expand Down
4 changes: 3 additions & 1 deletion app/logic/Mail/SQL/SQLMailStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { SQLEMail } from "./SQLEMail";
import type { Folder } from "../Folder";
import { SQLFolder } from "./SQLFolder";
import type { Collection } from "svelte-collections";
import { backgroundError } from "../../../frontend/Util/error";

export class SQLMailStorage implements MailAccountStorage {
async saveAccount(account: MailAccount): Promise<void> {
Expand Down Expand Up @@ -46,6 +45,9 @@ export class SQLMailStorage implements MailAccountStorage {
async saveMessage(email: EMail): Promise<void> {
await SQLEMail.save(email);
}
async saveMessages(emails: Collection<EMail>): Promise<void> {
await SQLEMail.saveMultiple(emails);
}
async saveMessageWritableProps(email: EMail): Promise<void> {
await SQLEMail.saveWritableProps(email);
}
Expand Down

0 comments on commit e40cc57

Please sign in to comment.