Show and log progress during the SQLCipher migration
This commit is contained in:
parent
6b78f2582b
commit
1d7987108b
7 changed files with 98 additions and 24 deletions
|
@ -157,6 +157,17 @@
|
||||||
"description":
|
"description":
|
||||||
"Message shown on the loading screen while we are doing application optimizations"
|
"Message shown on the loading screen while we are doing application optimizations"
|
||||||
},
|
},
|
||||||
|
"migratingToSQLCipher": {
|
||||||
|
"message": "Optimizing messages... $status$ complete.",
|
||||||
|
"description":
|
||||||
|
"Message shown on the loading screen while we are doing application optimizations",
|
||||||
|
"placeholders": {
|
||||||
|
"status": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "45/200"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"chooseDirectory": {
|
"chooseDirectory": {
|
||||||
"message": "Choose folder",
|
"message": "Choose folder",
|
||||||
"description": "Button to allow the user to find a folder on disk"
|
"description": "Button to allow the user to find a folder on disk"
|
||||||
|
|
|
@ -319,11 +319,33 @@
|
||||||
await upgradeMessages();
|
await upgradeMessages();
|
||||||
|
|
||||||
const db = await Whisper.Database.open();
|
const db = await Whisper.Database.open();
|
||||||
|
const totalMessages = await MessageDataMigrator.getNumMessages({
|
||||||
|
connection: db,
|
||||||
|
});
|
||||||
|
|
||||||
|
function showMigrationStatus(current) {
|
||||||
|
const status = `${current}/${totalMessages}`;
|
||||||
|
Views.Initialization.setMessage(
|
||||||
|
window.i18n('migratingToSQLCipher', [status])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalMessages) {
|
||||||
|
window.log.info(`About to migrate ${totalMessages} messages`);
|
||||||
|
|
||||||
|
showMigrationStatus(0);
|
||||||
await window.Signal.migrateToSQL({
|
await window.Signal.migrateToSQL({
|
||||||
db,
|
db,
|
||||||
clearStores: Whisper.Database.clearStores,
|
clearStores: Whisper.Database.clearStores,
|
||||||
handleDOMException: Whisper.Database.handleDOMException,
|
handleDOMException: Whisper.Database.handleDOMException,
|
||||||
|
countCallback: count => {
|
||||||
|
window.log.info(`Migration: ${count} messages complete`);
|
||||||
|
showMigrationStatus(count);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Views.Initialization.setMessage(window.i18n('loading'));
|
||||||
|
|
||||||
// Note: We are not invoking the second set of IndexedDB migrations because it is
|
// Note: We are not invoking the second set of IndexedDB migrations because it is
|
||||||
// likely that any future migrations will simply extracting things from IndexedDB.
|
// likely that any future migrations will simply extracting things from IndexedDB.
|
||||||
|
|
|
@ -155,7 +155,6 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.log.info('Merging updated message into collection');
|
|
||||||
existing.merge(message.attributes);
|
existing.merge(message.attributes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ exports.dangerouslyProcessAllWithoutIndex = async ({
|
||||||
// NOTE: Even if we make this async using `then`, requesting `count` on an
|
// NOTE: Even if we make this async using `then`, requesting `count` on an
|
||||||
// IndexedDB store blocks all subsequent transactions, so we might as well
|
// IndexedDB store blocks all subsequent transactions, so we might as well
|
||||||
// explicitly wait for it here:
|
// explicitly wait for it here:
|
||||||
const numTotalMessages = await _getNumMessages({ connection });
|
const numTotalMessages = await exports.getNumMessages({ connection });
|
||||||
|
|
||||||
const migrationStartTime = Date.now();
|
const migrationStartTime = Date.now();
|
||||||
let numCumulativeMessagesProcessed = 0;
|
let numCumulativeMessagesProcessed = 0;
|
||||||
|
@ -366,7 +366,7 @@ const _dangerouslyFetchMessagesRequiringSchemaUpgradeWithoutIndex = ({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const _getNumMessages = async ({ connection } = {}) => {
|
exports.getNumMessages = async ({ connection } = {}) => {
|
||||||
if (!isObject(connection)) {
|
if (!isObject(connection)) {
|
||||||
throw new TypeError("'connection' is required");
|
throw new TypeError("'connection' is required");
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ const {
|
||||||
const {
|
const {
|
||||||
getMessageExportLastIndex,
|
getMessageExportLastIndex,
|
||||||
setMessageExportLastIndex,
|
setMessageExportLastIndex,
|
||||||
|
getMessageExportCount,
|
||||||
|
setMessageExportCount,
|
||||||
getUnprocessedExportLastIndex,
|
getUnprocessedExportLastIndex,
|
||||||
setUnprocessedExportLastIndex,
|
setUnprocessedExportLastIndex,
|
||||||
} = require('./settings');
|
} = require('./settings');
|
||||||
|
@ -18,7 +20,12 @@ module.exports = {
|
||||||
migrateToSQL,
|
migrateToSQL,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function migrateToSQL({ db, clearStores, handleDOMException }) {
|
async function migrateToSQL({
|
||||||
|
db,
|
||||||
|
clearStores,
|
||||||
|
handleDOMException,
|
||||||
|
countCallback,
|
||||||
|
}) {
|
||||||
if (!db) {
|
if (!db) {
|
||||||
throw new Error('Need db for IndexedDB connection!');
|
throw new Error('Need db for IndexedDB connection!');
|
||||||
}
|
}
|
||||||
|
@ -31,7 +38,10 @@ async function migrateToSQL({ db, clearStores, handleDOMException }) {
|
||||||
|
|
||||||
window.log.info('migrateToSQL: start');
|
window.log.info('migrateToSQL: start');
|
||||||
|
|
||||||
let lastIndex = await getMessageExportLastIndex(db);
|
let [lastIndex, doneSoFar] = await Promise.all([
|
||||||
|
getMessageExportLastIndex(db),
|
||||||
|
getMessageExportCount(db),
|
||||||
|
]);
|
||||||
let complete = false;
|
let complete = false;
|
||||||
|
|
||||||
while (!complete) {
|
while (!complete) {
|
||||||
|
@ -48,7 +58,16 @@ async function migrateToSQL({ db, clearStores, handleDOMException }) {
|
||||||
({ complete, lastIndex } = status);
|
({ complete, lastIndex } = status);
|
||||||
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
await setMessageExportLastIndex(db, lastIndex);
|
await Promise.all([
|
||||||
|
setMessageExportCount(db, doneSoFar),
|
||||||
|
setMessageExportLastIndex(db, lastIndex),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const { count } = status;
|
||||||
|
doneSoFar += count;
|
||||||
|
if (countCallback) {
|
||||||
|
countCallback(doneSoFar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
window.log.info('migrateToSQL: migrate of messages complete');
|
window.log.info('migrateToSQL: migrate of messages complete');
|
||||||
|
|
||||||
|
@ -85,7 +104,7 @@ async function migrateStoreToSQLite({
|
||||||
storeName,
|
storeName,
|
||||||
handleDOMException,
|
handleDOMException,
|
||||||
lastIndex = null,
|
lastIndex = null,
|
||||||
batchSize = 20,
|
batchSize = 50,
|
||||||
}) {
|
}) {
|
||||||
if (!db) {
|
if (!db) {
|
||||||
throw new Error('Need db for IndexedDB connection!');
|
throw new Error('Need db for IndexedDB connection!');
|
||||||
|
|
|
@ -4,6 +4,7 @@ const ITEMS_STORE_NAME = 'items';
|
||||||
const LAST_PROCESSED_INDEX_KEY = 'attachmentMigration_lastProcessedIndex';
|
const LAST_PROCESSED_INDEX_KEY = 'attachmentMigration_lastProcessedIndex';
|
||||||
const IS_MIGRATION_COMPLETE_KEY = 'attachmentMigration_isComplete';
|
const IS_MIGRATION_COMPLETE_KEY = 'attachmentMigration_isComplete';
|
||||||
const MESSAGE_LAST_INDEX_KEY = 'sqlMigration_messageLastIndex';
|
const MESSAGE_LAST_INDEX_KEY = 'sqlMigration_messageLastIndex';
|
||||||
|
const MESSAGE_COUNT_KEY = 'sqlMigration_messageCount';
|
||||||
const UNPROCESSED_LAST_INDEX_KEY = 'sqlMigration_unprocessedLastIndex';
|
const UNPROCESSED_LAST_INDEX_KEY = 'sqlMigration_unprocessedLastIndex';
|
||||||
|
|
||||||
// Public API
|
// Public API
|
||||||
|
@ -25,6 +26,10 @@ exports.getMessageExportLastIndex = connection =>
|
||||||
exports._getItem(connection, MESSAGE_LAST_INDEX_KEY);
|
exports._getItem(connection, MESSAGE_LAST_INDEX_KEY);
|
||||||
exports.setMessageExportLastIndex = (connection, lastIndex) =>
|
exports.setMessageExportLastIndex = (connection, lastIndex) =>
|
||||||
exports._setItem(connection, MESSAGE_LAST_INDEX_KEY, lastIndex);
|
exports._setItem(connection, MESSAGE_LAST_INDEX_KEY, lastIndex);
|
||||||
|
exports.getMessageExportCount = connection =>
|
||||||
|
exports._getItem(connection, MESSAGE_COUNT_KEY);
|
||||||
|
exports.setMessageExportCount = (connection, count) =>
|
||||||
|
exports._setItem(connection, MESSAGE_COUNT_KEY, count);
|
||||||
|
|
||||||
exports.getUnprocessedExportLastIndex = connection =>
|
exports.getUnprocessedExportLastIndex = connection =>
|
||||||
exports._getItem(connection, UNPROCESSED_LAST_INDEX_KEY);
|
exports._getItem(connection, UNPROCESSED_LAST_INDEX_KEY);
|
||||||
|
|
|
@ -2,26 +2,44 @@
|
||||||
|
|
||||||
/* global i18n: false */
|
/* global i18n: false */
|
||||||
|
|
||||||
const OPTIMIZATION_MESSAGE_DISPLAY_THRESHOLD = 1000; // milliseconds
|
const DISPLAY_THRESHOLD = 3000; // milliseconds
|
||||||
|
const SELECTOR = '.app-loading-screen .message';
|
||||||
|
|
||||||
const setMessage = () => {
|
let timeout;
|
||||||
const message = document.querySelector('.app-loading-screen .message');
|
let targetString;
|
||||||
if (!message) {
|
let didTimeout = false;
|
||||||
return () => {};
|
|
||||||
|
const clear = () => {
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
}
|
}
|
||||||
message.innerText = i18n('loading');
|
};
|
||||||
|
|
||||||
const optimizingMessageTimeoutId = setTimeout(() => {
|
const setMessage = loadingText => {
|
||||||
const innerMessage = document.querySelector('.app-loading-screen .message');
|
const message = document.querySelector(SELECTOR);
|
||||||
|
if (!message) {
|
||||||
|
return clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetString = loadingText || i18n('optimizingApplication');
|
||||||
|
|
||||||
|
message.innerText = didTimeout ? targetString : i18n('loading');
|
||||||
|
|
||||||
|
if (timeout) {
|
||||||
|
return clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
didTimeout = true;
|
||||||
|
const innerMessage = document.querySelector(SELECTOR);
|
||||||
if (!innerMessage) {
|
if (!innerMessage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
innerMessage.innerText = i18n('optimizingApplication');
|
innerMessage.innerText = targetString;
|
||||||
}, OPTIMIZATION_MESSAGE_DISPLAY_THRESHOLD);
|
}, DISPLAY_THRESHOLD);
|
||||||
|
|
||||||
return () => {
|
return clear;
|
||||||
clearTimeout(optimizingMessageTimeoutId);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue