| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| 11 * notice, this list of conditions and the following disclaimer in the | 11 * notice, this list of conditions and the following disclaimer in the |
| 12 * documentation and/or other materials provided with the distribution. | 12 * documentation and/or other materials provided with the distribution. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 40 #include <wtf/HashMap.h> | 40 #include <wtf/HashMap.h> |
| 41 #include <wtf/HashSet.h> | 41 #include <wtf/HashSet.h> |
| 42 #include <wtf/PassRefPtr.h> | 42 #include <wtf/PassRefPtr.h> |
| 43 #include <wtf/RefPtr.h> | 43 #include <wtf/RefPtr.h> |
| 44 #include <wtf/StdLibExtras.h> | 44 #include <wtf/StdLibExtras.h> |
| 45 #include <wtf/text/CString.h> | 45 #include <wtf/text/CString.h> |
| 46 #include <wtf/text/StringHash.h> | 46 #include <wtf/text/StringHash.h> |
| 47 | 47 |
| 48 namespace WebCore { | 48 namespace WebCore { |
| 49 | 49 |
| 50 static const char versionKey[] = "WebKitDatabaseVersionKey"; |
| 51 static const char infoTableName[] = "__WebKitDatabaseInfoTable__"; |
| 52 |
| 50 static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& que
ry, String& resultString) | 53 static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& que
ry, String& resultString) |
| 51 { | 54 { |
| 52 SQLiteStatement statement(db, query); | 55 SQLiteStatement statement(db, query); |
| 53 int result = statement.prepare(); | 56 int result = statement.prepare(); |
| 54 | 57 |
| 55 if (result != SQLResultOk) { | 58 if (result != SQLResultOk) { |
| 56 LOG_ERROR("Error (%i) preparing statement to read text result from datab
ase (%s)", result, query.ascii().data()); | 59 LOG_ERROR("Error (%i) preparing statement to read text result from datab
ase (%s)", result, query.ascii().data()); |
| 57 return false; | 60 return false; |
| 58 } | 61 } |
| 59 | 62 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 88 LOG_ERROR("Failed to step statement to set value in database (%s)", quer
y.ascii().data()); | 91 LOG_ERROR("Failed to step statement to set value in database (%s)", quer
y.ascii().data()); |
| 89 return false; | 92 return false; |
| 90 } | 93 } |
| 91 | 94 |
| 92 return true; | 95 return true; |
| 93 } | 96 } |
| 94 | 97 |
| 95 // FIXME: move all guid-related functions to a DatabaseVersionTracker class. | 98 // FIXME: move all guid-related functions to a DatabaseVersionTracker class. |
| 96 static Mutex& guidMutex() | 99 static Mutex& guidMutex() |
| 97 { | 100 { |
| 98 // Note: We don't have to use AtomicallyInitializedStatic here because | 101 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); |
| 99 // this function is called once in the constructor on the main thread | |
| 100 // before any other threads that call this function are used. | |
| 101 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); | |
| 102 return mutex; | 102 return mutex; |
| 103 } | 103 } |
| 104 | 104 |
| 105 typedef HashMap<int, String> GuidVersionMap; | 105 typedef HashMap<int, String> GuidVersionMap; |
| 106 static GuidVersionMap& guidToVersionMap() | 106 static GuidVersionMap& guidToVersionMap() |
| 107 { | 107 { |
| 108 // Ensure the the mutex is locked. |
| 109 ASSERT(!guidMutex().tryLock()); |
| 108 DEFINE_STATIC_LOCAL(GuidVersionMap, map, ()); | 110 DEFINE_STATIC_LOCAL(GuidVersionMap, map, ()); |
| 109 return map; | 111 return map; |
| 110 } | 112 } |
| 111 | 113 |
| 112 // NOTE: Caller must lock guidMutex(). | 114 // NOTE: Caller must lock guidMutex(). |
| 113 static inline void updateGuidVersionMap(int guid, String newVersion) | 115 static inline void updateGuidVersionMap(int guid, String newVersion) |
| 114 { | 116 { |
| 115 // Ensure the the mutex is locked. | 117 // Ensure the the mutex is locked. |
| 116 ASSERT(!guidMutex().tryLock()); | 118 ASSERT(!guidMutex().tryLock()); |
| 117 | 119 |
| 118 // Note: It is not safe to put an empty string into the guidToVersionMap() m
ap. | 120 // Note: It is not safe to put an empty string into the guidToVersionMap() m
ap. |
| 119 // That's because the map is cross-thread, but empty strings are per-thread. | 121 // That's because the map is cross-thread, but empty strings are per-thread. |
| 120 // The copy() function makes a version of the string you can use on the curr
ent | 122 // The copy() function makes a version of the string you can use on the curr
ent |
| 121 // thread, but we need a string we can keep in a cross-thread data structure
. | 123 // thread, but we need a string we can keep in a cross-thread data structure
. |
| 122 // FIXME: This is a quite-awkward restriction to have to program with. | 124 // FIXME: This is a quite-awkward restriction to have to program with. |
| 123 | 125 |
| 124 // Map null string to empty string (see comment above). | 126 // Map null string to empty string (see comment above). |
| 125 guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.th
readsafeCopy()); | 127 guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.th
readsafeCopy()); |
| 126 } | 128 } |
| 127 | 129 |
| 128 typedef HashMap<int, HashSet<AbstractDatabase*>*> GuidDatabaseMap; | 130 typedef HashMap<int, HashSet<AbstractDatabase*>*> GuidDatabaseMap; |
| 129 static GuidDatabaseMap& guidToDatabaseMap() | 131 static GuidDatabaseMap& guidToDatabaseMap() |
| 130 { | 132 { |
| 133 // Ensure the the mutex is locked. |
| 134 ASSERT(!guidMutex().tryLock()); |
| 131 DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ()); | 135 DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ()); |
| 132 return map; | 136 return map; |
| 133 } | 137 } |
| 134 | 138 |
| 135 static int guidForOriginAndName(const String& origin, const String& name) | 139 static int guidForOriginAndName(const String& origin, const String& name) |
| 136 { | 140 { |
| 141 // Ensure the the mutex is locked. |
| 142 ASSERT(!guidMutex().tryLock()); |
| 143 |
| 137 String stringID = origin + "/" + name; | 144 String stringID = origin + "/" + name; |
| 138 | 145 |
| 139 // Note: We don't have to use AtomicallyInitializedStatic here because | |
| 140 // this function is called once in the constructor on the main thread | |
| 141 // before any other threads that call this function are used. | |
| 142 DEFINE_STATIC_LOCAL(Mutex, stringIdentifierMutex, ()); | |
| 143 MutexLocker locker(stringIdentifierMutex); | |
| 144 typedef HashMap<String, int> IDGuidMap; | 146 typedef HashMap<String, int> IDGuidMap; |
| 145 DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ()); | 147 DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ()); |
| 146 int guid = stringIdentifierToGUIDMap.get(stringID); | 148 int guid = stringIdentifierToGUIDMap.get(stringID); |
| 147 if (!guid) { | 149 if (!guid) { |
| 148 static int currentNewGUID = 1; | 150 static int currentNewGUID = 1; |
| 149 guid = currentNewGUID++; | 151 guid = currentNewGUID++; |
| 150 stringIdentifierToGUIDMap.set(stringID, guid); | 152 stringIdentifierToGUIDMap.set(stringID, guid); |
| 151 } | 153 } |
| 152 | 154 |
| 153 return guid; | 155 return guid; |
| 154 } | 156 } |
| 155 | 157 |
| 156 static bool isDatabaseAvailable = true; | 158 static bool isDatabaseAvailable = true; |
| 157 | 159 |
| 158 bool AbstractDatabase::isAvailable() | 160 bool AbstractDatabase::isAvailable() |
| 159 { | 161 { |
| 160 return isDatabaseAvailable; | 162 return isDatabaseAvailable; |
| 161 } | 163 } |
| 162 | 164 |
| 163 void AbstractDatabase::setIsAvailable(bool available) | 165 void AbstractDatabase::setIsAvailable(bool available) |
| 164 { | 166 { |
| 165 isDatabaseAvailable = available; | 167 isDatabaseAvailable = available; |
| 166 } | 168 } |
| 167 | 169 |
| 168 // static | 170 // static |
| 169 const String& AbstractDatabase::databaseInfoTableName() | 171 const char* AbstractDatabase::databaseInfoTableName() |
| 170 { | 172 { |
| 171 DEFINE_STATIC_LOCAL(String, name, ("__WebKitDatabaseInfoTable__")); | 173 return infoTableName; |
| 172 return name; | |
| 173 } | 174 } |
| 174 | 175 |
| 175 AbstractDatabase::AbstractDatabase(ScriptExecutionContext* context, const String
& name, const String& expectedVersion, | 176 AbstractDatabase::AbstractDatabase(ScriptExecutionContext* context, const String
& name, const String& expectedVersion, |
| 176 const String& displayName, unsigned long esti
matedSize) | 177 const String& displayName, unsigned long esti
matedSize) |
| 177 : m_scriptExecutionContext(context) | 178 : m_scriptExecutionContext(context) |
| 178 , m_name(name.crossThreadString()) | 179 , m_name(name.crossThreadString()) |
| 179 , m_expectedVersion(expectedVersion.crossThreadString()) | 180 , m_expectedVersion(expectedVersion.crossThreadString()) |
| 180 , m_displayName(displayName.crossThreadString()) | 181 , m_displayName(displayName.crossThreadString()) |
| 181 , m_estimatedSize(estimatedSize) | 182 , m_estimatedSize(estimatedSize) |
| 182 , m_guid(0) | 183 , m_guid(0) |
| 183 , m_opened(false) | 184 , m_opened(false) |
| 184 , m_new(false) | 185 , m_new(false) |
| 185 { | 186 { |
| 186 ASSERT(context->isContextThread()); | 187 ASSERT(context->isContextThread()); |
| 187 m_contextThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin(); | 188 m_contextThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin(); |
| 188 | 189 |
| 189 m_databaseAuthorizer = DatabaseAuthorizer::create(databaseInfoTableName()); | 190 m_databaseAuthorizer = DatabaseAuthorizer::create(infoTableName); |
| 190 | 191 |
| 191 if (m_name.isNull()) | 192 if (m_name.isNull()) |
| 192 m_name = ""; | 193 m_name = ""; |
| 193 | 194 |
| 194 m_guid = guidForOriginAndName(securityOrigin()->toString(), name); | |
| 195 { | 195 { |
| 196 MutexLocker locker(guidMutex()); | 196 MutexLocker locker(guidMutex()); |
| 197 | 197 m_guid = guidForOriginAndName(securityOrigin()->toString(), name); |
| 198 HashSet<AbstractDatabase*>* hashSet = guidToDatabaseMap().get(m_guid); | 198 HashSet<AbstractDatabase*>* hashSet = guidToDatabaseMap().get(m_guid); |
| 199 if (!hashSet) { | 199 if (!hashSet) { |
| 200 hashSet = new HashSet<AbstractDatabase*>; | 200 hashSet = new HashSet<AbstractDatabase*>; |
| 201 guidToDatabaseMap().set(m_guid, hashSet); | 201 guidToDatabaseMap().set(m_guid, hashSet); |
| 202 } | 202 } |
| 203 | 203 |
| 204 hashSet->add(this); | 204 hashSet->add(this); |
| 205 } | 205 } |
| 206 | 206 |
| 207 m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin()
, m_name); | 207 m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin()
, m_name); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 | 256 |
| 257 m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime); | 257 m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime); |
| 258 | 258 |
| 259 String currentVersion; | 259 String currentVersion; |
| 260 { | 260 { |
| 261 MutexLocker locker(guidMutex()); | 261 MutexLocker locker(guidMutex()); |
| 262 | 262 |
| 263 GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid); | 263 GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid); |
| 264 if (entry != guidToVersionMap().end()) { | 264 if (entry != guidToVersionMap().end()) { |
| 265 // Map null string to empty string (see updateGuidVersionMap()). | 265 // Map null string to empty string (see updateGuidVersionMap()). |
| 266 currentVersion = entry->second.isNull() ? String("") : entry->second
; | 266 currentVersion = entry->second.isNull() ? String("") : entry->second
.threadsafeCopy(); |
| 267 LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid,
currentVersion.ascii().data()); | 267 LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid,
currentVersion.ascii().data()); |
| 268 | 268 |
| 269 #if PLATFORM(CHROMIUM) | 269 #if PLATFORM(CHROMIUM) |
| 270 // Note: In multi-process browsers the cached value may be inaccurat
e, but | 270 // Note: In multi-process browsers the cached value may be inaccurat
e, but |
| 271 // we cannot read the actual version from the database without poten
tially | 271 // we cannot read the actual version from the database without poten
tially |
| 272 // inducing a form of deadlock, a busytimeout error when trying to | 272 // inducing a form of deadlock, a busytimeout error when trying to |
| 273 // access the database. So we'll use the cached value if we're able
to read | 273 // access the database. So we'll use the cached value if we're unabl
e to read |
| 274 // the value without waiting, and otherwise use the cached value (wh
ich may be off). | 274 // the value from the database file without waiting. |
| 275 // FIXME: Add an async openDatabase method to the DatabaseAPI. | 275 // FIXME: Add an async openDatabase method to the DatabaseAPI. |
| 276 const int noSqliteBusyWaitTime = 0; | 276 const int noSqliteBusyWaitTime = 0; |
| 277 m_sqliteDatabase.setBusyTimeout(noSqliteBusyWaitTime); | 277 m_sqliteDatabase.setBusyTimeout(noSqliteBusyWaitTime); |
| 278 String versionFromDatabase; | 278 String versionFromDatabase; |
| 279 if (getVersionFromDatabase(versionFromDatabase, false)) { | 279 if (getVersionFromDatabase(versionFromDatabase, false)) { |
| 280 currentVersion = versionFromDatabase; | 280 currentVersion = versionFromDatabase; |
| 281 updateGuidVersionMap(m_guid, currentVersion); | 281 updateGuidVersionMap(m_guid, currentVersion); |
| 282 } | 282 } |
| 283 m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime); | 283 m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime); |
| 284 #endif | 284 #endif |
| 285 } else { | 285 } else { |
| 286 LOG(StorageAPI, "No cached version for guid %i", m_guid); | 286 LOG(StorageAPI, "No cached version for guid %i", m_guid); |
| 287 | 287 |
| 288 SQLiteTransaction transaction(m_sqliteDatabase); | 288 SQLiteTransaction transaction(m_sqliteDatabase); |
| 289 transaction.begin(); | 289 transaction.begin(); |
| 290 if (!transaction.inProgress()) { | 290 if (!transaction.inProgress()) { |
| 291 LOG_ERROR("Unable to begin transaction while opening %s", databa
seDebugName().ascii().data()); | 291 LOG_ERROR("Unable to begin transaction while opening %s", databa
seDebugName().ascii().data()); |
| 292 ec = INVALID_STATE_ERR; | 292 ec = INVALID_STATE_ERR; |
| 293 m_sqliteDatabase.close(); | 293 m_sqliteDatabase.close(); |
| 294 return false; | 294 return false; |
| 295 } | 295 } |
| 296 | 296 |
| 297 if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) { | 297 String tableName(infoTableName); |
| 298 if (!m_sqliteDatabase.tableExists(tableName)) { |
| 298 m_new = true; | 299 m_new = true; |
| 299 | 300 |
| 300 if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + databaseI
nfoTableName() + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLAC
E,value TEXT NOT NULL ON CONFLICT FAIL);")) { | 301 if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + tableName
+ " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT N
OT NULL ON CONFLICT FAIL);")) { |
| 301 LOG_ERROR("Unable to create table %s in database %s", databa
seInfoTableName().ascii().data(), databaseDebugName().ascii().data()); | 302 LOG_ERROR("Unable to create table %s in database %s", infoTa
bleName, databaseDebugName().ascii().data()); |
| 302 ec = INVALID_STATE_ERR; | 303 ec = INVALID_STATE_ERR; |
| 303 transaction.rollback(); | 304 transaction.rollback(); |
| 304 m_sqliteDatabase.close(); | 305 m_sqliteDatabase.close(); |
| 305 return false; | 306 return false; |
| 306 } | 307 } |
| 307 } else if (!getVersionFromDatabase(currentVersion, false)) { | 308 } else if (!getVersionFromDatabase(currentVersion, false)) { |
| 308 LOG_ERROR("Failed to get current version from database %s", data
baseDebugName().ascii().data()); | 309 LOG_ERROR("Failed to get current version from database %s", data
baseDebugName().ascii().data()); |
| 309 ec = INVALID_STATE_ERR; | 310 ec = INVALID_STATE_ERR; |
| 310 transaction.rollback(); | 311 transaction.rollback(); |
| 311 m_sqliteDatabase.close(); | 312 m_sqliteDatabase.close(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 { | 383 { |
| 383 return m_estimatedSize; | 384 return m_estimatedSize; |
| 384 } | 385 } |
| 385 | 386 |
| 386 String AbstractDatabase::fileName() const | 387 String AbstractDatabase::fileName() const |
| 387 { | 388 { |
| 388 // Return a deep copy for ref counting thread safety | 389 // Return a deep copy for ref counting thread safety |
| 389 return m_filename.threadsafeCopy(); | 390 return m_filename.threadsafeCopy(); |
| 390 } | 391 } |
| 391 | 392 |
| 392 // static | |
| 393 const String& AbstractDatabase::databaseVersionKey() | |
| 394 { | |
| 395 DEFINE_STATIC_LOCAL(String, key, ("WebKitDatabaseVersionKey")); | |
| 396 return key; | |
| 397 } | |
| 398 | |
| 399 bool AbstractDatabase::getVersionFromDatabase(String& version, bool shouldCacheV
ersion) | 393 bool AbstractDatabase::getVersionFromDatabase(String& version, bool shouldCacheV
ersion) |
| 400 { | 394 { |
| 401 DEFINE_STATIC_LOCAL(String, getVersionQuery, ("SELECT value FROM " + databas
eInfoTableName() + " WHERE key = '" + databaseVersionKey() + "';")); | 395 String query(String("SELECT value FROM ") + infoTableName + " WHERE key = '
" + versionKey + "';"); |
| 402 | 396 |
| 403 m_databaseAuthorizer->disable(); | 397 m_databaseAuthorizer->disable(); |
| 404 | 398 |
| 405 bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, getVersionQue
ry.threadsafeCopy(), version); | 399 bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, query, versio
n); |
| 406 if (result) { | 400 if (result) { |
| 407 if (shouldCacheVersion) | 401 if (shouldCacheVersion) |
| 408 setCachedVersion(version); | 402 setCachedVersion(version); |
| 409 } else | 403 } else |
| 410 LOG_ERROR("Failed to retrieve version from database %s", databaseDebugNa
me().ascii().data()); | 404 LOG_ERROR("Failed to retrieve version from database %s", databaseDebugNa
me().ascii().data()); |
| 411 | 405 |
| 412 m_databaseAuthorizer->enable(); | 406 m_databaseAuthorizer->enable(); |
| 413 | 407 |
| 414 return result; | 408 return result; |
| 415 } | 409 } |
| 416 | 410 |
| 417 bool AbstractDatabase::setVersionInDatabase(const String& version, bool shouldCa
cheVersion) | 411 bool AbstractDatabase::setVersionInDatabase(const String& version, bool shouldCa
cheVersion) |
| 418 { | 412 { |
| 419 // The INSERT will replace an existing entry for the database with the new v
ersion number, due to the UNIQUE ON CONFLICT REPLACE | 413 // The INSERT will replace an existing entry for the database with the new v
ersion number, due to the UNIQUE ON CONFLICT REPLACE |
| 420 // clause in the CREATE statement (see Database::performOpenAndVerify()). | 414 // clause in the CREATE statement (see Database::performOpenAndVerify()). |
| 421 DEFINE_STATIC_LOCAL(String, setVersionQuery, ("INSERT INTO " + databaseInfoT
ableName() + " (key, value) VALUES ('" + databaseVersionKey() + "', ?);")); | 415 String query(String("INSERT INTO ") + infoTableName + " (key, value) VALUES
('" + versionKey + "', ?);"); |
| 422 | 416 |
| 423 m_databaseAuthorizer->disable(); | 417 m_databaseAuthorizer->disable(); |
| 424 | 418 |
| 425 bool result = setTextValueInDatabase(m_sqliteDatabase, setVersionQuery.threa
dsafeCopy(), version); | 419 bool result = setTextValueInDatabase(m_sqliteDatabase, query, version); |
| 426 if (result) { | 420 if (result) { |
| 427 if (shouldCacheVersion) | 421 if (shouldCacheVersion) |
| 428 setCachedVersion(version); | 422 setCachedVersion(version); |
| 429 } else | 423 } else |
| 430 LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().d
ata(), setVersionQuery.ascii().data()); | 424 LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().d
ata(), query.ascii().data()); |
| 431 | 425 |
| 432 m_databaseAuthorizer->enable(); | 426 m_databaseAuthorizer->enable(); |
| 433 | 427 |
| 434 return result; | 428 return result; |
| 435 } | 429 } |
| 436 | 430 |
| 437 void AbstractDatabase::setExpectedVersion(const String& version) | 431 void AbstractDatabase::setExpectedVersion(const String& version) |
| 438 { | 432 { |
| 439 m_expectedVersion = version.threadsafeCopy(); | 433 m_expectedVersion = version.threadsafeCopy(); |
| 440 } | 434 } |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 | 533 |
| 540 bool AbstractDatabase::isInterrupted() | 534 bool AbstractDatabase::isInterrupted() |
| 541 { | 535 { |
| 542 MutexLocker locker(m_sqliteDatabase.databaseMutex()); | 536 MutexLocker locker(m_sqliteDatabase.databaseMutex()); |
| 543 return m_sqliteDatabase.isInterrupted(); | 537 return m_sqliteDatabase.isInterrupted(); |
| 544 } | 538 } |
| 545 | 539 |
| 546 } // namespace WebCore | 540 } // namespace WebCore |
| 547 | 541 |
| 548 #endif // ENABLE(DATABASE) | 542 #endif // ENABLE(DATABASE) |
| OLD | NEW |