Changeset 58366 in webkit


Ignore:
Timestamp:
Apr 27, 2010 6:24:12 PM (14 years ago)
Author:
dumi@chromium.org
Message:

WebCore: Turn on AUTO_VACUUM = INCREMENTAL for all HTML5 databases.
https://bugs.webkit.org/show_bug.cgi?id=38191

Reviewed by David Levin.

Vacuum all databases when the number of free pages is at least 10%
of the number of total pages. Also, add a guard against a bug that
was fixed in SQLite only starting with version 3.6.16.

  • platform/sql/SQLiteDatabase.cpp:

(WebCore::SQLiteDatabase::maximumSize):
(WebCore::SQLiteDatabase::freeSpaceSize):
(WebCore::SQLiteDatabase::totalSize):
(WebCore::SQLiteDatabase::runIncrementalVacuumCommand):
(WebCore::SQLiteDatabase::turnOnIncrementalAutoVacuum):

  • platform/sql/SQLiteDatabase.h:

(WebCore::SQLiteDatabase::):

  • platform/sql/SQLiteStatement.cpp:

(WebCore::SQLiteStatement::prepare):
(WebCore::SQLiteStatement::step):

  • storage/Database.cpp:

(WebCore::Database::performOpenAndVerify):
(WebCore::Database::incrementalVacuumIfNeeded):

  • storage/Database.h:
  • storage/SQLTransaction.cpp:

(WebCore::SQLTransaction::postflightAndCommit):

LayoutTests: Adjusting the expected amount of space used by quota-tracking.html.
https://bugs.webkit.org/show_bug.cgi?id=38191

Reviewed by David Levin.

The expectations changed because of AUTO_VACUUM's overhead.

  • platform/chromium/test_expectations.txt:
  • storage/quota-tracking-expected.txt:
  • storage/quota-tracking.html:
Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r58361 r58366  
     12010-04-27  Dumitru Daniliuc  <dumi@chromium.org>
     2
     3        Reviewed by David Levin.
     4
     5        Adjusting the expected amount of space used by quota-tracking.html.
     6        https://bugs.webkit.org/show_bug.cgi?id=38191
     7
     8        The expectations changed because of AUTO_VACUUM's overhead.
     9
     10        * platform/chromium/test_expectations.txt:
     11        * storage/quota-tracking-expected.txt:
     12        * storage/quota-tracking.html:
     13
    1142010-04-27  Evan Martin  <evan@chromium.org>
    215
  • trunk/LayoutTests/platform/chromium/test_expectations.txt

    r58361 r58366  
    28782878// Started failing at 58212
    28792879BUGWK38108 MAC : fast/backgrounds/size/contain-and-cover.html = IMAGE
    2880 
    2881 // Started failing after revert.
    2882 BUGWK38191 : storage/quota-tracking.html = TIMEOUT TEXT
  • trunk/LayoutTests/storage/quota-tracking-expected.txt

    r58302 r58366  
    11UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{file, , 0} database:QuotaManagementDatabase2
    22This test checks to make sure that quotas are enforced per-origin instead of per-database, as they were prior to http://trac.webkit.org/projects/webkit/changeset/29983.
    3 The test clears all databases, sets the quota for the origin to 32k, then tries to insert 17k of data into two databases. If things go as planned, the UI Delegate will be informed of the exceeded quota and should increase the quota for this origin. Inserting 17k of data the third time should succeed again.
     3The test clears all databases, sets the quota for the origin to 40k, then tries to insert 17k of data into two databases. If things go as planned, the second insert should fail, the UI Delegate should be informed of the exceeded quota and should increase the quota for this origin. Inserting 17k of data the third time should succeed again.
    44Adding a table
    55Inserting some data
  • trunk/LayoutTests/storage/quota-tracking.html

    r58302 r58366  
    9292        layoutTestController.clearAllDatabases();
    9393        layoutTestController.dumpDatabaseCallbacks();
    94         layoutTestController.setDatabaseQuota(32768);
     94        layoutTestController.setDatabaseQuota(40960);
    9595        layoutTestController.dumpAsText();
    9696        layoutTestController.waitUntilDone();
     
    106106<body onload="runTest()">
    107107This test checks to make sure that quotas are enforced per-origin instead of per-database, as they were prior to http://trac.webkit.org/projects/webkit/changeset/29983.<br>
    108 The test clears all databases, sets the quota for the origin to 32k, then tries to insert 17k of data into two databases. If things go as planned, the UI Delegate will be informed of the exceeded quota and should increase the quota for this origin. Inserting 17k of data the third time should succeed again.
     108The test clears all databases, sets the quota for the origin to 40k, then tries to insert 17k of data into two databases. If things go as planned, the second insert should fail, the UI Delegate should be informed of the exceeded quota and should increase the quota for this origin. Inserting 17k of data the third time should succeed again.
    109109<pre id="console">
    110110</pre>
  • trunk/WebCore/ChangeLog

    r58363 r58366  
     12010-04-27  Dumitru Daniliuc  <dumi@chromium.org>
     2
     3        Reviewed by David Levin.
     4
     5        Turn on AUTO_VACUUM = INCREMENTAL for all HTML5 databases.
     6        https://bugs.webkit.org/show_bug.cgi?id=38191
     7
     8        Vacuum all databases when the number of free pages is at least 10%
     9        of the number of total pages. Also, add a guard against a bug that
     10        was fixed in SQLite only starting with version 3.6.16.
     11
     12        * platform/sql/SQLiteDatabase.cpp:
     13        (WebCore::SQLiteDatabase::maximumSize):
     14        (WebCore::SQLiteDatabase::freeSpaceSize):
     15        (WebCore::SQLiteDatabase::totalSize):
     16        (WebCore::SQLiteDatabase::runIncrementalVacuumCommand):
     17        (WebCore::SQLiteDatabase::turnOnIncrementalAutoVacuum):
     18        * platform/sql/SQLiteDatabase.h:
     19        (WebCore::SQLiteDatabase::):
     20        * platform/sql/SQLiteStatement.cpp:
     21        (WebCore::SQLiteStatement::prepare):
     22        (WebCore::SQLiteStatement::step):
     23        * storage/Database.cpp:
     24        (WebCore::Database::performOpenAndVerify):
     25        (WebCore::Database::incrementalVacuumIfNeeded):
     26        * storage/Database.h:
     27        * storage/SQLTransaction.cpp:
     28        (WebCore::SQLTransaction::postflightAndCommit):
     29
    1302010-04-27  Garret Kelly  <gdk@chromium.org>
    231
  • trunk/WebCore/platform/sql/SQLiteDatabase.cpp

    r58302 r58366  
    103103int64_t SQLiteDatabase::maximumSize()
    104104{
    105     MutexLocker locker(m_authorizerLock);
    106     enableAuthorizer(false);
    107    
    108     SQLiteStatement statement(*this, "PRAGMA max_page_count");
    109     int64_t size = statement.getColumnInt64(0) * pageSize();
    110    
    111     enableAuthorizer(true);
    112     return size;
     105    int64_t maxPageCount = 0;
     106
     107    {
     108        MutexLocker locker(m_authorizerLock);
     109        enableAuthorizer(false);
     110        SQLiteStatement statement(*this, "PRAGMA max_page_count");
     111        maxPageCount = statement.getColumnInt64(0);
     112        enableAuthorizer(true);
     113    }
     114
     115    return maxPageCount * pageSize();
    113116}
    114117
     
    154157int64_t SQLiteDatabase::freeSpaceSize()
    155158{
    156     MutexLocker locker(m_authorizerLock);
    157     enableAuthorizer(false);
    158     // Note: freelist_count was added in SQLite 3.4.1.
    159     SQLiteStatement statement(*this, "PRAGMA freelist_count");
    160     int64_t size = statement.getColumnInt64(0) * pageSize();
    161 
    162     enableAuthorizer(true);
    163     return size;
     159    int64_t freelistCount = 0;
     160
     161    {
     162        MutexLocker locker(m_authorizerLock);
     163        enableAuthorizer(false);
     164        // Note: freelist_count was added in SQLite 3.4.1.
     165        SQLiteStatement statement(*this, "PRAGMA freelist_count");
     166        freelistCount = statement.getColumnInt64(0);
     167        enableAuthorizer(true);
     168    }
     169
     170    return freelistCount * pageSize();
     171}
     172
     173int64_t SQLiteDatabase::totalSize()
     174{
     175    int64_t pageCount = 0;
     176
     177    {
     178        MutexLocker locker(m_authorizerLock);
     179        enableAuthorizer(false);
     180        SQLiteStatement statement(*this, "PRAGMA page_count");
     181        pageCount = statement.getColumnInt64(0);
     182        enableAuthorizer(true);
     183    }
     184
     185    return pageCount * pageSize();
    164186}
    165187
     
    228250    if (!executeCommand("VACUUM;"))
    229251        LOG(SQLDatabase, "Unable to vacuum database - %s", lastErrorMsg());
     252}
     253
     254void SQLiteDatabase::runIncrementalVacuumCommand()
     255{
     256    MutexLocker locker(m_authorizerLock);
     257    enableAuthorizer(false);
     258
     259    if (!executeCommand("PRAGMA incremental_vacuum"))
     260        LOG(SQLDatabase, "Unable to run incremental vacuum - %s", lastErrorMsg());
     261
     262    enableAuthorizer(true);
    230263}
    231264
     
    380413}
    381414
     415bool SQLiteDatabase::turnOnIncrementalAutoVacuum()
     416{
     417    SQLiteStatement statement(*this, "PRAGMA auto_vacuum");
     418    int autoVacuumMode = statement.getColumnInt(0);
     419    int error = lastError();
     420
     421    // Check if we got an error while trying to get the value of the auto_vacuum flag.
     422    // If we got a SQLITE_BUSY error, then there's probably another transaction in
     423    // progress on this database. In this case, keep the current value of the
     424    // auto_vacuum flag and try to set it to INCREMENTAL the next time we open this
     425    // database. If the error is not SQLITE_BUSY, then we probably ran into a more
     426    // serious problem and should return false (to log an error message).
     427    if (error != SQLITE_ROW)
     428        return false;
     429
     430    switch (autoVacuumMode) {
     431    case AutoVacuumIncremental:
     432        return true;
     433    case AutoVacuumFull:
     434        return executeCommand("PRAGMA auto_vacuum = 2");
     435    case AutoVacuumNone:
     436    default:
     437        if (!executeCommand("PRAGMA auto_vacuum = 2"))
     438            return false;
     439        runVacuumCommand();
     440        error = lastError();
     441        return (error == SQLITE_OK);
     442    }
     443}
     444
    382445} // namespace WebCore
  • trunk/WebCore/platform/sql/SQLiteDatabase.h

    r58302 r58366  
    6666    void clearAllTables();
    6767    void runVacuumCommand();
     68    void runIncrementalVacuumCommand();
    6869   
    6970    bool transactionInProgress() const { return m_transactionInProgress; }
     
    8687    // Gets the number of unused bytes in the database file.
    8788    int64_t freeSpaceSize();
     89    int64_t totalSize();
    8890
    8991    // The SQLite SYNCHRONOUS pragma can be either FULL, NORMAL, or OFF
     
    108110    void unlock();
    109111    bool isAutoCommitOn() const;
     112
     113    // The SQLite AUTO_VACUUM pragma can be either NONE, FULL, or INCREMENTAL.
     114    // NONE - SQLite does not do any vacuuming
     115    // FULL - SQLite moves all empty pages to the end of the DB file and truncates
     116    //        the file to remove those pages after every transaction. This option
     117    //        requires SQLite to store additional information about each page in
     118    //        the database file.
     119    // INCREMENTAL - SQLite stores extra information for each page in the database
     120    //               file, but removes the empty pages only when PRAGMA INCREMANTAL_VACUUM
     121    //               is called.
     122    enum AutoVacuumPragma { AutoVacuumNone = 0, AutoVacuumFull = 1, AutoVacuumIncremental = 2 };
     123    bool turnOnIncrementalAutoVacuum();
    110124
    111125    // Set this flag to allow access from multiple threads.  Not all multi-threaded accesses are safe!
  • trunk/WebCore/platform/sql/SQLiteStatement.cpp

    r58302 r58366  
    6666    String strippedQuery = m_query.stripWhiteSpace();
    6767    int error = sqlite3_prepare16_v2(m_database.sqlite3Handle(), strippedQuery.charactersWithNullTermination(), -1, &m_statement, &tail);
     68
     69    // Starting with version 3.6.16, sqlite has a patch (http://www.sqlite.org/src/ci/256ec3c6af)
     70    // that should make sure sqlite3_prepare16_v2 doesn't return a SQLITE_SCHEMA error.
     71    // If we're using an older sqlite version, try to emulate the patch.
     72    if (error == SQLITE_SCHEMA) {
     73      sqlite3_finalize(m_statement);
     74      error = sqlite3_prepare16_v2(m_database.sqlite3Handle(), m_query.charactersWithNullTermination(), -1, &m_statement, &tail);
     75    }
     76
    6877    if (error != SQLITE_OK)
    6978        LOG(SQLDatabase, "sqlite3_prepare16 failed (%i)\n%s\n%s", error, m_query.ascii().data(), sqlite3_errmsg(m_database.sqlite3Handle()));
     
    8897            error, m_query.ascii().data(), sqlite3_errmsg(m_database.sqlite3Handle()));
    8998    }
     99
    90100    return error;
    91101}
  • trunk/WebCore/storage/Database.cpp

    r58302 r58366  
    544544        return false;
    545545    }
     546    if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum())
     547        LOG_ERROR("Unable to turn on incremental auto-vacuum for database %s", m_filename.ascii().data());
    546548
    547549    ASSERT(m_databaseAuthorizer);
     
    809811}
    810812
     813void Database::incrementalVacuumIfNeeded()
     814{
     815    int64_t freeSpaceSize = m_sqliteDatabase.freeSpaceSize();
     816    int64_t totalSize = m_sqliteDatabase.totalSize();
     817    if (totalSize <= 10 * freeSpaceSize)
     818        m_sqliteDatabase.runIncrementalVacuumCommand();
     819}
     820
    811821#endif // ENABLE(DATABASE)
    812822
  • trunk/WebCore/storage/Database.h

    r58302 r58366  
    134134    SQLTransactionCoordinator* transactionCoordinator() const;
    135135
     136    void incrementalVacuumIfNeeded();
     137
    136138private:
    137139    Database(ScriptExecutionContext* context, const String& name,
  • trunk/WebCore/storage/SQLTransaction.cpp

    r58302 r58366  
    467467    }
    468468
     469    // The commit was successful, so vacuum the database if needed
     470    m_database->incrementalVacuumIfNeeded();
     471
    469472    // The commit was successful, notify the delegates if the transaction modified this database
    470473    if (m_modifiedDatabase)
Note: See TracChangeset for help on using the changeset viewer.