This commit is contained in:
Thenewmanator15 2026-09-26 19:33:10 +01:00 • committed by GitHub
commit 6bdfcd59bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 61 additions and 3 deletions

View file

@ -1213,6 +1213,15 @@ Zotero.DBConnection.prototype.closeDatabase = async function (permanent) {
// potentially bad WAL data into the database file, which might be a valid file that a
// stale WAL file is being incorrectly replayed into.
if (!this._dbIsCorrupt) {
// Refresh statistics for tables whose size changed a lot this session
if (!this.readOnly) {
try {
await this._connection.execute("PRAGMA optimize");
}
catch (e) {
Zotero.logError(e);
}
}
try {
Zotero.debug("PRAGMA wal_checkpoint(TRUNCATE)");
await this._connection.execute("PRAGMA wal_checkpoint(TRUNCATE)");
@ -1664,9 +1673,11 @@ Zotero.DBConnection.prototype._openConnectionAsync = async function () {
}
}
// Set page cache size to 8MB
// Set page cache size to 64MB. Pages are allocated only as they're read,
// so small databases don't use it all, but loading a library larger than
// the cache re-reads most pages from disk for every data type.
let pageSize = await this.valueQueryAsync("PRAGMA page_size");
let cacheSize = 8192000 / pageSize;
let cacheSize = 65536000 / pageSize;
await this.queryAsync("PRAGMA cache_size=" + cacheSize);
// Enable foreign key checks
@ -1702,7 +1713,22 @@ Zotero.DBConnection.prototype._openConnectionAsync = async function () {
throw error;
}
}
// Gather query planner statistics for any table that needs them. Without them,
// SQLite reads every item through the items(libraryID, key) index instead of
// scanning the table, which is several times slower for a large library. After
// the first run, this is a no-op unless a table has grown or shrunk a lot.
// Use _connection.execute() directly, since an error here shouldn't start
// corruption handling -- the next real query will report a corrupt database.
if (!this.readOnly) {
try {
await this._connection.execute("PRAGMA optimize=0x10002");
}
catch (e) {
Zotero.logError(e);
}
}
// Register idle observer for DB backup
if (!this._idleObserverScheduled) {
this._idleObserverScheduled = true;

View file

@ -830,6 +830,38 @@ describe("Zotero.DB", function () {
assert.isFalse(db.readOnly);
await db.closeDatabase();
});
it("should set a 64MB page cache", async function () {
var pageSize = await Zotero.DB.valueQueryAsync("PRAGMA page_size");
assert.equal(await Zotero.DB.valueQueryAsync("PRAGMA cache_size"), 65536000 / pageSize);
});
it("should gather query planner statistics", async function () {
let dir = await getTempDirectory();
let dbPath = PathUtils.join(dir, 'test.sqlite');
let db = new Zotero.DBConnection(dbPath);
await db.queryAsync("CREATE TABLE foo (a INT, b INT)");
await db.queryAsync("CREATE INDEX foo_a ON foo(a)");
await db.executeTransaction(async function () {
for (let i = 0; i < 1000; i++) {
await db.queryAsync("INSERT INTO foo VALUES (?, ?)", [i % 10, i]);
}
});
await db.closeDatabase();
// Open through internal initialization
db._externalDB = false;
try {
await db.queryAsync("SELECT COUNT(*) FROM foo");
assert.isAbove(
await db.valueQueryAsync("SELECT COUNT(*) FROM sqlite_stat1 WHERE tbl='foo'"),
0
);
}
finally {
await db.closeDatabase();
}
});
});