Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/**
* Any copyright is dedicated to the Public Domain.
*/
/* exported testSteps */
async function testSteps() {
// A constant used to deal with small decrease in usage when transactions are
// transferred from the WAL file back into the original database, also called
// as checkpointing.
const cosmologicalConstant = 35000;
// The maximum number of threads that can be used for database activity at a
// single time.
const maxConnectionThreadCount = 20;
// The length of time that database connections will be held open after all
// transactions have completed before doing idle maintenance.
const connectionIdleMaintenanceMS = 2 * 1000;
const name = "test_connection_idle_maintenance_stop";
const abc = "abcdefghijklmnopqrstuvwxyz";
// IndexedDB on Android does `PRAGMA auto_vacuum = FULL`, so the freelist
// pages are moved to the end of the database file and the database file is
// truncated to remove the freelist pages at every transaction commit.
if (mozinfo.os == "android") {
info("Test disabled on Android for now");
return;
}
info("Setting pref");
Services.prefs.setIntPref(
"dom.indexedDB.connectionIdleMaintenance.pauseOnConnectionThreadMs",
2 * connectionIdleMaintenanceMS
);
info("Forcing only one connection thread to be available");
let done = false;
// Create databases which will continuously keep their connection threads
// busy.
const completePromises = await (async function () {
let promises = [];
for (let index = 0; index < maxConnectionThreadCount - 1; index++) {
const request = indexedDB.open(name + "-" + index, 1);
{
const event = await expectingUpgrade(request);
const database = event.target.result;
const objectStore = database.createObjectStore(name);
objectStore.add("foo", 42);
}
const event = await expectingSuccess(request);
const database = event.target.result;
const transaction = database.transaction(name);
const objectStore = transaction.objectStore(name);
function doWork() {
const request = objectStore.get(42);
request.onsuccess = function () {
if (!done) {
doWork();
}
};
}
doWork();
const promise = new Promise(function (resolve) {
transaction.oncomplete = resolve;
});
promises.push(promise);
}
return promises;
})();
info("Creating database A");
// Create a database which will be used for stopping of the connection idle
// maintenance.
const databaseA = await (async function () {
const request = indexedDB.open(name + "-a", 1);
{
const event = await expectingUpgrade(request);
const database = event.target.result;
database.createObjectStore(name);
}
const event = await expectingSuccess(request);
const database = event.target.result;
return database;
})();
info("Creating database B");
// Create a database for checking of the connection idle maintenance.
{
const request = indexedDB.open(name + "-b", 1);
const event = await expectingUpgrade(request);
const database = event.target.result;
const objectStore = database.createObjectStore(name);
// Add lots of data...
for (let index = 0; index < 10000; index++) {
objectStore.add(abc, index);
}
// And then clear it so that maintenance has some space to reclaim.
objectStore.clear();
await expectingSuccess(request);
}
info("Getting database usage before maintenance");
const databaseUsageBeforeMaintenance = await new Promise(function (resolve) {
getCurrentUsage(function (request) {
resolve(request.result.databaseUsage);
});
});
info("Waiting for maintenance to start");
// This time is a double of connectionIdleMaintenanceMS which should be
// pessimistic enough to work with randomly slowed down threads in the
// chaos mode.
await new Promise(function (resolve) {
do_timeout(2 * connectionIdleMaintenanceMS, resolve);
});
info("Activating database A");
// Activate an open database which should trigger stopping of the connection
// idle maintenance of the database which had a lot of data.
{
const transaction = databaseA.transaction(name);
const objectStore = transaction.objectStore(name);
const request = objectStore.get(42);
await requestSucceeded(request);
}
info("Waiting for maintenance to finish");
// This time is a double of connectionIdleMaintenanceMS which should be
// pessimistic enough to work with randomly slowed down threads in the
// chaos mode.
await new Promise(function (resolve) {
do_timeout(2 * connectionIdleMaintenanceMS, resolve);
});
info("Getting database usage after maintenance");
const databaseUsageAfterMaintenance = await new Promise(function (resolve) {
getCurrentUsage(function (request) {
resolve(request.result.databaseUsage);
});
});
info(
"Database usage before: " +
databaseUsageBeforeMaintenance +
". " +
"Database usage after: " +
databaseUsageAfterMaintenance
);
// Checkpointing done immediately after the maintenance can slightly decrease
// the usage even when the maintenance was stopped very early.
ok(
databaseUsageBeforeMaintenance - databaseUsageAfterMaintenance <
cosmologicalConstant,
"Maintenance did not significantly decrease database usage"
);
done = true;
info("Waiting for transactions to complete");
await Promise.all(completePromises);
}