mirror of
https://github.com/abraunegg/onedrive
synced 2024-05-23 08:02:16 +02:00
make sure sqlite checkpointing works by properly finalizing statements (#310)
If an sqlite statement is prepared and reused by using reset again and again, the connection keeps a lock on the database, and checkpointing cannot ensure that transaction from the wal file are carried over into the main database. By preparing the statement every time it is used, the destructor calls finalize and thus the lock is released. Possible impacts during high frequency changes via monitor mode etc might arise.
This commit is contained in:
parent
5d388581b1
commit
2ec6aa3df6
82
src/itemdb.d
82
src/itemdb.d
|
@ -34,11 +34,11 @@ final class ItemDatabase
|
||||||
immutable int itemDatabaseVersion = 7;
|
immutable int itemDatabaseVersion = 7;
|
||||||
|
|
||||||
Database db;
|
Database db;
|
||||||
Statement insertItemStmt;
|
string insertItemStmt;
|
||||||
Statement updateItemStmt;
|
string updateItemStmt;
|
||||||
Statement selectItemByIdStmt;
|
string selectItemByIdStmt;
|
||||||
Statement selectItemByParentIdStmt;
|
string selectItemByParentIdStmt;
|
||||||
Statement deleteItemByIdStmt;
|
string deleteItemByIdStmt;
|
||||||
|
|
||||||
this(const(char)[] filename)
|
this(const(char)[] filename)
|
||||||
{
|
{
|
||||||
|
@ -63,22 +63,22 @@ final class ItemDatabase
|
||||||
db.exec("PRAGMA recursive_triggers = ON");
|
db.exec("PRAGMA recursive_triggers = ON");
|
||||||
db.exec("PRAGMA journal_mode = WAL");
|
db.exec("PRAGMA journal_mode = WAL");
|
||||||
|
|
||||||
insertItemStmt = db.prepare("
|
insertItemStmt = "
|
||||||
INSERT OR REPLACE INTO item (driveId, id, name, type, eTag, cTag, mtime, parentId, crc32Hash, sha1Hash, quickXorHash, remoteDriveId, remoteId)
|
INSERT OR REPLACE INTO item (driveId, id, name, type, eTag, cTag, mtime, parentId, crc32Hash, sha1Hash, quickXorHash, remoteDriveId, remoteId)
|
||||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)
|
||||||
");
|
";
|
||||||
updateItemStmt = db.prepare("
|
updateItemStmt = "
|
||||||
UPDATE item
|
UPDATE item
|
||||||
SET name = ?3, type = ?4, eTag = ?5, cTag = ?6, mtime = ?7, parentId = ?8, crc32Hash = ?9, sha1Hash = ?10, quickXorHash = ?11, remoteDriveId = ?12, remoteId = ?13
|
SET name = ?3, type = ?4, eTag = ?5, cTag = ?6, mtime = ?7, parentId = ?8, crc32Hash = ?9, sha1Hash = ?10, quickXorHash = ?11, remoteDriveId = ?12, remoteId = ?13
|
||||||
WHERE driveId = ?1 AND id = ?2
|
WHERE driveId = ?1 AND id = ?2
|
||||||
");
|
";
|
||||||
selectItemByIdStmt = db.prepare("
|
selectItemByIdStmt = "
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM item
|
FROM item
|
||||||
WHERE driveId = ?1 AND id = ?2
|
WHERE driveId = ?1 AND id = ?2
|
||||||
");
|
";
|
||||||
selectItemByParentIdStmt = db.prepare("SELECT * FROM item WHERE driveId = ? AND parentId = ?");
|
selectItemByParentIdStmt = "SELECT * FROM item WHERE driveId = ? AND parentId = ?";
|
||||||
deleteItemByIdStmt = db.prepare("DELETE FROM item WHERE driveId = ? AND id = ?");
|
deleteItemByIdStmt = "DELETE FROM item WHERE driveId = ? AND id = ?";
|
||||||
}
|
}
|
||||||
|
|
||||||
void createTable()
|
void createTable()
|
||||||
|
@ -111,14 +111,26 @@ final class ItemDatabase
|
||||||
|
|
||||||
void insert(const ref Item item)
|
void insert(const ref Item item)
|
||||||
{
|
{
|
||||||
bindItem(item, insertItemStmt);
|
auto p = db.prepare(insertItemStmt);
|
||||||
insertItemStmt.exec();
|
bindItem(item, p);
|
||||||
|
p.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(const ref Item item)
|
void update(const ref Item item)
|
||||||
{
|
{
|
||||||
bindItem(item, updateItemStmt);
|
auto p = db.prepare(updateItemStmt);
|
||||||
updateItemStmt.exec();
|
bindItem(item, p);
|
||||||
|
p.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_open_statements()
|
||||||
|
{
|
||||||
|
db.dump_open_statements();
|
||||||
|
}
|
||||||
|
|
||||||
|
int db_checkpoint()
|
||||||
|
{
|
||||||
|
return db.db_checkpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void upsert(const ref Item item)
|
void upsert(const ref Item item)
|
||||||
|
@ -127,18 +139,19 @@ final class ItemDatabase
|
||||||
s.bind(1, item.driveId);
|
s.bind(1, item.driveId);
|
||||||
s.bind(2, item.id);
|
s.bind(2, item.id);
|
||||||
auto r = s.exec();
|
auto r = s.exec();
|
||||||
Statement* stmt;
|
Statement stmt;
|
||||||
if (r.front[0] == "0") stmt = &insertItemStmt;
|
if (r.front[0] == "0") stmt = db.prepare(insertItemStmt);
|
||||||
else stmt = &updateItemStmt;
|
else stmt = db.prepare(updateItemStmt);
|
||||||
bindItem(item, *stmt);
|
bindItem(item, stmt);
|
||||||
stmt.exec();
|
stmt.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
Item[] selectChildren(const(char)[] driveId, const(char)[] id)
|
Item[] selectChildren(const(char)[] driveId, const(char)[] id)
|
||||||
{
|
{
|
||||||
selectItemByParentIdStmt.bind(1, driveId);
|
auto p = db.prepare(selectItemByParentIdStmt);
|
||||||
selectItemByParentIdStmt.bind(2, id);
|
p.bind(1, driveId);
|
||||||
auto res = selectItemByParentIdStmt.exec();
|
p.bind(2, id);
|
||||||
|
auto res = p.exec();
|
||||||
Item[] items;
|
Item[] items;
|
||||||
while (!res.empty) {
|
while (!res.empty) {
|
||||||
items ~= buildItem(res);
|
items ~= buildItem(res);
|
||||||
|
@ -149,9 +162,10 @@ final class ItemDatabase
|
||||||
|
|
||||||
bool selectById(const(char)[] driveId, const(char)[] id, out Item item)
|
bool selectById(const(char)[] driveId, const(char)[] id, out Item item)
|
||||||
{
|
{
|
||||||
selectItemByIdStmt.bind(1, driveId);
|
auto p = db.prepare(selectItemByIdStmt);
|
||||||
selectItemByIdStmt.bind(2, id);
|
p.bind(1, driveId);
|
||||||
auto r = selectItemByIdStmt.exec();
|
p.bind(2, id);
|
||||||
|
auto r = p.exec();
|
||||||
if (!r.empty) {
|
if (!r.empty) {
|
||||||
item = buildItem(r);
|
item = buildItem(r);
|
||||||
return true;
|
return true;
|
||||||
|
@ -162,9 +176,10 @@ final class ItemDatabase
|
||||||
// returns if an item id is in the database
|
// returns if an item id is in the database
|
||||||
bool idInLocalDatabase(const(string) driveId, const(string)id)
|
bool idInLocalDatabase(const(string) driveId, const(string)id)
|
||||||
{
|
{
|
||||||
selectItemByIdStmt.bind(1, driveId);
|
auto p = db.prepare(selectItemByIdStmt);
|
||||||
selectItemByIdStmt.bind(2, id);
|
p.bind(1, driveId);
|
||||||
auto r = selectItemByIdStmt.exec();
|
p.bind(2, id);
|
||||||
|
auto r = p.exec();
|
||||||
if (!r.empty) {
|
if (!r.empty) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -218,9 +233,10 @@ final class ItemDatabase
|
||||||
|
|
||||||
void deleteById(const(char)[] driveId, const(char)[] id)
|
void deleteById(const(char)[] driveId, const(char)[] id)
|
||||||
{
|
{
|
||||||
deleteItemByIdStmt.bind(1, driveId);
|
auto p = db.prepare(deleteItemByIdStmt);
|
||||||
deleteItemByIdStmt.bind(2, id);
|
p.bind(1, driveId);
|
||||||
deleteItemByIdStmt.exec();
|
p.bind(2, id);
|
||||||
|
p.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindItem(const ref Item item, ref Statement stmt)
|
private void bindItem(const ref Item item, ref Statement stmt)
|
||||||
|
|
|
@ -492,6 +492,10 @@ int main(string[] args)
|
||||||
if (!downloadOnly) m.update(online);
|
if (!downloadOnly) m.update(online);
|
||||||
auto currTime = MonoTime.currTime();
|
auto currTime = MonoTime.currTime();
|
||||||
if (currTime - lastCheckTime > checkInterval) {
|
if (currTime - lastCheckTime > checkInterval) {
|
||||||
|
// log.logAndNotify("DEBUG trying to create checkpoint");
|
||||||
|
// auto res = itemdb.db_checkpoint();
|
||||||
|
// log.logAndNotify("Checkpoint return: ", res);
|
||||||
|
// itemdb.dump_open_statements();
|
||||||
try {
|
try {
|
||||||
if (!initSyncEngine(sync)) {
|
if (!initSyncEngine(sync)) {
|
||||||
onedrive.http.shutdown();
|
onedrive.http.shutdown();
|
||||||
|
|
16
src/sqlite.d
16
src/sqlite.d
|
@ -46,6 +46,22 @@ struct Database
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int db_checkpoint()
|
||||||
|
{
|
||||||
|
return sqlite3_wal_checkpoint(pDb, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_open_statements()
|
||||||
|
{
|
||||||
|
log.log("Dumpint open statements: \n");
|
||||||
|
auto p = sqlite3_next_stmt(pDb, null);
|
||||||
|
while (p != null) {
|
||||||
|
log.log (" - " ~ ifromStringz(sqlite3_sql(p)) ~ "\n");
|
||||||
|
p = sqlite3_next_stmt(pDb, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void open(const(char)[] filename)
|
void open(const(char)[] filename)
|
||||||
{
|
{
|
||||||
// https://www.sqlite.org/c3ref/open.html
|
// https://www.sqlite.org/c3ref/open.html
|
||||||
|
|
Loading…
Reference in a new issue