Disable message insert triggers during backup import
This commit is contained in:
parent
7dced11b57
commit
34ef8dc2c8
8 changed files with 101 additions and 1 deletions
|
@ -374,7 +374,6 @@ export class BackupImportStream extends Writable {
|
||||||
toastType: ToastType.FailedToImportBackup,
|
toastType: ToastType.FailedToImportBackup,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// TODO (DESKTOP-7934): throw in tests if we cannot process a frame
|
|
||||||
} else {
|
} else {
|
||||||
log.info(`${this.logId}: successfully processed all frames.`);
|
log.info(`${this.logId}: successfully processed all frames.`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,6 +305,9 @@ export class BackupsService {
|
||||||
log.info(`importBackup: starting ${backupType}...`);
|
log.info(`importBackup: starting ${backupType}...`);
|
||||||
this.isRunning = 'import';
|
this.isRunning = 'import';
|
||||||
const importStart = Date.now();
|
const importStart = Date.now();
|
||||||
|
|
||||||
|
await DataWriter.disableMessageInsertTriggers();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const importStream = await BackupImportStream.create(backupType);
|
const importStream = await BackupImportStream.create(backupType);
|
||||||
if (backupType === BackupType.Ciphertext) {
|
if (backupType === BackupType.Ciphertext) {
|
||||||
|
@ -397,6 +400,8 @@ export class BackupsService {
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
this.isRunning = false;
|
this.isRunning = false;
|
||||||
|
await DataWriter.enableMessageInsertTriggersAndBackfill();
|
||||||
|
|
||||||
window.IPC.stopTrackingQueryStats({ epochName: 'Backup Import' });
|
window.IPC.stopTrackingQueryStats({ epochName: 'Backup Import' });
|
||||||
if (window.SignalCI) {
|
if (window.SignalCI) {
|
||||||
window.SignalCI.handleEvent('backupImportComplete', {
|
window.SignalCI.handleEvent('backupImportComplete', {
|
||||||
|
|
|
@ -952,6 +952,10 @@ type WritableInterface = {
|
||||||
insertJob(job: Readonly<StoredJob>): void;
|
insertJob(job: Readonly<StoredJob>): void;
|
||||||
deleteJob(id: string): void;
|
deleteJob(id: string): void;
|
||||||
|
|
||||||
|
disableMessageInsertTriggers(): void;
|
||||||
|
enableMessageInsertTriggersAndBackfill(): void;
|
||||||
|
ensureMessageInsertTriggersAreEnabled(): void;
|
||||||
|
|
||||||
processGroupCallRingCancellation(ringId: bigint): void;
|
processGroupCallRingCancellation(ringId: bigint): void;
|
||||||
cleanExpiredGroupCallRingCancellations(): void;
|
cleanExpiredGroupCallRingCancellations(): void;
|
||||||
};
|
};
|
||||||
|
|
|
@ -543,6 +543,10 @@ export const DataWriter: ServerWritableInterface = {
|
||||||
processGroupCallRingCancellation,
|
processGroupCallRingCancellation,
|
||||||
cleanExpiredGroupCallRingCancellations,
|
cleanExpiredGroupCallRingCancellations,
|
||||||
|
|
||||||
|
disableMessageInsertTriggers,
|
||||||
|
enableMessageInsertTriggersAndBackfill,
|
||||||
|
ensureMessageInsertTriggersAreEnabled,
|
||||||
|
|
||||||
// Server-only
|
// Server-only
|
||||||
|
|
||||||
removeKnownStickers,
|
removeKnownStickers,
|
||||||
|
@ -7463,3 +7467,84 @@ function getUnreadEditedMessagesAndMarkRead(
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function disableMessageInsertTriggers(db: WritableDB): void {
|
||||||
|
db.transaction(() => {
|
||||||
|
createOrUpdateItem(db, {
|
||||||
|
id: 'messageInsertTriggersDisabled',
|
||||||
|
value: true,
|
||||||
|
});
|
||||||
|
db.exec('DROP TRIGGER IF EXISTS messages_on_insert;');
|
||||||
|
db.exec('DROP TRIGGER IF EXISTS messages_on_insert_insert_mentions;');
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectMentionsFromMessages = `
|
||||||
|
SELECT messages.id, bodyRanges.value ->> 'mentionAci' as mentionAci,
|
||||||
|
bodyRanges.value ->> 'start' as start,
|
||||||
|
bodyRanges.value ->> 'length' as length
|
||||||
|
FROM messages, json_each(messages.json ->> 'bodyRanges') as bodyRanges
|
||||||
|
WHERE bodyRanges.value ->> 'mentionAci' IS NOT NULL
|
||||||
|
`;
|
||||||
|
|
||||||
|
function enableMessageInsertTriggersAndBackfill(db: WritableDB): void {
|
||||||
|
const createTriggersQuery = `
|
||||||
|
DROP TRIGGER IF EXISTS messages_on_insert;
|
||||||
|
CREATE TRIGGER messages_on_insert AFTER INSERT ON messages
|
||||||
|
WHEN new.isViewOnce IS NOT 1 AND new.storyId IS NULL
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO messages_fts
|
||||||
|
(rowid, body)
|
||||||
|
VALUES
|
||||||
|
(new.rowid, new.body);
|
||||||
|
END;
|
||||||
|
|
||||||
|
DROP TRIGGER IF EXISTS messages_on_insert_insert_mentions;
|
||||||
|
CREATE TRIGGER messages_on_insert_insert_mentions AFTER INSERT ON messages
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO mentions (messageId, mentionAci, start, length)
|
||||||
|
${selectMentionsFromMessages}
|
||||||
|
AND messages.id = new.id;
|
||||||
|
END;
|
||||||
|
`;
|
||||||
|
db.transaction(() => {
|
||||||
|
backfillMentionsTable(db);
|
||||||
|
backfillMessagesFtsTable(db);
|
||||||
|
db.exec(createTriggersQuery);
|
||||||
|
createOrUpdateItem(db, {
|
||||||
|
id: 'messageInsertTriggersDisabled',
|
||||||
|
value: false,
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
function backfillMessagesFtsTable(db: WritableDB): void {
|
||||||
|
db.exec(`
|
||||||
|
DELETE FROM messages_fts;
|
||||||
|
INSERT OR REPLACE INTO messages_fts (rowid, body)
|
||||||
|
SELECT rowid, body
|
||||||
|
FROM messages
|
||||||
|
WHERE isViewOnce IS NOT 1 AND storyId IS NULL;
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function backfillMentionsTable(db: WritableDB): void {
|
||||||
|
db.exec(`
|
||||||
|
DELETE FROM mentions;
|
||||||
|
INSERT INTO mentions (messageId, mentionAci, start, length)
|
||||||
|
${selectMentionsFromMessages};
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureMessageInsertTriggersAreEnabled(db: WritableDB): void {
|
||||||
|
db.transaction(() => {
|
||||||
|
const storedItem = getItemById(db, 'messageInsertTriggersDisabled');
|
||||||
|
const triggersDisabled = storedItem?.value;
|
||||||
|
if (triggersDisabled) {
|
||||||
|
logger.warn(
|
||||||
|
'Message insert triggers were disabled; reenabling and backfilling data'
|
||||||
|
);
|
||||||
|
enableMessageInsertTriggersAndBackfill(db);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ export default function updateToSchemaVersion45(
|
||||||
--- Message insert/update triggers to exclude stories and story replies
|
--- Message insert/update triggers to exclude stories and story replies
|
||||||
|
|
||||||
DROP TRIGGER messages_on_insert;
|
DROP TRIGGER messages_on_insert;
|
||||||
|
-- Note: any changes to this trigger must be reflected in
|
||||||
|
-- Server.ts: enableMessageInsertTriggersAndBackfill
|
||||||
CREATE TRIGGER messages_on_insert AFTER INSERT ON messages
|
CREATE TRIGGER messages_on_insert AFTER INSERT ON messages
|
||||||
WHEN new.isViewOnce IS NOT 1 AND new.storyId IS NULL
|
WHEN new.isViewOnce IS NOT 1 AND new.storyId IS NULL
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
|
@ -35,6 +35,8 @@ export default function updateToSchemaVersion84(
|
||||||
INSERT INTO mentions (messageId, mentionUuid, start, length)
|
INSERT INTO mentions (messageId, mentionUuid, start, length)
|
||||||
${selectMentionsFromMessages};
|
${selectMentionsFromMessages};
|
||||||
|
|
||||||
|
-- Note: any changes to this trigger must be reflected in
|
||||||
|
-- Server.ts: enableMessageInsertTriggersAndBackfill
|
||||||
CREATE TRIGGER messages_on_insert_insert_mentions AFTER INSERT ON messages
|
CREATE TRIGGER messages_on_insert_insert_mentions AFTER INSERT ON messages
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO mentions (messageId, mentionUuid, start, length)
|
INSERT INTO mentions (messageId, mentionUuid, start, length)
|
||||||
|
|
|
@ -105,6 +105,7 @@ import {
|
||||||
updateToSchemaVersion1250,
|
updateToSchemaVersion1250,
|
||||||
version as MAX_VERSION,
|
version as MAX_VERSION,
|
||||||
} from './1250-defunct-call-links-storage';
|
} from './1250-defunct-call-links-storage';
|
||||||
|
import { DataWriter } from '../Server';
|
||||||
|
|
||||||
function updateToSchemaVersion1(
|
function updateToSchemaVersion1(
|
||||||
currentVersion: number,
|
currentVersion: number,
|
||||||
|
@ -2132,6 +2133,7 @@ export function updateSchema(db: WritableDB, logger: LoggerType): void {
|
||||||
runSchemaUpdate(startingVersion, db, logger);
|
runSchemaUpdate(startingVersion, db, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataWriter.ensureMessageInsertTriggersAreEnabled(db);
|
||||||
enableFTS5SecureDelete(db, logger);
|
enableFTS5SecureDelete(db, logger);
|
||||||
|
|
||||||
if (startingVersion !== MAX_VERSION) {
|
if (startingVersion !== MAX_VERSION) {
|
||||||
|
|
1
ts/types/Storage.d.ts
vendored
1
ts/types/Storage.d.ts
vendored
|
@ -152,6 +152,7 @@ export type StorageAccessType = {
|
||||||
backupMediaDownloadPaused: boolean;
|
backupMediaDownloadPaused: boolean;
|
||||||
backupMediaDownloadBannerDismissed: boolean;
|
backupMediaDownloadBannerDismissed: boolean;
|
||||||
backupMediaDownloadIdle: boolean;
|
backupMediaDownloadIdle: boolean;
|
||||||
|
messageInsertTriggersDisabled: boolean;
|
||||||
setBackupMessagesSignatureKey: boolean;
|
setBackupMessagesSignatureKey: boolean;
|
||||||
setBackupMediaSignatureKey: boolean;
|
setBackupMediaSignatureKey: boolean;
|
||||||
lastReceivedAtCounter: number;
|
lastReceivedAtCounter: number;
|
||||||
|
|
Loading…
Reference in a new issue