mirror of
https://github.com/zadam/trilium.git
synced 2025-11-17 02:30:42 +01:00
added basic CLS support with re-entrant transactions
This commit is contained in:
@@ -7,6 +7,7 @@ const dataDir = require('./data_dir');
|
||||
const log = require('./log');
|
||||
const sql = require('./sql');
|
||||
const sync_mutex = require('./sync_mutex');
|
||||
const cls = require('./cls');
|
||||
|
||||
async function regularBackup() {
|
||||
const now = new Date();
|
||||
@@ -64,10 +65,10 @@ if (!fs.existsSync(dataDir.BACKUP_DIR)) {
|
||||
}
|
||||
|
||||
sql.dbReady.then(() => {
|
||||
setInterval(regularBackup, 60 * 60 * 1000);
|
||||
setInterval(cls.wrap(regularBackup), 60 * 60 * 1000);
|
||||
|
||||
// kickoff backup immediately
|
||||
setTimeout(regularBackup, 1000);
|
||||
setTimeout(cls.wrap(regularBackup), 1000);
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
|
||||
16
src/services/cls.js
Normal file
16
src/services/cls.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const clsHooked = require('cls-hooked');
|
||||
const namespace = clsHooked.createNamespace("trilium");
|
||||
|
||||
async function init(callback) {
|
||||
return await namespace.runAndReturn(callback);
|
||||
}
|
||||
|
||||
function wrap(callback) {
|
||||
return async () => await init(callback);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init,
|
||||
wrap,
|
||||
namespace
|
||||
};
|
||||
@@ -5,6 +5,7 @@ const log = require('./log');
|
||||
const messaging = require('./messaging');
|
||||
const sync_mutex = require('./sync_mutex');
|
||||
const utils = require('./utils');
|
||||
const cls = require('./cls');
|
||||
|
||||
async function runCheck(query, errorText, errorList) {
|
||||
utils.assertArguments(query, errorText, errorList);
|
||||
@@ -268,10 +269,10 @@ async function runChecks() {
|
||||
}
|
||||
|
||||
sql.dbReady.then(() => {
|
||||
setInterval(runChecks, 60 * 60 * 1000);
|
||||
setInterval(cls.wrap(runChecks), 60 * 60 * 1000);
|
||||
|
||||
// kickoff backup immediately
|
||||
setTimeout(runChecks, 10000);
|
||||
setTimeout(cls.wrap(runChecks), 10000);
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -262,16 +262,16 @@ async function loadFile(noteId, newNote, dataKey) {
|
||||
await protected_session.decryptNote(dataKey, oldNote);
|
||||
}
|
||||
|
||||
newNote.detail.content = oldNote.content;
|
||||
newNote.content = oldNote.content;
|
||||
}
|
||||
|
||||
async function updateNote(noteId, newNote, dataKey, sourceId) {
|
||||
if (newNote.detail.type === 'file') {
|
||||
if (newNote.type === 'file') {
|
||||
await loadFile(noteId, newNote, dataKey);
|
||||
}
|
||||
|
||||
if (newNote.detail.isProtected) {
|
||||
await protected_session.encryptNote(dataKey, newNote.detail);
|
||||
if (newNote.isProtected) {
|
||||
await protected_session.encryptNote(dataKey, newNote);
|
||||
}
|
||||
|
||||
const labelsMap = await labels.getNoteLabelMap(noteId);
|
||||
@@ -287,7 +287,7 @@ async function updateNote(noteId, newNote, dataKey, sourceId) {
|
||||
"SELECT noteRevisionId FROM note_revisions WHERE noteId = ? AND dateModifiedTo >= ?", [noteId, revisionCutoff]);
|
||||
|
||||
await sql.doInTransaction(async () => {
|
||||
const msSinceDateCreated = now.getTime() - utils.parseDateTime(newNote.detail.dateCreated).getTime();
|
||||
const msSinceDateCreated = now.getTime() - utils.parseDateTime(newNote.dateCreated).getTime();
|
||||
|
||||
if (labelsMap.disable_versioning !== 'true'
|
||||
&& !existingnoteRevisionId
|
||||
@@ -296,14 +296,14 @@ async function updateNote(noteId, newNote, dataKey, sourceId) {
|
||||
await saveNoteRevision(noteId, dataKey, sourceId, nowStr);
|
||||
}
|
||||
|
||||
await saveNoteImages(noteId, newNote.detail.content, sourceId);
|
||||
await saveNoteImages(noteId, newNote.content, sourceId);
|
||||
|
||||
await protectNoteRevisions(noteId, dataKey, newNote.detail.isProtected);
|
||||
await protectNoteRevisions(noteId, dataKey, newNote.isProtected);
|
||||
|
||||
await sql.execute("UPDATE notes SET title = ?, content = ?, isProtected = ?, dateModified = ? WHERE noteId = ?", [
|
||||
newNote.detail.title,
|
||||
newNote.detail.content,
|
||||
newNote.detail.isProtected,
|
||||
newNote.title,
|
||||
newNote.content,
|
||||
newNote.isProtected,
|
||||
nowStr,
|
||||
noteId]);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const script = require('./script');
|
||||
const Repository = require('./repository');
|
||||
const cls = require('./cls');
|
||||
|
||||
const repo = new Repository();
|
||||
|
||||
@@ -20,8 +21,8 @@ async function runNotesWithLabel(runAttrValue) {
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => runNotesWithLabel('backend_startup'), 10 * 1000);
|
||||
setTimeout(cls.wrap(() => runNotesWithLabel('backend_startup')), 10 * 1000);
|
||||
|
||||
setInterval(() => runNotesWithLabel('hourly'), 3600 * 1000);
|
||||
setInterval(cls.wrap(() => runNotesWithLabel('hourly')), 3600 * 1000);
|
||||
|
||||
setInterval(() => runNotesWithLabel('daily'), 24 * 3600 * 1000);
|
||||
setInterval(cls.wrap(() => runNotesWithLabel('daily'), 24 * 3600 * 1000));
|
||||
@@ -1,6 +1,7 @@
|
||||
const utils = require('./utils');
|
||||
const log = require('./log');
|
||||
const sql = require('./sql');
|
||||
const cls = require('./cls');
|
||||
|
||||
async function saveSourceId(sourceId) {
|
||||
await sql.doInTransaction(async () => {
|
||||
@@ -41,7 +42,7 @@ function isLocalSourceId(srcId) {
|
||||
const currentSourceId = createSourceId();
|
||||
|
||||
// this will also refresh source IDs
|
||||
sql.dbReady.then(() => saveSourceId(currentSourceId));
|
||||
sql.dbReady.then(cls.wrap(() => saveSourceId(currentSourceId)));
|
||||
|
||||
function getCurrentSourceId() {
|
||||
return currentSourceId;
|
||||
|
||||
@@ -6,6 +6,7 @@ const fs = require('fs');
|
||||
const sqlite = require('sqlite');
|
||||
const app_info = require('./app_info');
|
||||
const resource_dir = require('./resource_dir');
|
||||
const cls = require('./cls');
|
||||
|
||||
async function createConnection() {
|
||||
return await sqlite.open(dataDir.DOCUMENT_PATH, {Promise});
|
||||
@@ -15,7 +16,7 @@ const dbConnected = createConnection();
|
||||
|
||||
let dbReadyResolve = null;
|
||||
const dbReady = new Promise((resolve, reject) => {
|
||||
dbConnected.then(async db => {
|
||||
dbConnected.then(cls.wrap(async db => {
|
||||
await execute("PRAGMA foreign_keys = ON");
|
||||
|
||||
dbReadyResolve = () => {
|
||||
@@ -65,7 +66,7 @@ const dbReady = new Promise((resolve, reject) => {
|
||||
|
||||
resolve(db);
|
||||
}
|
||||
})
|
||||
}))
|
||||
.catch(e => {
|
||||
console.log("Error connecting to DB.", e);
|
||||
process.exit(1);
|
||||
@@ -191,6 +192,15 @@ let transactionActive = false;
|
||||
let transactionPromise = null;
|
||||
|
||||
async function doInTransaction(func) {
|
||||
if (cls.namespace.get('isInTransaction')) {
|
||||
console.log("Transaction already active");
|
||||
|
||||
return await func();
|
||||
}
|
||||
else {
|
||||
console.log("Starting new transaction");
|
||||
}
|
||||
|
||||
while (transactionActive) {
|
||||
await transactionPromise;
|
||||
}
|
||||
@@ -201,6 +211,8 @@ async function doInTransaction(func) {
|
||||
transactionActive = true;
|
||||
transactionPromise = new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
cls.namespace.set('isInTransaction', true);
|
||||
|
||||
await beginTransaction();
|
||||
|
||||
ret = await func();
|
||||
@@ -219,6 +231,9 @@ async function doInTransaction(func) {
|
||||
|
||||
reject(e);
|
||||
}
|
||||
finally {
|
||||
cls.namespace.set('isInTransaction', false);
|
||||
}
|
||||
});
|
||||
|
||||
if (transactionActive) {
|
||||
|
||||
@@ -15,6 +15,7 @@ const app_info = require('./app_info');
|
||||
const messaging = require('./messaging');
|
||||
const sync_setup = require('./sync_setup');
|
||||
const sync_mutex = require('./sync_mutex');
|
||||
const cls = require('./cls');
|
||||
|
||||
let proxyToggle = true;
|
||||
let syncServerCertificate = null;
|
||||
@@ -347,10 +348,10 @@ sql.dbReady.then(() => {
|
||||
syncServerCertificate = fs.readFileSync(sync_setup.SYNC_CERT_PATH);
|
||||
}
|
||||
|
||||
setInterval(sync, 60000);
|
||||
setInterval(cls.wrap(sync), 60000);
|
||||
|
||||
// kickoff initial sync immediately
|
||||
setTimeout(sync, 1000);
|
||||
setTimeout(cls.wrap(sync), 1000);
|
||||
}
|
||||
else {
|
||||
log.info("Sync server not configured, sync timer not running.")
|
||||
|
||||
Reference in New Issue
Block a user