Changeset 62153 in webkit


Ignore:
Timestamp:
Jun 29, 2010 5:30:25 PM (14 years ago)
Author:
dumi@chromium.org
Message:

WebCore: Implementing DatabaseSync::openDatabaseSync().
https://bugs.webkit.org/show_bug.cgi?id=40607

Reviewed by Darin Fisher.

  1. Moved some common code from Database to AbstractDatabase.
  2. Made performOpenAndVerify() virtual, since DatabaseSync doesn't need to interact with DatabaseThread.
  3. Removed the m_creationCallback field, since it's only needed in the openDatabase{Sync} methods.
  • storage/AbstractDatabase.cpp:

(WebCore::retrieveTextResultFromDatabase):
(WebCore::setTextValueInDatabase):
(WebCore::guidMutex):
(WebCore::guidToVersionMap):
(WebCore::updateGuidVersionMap):
(WebCore::guidToDatabaseMap):
(WebCore::guidForOriginAndName):
(WebCore::AbstractDatabase::databaseInfoTableName):
(WebCore::AbstractDatabase::AbstractDatabase):
(WebCore::AbstractDatabase::closeDatabase):
(WebCore::AbstractDatabase::version):
(WebCore::AbstractDatabase::performOpenAndVerify):
(WebCore::AbstractDatabase::scriptExecutionContext):
(WebCore::AbstractDatabase::securityOrigin):
(WebCore::AbstractDatabase::stringIdentifier):
(WebCore::AbstractDatabase::displayName):
(WebCore::AbstractDatabase::estimatedSize):
(WebCore::AbstractDatabase::fileName):
(WebCore::AbstractDatabase::databaseVersionKey):
(WebCore::AbstractDatabase::getVersionFromDatabase):
(WebCore::AbstractDatabase::setVersionInDatabase):
(WebCore::AbstractDatabase::versionMatchesExpected):
(WebCore::AbstractDatabase::setExpectedVersion):
(WebCore::AbstractDatabase::disableAuthorizer):
(WebCore::AbstractDatabase::enableAuthorizer):
(WebCore::AbstractDatabase::setAuthorizerReadOnly):
(WebCore::AbstractDatabase::lastActionChangedDatabase):
(WebCore::AbstractDatabase::lastActionWasInsert):
(WebCore::AbstractDatabase::resetDeletes):
(WebCore::AbstractDatabase::hadDeletes):
(WebCore::AbstractDatabase::resetAuthorizer):

  • storage/AbstractDatabase.h:

(WebCore::AbstractDatabase::opened):
(WebCore::AbstractDatabase::isNew):
(WebCore::AbstractDatabase::databaseDebugName):

  • storage/Database.cpp:

(WebCore::DatabaseCreationCallbackTask::create):
(WebCore::DatabaseCreationCallbackTask::performTask):
(WebCore::DatabaseCreationCallbackTask::DatabaseCreationCallbackTask):
(WebCore::Database::openDatabase):
(WebCore::Database::Database):
(WebCore::Database::version):
(WebCore::Database::openAndVerifyVersion):
(WebCore::Database::close):
(WebCore::Database::stop):
(WebCore::Database::performOpenAndVerify):

  • storage/Database.h:

(WebCore::Database::sqliteDatabase):

  • storage/DatabaseAuthorizer.cpp:

(WebCore::DatabaseAuthorizer::create):
(WebCore::DatabaseAuthorizer::DatabaseAuthorizer):
(WebCore::DatabaseAuthorizer::denyBasedOnTableName):

  • storage/DatabaseAuthorizer.h:
  • storage/DatabaseSync.cpp:

(WebCore::DatabaseSync::openDatabaseSync):
(WebCore::DatabaseSync::DatabaseSync):
(WebCore::DatabaseSync::~DatabaseSync):
(WebCore::DatabaseSync::markAsDeletedAndClose):
(WebCore::CloseSyncDatabaseOnContextThreadTask::create):
(WebCore::CloseSyncDatabaseOnContextThreadTask::performTask):
(WebCore::CloseSyncDatabaseOnContextThreadTask::CloseSyncDatabaseOnContextThreadTask):
(WebCore::DatabaseSync::closeImmediately):

  • storage/DatabaseSync.h:
  • storage/DatabaseTask.cpp:

(WebCore::DatabaseOpenTask::DatabaseOpenTask):
(WebCore::DatabaseOpenTask::doPerformTask):

  • storage/DatabaseTask.h:

(WebCore::DatabaseOpenTask::create):

WebKit/chromium: Simplify the WebDatabase interface.
https://bugs.webkit.org/show_bug.cgi?id=40607

Reviewed by Darin Fisher.

Do not ref()/deref() the private AbstractDatabase member. This
allows us to use WebDatabase in the destructors of the DB
classes.

  • public/WebDatabase.h:

(WebKit::WebDatabase::WebDatabase):

  • src/WebDatabase.cpp:

(WebKit::WebDatabase::name):
(WebKit::WebDatabase::displayName):
(WebKit::WebDatabase::estimatedSize):
(WebKit::WebDatabase::securityOrigin):
(WebKit::WebDatabase::WebDatabase):

LayoutTests: Uncomment some test cases in open-database-sync-inputs, and
comment out for now the ones that fail in V8.
https://bugs.webkit.org/show_bug.cgi?id=40607

Reviewed by Darin Fisher.

  • fast/workers/storage/open-database-sync-inputs-expected.txt:
  • fast/workers/storage/resources/open-database-sync-inputs.js:

(catch):

Location:
trunk
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r62152 r62153  
     12010-06-29  Dumitru Daniliuc  <dumi@chromium.org>
     2
     3        Reviewed by Darin Fisher.
     4
     5        Uncomment some test cases in open-database-sync-inputs, and
     6        comment out for now the ones that fail in V8.
     7        https://bugs.webkit.org/show_bug.cgi?id=40607
     8
     9        * fast/workers/storage/open-database-sync-inputs-expected.txt:
     10        * fast/workers/storage/resources/open-database-sync-inputs.js:
     11        (catch):
     12
    1132010-06-29  François Sausset  <sausset@gmail.com>
    214
  • trunk/LayoutTests/fast/workers/storage/open-database-sync-inputs-expected.txt

    r61866 r62153  
    66PASS: undefined
    77PASS: TYPE_MISMATCH_ERR: DOM Exception 17
     8PASS: openDatabaseSync() succeeded.
     9PASS: openDatabaseSync() succeeded.
     10PASS: calling openDatabaseSync() with a creation callback succeeded.
    811
  • trunk/LayoutTests/fast/workers/storage/resources/open-database-sync-inputs.js

    r61866 r62153  
    3535try {
    3636    db = openDatabaseSync("DBName", "DBVersion", notAString, 1024);
    37     postMessage("FAIL: the fourth argument to openDatabaseSync() must be an integer.");
     37    postMessage("FAIL: the third argument to openDatabaseSync() must be a string.");
    3838} catch (err) {
    3939    postMessage("PASS: " + err.message);
     
    4747}
    4848
    49 // FIXME: Uncomment these tests when the sync DB API is implemented.
    50 //try {
    51 //    db = openDatabaseSync("DBName", "DBVersion", "DBDescription", 1024);
    52 //    postMessage("PASS: openDatabaseSync() succeeded.");
    53 //} catch (err) {
    54 //    postMessage("FAIL: " + err.message);
    55 //}
    56 //
    57 //try {
    58 //    db = openDatabaseSync("DBName", "DBVersion", "DBDescription", 1024, function(db) { });
    59 //    postMessage("PASS: calling openDatabaseSync() with a creation callback succeeded.");
    60 //} catch (err) {
    61 //    postMessage("FAIL: " + err.message);
    62 //}
     49try {
     50    db = openDatabaseSync("DBName", "DBVersion", "DBDescription", 1024);
     51    postMessage("PASS: openDatabaseSync() succeeded.");
     52} catch (err) {
     53    postMessage("FAIL: " + err.message);
     54}
     55
     56// Run this test case one more time, to test the code with an existing database.
     57try {
     58    db = openDatabaseSync("DBName", "DBVersion", "DBDescription", 1024);
     59    postMessage("PASS: openDatabaseSync() succeeded.");
     60} catch (err) {
     61    postMessage("FAIL: " + err.message);
     62}
     63
     64try {
     65    // Need to create a new database, otherwise the creation callback won't be invoked.
     66    db = openDatabaseSync("DBNameCreationCallback" + (new Date()).getTime(), "DBVersion", "DBDescription", 1024,
     67                          function(db) {
     68                              postMessage("PASS: calling openDatabaseSync() with a creation callback succeeded.");
     69                          });
     70} catch (err) {
     71    postMessage("FAIL: " + err.message);
     72}
    6373
    6474postMessage("done");
  • trunk/WebCore/ChangeLog

    r62152 r62153  
     12010-06-29  Dumitru Daniliuc  <dumi@chromium.org>
     2
     3        Reviewed by Darin Fisher.
     4
     5        Implementing DatabaseSync::openDatabaseSync().
     6        https://bugs.webkit.org/show_bug.cgi?id=40607
     7
     8        1. Moved some common code from Database to AbstractDatabase.
     9        2. Made performOpenAndVerify() virtual, since DatabaseSync doesn't
     10           need to interact with DatabaseThread.
     11        3. Removed the m_creationCallback field, since it's only needed in
     12           the openDatabase{Sync} methods.
     13
     14        * storage/AbstractDatabase.cpp:
     15        (WebCore::retrieveTextResultFromDatabase):
     16        (WebCore::setTextValueInDatabase):
     17        (WebCore::guidMutex):
     18        (WebCore::guidToVersionMap):
     19        (WebCore::updateGuidVersionMap):
     20        (WebCore::guidToDatabaseMap):
     21        (WebCore::guidForOriginAndName):
     22        (WebCore::AbstractDatabase::databaseInfoTableName):
     23        (WebCore::AbstractDatabase::AbstractDatabase):
     24        (WebCore::AbstractDatabase::closeDatabase):
     25        (WebCore::AbstractDatabase::version):
     26        (WebCore::AbstractDatabase::performOpenAndVerify):
     27        (WebCore::AbstractDatabase::scriptExecutionContext):
     28        (WebCore::AbstractDatabase::securityOrigin):
     29        (WebCore::AbstractDatabase::stringIdentifier):
     30        (WebCore::AbstractDatabase::displayName):
     31        (WebCore::AbstractDatabase::estimatedSize):
     32        (WebCore::AbstractDatabase::fileName):
     33        (WebCore::AbstractDatabase::databaseVersionKey):
     34        (WebCore::AbstractDatabase::getVersionFromDatabase):
     35        (WebCore::AbstractDatabase::setVersionInDatabase):
     36        (WebCore::AbstractDatabase::versionMatchesExpected):
     37        (WebCore::AbstractDatabase::setExpectedVersion):
     38        (WebCore::AbstractDatabase::disableAuthorizer):
     39        (WebCore::AbstractDatabase::enableAuthorizer):
     40        (WebCore::AbstractDatabase::setAuthorizerReadOnly):
     41        (WebCore::AbstractDatabase::lastActionChangedDatabase):
     42        (WebCore::AbstractDatabase::lastActionWasInsert):
     43        (WebCore::AbstractDatabase::resetDeletes):
     44        (WebCore::AbstractDatabase::hadDeletes):
     45        (WebCore::AbstractDatabase::resetAuthorizer):
     46        * storage/AbstractDatabase.h:
     47        (WebCore::AbstractDatabase::opened):
     48        (WebCore::AbstractDatabase::isNew):
     49        (WebCore::AbstractDatabase::databaseDebugName):
     50        * storage/Database.cpp:
     51        (WebCore::DatabaseCreationCallbackTask::create):
     52        (WebCore::DatabaseCreationCallbackTask::performTask):
     53        (WebCore::DatabaseCreationCallbackTask::DatabaseCreationCallbackTask):
     54        (WebCore::Database::openDatabase):
     55        (WebCore::Database::Database):
     56        (WebCore::Database::version):
     57        (WebCore::Database::openAndVerifyVersion):
     58        (WebCore::Database::close):
     59        (WebCore::Database::stop):
     60        (WebCore::Database::performOpenAndVerify):
     61        * storage/Database.h:
     62        (WebCore::Database::sqliteDatabase):
     63        * storage/DatabaseAuthorizer.cpp:
     64        (WebCore::DatabaseAuthorizer::create):
     65        (WebCore::DatabaseAuthorizer::DatabaseAuthorizer):
     66        (WebCore::DatabaseAuthorizer::denyBasedOnTableName):
     67        * storage/DatabaseAuthorizer.h:
     68        * storage/DatabaseSync.cpp:
     69        (WebCore::DatabaseSync::openDatabaseSync):
     70        (WebCore::DatabaseSync::DatabaseSync):
     71        (WebCore::DatabaseSync::~DatabaseSync):
     72        (WebCore::DatabaseSync::markAsDeletedAndClose):
     73        (WebCore::CloseSyncDatabaseOnContextThreadTask::create):
     74        (WebCore::CloseSyncDatabaseOnContextThreadTask::performTask):
     75        (WebCore::CloseSyncDatabaseOnContextThreadTask::CloseSyncDatabaseOnContextThreadTask):
     76        (WebCore::DatabaseSync::closeImmediately):
     77        * storage/DatabaseSync.h:
     78        * storage/DatabaseTask.cpp:
     79        (WebCore::DatabaseOpenTask::DatabaseOpenTask):
     80        (WebCore::DatabaseOpenTask::doPerformTask):
     81        * storage/DatabaseTask.h:
     82        (WebCore::DatabaseOpenTask::create):
     83
    1842010-06-29  François Sausset  <sausset@gmail.com>
    285
  • trunk/WebCore/storage/AbstractDatabase.cpp

    r61866 r62153  
    3131
    3232#if ENABLE(DATABASE)
     33#include "DatabaseAuthorizer.h"
     34#include "DatabaseTracker.h"
     35#include "ExceptionCode.h"
     36#include "Logging.h"
     37#include "SQLiteStatement.h"
     38#include "ScriptExecutionContext.h"
     39#include "SecurityOrigin.h"
     40#include "StringHash.h"
     41#include <wtf/HashMap.h>
     42#include <wtf/HashSet.h>
     43#include <wtf/PassRefPtr.h>
     44#include <wtf/RefPtr.h>
     45#include <wtf/StdLibExtras.h>
    3346
    3447namespace WebCore {
    3548
     49static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
     50{
     51    SQLiteStatement statement(db, query);
     52    int result = statement.prepare();
     53
     54    if (result != SQLResultOk) {
     55        LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data());
     56        return false;
     57    }
     58
     59    result = statement.step();
     60    if (result == SQLResultRow) {
     61        resultString = statement.getColumnText(0);
     62        return true;
     63    }
     64    if (result == SQLResultDone) {
     65        resultString = String();
     66        return true;
     67    }
     68
     69    LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data());
     70    return false;
     71}
     72
     73static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value)
     74{
     75    SQLiteStatement statement(db, query);
     76    int result = statement.prepare();
     77
     78    if (result != SQLResultOk) {
     79        LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data());
     80        return false;
     81    }
     82
     83    statement.bindText(1, value);
     84
     85    result = statement.step();
     86    if (result != SQLResultDone) {
     87        LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data());
     88        return false;
     89    }
     90
     91    return true;
     92}
     93
     94// FIXME: move all guid-related functions to a DatabaseVersionTracker class.
     95static Mutex& guidMutex()
     96{
     97    // Note: We don't have to use AtomicallyInitializedStatic here because
     98    // this function is called once in the constructor on the main thread
     99    // before any other threads that call this function are used.
     100    DEFINE_STATIC_LOCAL(Mutex, mutex, ());
     101    return mutex;
     102}
     103
     104typedef HashMap<int, String> GuidVersionMap;
     105static GuidVersionMap& guidToVersionMap()
     106{
     107    DEFINE_STATIC_LOCAL(GuidVersionMap, map, ());
     108    return map;
     109}
     110
     111// NOTE: Caller must lock guidMutex().
     112static inline void updateGuidVersionMap(int guid, String newVersion)
     113{
     114    // Ensure the the mutex is locked.
     115    ASSERT(!guidMutex().tryLock());
     116
     117    // Note: It is not safe to put an empty string into the guidToVersionMap() map.
     118    // That's because the map is cross-thread, but empty strings are per-thread.
     119    // The copy() function makes a version of the string you can use on the current
     120    // thread, but we need a string we can keep in a cross-thread data structure.
     121    // FIXME: This is a quite-awkward restriction to have to program with.
     122
     123    // Map null string to empty string (see comment above).
     124    guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.threadsafeCopy());
     125}
     126
     127typedef HashMap<int, HashSet<AbstractDatabase*>*> GuidDatabaseMap;
     128static GuidDatabaseMap& guidToDatabaseMap()
     129{
     130    DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ());
     131    return map;
     132}
     133
     134static int guidForOriginAndName(const String& origin, const String& name)
     135{
     136    String stringID = origin + "/" + name;
     137
     138    // Note: We don't have to use AtomicallyInitializedStatic here because
     139    // this function is called once in the constructor on the main thread
     140    // before any other threads that call this function are used.
     141    DEFINE_STATIC_LOCAL(Mutex, stringIdentifierMutex, ());
     142    MutexLocker locker(stringIdentifierMutex);
     143    typedef HashMap<String, int> IDGuidMap;
     144    DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ());
     145    int guid = stringIdentifierToGUIDMap.get(stringID);
     146    if (!guid) {
     147        static int currentNewGUID = 1;
     148        guid = currentNewGUID++;
     149        stringIdentifierToGUIDMap.set(stringID, guid);
     150    }
     151
     152    return guid;
     153}
     154
    36155static bool isDatabaseAvailable = true;
    37156
     
    46165}
    47166
     167// static
     168const String& AbstractDatabase::databaseInfoTableName()
     169{
     170    DEFINE_STATIC_LOCAL(String, name, ("__WebKitDatabaseInfoTable__"));
     171    return name;
     172}
     173
     174AbstractDatabase::AbstractDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion,
     175                                   const String& displayName, unsigned long estimatedSize)
     176    : m_scriptExecutionContext(context)
     177    , m_name(name.crossThreadString())
     178    , m_expectedVersion(expectedVersion.crossThreadString())
     179    , m_displayName(displayName.crossThreadString())
     180    , m_estimatedSize(estimatedSize)
     181    , m_guid(0)
     182    , m_opened(false)
     183    , m_new(false)
     184{
     185    ASSERT(context->isContextThread());
     186    m_contextThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin();
     187
     188    m_databaseAuthorizer = DatabaseAuthorizer::create(databaseInfoTableName());
     189
     190    if (m_name.isNull())
     191        m_name = "";
     192
     193    m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
     194    {
     195        MutexLocker locker(guidMutex());
     196
     197        HashSet<AbstractDatabase*>* hashSet = guidToDatabaseMap().get(m_guid);
     198        if (!hashSet) {
     199            hashSet = new HashSet<AbstractDatabase*>;
     200            guidToDatabaseMap().set(m_guid, hashSet);
     201        }
     202
     203        hashSet->add(this);
     204    }
     205
     206    m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin(), m_name);
     207    DatabaseTracker::tracker().addOpenDatabase(this);
     208}
     209
    48210AbstractDatabase::~AbstractDatabase()
    49211{
    50212}
    51213
     214void AbstractDatabase::closeDatabase()
     215{
     216    if (!m_opened)
     217        return;
     218
     219    m_sqliteDatabase.close();
     220    m_opened = false;
     221    {
     222        MutexLocker locker(guidMutex());
     223
     224        HashSet<AbstractDatabase*>* hashSet = guidToDatabaseMap().get(m_guid);
     225        ASSERT(hashSet);
     226        ASSERT(hashSet->contains(this));
     227        hashSet->remove(this);
     228        if (hashSet->isEmpty()) {
     229            guidToDatabaseMap().remove(m_guid);
     230            delete hashSet;
     231            guidToVersionMap().remove(m_guid);
     232        }
     233    }
     234}
     235
     236String AbstractDatabase::version() const
     237{
     238    MutexLocker locker(guidMutex());
     239    return guidToVersionMap().get(m_guid).threadsafeCopy();
     240}
     241
     242static const int maxSqliteBusyWaitTime = 30000;
     243bool AbstractDatabase::performOpenAndVerify(bool shouldSetVersionInNewDatabase, ExceptionCode& ec)
     244{
     245    if (!m_sqliteDatabase.open(m_filename, true)) {
     246        LOG_ERROR("Unable to open database at path %s", m_filename.ascii().data());
     247        ec = INVALID_STATE_ERR;
     248        return false;
     249    }
     250    if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum())
     251        LOG_ERROR("Unable to turn on incremental auto-vacuum for database %s", m_filename.ascii().data());
     252
     253    ASSERT(m_databaseAuthorizer);
     254    m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer);
     255    m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
     256
     257    String currentVersion;
     258    {
     259        MutexLocker locker(guidMutex());
     260
     261        GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid);
     262        if (entry != guidToVersionMap().end()) {
     263            // Map null string to empty string (see updateGuidVersionMap()).
     264            currentVersion = entry->second.isNull() ? String("") : entry->second;
     265            LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());
     266        } else {
     267            LOG(StorageAPI, "No cached version for guid %i", m_guid);
     268
     269            if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) {
     270                m_new = true;
     271
     272                if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + databaseInfoTableName() + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
     273                    LOG_ERROR("Unable to create table %s in database %s", databaseInfoTableName().ascii().data(), databaseDebugName().ascii().data());
     274                    ec = INVALID_STATE_ERR;
     275                    // Close the handle to the database file.
     276                    m_sqliteDatabase.close();
     277                    return false;
     278                }
     279            }
     280
     281            if (!getVersionFromDatabase(currentVersion)) {
     282                LOG_ERROR("Failed to get current version from database %s", databaseDebugName().ascii().data());
     283                ec = INVALID_STATE_ERR;
     284                // Close the handle to the database file.
     285                m_sqliteDatabase.close();
     286                return false;
     287            }
     288            if (currentVersion.length()) {
     289                LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
     290            } else if (!m_new || shouldSetVersionInNewDatabase) {
     291                LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
     292                if (!setVersionInDatabase(m_expectedVersion)) {
     293                    LOG_ERROR("Failed to set version %s in database %s", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
     294                    ec = INVALID_STATE_ERR;
     295                    // Close the handle to the database file.
     296                    m_sqliteDatabase.close();
     297                    return false;
     298                }
     299                currentVersion = m_expectedVersion;
     300            }
     301
     302            updateGuidVersionMap(m_guid, currentVersion);
     303        }
     304    }
     305
     306    if (currentVersion.isNull()) {
     307        LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data());
     308        currentVersion = "";
     309    }
     310
     311    // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception.
     312    // If the expected version is the empty string, then we always return with whatever version of the database we have.
     313    if ((!m_new || shouldSetVersionInNewDatabase) && m_expectedVersion.length() && m_expectedVersion != currentVersion) {
     314        LOG(StorageAPI, "page expects version %s from database %s, which actually has version name %s - openDatabase() call will fail", m_expectedVersion.ascii().data(),
     315            databaseDebugName().ascii().data(), currentVersion.ascii().data());
     316        ec = INVALID_STATE_ERR;
     317        // Close the handle to the database file.
     318        m_sqliteDatabase.close();
     319        return false;
     320    }
     321
     322    m_opened = true;
     323
     324    return true;
     325}
     326
     327ScriptExecutionContext* AbstractDatabase::scriptExecutionContext() const
     328{
     329    return m_scriptExecutionContext.get();
     330}
     331
     332SecurityOrigin* AbstractDatabase::securityOrigin() const
     333{
     334    return m_contextThreadSecurityOrigin.get();
     335}
     336
     337String AbstractDatabase::stringIdentifier() const
     338{
     339    // Return a deep copy for ref counting thread safety
     340    return m_name.threadsafeCopy();
     341}
     342
     343String AbstractDatabase::displayName() const
     344{
     345    // Return a deep copy for ref counting thread safety
     346    return m_displayName.threadsafeCopy();
     347}
     348
     349unsigned long AbstractDatabase::estimatedSize() const
     350{
     351    return m_estimatedSize;
     352}
     353
     354String AbstractDatabase::fileName() const
     355{
     356    // Return a deep copy for ref counting thread safety
     357    return m_filename.threadsafeCopy();
     358}
     359
     360// static
     361const String& AbstractDatabase::databaseVersionKey()
     362{
     363    DEFINE_STATIC_LOCAL(String, key, ("WebKitDatabaseVersionKey"));
     364    return key;
     365}
     366
     367bool AbstractDatabase::getVersionFromDatabase(String& version)
     368{
     369    DEFINE_STATIC_LOCAL(String, getVersionQuery, ("SELECT value FROM " + databaseInfoTableName() + " WHERE key = '" + databaseVersionKey() + "';"));
     370
     371    m_databaseAuthorizer->disable();
     372
     373    bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, getVersionQuery.threadsafeCopy(), version);
     374    if (!result)
     375        LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data());
     376
     377    m_databaseAuthorizer->enable();
     378
     379    return result;
     380}
     381
     382bool AbstractDatabase::setVersionInDatabase(const String& version)
     383{
     384    // The INSERT will replace an existing entry for the database with the new version number, due to the UNIQUE ON CONFLICT REPLACE
     385    // clause in the CREATE statement (see Database::performOpenAndVerify()).
     386    DEFINE_STATIC_LOCAL(String, setVersionQuery, ("INSERT INTO " + databaseInfoTableName() + " (key, value) VALUES ('" + databaseVersionKey() + "', ?);"));
     387
     388    m_databaseAuthorizer->disable();
     389
     390    bool result = setTextValueInDatabase(m_sqliteDatabase, setVersionQuery.threadsafeCopy(), version);
     391    if (!result)
     392        LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), setVersionQuery.ascii().data());
     393
     394    m_databaseAuthorizer->enable();
     395
     396    return result;
     397}
     398
     399bool AbstractDatabase::versionMatchesExpected() const
     400{
     401    if (!m_expectedVersion.isEmpty()) {
     402        MutexLocker locker(guidMutex());
     403        return m_expectedVersion == guidToVersionMap().get(m_guid);
     404    }
     405
     406    return true;
     407}
     408
     409void AbstractDatabase::setExpectedVersion(const String& version)
     410{
     411    m_expectedVersion = version.threadsafeCopy();
     412    // Update the in memory database version map.
     413    MutexLocker locker(guidMutex());
     414    updateGuidVersionMap(m_guid, version);
     415}
     416
     417void AbstractDatabase::disableAuthorizer()
     418{
     419    ASSERT(m_databaseAuthorizer);
     420    m_databaseAuthorizer->disable();
     421}
     422
     423void AbstractDatabase::enableAuthorizer()
     424{
     425    ASSERT(m_databaseAuthorizer);
     426    m_databaseAuthorizer->enable();
     427}
     428
     429void AbstractDatabase::setAuthorizerReadOnly()
     430{
     431    ASSERT(m_databaseAuthorizer);
     432    m_databaseAuthorizer->setReadOnly();
     433}
     434
     435bool AbstractDatabase::lastActionChangedDatabase()
     436{
     437    ASSERT(m_databaseAuthorizer);
     438    return m_databaseAuthorizer->lastActionChangedDatabase();
     439}
     440
     441bool AbstractDatabase::lastActionWasInsert()
     442{
     443    ASSERT(m_databaseAuthorizer);
     444    return m_databaseAuthorizer->lastActionWasInsert();
     445}
     446
     447void AbstractDatabase::resetDeletes()
     448{
     449    ASSERT(m_databaseAuthorizer);
     450    m_databaseAuthorizer->resetDeletes();
     451}
     452
     453bool AbstractDatabase::hadDeletes()
     454{
     455    ASSERT(m_databaseAuthorizer);
     456    return m_databaseAuthorizer->hadDeletes();
     457}
     458
     459void AbstractDatabase::resetAuthorizer()
     460{
     461    if (m_databaseAuthorizer)
     462        m_databaseAuthorizer->reset();
     463}
     464
    52465} // namespace WebCore
    53466
  • trunk/WebCore/storage/AbstractDatabase.h

    r61866 r62153  
    3333
    3434#include "PlatformString.h"
     35#include "SQLiteDatabase.h"
     36#include <wtf/Forward.h>
    3537#include <wtf/ThreadSafeShared.h>
     38#ifndef NDEBUG
     39#include "SecurityOrigin.h"
     40#endif
    3641
    3742namespace WebCore {
    3843
     44class DatabaseAuthorizer;
    3945class ScriptExecutionContext;
    4046class SecurityOrigin;
     47
     48typedef int ExceptionCode;
    4149
    4250class AbstractDatabase : public ThreadSafeShared<AbstractDatabase> {
     
    4755    virtual ~AbstractDatabase();
    4856
    49     virtual ScriptExecutionContext* scriptExecutionContext() const = 0;
    50     virtual SecurityOrigin* securityOrigin() const = 0;
    51     virtual String stringIdentifier() const = 0;
    52     virtual String displayName() const = 0;
    53     virtual unsigned long estimatedSize() const = 0;
    54     virtual String fileName() const = 0;
     57    virtual String version() const;
     58
     59    bool opened() const { return m_opened; }
     60    bool isNew() const { return m_new; }
     61
     62    virtual ScriptExecutionContext* scriptExecutionContext() const;
     63    virtual SecurityOrigin* securityOrigin() const;
     64    virtual String stringIdentifier() const;
     65    virtual String displayName() const;
     66    virtual unsigned long estimatedSize() const;
     67    virtual String fileName() const;
     68
     69    // FIXME: move all version-related methods to a DatabaseVersionTracker class
     70    bool versionMatchesExpected() const;
     71    void setExpectedVersion(const String& version);
     72    bool getVersionFromDatabase(String& version);
     73    bool setVersionInDatabase(const String& version);
     74
     75    void disableAuthorizer();
     76    void enableAuthorizer();
     77    void setAuthorizerReadOnly();
     78    bool lastActionChangedDatabase();
     79    bool lastActionWasInsert();
     80    void resetDeletes();
     81    bool hadDeletes();
     82    void resetAuthorizer();
    5583
    5684    virtual void markAsDeletedAndClose() = 0;
    5785    virtual void closeImmediately() = 0;
     86
     87protected:
     88    AbstractDatabase(ScriptExecutionContext*, const String& name, const String& expectedVersion,
     89                     const String& displayName, unsigned long estimatedSize);
     90
     91    void closeDatabase();
     92
     93    virtual bool performOpenAndVerify(bool shouldSetVersionInNewDatabase, ExceptionCode& ec);
     94
     95    static const String& databaseInfoTableName();
     96
     97    RefPtr<ScriptExecutionContext> m_scriptExecutionContext;
     98    RefPtr<SecurityOrigin> m_contextThreadSecurityOrigin;
     99
     100    String m_name;
     101    String m_expectedVersion;
     102    String m_displayName;
     103    unsigned long m_estimatedSize;
     104    String m_filename;
     105
     106    SQLiteDatabase m_sqliteDatabase;
     107
     108#ifndef NDEBUG
     109    String databaseDebugName() const { return m_contextThreadSecurityOrigin->toString() + "::" + m_name; }
     110#endif
     111
     112private:
     113    static const String& databaseVersionKey();
     114
     115    int m_guid;
     116    bool m_opened;
     117    bool m_new;
     118
     119    RefPtr<DatabaseAuthorizer> m_databaseAuthorizer;
    58120};
    59121
  • trunk/WebCore/storage/Database.cpp

    r61866 r62153  
    3232#if ENABLE(DATABASE)
    3333#include "ChangeVersionWrapper.h"
    34 #include "DatabaseAuthorizer.h"
    3534#include "DatabaseCallback.h"
    3635#include "DatabaseTask.h"
     
    5150#include "ScriptExecutionContext.h"
    5251#include "SecurityOrigin.h"
    53 #include "StringHash.h"
    5452#include "VoidCallback.h"
    5553#include <wtf/OwnPtr.h>
     
    6563namespace WebCore {
    6664
    67 // If we sleep for more the 30 seconds while blocked on SQLITE_BUSY, give up.
    68 static const int maxSqliteBusyWaitTime = 30000;
    69 
    70 const String& Database::databaseInfoTableName()
    71 {
    72     DEFINE_STATIC_LOCAL(String, name, ("__WebKitDatabaseInfoTable__"));
    73     return name;
    74 }
    75 
    76 static Mutex& guidMutex()
    77 {
    78     // Note: We don't have to use AtomicallyInitializedStatic here because
    79     // this function is called once in the constructor on the main thread
    80     // before any other threads that call this function are used.
    81     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
    82     return mutex;
    83 }
    84 
    85 typedef HashMap<int, String> GuidVersionMap;
    86 static GuidVersionMap& guidToVersionMap()
    87 {
    88     DEFINE_STATIC_LOCAL(GuidVersionMap, map, ());
    89     return map;
    90 }
    91 
    92 // NOTE: Caller must lock guidMutex().
    93 static inline void updateGuidVersionMap(int guid, String newVersion)
    94 {
    95     // Ensure the the mutex is locked.
    96     ASSERT(!guidMutex().tryLock());
    97 
    98     // Note: It is not safe to put an empty string into the guidToVersionMap() map.
    99     // That's because the map is cross-thread, but empty strings are per-thread.
    100     // The copy() function makes a version of the string you can use on the current
    101     // thread, but we need a string we can keep in a cross-thread data structure.
    102     // FIXME: This is a quite-awkward restriction to have to program with.
    103 
    104     // Map null string to empty string (see comment above).
    105     guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.threadsafeCopy());
    106 }
    107 
    108 typedef HashMap<int, HashSet<Database*>*> GuidDatabaseMap;
    109 static GuidDatabaseMap& guidToDatabaseMap()
    110 {
    111     DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ());
    112     return map;
    113 }
    114 
    115 static const String& databaseVersionKey()
    116 {
    117     DEFINE_STATIC_LOCAL(String, key, ("WebKitDatabaseVersionKey"));
    118     return key;
    119 }
    120 
    121 static int guidForOriginAndName(const String& origin, const String& name);
    122 
    12365class DatabaseCreationCallbackTask : public ScriptExecutionContext::Task {
    12466public:
    125     static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtr<Database> database)
    126     {
    127         return new DatabaseCreationCallbackTask(database);
    128     }
    129 
    130     virtual void performTask(ScriptExecutionContext*)
    131     {
    132         m_database->performCreationCallback();
     67    static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtr<Database> database, PassRefPtr<DatabaseCallback> creationCallback)
     68    {
     69        return new DatabaseCreationCallbackTask(database, creationCallback);
     70    }
     71
     72    virtual void performTask(ScriptExecutionContext* context)
     73    {
     74        m_creationCallback->handleEvent(context, m_database.get());
    13375    }
    13476
    13577private:
    136     DatabaseCreationCallbackTask(PassRefPtr<Database> database)
     78    DatabaseCreationCallbackTask(PassRefPtr<Database> database, PassRefPtr<DatabaseCallback> callback)
    13779        : m_database(database)
     80        , m_creationCallback(callback)
    13881    {
    13982    }
    14083
    14184    RefPtr<Database> m_database;
     85    RefPtr<DatabaseCallback> m_creationCallback;
    14286};
    14387
     
    14892{
    14993    if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) {
    150         // FIXME: There should be an exception raised here in addition to returning a null Database object.  The question has been raised with the WHATWG.
    15194        LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data());
    15295        return 0;
    15396    }
    15497
    155     RefPtr<Database> database = adoptRef(new Database(context, name, expectedVersion, displayName, estimatedSize, creationCallback));
    156 
    157     if (!database->openAndVerifyVersion(e)) {
     98    RefPtr<Database> database = adoptRef(new Database(context, name, expectedVersion, displayName, estimatedSize));
     99
     100    if (!database->openAndVerifyVersion(!creationCallback, e)) {
    158101        LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data());
    159102        context->removeOpenDatabase(database.get());
     
    177120    // implementation issues, we have to reset m_expectedVersion here instead of doing
    178121    // it inside performOpenAndVerify() which is run on the DB thread.
    179     if (database->isNew() && database->m_creationCallback.get()) {
     122    if (database->isNew() && creationCallback.get()) {
    180123        database->m_expectedVersion = "";
    181124        LOG(StorageAPI, "Scheduling DatabaseCreationCallbackTask for database %p\n", database.get());
    182         database->m_scriptExecutionContext->postTask(DatabaseCreationCallbackTask::create(database));
     125        database->m_scriptExecutionContext->postTask(DatabaseCreationCallbackTask::create(database, creationCallback));
    183126    }
    184127
     
    186129}
    187130
    188 Database::Database(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback)
    189     : m_transactionInProgress(false)
     131Database::Database(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
     132    : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize)
     133    , m_transactionInProgress(false)
    190134    , m_isTransactionQueueEnabled(true)
    191     , m_scriptExecutionContext(context)
    192     , m_name(name.crossThreadString())
    193     , m_guid(0)
    194     , m_expectedVersion(expectedVersion.crossThreadString())
    195     , m_displayName(displayName.crossThreadString())
    196     , m_estimatedSize(estimatedSize)
    197135    , m_deleted(false)
    198136    , m_stopped(false)
    199     , m_opened(false)
    200     , m_new(false)
    201     , m_creationCallback(creationCallback)
    202 {
    203     ASSERT(m_scriptExecutionContext.get());
    204     m_contextThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin();
     137{
    205138    m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->threadsafeCopy();
    206     if (m_name.isNull())
    207         m_name = "";
    208139
    209140    ScriptController::initializeThreading();
    210 
    211     m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
    212 
    213     {
    214         MutexLocker locker(guidMutex());
    215 
    216         HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
    217         if (!hashSet) {
    218             hashSet = new HashSet<Database*>;
    219             guidToDatabaseMap().set(m_guid, hashSet);
    220         }
    221 
    222         hashSet->add(this);
    223     }
    224 
    225141    ASSERT(m_scriptExecutionContext->databaseThread());
    226     m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin(), m_name);
    227 
    228     DatabaseTracker::tracker().addOpenDatabase(this);
    229     context->addOpenDatabase(this);
     142
     143    m_scriptExecutionContext->addOpenDatabase(this);
    230144}
    231145
     
    254168}
    255169
    256 bool Database::openAndVerifyVersion(ExceptionCode& e)
     170String Database::version() const
     171{
     172    if (m_deleted)
     173        return String();
     174    return AbstractDatabase::version();
     175}
     176
     177bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode& e)
    257178{
    258179    if (!m_scriptExecutionContext->databaseThread())
    259180        return false;
    260     m_databaseAuthorizer = DatabaseAuthorizer::create();
    261181
    262182    bool success = false;
    263183    DatabaseTaskSynchronizer synchronizer;
    264     OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, &synchronizer, e, success);
     184    OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, e, success);
    265185
    266186    m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
     
    268188
    269189    return success;
    270 }
    271 
    272 
    273 static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
    274 {
    275     SQLiteStatement statement(db, query);
    276     int result = statement.prepare();
    277 
    278     if (result != SQLResultOk) {
    279         LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data());
    280         return false;
    281     }
    282 
    283     result = statement.step();
    284     if (result == SQLResultRow) {
    285         resultString = statement.getColumnText(0);
    286         return true;
    287     } else if (result == SQLResultDone) {
    288         resultString = String();
    289         return true;
    290     } else {
    291         LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data());
    292         return false;
    293     }
    294 }
    295 
    296 bool Database::getVersionFromDatabase(String& version)
    297 {
    298     DEFINE_STATIC_LOCAL(String, getVersionQuery, ("SELECT value FROM " + databaseInfoTableName() + " WHERE key = '" + databaseVersionKey() + "';"));
    299 
    300     m_databaseAuthorizer->disable();
    301 
    302     bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, getVersionQuery.threadsafeCopy(), version);
    303     if (!result)
    304         LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data());
    305 
    306     m_databaseAuthorizer->enable();
    307 
    308     return result;
    309 }
    310 
    311 static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value)
    312 {
    313     SQLiteStatement statement(db, query);
    314     int result = statement.prepare();
    315 
    316     if (result != SQLResultOk) {
    317         LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data());
    318         return false;
    319     }
    320 
    321     statement.bindText(1, value);
    322 
    323     result = statement.step();
    324     if (result != SQLResultDone) {
    325         LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data());
    326         return false;
    327     }
    328 
    329     return true;
    330 }
    331 
    332 bool Database::setVersionInDatabase(const String& version)
    333 {
    334     // The INSERT will replace an existing entry for the database with the new version number, due to the UNIQUE ON CONFLICT REPLACE
    335     // clause in the CREATE statement (see Database::performOpenAndVerify()).
    336     DEFINE_STATIC_LOCAL(String, setVersionQuery, ("INSERT INTO " + databaseInfoTableName() + " (key, value) VALUES ('" + databaseVersionKey() + "', ?);"));
    337 
    338     m_databaseAuthorizer->disable();
    339 
    340     bool result = setTextValueInDatabase(m_sqliteDatabase, setVersionQuery.threadsafeCopy(), version);
    341     if (!result)
    342         LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), setVersionQuery.ascii().data());
    343 
    344     m_databaseAuthorizer->enable();
    345 
    346     return result;
    347 }
    348 
    349 bool Database::versionMatchesExpected() const
    350 {
    351     if (!m_expectedVersion.isEmpty()) {
    352         MutexLocker locker(guidMutex());
    353         return m_expectedVersion == guidToVersionMap().get(m_guid);
    354     }
    355 
    356     return true;
    357190}
    358191
     
    411244    RefPtr<Database> protect = this;
    412245
    413     if (!m_opened)
    414         return;
    415 
    416246    ASSERT(m_scriptExecutionContext->databaseThread());
    417247    ASSERT(currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID());
    418     m_sqliteDatabase.close();
     248
     249    closeDatabase();
     250
    419251    // Must ref() before calling databaseThread()->recordDatabaseClosed().
    420252    m_scriptExecutionContext->databaseThread()->recordDatabaseClosed(this);
    421     m_opened = false;
    422 
    423     {
    424         MutexLocker locker(guidMutex());
    425 
    426         HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
    427         ASSERT(hashSet);
    428         ASSERT(hashSet->contains(this));
    429         hashSet->remove(this);
    430         if (hashSet->isEmpty()) {
    431             guidToDatabaseMap().remove(m_guid);
    432             delete hashSet;
    433             guidToVersionMap().remove(m_guid);
    434         }
    435     }
    436 
    437253    m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
    438254    if (policy == RemoveDatabaseFromContext)
     
    464280        m_transactionInProgress = false;
    465281    }
     282
     283    if (m_scriptExecutionContext->databaseThread())
     284        m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
    466285}
    467286
     
    469288{
    470289    return DatabaseTracker::tracker().getMaxSizeForDatabase(this);
    471 }
    472 
    473 void Database::disableAuthorizer()
    474 {
    475     ASSERT(m_databaseAuthorizer);
    476     m_databaseAuthorizer->disable();
    477 }
    478 
    479 void Database::enableAuthorizer()
    480 {
    481     ASSERT(m_databaseAuthorizer);
    482     m_databaseAuthorizer->enable();
    483 }
    484 
    485 void Database::setAuthorizerReadOnly()
    486 {
    487     ASSERT(m_databaseAuthorizer);
    488     m_databaseAuthorizer->setReadOnly();
    489 }
    490 
    491 bool Database::lastActionChangedDatabase()
    492 {
    493     ASSERT(m_databaseAuthorizer);
    494     return m_databaseAuthorizer->lastActionChangedDatabase();
    495 }
    496 
    497 bool Database::lastActionWasInsert()
    498 {
    499     ASSERT(m_databaseAuthorizer);
    500     return m_databaseAuthorizer->lastActionWasInsert();
    501 }
    502 
    503 void Database::resetDeletes()
    504 {
    505     ASSERT(m_databaseAuthorizer);
    506     m_databaseAuthorizer->resetDeletes();
    507 }
    508 
    509 bool Database::hadDeletes()
    510 {
    511     ASSERT(m_databaseAuthorizer);
    512     return m_databaseAuthorizer->hadDeletes();
    513 }
    514 
    515 static int guidForOriginAndName(const String& origin, const String& name)
    516 {
    517     String stringID;
    518     if (origin.endsWith("/"))
    519         stringID = origin + name;
    520     else
    521         stringID = origin + "/" + name;
    522 
    523     // Note: We don't have to use AtomicallyInitializedStatic here because
    524     // this function is called once in the constructor on the main thread
    525     // before any other threads that call this function are used.
    526     DEFINE_STATIC_LOCAL(Mutex, stringIdentifierMutex, ());
    527     MutexLocker locker(stringIdentifierMutex);
    528     typedef HashMap<String, int> IDGuidMap;
    529     DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ());
    530     int guid = stringIdentifierToGUIDMap.get(stringID);
    531     if (!guid) {
    532         static int currentNewGUID = 1;
    533         guid = currentNewGUID++;
    534         stringIdentifierToGUIDMap.set(stringID, guid);
    535     }
    536 
    537     return guid;
    538 }
    539 
    540 void Database::resetAuthorizer()
    541 {
    542     if (m_databaseAuthorizer)
    543         m_databaseAuthorizer->reset();
    544290}
    545291
     
    558304}
    559305
    560 bool Database::performOpenAndVerify(ExceptionCode& e)
    561 {
    562     if (!m_sqliteDatabase.open(m_filename, true)) {
    563         LOG_ERROR("Unable to open database at path %s", m_filename.ascii().data());
    564         e = INVALID_STATE_ERR;
    565         return false;
    566     }
    567     if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum())
    568         LOG_ERROR("Unable to turn on incremental auto-vacuum for database %s", m_filename.ascii().data());
    569 
    570     ASSERT(m_databaseAuthorizer);
    571     m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer);
    572     m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
    573 
    574     String currentVersion;
    575     {
    576         MutexLocker locker(guidMutex());
    577 
    578         GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid);
    579         if (entry != guidToVersionMap().end()) {
    580             // Map null string to empty string (see updateGuidVersionMap()).
    581             currentVersion = entry->second.isNull() ? String("") : entry->second;
    582             LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());
    583         } else {
    584             LOG(StorageAPI, "No cached version for guid %i", m_guid);
    585 
    586             if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) {
    587                 m_new = true;
    588 
    589                 if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + databaseInfoTableName() + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
    590                     LOG_ERROR("Unable to create table %s in database %s", databaseInfoTableName().ascii().data(), databaseDebugName().ascii().data());
    591                     e = INVALID_STATE_ERR;
    592                     // Close the handle to the database file.
    593                     m_sqliteDatabase.close();
    594                     return false;
    595                 }
    596             }
    597 
    598             if (!getVersionFromDatabase(currentVersion)) {
    599                 LOG_ERROR("Failed to get current version from database %s", databaseDebugName().ascii().data());
    600                 e = INVALID_STATE_ERR;
    601                 // Close the handle to the database file.
    602                 m_sqliteDatabase.close();
    603                 return false;
    604             }
    605             if (currentVersion.length()) {
    606                 LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
    607             } else if (!m_new || !m_creationCallback) {
    608                 LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
    609                 if (!setVersionInDatabase(m_expectedVersion)) {
    610                     LOG_ERROR("Failed to set version %s in database %s", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
    611                     e = INVALID_STATE_ERR;
    612                     // Close the handle to the database file.
    613                     m_sqliteDatabase.close();
    614                     return false;
    615                 }
    616                 currentVersion = m_expectedVersion;
    617             }
    618 
    619             updateGuidVersionMap(m_guid, currentVersion);
    620         }
    621     }
    622 
    623     if (currentVersion.isNull()) {
    624         LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data());
    625         currentVersion = "";
    626     }
    627 
    628     // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception.
    629     // If the expected version is the empty string, then we always return with whatever version of the database we have.
    630     if ((!m_new || !m_creationCallback) && m_expectedVersion.length() && m_expectedVersion != currentVersion) {
    631         LOG(StorageAPI, "page expects version %s from database %s, which actually has version name %s - openDatabase() call will fail", m_expectedVersion.ascii().data(),
    632             databaseDebugName().ascii().data(), currentVersion.ascii().data());
    633         e = INVALID_STATE_ERR;
    634         // Close the handle to the database file.
    635         m_sqliteDatabase.close();
    636         return false;
    637     }
    638 
    639     // All checks passed and we still have a handle to this database file.
    640     // Make sure DatabaseThread closes it when DatabaseThread goes away.
    641     m_opened = true;
    642     if (m_scriptExecutionContext->databaseThread())
    643         m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this);
    644 
    645     return true;
     306bool Database::performOpenAndVerify(bool setVersionInNewDatabase, ExceptionCode& e)
     307{
     308    if (AbstractDatabase::performOpenAndVerify(setVersionInNewDatabase, e)) {
     309        if (m_scriptExecutionContext->databaseThread())
     310            m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this);
     311
     312        return true;
     313    }
     314
     315    return false;
    646316}
    647317
     
    758428}
    759429
    760 void Database::performCreationCallback()
    761 {
    762     m_creationCallback->handleEvent(m_scriptExecutionContext.get(), this);
    763 }
    764 
    765430SQLTransactionClient* Database::transactionClient() const
    766431{
     
    771436{
    772437    return m_scriptExecutionContext->databaseThread()->transactionCoordinator();
    773 }
    774 
    775 String Database::version() const
    776 {
    777     if (m_deleted)
    778         return String();
    779     MutexLocker locker(guidMutex());
    780     return guidToVersionMap().get(m_guid).threadsafeCopy();
    781438}
    782439
     
    798455}
    799456
    800 void Database::setExpectedVersion(const String& version)
    801 {
    802     m_expectedVersion = version.threadsafeCopy();
    803     // Update the in memory database version map.
    804     MutexLocker locker(guidMutex());
    805     updateGuidVersionMap(m_guid, version);
    806 }
    807 
    808457SecurityOrigin* Database::securityOrigin() const
    809458{
     
    815464}
    816465
    817 String Database::stringIdentifier() const
    818 {
    819     // Return a deep copy for ref counting thread safety
    820     return m_name.threadsafeCopy();
    821 }
    822 
    823 String Database::displayName() const
    824 {
    825     // Return a deep copy for ref counting thread safety
    826     return m_displayName.threadsafeCopy();
    827 }
    828 
    829 unsigned long Database::estimatedSize() const
    830 {
    831     return m_estimatedSize;
    832 }
    833 
    834 String Database::fileName() const
    835 {
    836     // Return a deep copy for ref counting thread safety
    837     return m_filename.threadsafeCopy();
    838 }
    839 
    840466void Database::incrementalVacuumIfNeeded()
    841467{
  • trunk/WebCore/storage/Database.h

    r61866 r62153  
    3434#include "PlatformString.h"
    3535#include "SQLiteDatabase.h"
    36 #ifndef NDEBUG
    37 #include "SecurityOrigin.h"
    38 #endif
    3936
    4037#include <wtf/Deque.h>
     
    4340namespace WebCore {
    4441
    45 class DatabaseAuthorizer;
    4642class DatabaseCallback;
    47 class DatabaseThread;
    4843class ScriptExecutionContext;
    4944class SecurityOrigin;
     
    5550class VoidCallback;
    5651
    57 typedef int ExceptionCode;
    58 
    5952class Database : public AbstractDatabase {
    6053public:
     
    6457    static PassRefPtr<Database> openDatabase(ScriptExecutionContext*, const String& name, const String& expectedVersion, const String& displayName,
    6558                                             unsigned long estimatedSize, PassRefPtr<DatabaseCallback>, ExceptionCode&);
    66     String version() const;
     59    virtual String version() const;
    6760    void changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr<SQLTransactionCallback>,
    6861                       PassRefPtr<SQLTransactionErrorCallback>, PassRefPtr<VoidCallback> successCallback);
     
    7164
    7265    // Internal engine support
    73     static const String& databaseInfoTableName();
    74 
    75     void disableAuthorizer();
    76     void enableAuthorizer();
    77     void setAuthorizerReadOnly();
    78     bool lastActionChangedDatabase();
    79     bool lastActionWasInsert();
    80     void resetDeletes();
    81     bool hadDeletes();
    82 
    8366    Vector<String> tableNames();
    8467
    85     virtual ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext.get(); }
    8668    virtual SecurityOrigin* securityOrigin() const;
    8769    SQLiteDatabase& sqliteDatabase() { return m_sqliteDatabase; }
    88     virtual String stringIdentifier() const;
    89     virtual String displayName() const;
    90     virtual unsigned long estimatedSize() const;
    91     virtual String fileName() const;
    92 
    93     bool getVersionFromDatabase(String&);
    94     bool setVersionInDatabase(const String&);
    95     void setExpectedVersion(const String&);
    96     bool versionMatchesExpected() const;
    9770
    9871    virtual void markAsDeletedAndClose();
     
    10275    void close(ClosePolicy);
    10376    virtual void closeImmediately();
    104     bool opened() const { return m_opened; }
    10577
    10678    void stop();
    10779    bool stopped() const { return m_stopped; }
    108 
    109     bool isNew() const { return m_new; }
    11080
    11181    unsigned long long databaseSize() const;
     
    11383
    11484    // Called from DatabaseThread, must be prepared to work on the background thread
    115     void resetAuthorizer();
    11685    void performPolicyChecks();
    11786
    118     bool performOpenAndVerify(ExceptionCode&);
     87    virtual bool performOpenAndVerify(bool setVersionInNewDatabase, ExceptionCode&);
    11988
    12089    void inProgressTransactionCompleted();
     
    12392
    12493    Vector<String> performGetTableNames();
    125     void performCreationCallback();
    12694
    12795    SQLTransactionClient* transactionClient() const;
     
    132100private:
    133101    Database(ScriptExecutionContext*, const String& name, const String& expectedVersion,
    134              const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback>);
     102             const String& displayName, unsigned long estimatedSize);
    135103
    136     bool openAndVerifyVersion(ExceptionCode&);
     104    bool openAndVerifyVersion(bool setVersionInNewDatabase, ExceptionCode&);
    137105
    138106    void scheduleTransaction();
     107
     108    static void deliverPendingCallback(void*);
    139109
    140110    Deque<RefPtr<SQLTransaction> > m_transactionQueue;
     
    143113    bool m_isTransactionQueueEnabled;
    144114
    145     static void deliverPendingCallback(void*);
    146 
    147     RefPtr<ScriptExecutionContext> m_scriptExecutionContext;
    148     RefPtr<SecurityOrigin> m_contextThreadSecurityOrigin;
    149115    RefPtr<SecurityOrigin> m_databaseThreadSecurityOrigin;
    150     String m_name;
    151     int m_guid;
    152     String m_expectedVersion;
    153     String m_displayName;
    154     unsigned long m_estimatedSize;
    155     String m_filename;
    156116
    157117    bool m_deleted;
    158 
    159118    bool m_stopped;
    160 
    161     bool m_opened;
    162 
    163     bool m_new;
    164 
    165     SQLiteDatabase m_sqliteDatabase;
    166     RefPtr<DatabaseAuthorizer> m_databaseAuthorizer;
    167 
    168     RefPtr<DatabaseCallback> m_creationCallback;
    169 
    170 #ifndef NDEBUG
    171     String databaseDebugName() const { return m_contextThreadSecurityOrigin->toString() + "::" + m_name; }
    172 #endif
    173119};
    174120
  • trunk/WebCore/storage/DatabaseAuthorizer.cpp

    r61866 r62153  
    3131
    3232#if ENABLE(DATABASE)
    33 #include "Database.h"
    3433#include "PlatformString.h"
     34#include <wtf/PassRefPtr.h>
    3535
    3636namespace WebCore {
    3737
    38 DatabaseAuthorizer::DatabaseAuthorizer()
     38PassRefPtr<DatabaseAuthorizer> DatabaseAuthorizer::create(const String& databaseInfoTableName)
     39{
     40    return adoptRef(new DatabaseAuthorizer(databaseInfoTableName));
     41}
     42
     43DatabaseAuthorizer::DatabaseAuthorizer(const String& databaseInfoTableName)
    3944    : m_securityEnabled(false)
     45    , m_databaseInfoTableName(databaseInfoTableName)
    4046{
    4147    reset();
     
    389395}
    390396
    391 int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName)
     397int DatabaseAuthorizer::denyBasedOnTableName(const String& tableName) const
    392398{
    393399    if (!m_securityEnabled)
     
    400406    //        return SQLAuthDeny;
    401407
    402     if (equalIgnoringCase(tableName, Database::databaseInfoTableName()))
     408    if (equalIgnoringCase(tableName, m_databaseInfoTableName))
    403409        return SQLAuthDeny;
    404410
  • trunk/WebCore/storage/DatabaseAuthorizer.h

    r61866 r62153  
    2929#define DatabaseAuthorizer_h
    3030
     31#include "PlatformString.h"
    3132#include "StringHash.h"
     33#include <wtf/Forward.h>
    3234#include <wtf/HashSet.h>
    33 #include <wtf/PassRefPtr.h>
    34 #include <wtf/Threading.h>
     35#include <wtf/ThreadSafeShared.h>
    3536
    3637namespace WebCore {
     
    4445class DatabaseAuthorizer : public ThreadSafeShared<DatabaseAuthorizer> {
    4546public:
    46     static PassRefPtr<DatabaseAuthorizer> create() { return adoptRef(new DatabaseAuthorizer); }
     47    static PassRefPtr<DatabaseAuthorizer> create(const String& databaseInfoTableName);
    4748
    4849    int createTable(const String& tableName);
     
    9899
    99100private:
    100     DatabaseAuthorizer();
     101    DatabaseAuthorizer(const String& databaseInfoTableName);
    101102    void addWhitelistedFunctions();
    102     int denyBasedOnTableName(const String&);
     103    int denyBasedOnTableName(const String&) const;
    103104    int updateDeletesBasedOnTableName(const String&);
    104105
     
    109110    bool m_hadDeletes : 1;
    110111
     112    const String m_databaseInfoTableName;
     113
    111114    HashSet<String, CaseFoldingHash> m_whitelistedFunctions;
    112115};
  • trunk/WebCore/storage/DatabaseSync.cpp

    r61866 r62153  
    3232#if ENABLE(DATABASE)
    3333#include "DatabaseCallback.h"
     34#include "DatabaseTracker.h"
    3435#include "ExceptionCode.h"
     36#include "Logging.h"
    3537#include "SQLTransactionSyncCallback.h"
    3638#include "ScriptExecutionContext.h"
     39#include "SecurityOrigin.h"
    3740#include <wtf/PassRefPtr.h>
    3841#include <wtf/RefPtr.h>
    39 #include <wtf/StdLibExtras.h>
    4042
    4143namespace WebCore {
    4244
    43 const String& DatabaseSync::databaseInfoTableName()
     45PassRefPtr<DatabaseSync> DatabaseSync::openDatabaseSync(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName,
     46                                                        unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& ec)
    4447{
    45     DEFINE_STATIC_LOCAL(String, name, ("__WebKitDatabaseInfoTable__"));
    46     return name;
    47 }
     48    ASSERT(context->isContextThread());
    4849
    49 PassRefPtr<DatabaseSync> DatabaseSync::openDatabaseSync(ScriptExecutionContext*, const String&, const String&, const String&,
    50                                                         unsigned long, PassRefPtr<DatabaseCallback>, ExceptionCode& ec)
    51 {
    52     // FIXME: uncomment the assert once we use the ScriptExecutionContext* parameter
    53     //ASSERT(context->isContextThread());
     50    if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) {
     51        LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data());
     52        return 0;
     53    }
    5454
    55     ec = SECURITY_ERR;
    56     return 0;
     55    RefPtr<DatabaseSync> database = adoptRef(new DatabaseSync(context, name, expectedVersion, displayName, estimatedSize));
     56
     57    if (!database->performOpenAndVerify(!creationCallback, ec)) {
     58        LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data());
     59        DatabaseTracker::tracker().removeOpenDatabase(database.get());
     60        return 0;
     61    }
     62
     63    DatabaseTracker::tracker().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
     64
     65    if (database->isNew() && creationCallback.get()) {
     66        database->m_expectedVersion = "";
     67        LOG(StorageAPI, "Invoking the creation callback for database %p\n", database.get());
     68        creationCallback->handleEvent(context, database.get());
     69    }
     70
     71    return database;
    5772}
    5873
    5974DatabaseSync::DatabaseSync(ScriptExecutionContext* context, const String& name, const String& expectedVersion,
    60                            const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback)
    61     : m_scriptExecutionContext(context)
    62     , m_name(name.crossThreadString())
    63     , m_expectedVersion(expectedVersion.crossThreadString())
    64     , m_displayName(displayName.crossThreadString())
    65     , m_estimatedSize(estimatedSize)
    66     , m_creationCallback(creationCallback)
     75                           const String& displayName, unsigned long estimatedSize)
     76    : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize)
    6777{
    68     ASSERT(context->isContextThread());
    6978}
    7079
     
    7281{
    7382    ASSERT(m_scriptExecutionContext->isContextThread());
    74 }
    7583
    76 String DatabaseSync::version() const
    77 {
    78     ASSERT(m_scriptExecutionContext->isContextThread());
    79     return String();
     84    if (opened()) {
     85        DatabaseTracker::tracker().removeOpenDatabase(this);
     86        closeDatabase();
     87    }
    8088}
    8189
     
    9098}
    9199
    92 ScriptExecutionContext* DatabaseSync::scriptExecutionContext() const
     100void DatabaseSync::markAsDeletedAndClose()
    93101{
    94     ASSERT(m_scriptExecutionContext->isContextThread());
    95     return m_scriptExecutionContext.get();
     102    // FIXME: need to do something similar to closeImmediately(), but in a sync way
     103}
     104
     105class CloseSyncDatabaseOnContextThreadTask : public ScriptExecutionContext::Task {
     106public:
     107    static PassOwnPtr<CloseSyncDatabaseOnContextThreadTask> create(PassRefPtr<DatabaseSync> database)
     108    {
     109        return new CloseSyncDatabaseOnContextThreadTask(database);
     110    }
     111
     112    virtual void performTask(ScriptExecutionContext*)
     113    {
     114        m_database->closeImmediately();
     115    }
     116
     117private:
     118    CloseSyncDatabaseOnContextThreadTask(PassRefPtr<DatabaseSync> database)
     119        : m_database(database)
     120    {
     121    }
     122
     123    RefPtr<DatabaseSync> m_database;
     124};
     125
     126void DatabaseSync::closeImmediately()
     127{
     128    if (!m_scriptExecutionContext->isContextThread()) {
     129        m_scriptExecutionContext->postTask(CloseSyncDatabaseOnContextThreadTask::create(this));
     130        return;
     131    }
     132
     133    if (!opened())
     134        return;
     135
     136    DatabaseTracker::tracker().removeOpenDatabase(this);
     137
     138    closeDatabase();
    96139}
    97140
  • trunk/WebCore/storage/DatabaseSync.h

    r61866 r62153  
    3131
    3232#if ENABLE(DATABASE)
     33#include "AbstractDatabase.h"
    3334#include "PlatformString.h"
    3435#include <wtf/Forward.h>
     36#ifndef NDEBUG
     37#include "SecurityOrigin.h"
     38#endif
    3539
    3640namespace WebCore {
     
    3943class SQLTransactionSyncCallback;
    4044class ScriptExecutionContext;
    41 
    42 typedef int ExceptionCode;
     45class SecurityOrigin;
    4346
    4447// Instances of this class should be created and used only on the worker's context thread.
    45 class DatabaseSync : public RefCounted<DatabaseSync> {
     48class DatabaseSync : public AbstractDatabase {
    4649public:
    47     ~DatabaseSync();
     50    virtual ~DatabaseSync();
    4851
    49     // Direct support for the DOM API
    5052    static PassRefPtr<DatabaseSync> openDatabaseSync(ScriptExecutionContext*, const String& name, const String& expectedVersion,
    5153                                                     const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback>, ExceptionCode&);
    52     String version() const;
    5354    void changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr<SQLTransactionSyncCallback>, ExceptionCode&);
    5455    void transaction(PassRefPtr<SQLTransactionSyncCallback>, bool readOnly, ExceptionCode&);
    5556
    56     // Internal engine support
    57     ScriptExecutionContext* scriptExecutionContext() const;
    58 
    59     static const String& databaseInfoTableName();
     57    virtual void markAsDeletedAndClose();
     58    virtual void closeImmediately();
    6059
    6160private:
    6261    DatabaseSync(ScriptExecutionContext*, const String& name, const String& expectedVersion,
    63                  const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback>);
    64 
    65     RefPtr<ScriptExecutionContext> m_scriptExecutionContext;
    66     String m_name;
    67     String m_expectedVersion;
    68     String m_displayName;
    69     unsigned long m_estimatedSize;
    70     RefPtr<DatabaseCallback> m_creationCallback;
    71 
    72 #ifndef NDEBUG
    73     String databaseDebugName() const { return String(); }
    74 #endif
     62                 const String& displayName, unsigned long estimatedSize);
    7563};
    7664
  • trunk/WebCore/storage/DatabaseTask.cpp

    r61866 r62153  
    8888// Opens the database file and verifies the version matches the expected version.
    8989
    90 DatabaseOpenTask::DatabaseOpenTask(Database* database, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
     90DatabaseOpenTask::DatabaseOpenTask(Database* database, bool setVersionInNewDatabase, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
    9191    : DatabaseTask(database, synchronizer)
     92    , m_setVersionInNewDatabase(setVersionInNewDatabase)
    9293    , m_code(code)
    9394    , m_success(success)
     
    9899void DatabaseOpenTask::doPerformTask()
    99100{
    100     m_success = database()->performOpenAndVerify(m_code);
     101    m_success = database()->performOpenAndVerify(m_setVersionInNewDatabase, m_code);
    101102}
    102103
  • trunk/WebCore/storage/DatabaseTask.h

    r61866 r62153  
    8686class DatabaseOpenTask : public DatabaseTask {
    8787public:
    88     static PassOwnPtr<DatabaseOpenTask> create(Database* db, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
     88    static PassOwnPtr<DatabaseOpenTask> create(Database* db, bool setVersionInNewDatabase, DatabaseTaskSynchronizer* synchronizer, ExceptionCode& code, bool& success)
    8989    {
    90         return new DatabaseOpenTask(db, synchronizer, code, success);
     90        return new DatabaseOpenTask(db, setVersionInNewDatabase, synchronizer, code, success);
    9191    }
    9292
    9393private:
    94     DatabaseOpenTask(Database*, DatabaseTaskSynchronizer*, ExceptionCode&, bool& success);
     94    DatabaseOpenTask(Database*, bool setVersionInNewDatabase, DatabaseTaskSynchronizer*, ExceptionCode&, bool& success);
    9595
    9696    virtual void doPerformTask();
     
    9999#endif
    100100
     101    bool m_setVersionInNewDatabase;
    101102    ExceptionCode& m_code;
    102103    bool& m_success;
  • trunk/WebKit/chromium/ChangeLog

    r62136 r62153  
     12010-06-29  Dumitru Daniliuc  <dumi@chromium.org>
     2
     3        Reviewed by Darin Fisher.
     4
     5        Simplify the WebDatabase interface.
     6        https://bugs.webkit.org/show_bug.cgi?id=40607
     7
     8        Do not ref()/deref() the private AbstractDatabase member. This
     9        allows us to use WebDatabase in the destructors of the DB
     10        classes.
     11
     12        * public/WebDatabase.h:
     13        (WebKit::WebDatabase::WebDatabase):
     14        * src/WebDatabase.cpp:
     15        (WebKit::WebDatabase::name):
     16        (WebKit::WebDatabase::displayName):
     17        (WebKit::WebDatabase::estimatedSize):
     18        (WebKit::WebDatabase::securityOrigin):
     19        (WebKit::WebDatabase::WebDatabase):
     20
    1212010-06-29  Zhe Su  <suzhe@chromium.org>
    222
  • trunk/WebKit/chromium/public/WebDatabase.h

    r61154 r62153  
    3535#include "WebSecurityOrigin.h"
    3636
    37 #if WEBKIT_IMPLEMENTATION
    3837namespace WebCore { class AbstractDatabase; }
    39 namespace WTF { template <typename T> class PassRefPtr; }
    40 #endif
    4138
    4239namespace WebKit {
    4340
    4441class WebDatabaseObserver;
    45 class WebDatabasePrivate;
    4642class WebString;
    4743
    4844class WebDatabase {
    4945public:
    50     WebDatabase() : m_private(0) { }
    51     WebDatabase(const WebDatabase& d) : m_private(0) { assign(d); }
    52     ~WebDatabase() { reset(); }
    53 
    54     WebDatabase& operator=(const WebDatabase& d)
    55     {
    56         assign(d);
    57         return *this;
    58     }
    59 
    60     WEBKIT_API void reset();
    61     WEBKIT_API void assign(const WebDatabase&);
    62     bool isNull() const { return !m_private; }
    63 
    6446    WEBKIT_API WebString name() const;
    6547    WEBKIT_API WebString displayName() const;
     
    7759
    7860#if WEBKIT_IMPLEMENTATION
    79     WebDatabase(const WTF::PassRefPtr<WebCore::AbstractDatabase>&);
    80     WebDatabase& operator=(const WTF::PassRefPtr<WebCore::AbstractDatabase>&);
    81     operator WTF::PassRefPtr<WebCore::AbstractDatabase>() const;
     61    WebDatabase(const WebCore::AbstractDatabase*);
    8262#endif
    8363
    8464private:
    85     void assign(WebDatabasePrivate*);
    86 
    87     WebDatabasePrivate* m_private;
     65    WebDatabase() { }
     66    const WebCore::AbstractDatabase* m_database;
    8867};
    8968
  • trunk/WebKit/chromium/src/WebDatabase.cpp

    r61154 r62153  
    3333
    3434#include "AbstractDatabase.h"
    35 #include "DatabaseTask.h"
    36 #include "DatabaseThread.h"
    3735#include "DatabaseTracker.h"
    38 #include "Document.h"
    39 #include "KURL.h"
    4036#include "QuotaTracker.h"
    4137#include "SecurityOrigin.h"
     
    5147static WebDatabaseObserver* databaseObserver = 0;
    5248
    53 class WebDatabasePrivate : public AbstractDatabase {
    54 };
    55 
    56 void WebDatabase::reset()
    57 {
    58     assign(0);
    59 }
    60 
    61 void WebDatabase::assign(const WebDatabase& other)
    62 {
    63     WebDatabasePrivate* d = const_cast<WebDatabasePrivate*>(other.m_private);
    64     if (d)
    65         d->ref();
    66     assign(d);
    67 }
    68 
    6949WebString WebDatabase::name() const
    7050{
    71     ASSERT(m_private);
    72     return m_private->stringIdentifier();
     51    ASSERT(m_database);
     52    return m_database->stringIdentifier();
    7353}
    7454
    7555WebString WebDatabase::displayName() const
    7656{
    77     ASSERT(m_private);
    78     return m_private->displayName();
     57    ASSERT(m_database);
     58    return m_database->displayName();
    7959}
    8060
    8161unsigned long WebDatabase::estimatedSize() const
    8262{
    83     ASSERT(m_private);
    84     return m_private->estimatedSize();
     63    ASSERT(m_database);
     64    return m_database->estimatedSize();
    8565}
    8666
    8767WebSecurityOrigin WebDatabase::securityOrigin() const
    8868{
    89     ASSERT(m_private);
    90     return WebSecurityOrigin(m_private->securityOrigin());
     69    ASSERT(m_database);
     70    return WebSecurityOrigin(m_database->securityOrigin());
    9171}
    9272
     
    11898}
    11999
    120 WebDatabase::WebDatabase(const WTF::PassRefPtr<AbstractDatabase>& database)
    121     : m_private(static_cast<WebDatabasePrivate*>(database.releaseRef()))
     100WebDatabase::WebDatabase(const AbstractDatabase* database)
     101    : m_database(database)
    122102{
    123103}
    124104
    125 WebDatabase& WebDatabase::operator=(const WTF::PassRefPtr<AbstractDatabase>& database)
    126 {
    127     assign(static_cast<WebDatabasePrivate*>(database.releaseRef()));
    128     return *this;
    129 }
    130 
    131 WebDatabase::operator WTF::PassRefPtr<AbstractDatabase>() const
    132 {
    133     return PassRefPtr<AbstractDatabase>(const_cast<WebDatabasePrivate*>(m_private));
    134 }
    135 
    136 void WebDatabase::assign(WebDatabasePrivate* d)
    137 {
    138     // d is already ref'd for us by the caller
    139     if (m_private)
    140         m_private->deref();
    141     m_private = d;
    142 }
    143 
    144105} // namespace WebKit
Note: See TracChangeset for help on using the changeset viewer.