Bug 581606 - Avoid sqlite fragmentation via SQLITE_FCNTL_CHUNK_SIZE r=asuth sr=shaver a=b6

This commit is contained in:
Taras Glek 2010-09-01 20:35:46 -05:00
parent ca8bdb6f3c
commit 96bd2a13d9
6 changed files with 80 additions and 1 deletions

View File

@ -735,6 +735,9 @@ nsCookieService::TryInitDB(PRBool aDeleteExistingDB)
rv = mStorageService->OpenDatabase(cookieFile, getter_AddRefs(mDBState->dbConn));
NS_ENSURE_SUCCESS(rv, rv);
// Grow cookie db in 512KB increments
mDBState->dbConn->SetGrowthIncrement(512 * 1024, EmptyCString());
PRBool tableExists = PR_FALSE;
mDBState->dbConn->TableExists(NS_LITERAL_CSTRING("moz_cookies"), &tableExists);
if (!tableExists) {

View File

@ -61,7 +61,7 @@ interface nsIFile;
*
* @threadsafe
*/
[scriptable, uuid(7b5ed315-58b3-41fd-8257-d5768943021d)]
[scriptable, uuid(ad035628-4ffb-42ff-a256-0ed9e410b859)]
interface mozIStorageConnection : nsISupports {
/**
* Closes a database connection. Callers must finalize all statements created
@ -350,4 +350,16 @@ interface mozIStorageConnection : nsISupports {
* @return previous registered handler.
*/
mozIStorageProgressHandler removeProgressHandler();
/**
* Controls SQLITE_FCNTL_CHUNK_SIZE setting in sqlite. This helps avoid fragmentation
* by growing/shrinking the database file in SQLITE_FCNTL_CHUNK_SIZE increments.
*
* @param aIncrement
* The database file will grow in multiples of chunkSize.
* @param aDatabaseName
* Sqlite database name. "" means pass NULL for zDbName to sqlite3_file_control.
* See http://sqlite.org/c3ref/file_control.html for more details.
*/
void setGrowthIncrement(in PRInt32 aIncrement, in AUTF8String aDatabaseName);
};

View File

@ -1105,5 +1105,15 @@ Connection::RemoveProgressHandler(mozIStorageProgressHandler **_oldHandler)
return NS_OK;
}
NS_IMETHODIMP
Connection::SetGrowthIncrement(PRInt32 aChunkSize, const nsACString &aDatabaseName)
{
(void)::sqlite3_file_control(mDBConn,
aDatabaseName.Length() ? nsPromiseFlatCString(aDatabaseName).get() : NULL,
SQLITE_FCNTL_CHUNK_SIZE,
&aChunkSize);
return NS_OK;
}
} // namespace storage
} // namespace mozilla

View File

@ -0,0 +1,50 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// This file tests SQLITE_FCNTL_CHUNK_SIZE behaves as expected
function run_sql(d, sql) {
var stmt = d.createStatement(sql)
stmt.execute()
stmt.finalize();
}
function new_file(name)
{
var file = dirSvc.get("ProfD", Ci.nsIFile);
file.append(name);
return file;
}
function get_size(name) {
return new_file(name).fileSize
}
function run_test()
{
const filename = "chunked.sqlite";
const CHUNK_SIZE = 512 * 1024;
var d = getDatabase(new_file(filename));
d.setGrowthIncrement(CHUNK_SIZE, "");
run_sql(d, "CREATE TABLE bloat(data varchar)");
var orig_size = get_size(filename);
/* Dump in at least 32K worth of data.
* While writing ensure that the file size growth in chunksize set above.
*/
const str1024 = new Array(1024).join("T");
for(var i = 0; i < 32; i++) {
run_sql(d, "INSERT INTO bloat VALUES('" + str1024 + "')");
var size = get_size(filename)
// Must not grow in small increments.
do_check_true(size == orig_size || size >= CHUNK_SIZE);
}
/* In addition to growing in chunk-size increments, the db
* should shrink in chunk-size increments too.
*/
run_sql(d, "DELETE FROM bloat")
run_sql(d, "VACUUM")
do_check_true(get_size(filename) >= CHUNK_SIZE)
}

View File

@ -709,6 +709,9 @@ nsNavHistory::InitDB()
// a transaction for performances.
mozStorageTransaction transaction(mDBConn, PR_FALSE);
// Grow places in 10MB increments
mDBConn->SetGrowthIncrement(10 * 1024 * 1024, EmptyCString());
// Initialize the other Places services' database tables before creating our
// statements. Some of our statements depend on these external tables, such as
// the bookmarks or favicon tables.

View File

@ -3418,6 +3418,7 @@ nsUrlClassifierDBServiceWorker::OpenDb()
}
}
connection->SetGrowthIncrement(5 * 1024 * 1024, EmptyCString());
rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA synchronous=OFF"));
NS_ENSURE_SUCCESS(rv, rv);