| Index: Source/WebCore/storage/AbstractDatabase.cpp
|
| ===================================================================
|
| --- Source/WebCore/storage/AbstractDatabase.cpp (revision 96741)
|
| +++ Source/WebCore/storage/AbstractDatabase.cpp (working copy)
|
| @@ -1,5 +1,5 @@
|
| /*
|
| - * Copyright (C) 2010 Google Inc. All rights reserved.
|
| + * Copyright (C) 2011 Google Inc. All rights reserved.
|
| *
|
| * Redistribution and use in source and binary forms, with or without
|
| * modification, are permitted provided that the following conditions
|
| @@ -47,6 +47,9 @@
|
|
|
| namespace WebCore {
|
|
|
| +static const char versionKey[] = "WebKitDatabaseVersionKey";
|
| +static const char infoTableName[] = "__WebKitDatabaseInfoTable__";
|
| +
|
| static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
|
| {
|
| SQLiteStatement statement(db, query);
|
| @@ -95,16 +98,15 @@
|
| // FIXME: move all guid-related functions to a DatabaseVersionTracker class.
|
| static Mutex& guidMutex()
|
| {
|
| - // Note: We don't have to use AtomicallyInitializedStatic here because
|
| - // this function is called once in the constructor on the main thread
|
| - // before any other threads that call this function are used.
|
| - DEFINE_STATIC_LOCAL(Mutex, mutex, ());
|
| + AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
|
| return mutex;
|
| }
|
|
|
| typedef HashMap<int, String> GuidVersionMap;
|
| static GuidVersionMap& guidToVersionMap()
|
| {
|
| + // Ensure the the mutex is locked.
|
| + ASSERT(!guidMutex().tryLock());
|
| DEFINE_STATIC_LOCAL(GuidVersionMap, map, ());
|
| return map;
|
| }
|
| @@ -128,19 +130,19 @@
|
| typedef HashMap<int, HashSet<AbstractDatabase*>*> GuidDatabaseMap;
|
| static GuidDatabaseMap& guidToDatabaseMap()
|
| {
|
| + // Ensure the the mutex is locked.
|
| + ASSERT(!guidMutex().tryLock());
|
| DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ());
|
| return map;
|
| }
|
|
|
| static int guidForOriginAndName(const String& origin, const String& name)
|
| {
|
| + // Ensure the the mutex is locked.
|
| + ASSERT(!guidMutex().tryLock());
|
| +
|
| String stringID = origin + "/" + name;
|
|
|
| - // Note: We don't have to use AtomicallyInitializedStatic here because
|
| - // this function is called once in the constructor on the main thread
|
| - // before any other threads that call this function are used.
|
| - DEFINE_STATIC_LOCAL(Mutex, stringIdentifierMutex, ());
|
| - MutexLocker locker(stringIdentifierMutex);
|
| typedef HashMap<String, int> IDGuidMap;
|
| DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ());
|
| int guid = stringIdentifierToGUIDMap.get(stringID);
|
| @@ -166,10 +168,9 @@
|
| }
|
|
|
| // static
|
| -const String& AbstractDatabase::databaseInfoTableName()
|
| +const char* AbstractDatabase::databaseInfoTableName()
|
| {
|
| - DEFINE_STATIC_LOCAL(String, name, ("__WebKitDatabaseInfoTable__"));
|
| - return name;
|
| + return infoTableName;
|
| }
|
|
|
| AbstractDatabase::AbstractDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion,
|
| @@ -186,15 +187,14 @@
|
| ASSERT(context->isContextThread());
|
| m_contextThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin();
|
|
|
| - m_databaseAuthorizer = DatabaseAuthorizer::create(databaseInfoTableName());
|
| + m_databaseAuthorizer = DatabaseAuthorizer::create(infoTableName);
|
|
|
| if (m_name.isNull())
|
| m_name = "";
|
|
|
| - m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
|
| {
|
| MutexLocker locker(guidMutex());
|
| -
|
| + m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
|
| HashSet<AbstractDatabase*>* hashSet = guidToDatabaseMap().get(m_guid);
|
| if (!hashSet) {
|
| hashSet = new HashSet<AbstractDatabase*>;
|
| @@ -263,15 +263,15 @@
|
| GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid);
|
| if (entry != guidToVersionMap().end()) {
|
| // Map null string to empty string (see updateGuidVersionMap()).
|
| - currentVersion = entry->second.isNull() ? String("") : entry->second;
|
| + currentVersion = entry->second.isNull() ? String("") : entry->second.threadsafeCopy();
|
| LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());
|
|
|
| #if PLATFORM(CHROMIUM)
|
| // Note: In multi-process browsers the cached value may be inaccurate, but
|
| // we cannot read the actual version from the database without potentially
|
| // inducing a form of deadlock, a busytimeout error when trying to
|
| - // access the database. So we'll use the cached value if we're able to read
|
| - // the value without waiting, and otherwise use the cached value (which may be off).
|
| + // access the database. So we'll use the cached value if we're unable to read
|
| + // the value from the database file without waiting.
|
| // FIXME: Add an async openDatabase method to the DatabaseAPI.
|
| const int noSqliteBusyWaitTime = 0;
|
| m_sqliteDatabase.setBusyTimeout(noSqliteBusyWaitTime);
|
| @@ -294,11 +294,12 @@
|
| return false;
|
| }
|
|
|
| - if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) {
|
| + String tableName(infoTableName);
|
| + if (!m_sqliteDatabase.tableExists(tableName)) {
|
| m_new = true;
|
|
|
| - 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);")) {
|
| - LOG_ERROR("Unable to create table %s in database %s", databaseInfoTableName().ascii().data(), databaseDebugName().ascii().data());
|
| + if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + tableName + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
|
| + LOG_ERROR("Unable to create table %s in database %s", infoTableName, databaseDebugName().ascii().data());
|
| ec = INVALID_STATE_ERR;
|
| transaction.rollback();
|
| m_sqliteDatabase.close();
|
| @@ -389,20 +390,13 @@
|
| return m_filename.threadsafeCopy();
|
| }
|
|
|
| -// static
|
| -const String& AbstractDatabase::databaseVersionKey()
|
| -{
|
| - DEFINE_STATIC_LOCAL(String, key, ("WebKitDatabaseVersionKey"));
|
| - return key;
|
| -}
|
| -
|
| bool AbstractDatabase::getVersionFromDatabase(String& version, bool shouldCacheVersion)
|
| {
|
| - DEFINE_STATIC_LOCAL(String, getVersionQuery, ("SELECT value FROM " + databaseInfoTableName() + " WHERE key = '" + databaseVersionKey() + "';"));
|
| + String query(String("SELECT value FROM ") + infoTableName + " WHERE key = '" + versionKey + "';");
|
|
|
| m_databaseAuthorizer->disable();
|
|
|
| - bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, getVersionQuery.threadsafeCopy(), version);
|
| + bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, query, version);
|
| if (result) {
|
| if (shouldCacheVersion)
|
| setCachedVersion(version);
|
| @@ -418,16 +412,16 @@
|
| {
|
| // The INSERT will replace an existing entry for the database with the new version number, due to the UNIQUE ON CONFLICT REPLACE
|
| // clause in the CREATE statement (see Database::performOpenAndVerify()).
|
| - DEFINE_STATIC_LOCAL(String, setVersionQuery, ("INSERT INTO " + databaseInfoTableName() + " (key, value) VALUES ('" + databaseVersionKey() + "', ?);"));
|
| + String query(String("INSERT INTO ") + infoTableName + " (key, value) VALUES ('" + versionKey + "', ?);");
|
|
|
| m_databaseAuthorizer->disable();
|
|
|
| - bool result = setTextValueInDatabase(m_sqliteDatabase, setVersionQuery.threadsafeCopy(), version);
|
| + bool result = setTextValueInDatabase(m_sqliteDatabase, query, version);
|
| if (result) {
|
| if (shouldCacheVersion)
|
| setCachedVersion(version);
|
| } else
|
| - LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), setVersionQuery.ascii().data());
|
| + LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), query.ascii().data());
|
|
|
| m_databaseAuthorizer->enable();
|
|
|
|
|