Я столкнулся с той же проблемой. Вот как я это решил:
Шаг 1: доступ к базе данных Dnsure осуществляется через набор функций библиотеки, где база данных передается в качестве первого входного параметра.
Шаг 2: При создании объекта базы данных (с помощью new sqlite3.Database('path')
), оберните объект с некоторой дополнительной метаинформацией:
Вот как я завернут мой:
var wrap = { db_obj : new sqlite3.Database('path'), locked : "UNLOCKED", work_queue : [] }
Шаг 3: Создайте функцию, которая будет использоваться для запуска функций db. Если база данных заблокирована, эта функция отложит их выполнение до конца. Я назвал мое «runAsync»:
function runAsync(db, fn, callBack) {
if (db.locked === "LOCKED") {
db.work_queue.push(function() { runAsync(db, fn, callBack); });
return;
}
fn(db,callBack);
}
Мы можем видеть, что эта функция проверяет состояние упакованного объекта БД. Если он заблокирован, мы откладываем выполнение, сохраняя функцию в «рабочей очереди», которая будет выполнена позже (путем выполнения fn()
).
Шаг 4: Создать функцию, которая будет использоваться для запуска БД функции исключительно. Если база данных заблокирована, эта функция отсрочит выполнение до конца, иначе она заблокирует базу данных, запустит ее функцию и затем разблокирует базу данных. Я назвал мое: runAsyncExclusive()
:
function runAsyncExclusive(db, fn, callBack) {
if(db.locked === "LOCKED") {
db.work_queue.push(function() { runAsyncExclusive(db, fn, callBack) });
return;
}
var exclusiveDb = {
db_obj : db.db_obj,
locked : "UNLOCKED",
work_queue : []
};
db.locked = "LOCKED";
fn(exclusiveDb, function(err,res) {
db.locked = "UNLOCKED";
var workItems = db.work_queue;
_.each(workItems, function(fn) { fn(); });
db.work_queue = [];
callBack(err,res);
})
}
Объект exclusiveDb, который передается в функцию позволит монопольный доступ к БД. Этот объект может быть заблокирован, что допускает сколь угодно глубокую вложенную блокировку.
Шаг 5: Настройте библиотеку функций таким образом, что они называют asyncRun()
и asyncRunExclusive()
где это уместно:
function get(db,sql,params,callBack) {
db.get(sql,params,callBack);
}
становится ...
function get(db,sql,params,callBack) {
runAsync(db, function(db,cb) { db.get(sql,params,cb); }, callBack);
}
Вуаля!
(Извините, если это было недостаточно ясно)
Это имеет смысл - спасибо! Я полагаю, что вы используете пару функций runAsync и runAsyncExclusive для реализации таких шаблонов, как multi-reader-vs-single-writer? –
Не похоже на потокобезопасность. Чтение-запись db.locked не выполняется атомарно. Что делать, если два потока одновременно называют runAsyncExclusive? Вы могли бы получить два потока, читающих db.locked === "UNLOCKED" и начать свой бизнес. –
Вы правы в том, что это не потокобезопасно. Это не должно быть проблемой, хотя node.js имеет однопоточную правку? – maambmb