| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007, 2008 Apple 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 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 44 #include "SecurityOriginHash.h" | 44 #include "SecurityOriginHash.h" |
| 45 #include "SQLiteFileSystem.h" | 45 #include "SQLiteFileSystem.h" |
| 46 #include "SQLiteStatement.h" | 46 #include "SQLiteStatement.h" |
| 47 #include <wtf/MainThread.h> | 47 #include <wtf/MainThread.h> |
| 48 #include <wtf/StdLibExtras.h> | 48 #include <wtf/StdLibExtras.h> |
| 49 | 49 |
| 50 using namespace std; | 50 using namespace std; |
| 51 | 51 |
| 52 namespace WebCore { | 52 namespace WebCore { |
| 53 | 53 |
| 54 OriginQuotaManager& DatabaseTracker::originQuotaManagerNoLock() |
| 55 { |
| 56 ASSERT(m_quotaManager); |
| 57 return *m_quotaManager; |
| 58 } |
| 59 |
| 54 OriginQuotaManager& DatabaseTracker::originQuotaManager() | 60 OriginQuotaManager& DatabaseTracker::originQuotaManager() |
| 55 { | 61 { |
| 62 MutexLocker lockDatabase(m_databaseGuard); |
| 56 populateOrigins(); | 63 populateOrigins(); |
| 57 ASSERT(m_quotaManager); | 64 return originQuotaManagerNoLock(); |
| 58 return *m_quotaManager; | |
| 59 } | 65 } |
| 60 | 66 |
| 61 DatabaseTracker& DatabaseTracker::tracker() | 67 DatabaseTracker& DatabaseTracker::tracker() |
| 62 { | 68 { |
| 63 DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, ()); | 69 DEFINE_STATIC_LOCAL(DatabaseTracker, tracker, ()); |
| 64 return tracker; | 70 return tracker; |
| 65 } | 71 } |
| 66 | 72 |
| 67 DatabaseTracker::DatabaseTracker() | 73 DatabaseTracker::DatabaseTracker() |
| 68 : m_client(0) | 74 : m_client(0) |
| 69 , m_proposedDatabase(0) | |
| 70 #ifndef NDEBUG | |
| 71 , m_thread(currentThread()) | |
| 72 #endif | |
| 73 { | 75 { |
| 74 SQLiteFileSystem::registerSQLiteVFS(); | 76 SQLiteFileSystem::registerSQLiteVFS(); |
| 75 } | 77 } |
| 76 | 78 |
| 77 void DatabaseTracker::setDatabaseDirectoryPath(const String& path) | 79 void DatabaseTracker::setDatabaseDirectoryPath(const String& path) |
| 78 { | 80 { |
| 79 ASSERT(currentThread() == m_thread); | |
| 80 ASSERT(!m_database.isOpen()); | 81 ASSERT(!m_database.isOpen()); |
| 81 m_databaseDirectoryPath = path; | 82 m_databaseDirectoryPath = path; |
| 82 } | 83 } |
| 83 | 84 |
| 84 const String& DatabaseTracker::databaseDirectoryPath() const | 85 String DatabaseTracker::databaseDirectoryPath() const |
| 85 { | 86 { |
| 86 ASSERT(currentThread() == m_thread); | 87 return m_databaseDirectoryPath.threadsafeCopy(); |
| 87 return m_databaseDirectoryPath; | |
| 88 } | 88 } |
| 89 | 89 |
| 90 String DatabaseTracker::trackerDatabasePath() const | 90 String DatabaseTracker::trackerDatabasePath() const |
| 91 { | 91 { |
| 92 ASSERT(currentThread() == m_thread); | |
| 93 return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPat
h, "Databases.db"); | 92 return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPat
h, "Databases.db"); |
| 94 } | 93 } |
| 95 | 94 |
| 96 void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist) | 95 void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist) |
| 97 { | 96 { |
| 98 ASSERT(currentThread() == m_thread); | 97 ASSERT(!m_databaseGuard.tryLock()); |
| 99 | 98 |
| 100 if (m_database.isOpen()) | 99 if (m_database.isOpen()) |
| 101 return; | 100 return; |
| 102 | 101 |
| 103 String databasePath = trackerDatabasePath(); | 102 String databasePath = trackerDatabasePath(); |
| 104 if (!SQLiteFileSystem::ensureDatabaseFileExists(databasePath, createIfDoesNo
tExist)) | 103 if (!SQLiteFileSystem::ensureDatabaseFileExists(databasePath, createIfDoesNo
tExist)) |
| 105 return; | 104 return; |
| 106 | 105 |
| 107 if (!m_database.open(databasePath)) { | 106 if (!m_database.open(databasePath)) { |
| 108 // FIXME: What do do here? | 107 // FIXME: What do do here? |
| 108 LOG_ERROR("Failed to open databasePath %s.", databasePath.ascii().data()
); |
| 109 return; | 109 return; |
| 110 } | 110 } |
| 111 m_database.setSharable(true); |
| 111 if (!m_database.tableExists("Origins")) { | 112 if (!m_database.tableExists("Origins")) { |
| 112 if (!m_database.executeCommand("CREATE TABLE Origins (origin TEXT UNIQUE
ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);")) { | 113 if (!m_database.executeCommand("CREATE TABLE Origins (origin TEXT UNIQUE
ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);")) { |
| 113 // FIXME: and here | 114 // FIXME: and here |
| 115 LOG_ERROR("Failed to create Origins table"); |
| 114 } | 116 } |
| 115 } | 117 } |
| 116 if (!m_database.tableExists("Databases")) { | 118 if (!m_database.tableExists("Databases")) { |
| 117 if (!m_database.executeCommand("CREATE TABLE Databases (guid INTEGER PRI
MARY KEY AUTOINCREMENT, origin TEXT, name TEXT, displayName TEXT, estimatedSize
INTEGER, path TEXT);")) { | 119 if (!m_database.executeCommand("CREATE TABLE Databases (guid INTEGER PRI
MARY KEY AUTOINCREMENT, origin TEXT, name TEXT, displayName TEXT, estimatedSize
INTEGER, path TEXT);")) { |
| 118 // FIXME: and here | 120 // FIXME: and here |
| 121 LOG_ERROR("Failed to create Databases table"); |
| 119 } | 122 } |
| 120 } | 123 } |
| 121 } | 124 } |
| 122 | 125 |
| 123 bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* context, cons
t String& name, const String& displayName, unsigned long estimatedSize) | 126 bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* context, cons
t String& name, const String& displayName, unsigned long estimatedSize) |
| 124 { | 127 { |
| 125 ASSERT(currentThread() == m_thread); | 128 SecurityOrigin* origin = context->securityOrigin(); |
| 129 ProposedDatabase details; |
| 126 | 130 |
| 127 // Populate the origins before we establish a database; this guarantees that
quotaForOrigin | 131 unsigned long long requirement; |
| 128 // can run on the database thread later. | 132 unsigned long long tempUsage; |
| 129 populateOrigins(); | 133 { |
| 134 Locker<OriginQuotaManager> locker(originQuotaManager()); |
| 135 MutexLocker lockDatabase(m_databaseGuard); |
| 130 | 136 |
| 131 SecurityOrigin* origin = context->securityOrigin(); | 137 populateOrigins(); |
| 132 | 138 |
| 133 // Since we're imminently opening a database within this context's origin, m
ake sure this origin is being tracked by the QuotaTracker | 139 // Since we're imminently opening a database within this context's origi
n, make sure this origin is being tracked by the QuotaTracker |
| 134 // by fetching it's current usage now | 140 // by fetching its current usage now. |
| 135 unsigned long long usage = usageForOrigin(origin); | 141 unsigned long long usage = usageForOriginNoLock(origin); |
| 136 | 142 |
| 137 // If a database already exists, ignore the passed-in estimated size and say
it's OK. | 143 // If a database already exists, ignore the passed-in estimated size and
say it's OK. |
| 138 if (hasEntryForDatabase(origin, name)) | 144 if (hasEntryForDatabase(origin, name)) |
| 139 return true; | 145 return true; |
| 140 | 146 |
| 141 // If the database will fit, allow its creation. | 147 // If the database will fit, allow its creation. |
| 142 unsigned long long requirement = usage + max(1UL, estimatedSize); | 148 requirement = usage + max(1UL, estimatedSize); |
| 143 if (requirement < usage) | 149 tempUsage = usage; |
| 144 return false; // If the estimated size is so big it causes an overflow,
don't allow creation. | 150 if (requirement < usage) |
| 145 if (requirement <= quotaForOrigin(origin)) | 151 return false; // If the estimated size is so big it causes an overfl
ow, don't allow creation. |
| 146 return true; | 152 if (requirement <= quotaForOriginNoLock(origin)) |
| 153 return true; |
| 147 | 154 |
| 148 // Give the chrome client a chance to increase the quota. | 155 // Give the chrome client a chance to increase the quota. |
| 149 // Temporarily make the details of the proposed database available, so the c
lient can get at them. | 156 // Temporarily make the details of the proposed database available, so t
he client can get at them. |
| 150 pair<SecurityOrigin*, DatabaseDetails> details(origin, DatabaseDetails(name,
displayName, estimatedSize, 0)); | 157 // FIXME: We should really just pass the details into this call, rather
than using m_proposedDatabases. |
| 151 m_proposedDatabase = &details; | 158 details = ProposedDatabase(origin, DatabaseDetails(name, displayName, es
timatedSize, 0)); |
| 159 m_proposedDatabases.add(&details); |
| 160 } |
| 161 // Drop all locks before calling out; we don't know what they'll do. |
| 152 context->databaseExceededQuota(name); | 162 context->databaseExceededQuota(name); |
| 153 m_proposedDatabase = 0; | 163 { |
| 164 MutexLocker lockDatabase(m_databaseGuard); |
| 165 m_proposedDatabases.remove(&details); |
| 166 } |
| 154 | 167 |
| 155 // If the database will fit now, allow its creation. | 168 // If the database will fit now, allow its creation. |
| 156 return requirement <= quotaForOrigin(origin); | 169 return requirement <= quotaForOrigin(origin); |
| 157 } | 170 } |
| 158 | 171 |
| 172 bool DatabaseTracker::hasEntryForOriginNoLock(SecurityOrigin* origin) |
| 173 { |
| 174 ASSERT(!m_databaseGuard.tryLock()); |
| 175 ASSERT(m_quotaMap); |
| 176 return m_quotaMap->contains(origin); |
| 177 } |
| 178 |
| 159 bool DatabaseTracker::hasEntryForOrigin(SecurityOrigin* origin) | 179 bool DatabaseTracker::hasEntryForOrigin(SecurityOrigin* origin) |
| 160 { | 180 { |
| 161 ASSERT(currentThread() == m_thread); | 181 MutexLocker lockDatabase(m_databaseGuard); |
| 162 populateOrigins(); | 182 populateOrigins(); |
| 163 MutexLocker lockQuotaMap(m_quotaMapGuard); | 183 return hasEntryForOriginNoLock(origin); |
| 164 return m_quotaMap->contains(origin); | |
| 165 } | 184 } |
| 166 | 185 |
| 167 bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String&
databaseIdentifier) | 186 bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String&
databaseIdentifier) |
| 168 { | 187 { |
| 169 ASSERT(currentThread() == m_thread); | 188 ASSERT(!m_databaseGuard.tryLock()); |
| 170 openTrackerDatabase(false); | 189 openTrackerDatabase(false); |
| 171 if (!m_database.isOpen()) | 190 if (!m_database.isOpen()) |
| 172 return false; | 191 return false; |
| 173 SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE orig
in=? AND name=?;"); | 192 SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE orig
in=? AND name=?;"); |
| 174 | 193 |
| 175 if (statement.prepare() != SQLResultOk) | 194 if (statement.prepare() != SQLResultOk) |
| 176 return false; | 195 return false; |
| 177 | 196 |
| 178 statement.bindText(1, origin->databaseIdentifier()); | 197 statement.bindText(1, origin->databaseIdentifier()); |
| 179 statement.bindText(2, databaseIdentifier); | 198 statement.bindText(2, databaseIdentifier); |
| 180 | 199 |
| 181 return statement.step() == SQLResultRow; | 200 return statement.step() == SQLResultRow; |
| 182 } | 201 } |
| 183 | 202 |
| 184 unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* databa
se) | 203 unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* databa
se) |
| 185 { | 204 { |
| 186 ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread
()->getThreadID()); | 205 ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread
()->getThreadID()); |
| 187 // The maximum size for a database is the full quota for its origin, minus t
he current usage within the origin, | 206 // The maximum size for a database is the full quota for its origin, minus t
he current usage within the origin, |
| 188 // plus the current usage of the given database | 207 // plus the current usage of the given database |
| 189 Locker<OriginQuotaManager> locker(originQuotaManager()); | 208 Locker<OriginQuotaManager> locker(originQuotaManager()); |
| 190 SecurityOrigin* origin = database->securityOrigin(); | 209 SecurityOrigin* origin = database->securityOrigin(); |
| 191 return quotaForOrigin(origin) - originQuotaManager().diskUsage(origin) + SQL
iteFileSystem::getDatabaseFileSize(database->fileName()); | 210 return quotaForOrigin(origin) - originQuotaManager().diskUsage(origin) + SQL
iteFileSystem::getDatabaseFileSize(database->fileName()); |
| 192 } | 211 } |
| 193 | 212 |
| 194 String DatabaseTracker::originPath(SecurityOrigin* origin) const | 213 String DatabaseTracker::originPath(SecurityOrigin* origin) const |
| 195 { | 214 { |
| 196 ASSERT(currentThread() == m_thread); | 215 return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPat
h.threadsafeCopy(), origin->databaseIdentifier()); |
| 197 return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPat
h, origin->databaseIdentifier()); | |
| 198 } | 216 } |
| 199 | 217 |
| 200 String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
& name, bool createIfNotExists) | 218 String DatabaseTracker::fullPathForDatabaseNoLock(SecurityOrigin* origin, const
String& name, bool createIfNotExists) |
| 201 { | 219 { |
| 202 ASSERT(currentThread() == m_thread); | 220 ASSERT(!m_databaseGuard.tryLock()); |
| 221 ASSERT(!originQuotaManagerNoLock().tryLock()); |
| 203 | 222 |
| 204 if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedD
atabase->second.name() == name) | 223 for (HashSet<ProposedDatabase*>::iterator iter = m_proposedDatabases.begin()
; iter != m_proposedDatabases.end(); ++iter) |
| 205 return String(); | 224 if ((*iter)->first == origin && (*iter)->second.name() == name) |
| 225 return String(); |
| 206 | 226 |
| 207 String originIdentifier = origin->databaseIdentifier(); | 227 String originIdentifier = origin->databaseIdentifier(); |
| 208 String originPath = this->originPath(origin); | 228 String originPath = this->originPath(origin); |
| 209 | 229 |
| 210 // Make sure the path for this SecurityOrigin exists | 230 // Make sure the path for this SecurityOrigin exists |
| 211 if (createIfNotExists && !SQLiteFileSystem::ensureDatabaseDirectoryExists(or
iginPath)) | 231 if (createIfNotExists && !SQLiteFileSystem::ensureDatabaseDirectoryExists(or
iginPath)) |
| 212 return String(); | 232 return String(); |
| 213 | 233 |
| 214 // See if we have a path for this database yet | 234 // See if we have a path for this database yet |
| 215 openTrackerDatabase(false); | 235 // TODO: Why don't we try to open the database first? |
| 216 if (!m_database.isOpen()) | 236 if (!m_database.isOpen()) |
| 217 return String(); | 237 return String(); |
| 218 SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE orig
in=? AND name=?;"); | 238 SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE orig
in=? AND name=?;"); |
| 219 | 239 |
| 220 if (statement.prepare() != SQLResultOk) | 240 if (statement.prepare() != SQLResultOk) |
| 221 return String(); | 241 return String(); |
| 222 | 242 |
| 223 statement.bindText(1, originIdentifier); | 243 statement.bindText(1, originIdentifier); |
| 224 statement.bindText(2, name); | 244 statement.bindText(2, name); |
| 225 | 245 |
| 226 int result = statement.step(); | 246 int result = statement.step(); |
| 227 | 247 |
| 228 if (result == SQLResultRow) | 248 if (result == SQLResultRow) |
| 229 return SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, statem
ent.getColumnText(0)); | 249 return SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, statem
ent.getColumnText(0)); |
| 230 if (!createIfNotExists) | 250 if (!createIfNotExists) |
| 231 return String(); | 251 return String(); |
| 232 | 252 |
| 233 if (result != SQLResultDone) { | 253 if (result != SQLResultDone) { |
| 234 LOG_ERROR("Failed to retrieve filename from Database Tracker for origin
%s, name %s", origin->databaseIdentifier().ascii().data(), name.ascii().data()); | 254 LOG_ERROR("Failed to retrieve filename from Database Tracker for origin
%s, name %s", originIdentifier.ascii().data(), name.ascii().data()); |
| 235 return String(); | 255 return String(); |
| 236 } | 256 } |
| 237 statement.finalize(); | 257 statement.finalize(); |
| 238 | 258 |
| 239 String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, na
me, origin->databaseIdentifier(), &m_database); | 259 String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, na
me, originIdentifier, &m_database); |
| 240 if (!addDatabase(origin, name, fileName)) | 260 if (!addDatabase(origin, name, fileName)) |
| 241 return String(); | 261 return String(); |
| 242 | 262 |
| 243 // If this origin's quota is being tracked (open handle to a database in thi
s origin), add this new database | 263 // If this origin's quota is being tracked (open handle to a database in thi
s origin), add this new database |
| 244 // to the quota manager now | 264 // to the quota manager now |
| 245 String fullFilePath = SQLiteFileSystem::appendDatabaseFileNameToPath(originP
ath, fileName); | 265 String fullFilePath = SQLiteFileSystem::appendDatabaseFileNameToPath(originP
ath, fileName); |
| 246 { | 266 if (originQuotaManagerNoLock().tracksOrigin(origin)) |
| 247 Locker<OriginQuotaManager> locker(originQuotaManager()); | 267 originQuotaManagerNoLock().addDatabase(origin, name, fullFilePath); |
| 248 if (originQuotaManager().tracksOrigin(origin)) | |
| 249 originQuotaManager().addDatabase(origin, name, fullFilePath); | |
| 250 } | |
| 251 | 268 |
| 252 return fullFilePath; | 269 return fullFilePath; |
| 253 } | 270 } |
| 254 | 271 |
| 272 String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
& name, bool createIfNotExists) |
| 273 { |
| 274 Locker<OriginQuotaManager> locker(originQuotaManager()); |
| 275 MutexLocker lockDatabase(m_databaseGuard); |
| 276 populateOrigins(); |
| 277 |
| 278 return fullPathForDatabaseNoLock(origin, name, createIfNotExists); |
| 279 } |
| 280 |
| 255 void DatabaseTracker::populateOrigins() | 281 void DatabaseTracker::populateOrigins() |
| 256 { | 282 { |
| 283 ASSERT(!m_databaseGuard.tryLock()); |
| 257 if (m_quotaMap) | 284 if (m_quotaMap) |
| 258 return; | 285 return; |
| 259 | 286 |
| 260 ASSERT(currentThread() == m_thread); | |
| 261 | |
| 262 m_quotaMap.set(new QuotaMap); | 287 m_quotaMap.set(new QuotaMap); |
| 263 m_quotaManager.set(new OriginQuotaManager); | 288 if (!m_quotaManager) |
| 289 m_quotaManager.set(new OriginQuotaManager); |
| 264 | 290 |
| 265 openTrackerDatabase(false); | 291 openTrackerDatabase(false); |
| 266 if (!m_database.isOpen()) | 292 if (!m_database.isOpen()) |
| 267 return; | 293 return; |
| 268 | 294 |
| 269 SQLiteStatement statement(m_database, "SELECT origin, quota FROM Origins"); | 295 SQLiteStatement statement(m_database, "SELECT origin, quota FROM Origins"); |
| 270 | 296 |
| 271 if (statement.prepare() != SQLResultOk) | 297 if (statement.prepare() != SQLResultOk) { |
| 298 LOG_ERROR("Failed to prepare statement."); |
| 272 return; | 299 return; |
| 300 } |
| 273 | 301 |
| 274 int result; | 302 int result; |
| 275 while ((result = statement.step()) == SQLResultRow) { | 303 while ((result = statement.step()) == SQLResultRow) { |
| 276 RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromDatabaseIdenti
fier(statement.getColumnText(0)); | 304 RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromDatabaseIdenti
fier(statement.getColumnText(0)); |
| 277 m_quotaMap->set(origin.get(), statement.getColumnInt64(1)); | 305 m_quotaMap->set(origin.get(), statement.getColumnInt64(1)); |
| 278 } | 306 } |
| 279 | 307 |
| 280 if (result != SQLResultDone) | 308 if (result != SQLResultDone) |
| 281 LOG_ERROR("Failed to read in all origins from the database"); | 309 LOG_ERROR("Failed to read in all origins from the database."); |
| 282 } | 310 } |
| 283 | 311 |
| 284 void DatabaseTracker::origins(Vector<RefPtr<SecurityOrigin> >& result) | 312 void DatabaseTracker::origins(Vector<RefPtr<SecurityOrigin> >& result) |
| 285 { | 313 { |
| 286 ASSERT(currentThread() == m_thread); | 314 MutexLocker lockDatabase(m_databaseGuard); |
| 287 populateOrigins(); | 315 populateOrigins(); |
| 288 MutexLocker lockQuotaMap(m_quotaMapGuard); | 316 ASSERT(m_quotaMap); |
| 289 copyKeysToVector(*m_quotaMap, result); | 317 copyKeysToVector(*m_quotaMap, result); |
| 290 } | 318 } |
| 291 | 319 |
| 292 bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<Stri
ng>& resultVector) | 320 bool DatabaseTracker::databaseNamesForOriginNoLock(SecurityOrigin* origin, Vecto
r<String>& resultVector) |
| 293 { | 321 { |
| 294 ASSERT(currentThread() == m_thread); | 322 ASSERT(!m_databaseGuard.tryLock()); |
| 295 openTrackerDatabase(false); | 323 openTrackerDatabase(false); |
| 296 if (!m_database.isOpen()) | 324 if (!m_database.isOpen()) |
| 297 return false; | 325 return false; |
| 298 | 326 |
| 299 SQLiteStatement statement(m_database, "SELECT name FROM Databases where orig
in=?;"); | 327 SQLiteStatement statement(m_database, "SELECT name FROM Databases where orig
in=?;"); |
| 300 | 328 |
| 301 if (statement.prepare() != SQLResultOk) | 329 if (statement.prepare() != SQLResultOk) |
| 302 return false; | 330 return false; |
| 303 | 331 |
| 304 statement.bindText(1, origin->databaseIdentifier()); | 332 statement.bindText(1, origin->databaseIdentifier()); |
| 305 | 333 |
| 306 int result; | 334 int result; |
| 307 while ((result = statement.step()) == SQLResultRow) | 335 while ((result = statement.step()) == SQLResultRow) |
| 308 resultVector.append(statement.getColumnText(0)); | 336 resultVector.append(statement.getColumnText(0)); |
| 309 | 337 |
| 310 if (result != SQLResultDone) { | 338 if (result != SQLResultDone) { |
| 311 LOG_ERROR("Failed to retrieve all database names for origin %s", origin-
>databaseIdentifier().ascii().data()); | 339 LOG_ERROR("Failed to retrieve all database names for origin %s", origin-
>databaseIdentifier().ascii().data()); |
| 312 return false; | 340 return false; |
| 313 } | 341 } |
| 314 | 342 |
| 315 return true; | 343 return true; |
| 316 } | 344 } |
| 317 | 345 |
| 346 bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<Stri
ng>& resultVector) |
| 347 { |
| 348 MutexLocker lockDatabase(m_databaseGuard); |
| 349 return databaseNamesForOriginNoLock(origin, resultVector); |
| 350 } |
| 351 |
| 318 DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, Sec
urityOrigin* origin) | 352 DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, Sec
urityOrigin* origin) |
| 319 { | 353 { |
| 320 ASSERT(currentThread() == m_thread); | 354 String originIdentifier = origin->databaseIdentifier(); |
| 355 String displayName; |
| 356 int64_t expectedUsage; |
| 321 | 357 |
| 322 if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedD
atabase->second.name() == name) | 358 { |
| 323 return m_proposedDatabase->second; | 359 MutexLocker lockDatabase(m_databaseGuard); |
| 324 | 360 |
| 325 String originIdentifier = origin->databaseIdentifier(); | 361 for (HashSet<ProposedDatabase*>::iterator iter = m_proposedDatabases.beg
in(); iter != m_proposedDatabases.end(); ++iter) |
| 362 if ((*iter)->first == origin && (*iter)->second.name() == name) |
| 363 return (*iter)->second; |
| 326 | 364 |
| 327 openTrackerDatabase(false); | 365 openTrackerDatabase(false); |
| 328 if (!m_database.isOpen()) | 366 if (!m_database.isOpen()) |
| 329 return DatabaseDetails(); | 367 return DatabaseDetails(); |
| 330 SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FRO
M Databases WHERE origin=? AND name=?"); | 368 SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize
FROM Databases WHERE origin=? AND name=?"); |
| 331 if (statement.prepare() != SQLResultOk) | 369 if (statement.prepare() != SQLResultOk) |
| 332 return DatabaseDetails(); | 370 return DatabaseDetails(); |
| 333 | 371 |
| 334 statement.bindText(1, originIdentifier); | 372 statement.bindText(1, originIdentifier); |
| 335 statement.bindText(2, name); | 373 statement.bindText(2, name); |
| 336 | 374 |
| 337 int result = statement.step(); | 375 int result = statement.step(); |
| 338 if (result == SQLResultDone) | 376 if (result == SQLResultDone) |
| 339 return DatabaseDetails(); | 377 return DatabaseDetails(); |
| 340 | 378 |
| 341 if (result != SQLResultRow) { | 379 if (result != SQLResultRow) { |
| 342 LOG_ERROR("Error retrieving details for database %s in origin %s from tr
acker database", name.ascii().data(), originIdentifier.ascii().data()); | 380 LOG_ERROR("Error retrieving details for database %s in origin %s fro
m tracker database", name.ascii().data(), originIdentifier.ascii().data()); |
| 343 return DatabaseDetails(); | 381 return DatabaseDetails(); |
| 382 } |
| 383 displayName = statement.getColumnText(0); |
| 384 expectedUsage = statement.getColumnInt64(1); |
| 344 } | 385 } |
| 345 | 386 |
| 346 return DatabaseDetails(name, statement.getColumnText(0), statement.getColumn
Int64(1), usageForDatabase(name, origin)); | 387 return DatabaseDetails(name, displayName, expectedUsage, usageForDatabase(na
me, origin)); |
| 347 } | 388 } |
| 348 | 389 |
| 349 void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& n
ame, const String& displayName, unsigned long estimatedSize) | 390 void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& n
ame, const String& displayName, unsigned long estimatedSize) |
| 350 { | 391 { |
| 351 ASSERT(currentThread() == m_thread); | |
| 352 | |
| 353 String originIdentifier = origin->databaseIdentifier(); | 392 String originIdentifier = origin->databaseIdentifier(); |
| 354 int64_t guid = 0; | 393 int64_t guid = 0; |
| 355 | 394 |
| 395 MutexLocker lockDatabase(m_databaseGuard); |
| 396 |
| 356 openTrackerDatabase(true); | 397 openTrackerDatabase(true); |
| 357 if (!m_database.isOpen()) | 398 if (!m_database.isOpen()) |
| 358 return; | 399 return; |
| 359 SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE orig
in=? AND name=?"); | 400 SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE orig
in=? AND name=?"); |
| 360 if (statement.prepare() != SQLResultOk) | 401 if (statement.prepare() != SQLResultOk) |
| 361 return; | 402 return; |
| 362 | 403 |
| 363 statement.bindText(1, originIdentifier); | 404 statement.bindText(1, originIdentifier); |
| 364 statement.bindText(2, name); | 405 statement.bindText(2, name); |
| 365 | 406 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 393 LOG_ERROR("Failed to update details for database %s in origin %s", name.
ascii().data(), originIdentifier.ascii().data()); | 434 LOG_ERROR("Failed to update details for database %s in origin %s", name.
ascii().data(), originIdentifier.ascii().data()); |
| 394 return; | 435 return; |
| 395 } | 436 } |
| 396 | 437 |
| 397 if (m_client) | 438 if (m_client) |
| 398 m_client->dispatchDidModifyDatabase(origin, name); | 439 m_client->dispatchDidModifyDatabase(origin, name); |
| 399 } | 440 } |
| 400 | 441 |
| 401 unsigned long long DatabaseTracker::usageForDatabase(const String& name, Securit
yOrigin* origin) | 442 unsigned long long DatabaseTracker::usageForDatabase(const String& name, Securit
yOrigin* origin) |
| 402 { | 443 { |
| 403 ASSERT(currentThread() == m_thread); | |
| 404 String path = fullPathForDatabase(origin, name, false); | 444 String path = fullPathForDatabase(origin, name, false); |
| 405 if (path.isEmpty()) | 445 if (path.isEmpty()) |
| 406 return 0; | 446 return 0; |
| 407 | 447 |
| 408 return SQLiteFileSystem::getDatabaseFileSize(path); | 448 return SQLiteFileSystem::getDatabaseFileSize(path); |
| 409 } | 449 } |
| 410 | 450 |
| 411 void DatabaseTracker::addOpenDatabase(Database* database) | 451 void DatabaseTracker::addOpenDatabase(Database* database) |
| 412 { | 452 { |
| 413 if (!database) | 453 if (!database) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 434 databaseSet->add(database); | 474 databaseSet->add(database); |
| 435 | 475 |
| 436 LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier(
).ascii().data(), database); | 476 LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier(
).ascii().data(), database); |
| 437 } | 477 } |
| 438 | 478 |
| 439 void DatabaseTracker::removeOpenDatabase(Database* database) | 479 void DatabaseTracker::removeOpenDatabase(Database* database) |
| 440 { | 480 { |
| 441 if (!database) | 481 if (!database) |
| 442 return; | 482 return; |
| 443 | 483 |
| 484 Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); |
| 444 MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); | 485 MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); |
| 445 | 486 |
| 446 if (!m_openDatabaseMap) { | 487 if (!m_openDatabaseMap) { |
| 447 ASSERT_NOT_REACHED(); | 488 ASSERT_NOT_REACHED(); |
| 448 return; | 489 return; |
| 449 } | 490 } |
| 450 | 491 |
| 451 String name(database->stringIdentifier()); | 492 String name(database->stringIdentifier()); |
| 452 DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()
); | 493 DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()
); |
| 453 if (!nameMap) { | 494 if (!nameMap) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 469 return; | 510 return; |
| 470 | 511 |
| 471 nameMap->remove(name); | 512 nameMap->remove(name); |
| 472 delete databaseSet; | 513 delete databaseSet; |
| 473 | 514 |
| 474 if (!nameMap->isEmpty()) | 515 if (!nameMap->isEmpty()) |
| 475 return; | 516 return; |
| 476 | 517 |
| 477 m_openDatabaseMap->remove(database->securityOrigin()); | 518 m_openDatabaseMap->remove(database->securityOrigin()); |
| 478 delete nameMap; | 519 delete nameMap; |
| 520 originQuotaManagerNoLock().removeOrigin(database->securityOrigin()); |
| 521 |
| 522 // Throw away m_quotaMap whenever we've cleared out an origin--otherwise we
never get rid of stale entries. The next call that needs it will populateOrigin
s(). |
| 523 m_quotaMap.clear(); |
| 479 } | 524 } |
| 480 | 525 |
| 481 void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& nam
e, HashSet<RefPtr<Database> >* databases) | 526 void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& nam
e, HashSet<RefPtr<Database> >* databases) |
| 482 { | 527 { |
| 483 MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); | 528 MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); |
| 484 if (!m_openDatabaseMap) | 529 if (!m_openDatabaseMap) |
| 485 return; | 530 return; |
| 486 | 531 |
| 487 DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin); | 532 DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin); |
| 488 if (!nameMap) | 533 if (!nameMap) |
| 489 return; | 534 return; |
| 490 | 535 |
| 491 DatabaseSet* databaseSet = nameMap->get(name); | 536 DatabaseSet* databaseSet = nameMap->get(name); |
| 492 if (!databaseSet) | 537 if (!databaseSet) |
| 493 return; | 538 return; |
| 494 | 539 |
| 495 for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end
(); ++it) | 540 for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end
(); ++it) |
| 496 databases->add(*it); | 541 databases->add(*it); |
| 497 } | 542 } |
| 498 | 543 |
| 544 unsigned long long DatabaseTracker::usageForOriginNoLock(SecurityOrigin* origin) |
| 545 { |
| 546 ASSERT(!originQuotaManagerNoLock().tryLock()); |
| 547 |
| 548 // Use the OriginQuotaManager mechanism to calculate the usage |
| 549 if (originQuotaManagerNoLock().tracksOrigin(origin)) |
| 550 return originQuotaManagerNoLock().diskUsage(origin); |
| 551 |
| 552 // If the OriginQuotaManager doesn't track this origin already, prime it to
do so |
| 553 originQuotaManagerNoLock().trackOrigin(origin); |
| 554 |
| 555 Vector<String> names; |
| 556 databaseNamesForOriginNoLock(origin, names); |
| 557 |
| 558 for (unsigned i = 0; i < names.size(); ++i) |
| 559 originQuotaManagerNoLock().addDatabase(origin, names[i], fullPathForData
baseNoLock(origin, names[i], false)); |
| 560 |
| 561 if (!originQuotaManagerNoLock().tracksOrigin(origin)) |
| 562 return 0; |
| 563 return originQuotaManagerNoLock().diskUsage(origin); |
| 564 } |
| 565 |
| 499 unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin) | 566 unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin) |
| 500 { | 567 { |
| 501 ASSERT(currentThread() == m_thread); | |
| 502 Locker<OriginQuotaManager> locker(originQuotaManager()); | 568 Locker<OriginQuotaManager> locker(originQuotaManager()); |
| 503 | 569 |
| 504 // Use the OriginQuotaManager mechanism to calculate the usage | 570 return usageForOriginNoLock(origin); |
| 505 if (originQuotaManager().tracksOrigin(origin)) | 571 } |
| 506 return originQuotaManager().diskUsage(origin); | |
| 507 | 572 |
| 508 // If the OriginQuotaManager doesn't track this origin already, prime it to
do so | 573 unsigned long long DatabaseTracker::quotaForOriginNoLock(SecurityOrigin* origin) |
| 509 originQuotaManager().trackOrigin(origin); | 574 { |
| 510 | 575 ASSERT(!m_databaseGuard.tryLock()); |
| 511 Vector<String> names; | 576 ASSERT(m_quotaMap); |
| 512 databaseNamesForOrigin(origin, names); | 577 return m_quotaMap->get(origin); |
| 513 | |
| 514 for (unsigned i = 0; i < names.size(); ++i) | |
| 515 originQuotaManager().addDatabase(origin, names[i], fullPathForDatabase(o
rigin, names[i], false)); | |
| 516 | |
| 517 if (!originQuotaManager().tracksOrigin(origin)) | |
| 518 return 0; | |
| 519 return originQuotaManager().diskUsage(origin); | |
| 520 } | 578 } |
| 521 | 579 |
| 522 unsigned long long DatabaseTracker::quotaForOrigin(SecurityOrigin* origin) | 580 unsigned long long DatabaseTracker::quotaForOrigin(SecurityOrigin* origin) |
| 523 { | 581 { |
| 524 ASSERT(currentThread() == m_thread || m_quotaMap); | 582 MutexLocker lockDatabase(m_databaseGuard); |
| 525 populateOrigins(); | 583 populateOrigins(); |
| 526 MutexLocker lockQuotaMap(m_quotaMapGuard); | 584 return quotaForOriginNoLock(origin); |
| 527 return m_quotaMap->get(origin); | |
| 528 } | 585 } |
| 529 | 586 |
| 530 void DatabaseTracker::setQuota(SecurityOrigin* origin, unsigned long long quota) | 587 void DatabaseTracker::setQuota(SecurityOrigin* origin, unsigned long long quota) |
| 531 { | 588 { |
| 532 ASSERT(currentThread() == m_thread); | 589 MutexLocker lockDatabase(m_databaseGuard); |
| 533 if (quotaForOrigin(origin) == quota) | 590 |
| 591 populateOrigins(); |
| 592 if (quotaForOriginNoLock(origin) == quota) |
| 534 return; | 593 return; |
| 535 | 594 |
| 536 openTrackerDatabase(true); | 595 openTrackerDatabase(true); |
| 537 if (!m_database.isOpen()) | 596 if (!m_database.isOpen()) |
| 538 return; | 597 return; |
| 539 | 598 |
| 540 { | 599 if (!m_quotaMap->contains(origin)) { |
| 541 MutexLocker lockQuotaMap(m_quotaMapGuard); | 600 SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)
"); |
| 601 if (statement.prepare() != SQLResultOk) { |
| 602 LOG_ERROR("Unable to establish origin %s in the tracker", origin->da
tabaseIdentifier().ascii().data()); |
| 603 } else { |
| 604 statement.bindText(1, origin->databaseIdentifier()); |
| 605 statement.bindInt64(2, quota); |
| 542 | 606 |
| 543 if (!m_quotaMap->contains(origin)) { | 607 if (statement.step() != SQLResultDone) |
| 544 SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?
, ?)"); | |
| 545 if (statement.prepare() != SQLResultOk) { | |
| 546 LOG_ERROR("Unable to establish origin %s in the tracker", origin
->databaseIdentifier().ascii().data()); | 608 LOG_ERROR("Unable to establish origin %s in the tracker", origin
->databaseIdentifier().ascii().data()); |
| 547 } else { | 609 } |
| 548 statement.bindText(1, origin->databaseIdentifier()); | 610 } else { |
| 549 statement.bindInt64(2, quota); | 611 SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE
origin=?"); |
| 612 bool error = statement.prepare() != SQLResultOk; |
| 613 if (!error) { |
| 614 statement.bindInt64(1, quota); |
| 615 statement.bindText(2, origin->databaseIdentifier()); |
| 550 | 616 |
| 551 if (statement.step() != SQLResultDone) | 617 error = !statement.executeCommand(); |
| 552 LOG_ERROR("Unable to establish origin %s in the tracker", or
igin->databaseIdentifier().ascii().data()); | |
| 553 } | |
| 554 } else { | |
| 555 SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WH
ERE origin=?"); | |
| 556 bool error = statement.prepare() != SQLResultOk; | |
| 557 if (!error) { | |
| 558 statement.bindInt64(1, quota); | |
| 559 statement.bindText(2, origin->databaseIdentifier()); | |
| 560 | |
| 561 error = !statement.executeCommand(); | |
| 562 } | |
| 563 | |
| 564 if (error) | |
| 565 LOG_ERROR("Failed to set quota %llu in tracker database for orig
in %s", quota, origin->databaseIdentifier().ascii().data()); | |
| 566 } | 618 } |
| 567 | 619 |
| 568 // FIXME: Is it really OK to update the quota in memory if we failed to
update it on disk? | 620 if (error) |
| 569 m_quotaMap->set(origin, quota); | 621 LOG_ERROR("Failed to set quota %llu in tracker database for origin %
s", quota, origin->databaseIdentifier().ascii().data()); |
| 570 } | 622 } |
| 571 | 623 |
| 624 // FIXME: Is it really OK to update the quota in memory if we failed to upda
te it on disk? |
| 625 m_quotaMap->set(origin, quota); |
| 626 |
| 572 if (m_client) | 627 if (m_client) |
| 573 m_client->dispatchDidModifyOrigin(origin); | 628 m_client->dispatchDidModifyOrigin(origin); |
| 574 } | 629 } |
| 575 | 630 |
| 576 bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, co
nst String& path) | 631 bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, co
nst String& path) |
| 577 { | 632 { |
| 578 ASSERT(currentThread() == m_thread); | 633 ASSERT(!m_databaseGuard.tryLock()); |
| 634 ASSERT(m_quotaMap); |
| 579 openTrackerDatabase(true); | 635 openTrackerDatabase(true); |
| 580 if (!m_database.isOpen()) | 636 if (!m_database.isOpen()) |
| 581 return false; | 637 return false; |
| 582 | 638 |
| 583 // New database should never be added until the origin has been established | 639 // New database should never be added until the origin has been established |
| 584 ASSERT(hasEntryForOrigin(origin)); | 640 ASSERT(hasEntryForOriginNoLock(origin)); |
| 585 | 641 |
| 586 SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name,
path) VALUES (?, ?, ?);"); | 642 SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name,
path) VALUES (?, ?, ?);"); |
| 587 | 643 |
| 588 if (statement.prepare() != SQLResultOk) | 644 if (statement.prepare() != SQLResultOk) |
| 589 return false; | 645 return false; |
| 590 | 646 |
| 591 statement.bindText(1, origin->databaseIdentifier()); | 647 statement.bindText(1, origin->databaseIdentifier()); |
| 592 statement.bindText(2, name); | 648 statement.bindText(2, name); |
| 593 statement.bindText(3, path); | 649 statement.bindText(3, path); |
| 594 | 650 |
| 595 if (!statement.executeCommand()) { | 651 if (!statement.executeCommand()) { |
| 596 LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.ascii().d
ata(), origin->databaseIdentifier().ascii().data(), m_database.lastErrorMsg()); | 652 LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.ascii().d
ata(), origin->databaseIdentifier().ascii().data(), m_database.lastErrorMsg()); |
| 597 return false; | 653 return false; |
| 598 } | 654 } |
| 599 | 655 |
| 600 if (m_client) | 656 if (m_client) |
| 601 m_client->dispatchDidModifyOrigin(origin); | 657 m_client->dispatchDidModifyOrigin(origin); |
| 602 | 658 |
| 603 return true; | 659 return true; |
| 604 } | 660 } |
| 605 | 661 |
| 606 void DatabaseTracker::deleteAllDatabases() | 662 void DatabaseTracker::deleteAllDatabases() |
| 607 { | 663 { |
| 608 ASSERT(currentThread() == m_thread); | |
| 609 | |
| 610 Vector<RefPtr<SecurityOrigin> > originsCopy; | 664 Vector<RefPtr<SecurityOrigin> > originsCopy; |
| 611 origins(originsCopy); | 665 origins(originsCopy); |
| 612 | 666 |
| 613 for (unsigned i = 0; i < originsCopy.size(); ++i) | 667 for (unsigned i = 0; i < originsCopy.size(); ++i) |
| 614 deleteOrigin(originsCopy[i].get()); | 668 deleteOrigin(originsCopy[i].get()); |
| 615 } | 669 } |
| 616 | 670 |
| 671 // It is the caller's responsibility to make sure that nobody is trying to creat
e, delete, open, or close databases in this origin while the deletion is |
| 672 // taking place. |
| 617 void DatabaseTracker::deleteOrigin(SecurityOrigin* origin) | 673 void DatabaseTracker::deleteOrigin(SecurityOrigin* origin) |
| 618 { | 674 { |
| 619 ASSERT(currentThread() == m_thread); | 675 Vector<String> databaseNames; |
| 620 openTrackerDatabase(false); | 676 { |
| 621 if (!m_database.isOpen()) | 677 MutexLocker lockDatabase(m_databaseGuard); |
| 622 return; | 678 openTrackerDatabase(false); |
| 679 if (!m_database.isOpen()) |
| 680 return; |
| 623 | 681 |
| 624 Vector<String> databaseNames; | 682 if (!databaseNamesForOriginNoLock(origin, databaseNames)) { |
| 625 if (!databaseNamesForOrigin(origin, databaseNames)) { | 683 LOG_ERROR("Unable to retrieve list of database names for origin %s",
origin->databaseIdentifier().ascii().data()); |
| 626 LOG_ERROR("Unable to retrieve list of database names for origin %s", ori
gin->databaseIdentifier().ascii().data()); | 684 return; |
| 627 return; | 685 } |
| 628 } | 686 } |
| 629 | 687 |
| 688 // We drop the lock here because holding locks during a call to deleteDataba
seFile will deadlock. |
| 630 for (unsigned i = 0; i < databaseNames.size(); ++i) { | 689 for (unsigned i = 0; i < databaseNames.size(); ++i) { |
| 631 if (!deleteDatabaseFile(origin, databaseNames[i])) { | 690 if (!deleteDatabaseFile(origin, databaseNames[i])) { |
| 632 // Even if the file can't be deleted, we want to try and delete the
rest, don't return early here. | 691 // Even if the file can't be deleted, we want to try and delete the
rest, don't return early here. |
| 633 LOG_ERROR("Unable to delete file for database %s in origin %s", data
baseNames[i].ascii().data(), origin->databaseIdentifier().ascii().data()); | 692 LOG_ERROR("Unable to delete file for database %s in origin %s", data
baseNames[i].ascii().data(), origin->databaseIdentifier().ascii().data()); |
| 634 } | 693 } |
| 635 } | 694 } |
| 636 | 695 |
| 637 SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?"
); | 696 { |
| 638 if (statement.prepare() != SQLResultOk) { | 697 // To satisfy the lock hierarchy, we have to lock the originQuotaManager
before m_databaseGuard if there's any chance we'll to lock both. |
| 639 LOG_ERROR("Unable to prepare deletion of databases from origin %s from t
racker", origin->databaseIdentifier().ascii().data()); | 698 Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); |
| 640 return; | 699 MutexLocker lockDatabase(m_databaseGuard); |
| 641 } | 700 SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origi
n=?"); |
| 701 if (statement.prepare() != SQLResultOk) { |
| 702 LOG_ERROR("Unable to prepare deletion of databases from origin %s fr
om tracker", origin->databaseIdentifier().ascii().data()); |
| 703 return; |
| 704 } |
| 642 | 705 |
| 643 statement.bindText(1, origin->databaseIdentifier()); | 706 statement.bindText(1, origin->databaseIdentifier()); |
| 644 | 707 |
| 645 if (!statement.executeCommand()) { | 708 if (!statement.executeCommand()) { |
| 646 LOG_ERROR("Unable to execute deletion of databases from origin %s from t
racker", origin->databaseIdentifier().ascii().data()); | 709 LOG_ERROR("Unable to execute deletion of databases from origin %s fr
om tracker", origin->databaseIdentifier().ascii().data()); |
| 647 return; | 710 return; |
| 648 } | 711 } |
| 649 | 712 |
| 650 SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origi
n=?"); | 713 SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE o
rigin=?"); |
| 651 if (originStatement.prepare() != SQLResultOk) { | 714 if (originStatement.prepare() != SQLResultOk) { |
| 652 LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin
->databaseIdentifier().ascii().data()); | 715 LOG_ERROR("Unable to prepare deletion of origin %s from tracker", or
igin->databaseIdentifier().ascii().data()); |
| 653 return; | 716 return; |
| 654 } | 717 } |
| 655 | 718 |
| 656 originStatement.bindText(1, origin->databaseIdentifier()); | 719 originStatement.bindText(1, origin->databaseIdentifier()); |
| 657 | 720 |
| 658 if (!originStatement.executeCommand()) { | 721 if (!originStatement.executeCommand()) { |
| 659 LOG_ERROR("Unable to execute deletion of databases from origin %s from t
racker", origin->databaseIdentifier().ascii().data()); | 722 LOG_ERROR("Unable to execute deletion of databases from origin %s fr
om tracker", origin->databaseIdentifier().ascii().data()); |
| 660 return; | 723 return; |
| 661 } | 724 } |
| 662 | 725 |
| 663 SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin)); | 726 SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin)); |
| 664 | 727 |
| 665 RefPtr<SecurityOrigin> originPossiblyLastReference = origin; | 728 RefPtr<SecurityOrigin> originPossiblyLastReference = origin; |
| 666 { | |
| 667 MutexLocker lockQuotaMap(m_quotaMapGuard); | |
| 668 m_quotaMap->remove(origin); | 729 m_quotaMap->remove(origin); |
| 669 | 730 |
| 670 Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); | 731 originQuotaManagerNoLock().removeOrigin(origin); |
| 671 originQuotaManager().removeOrigin(origin); | |
| 672 | 732 |
| 673 // If we removed the last origin, do some additional deletion. | 733 // If we removed the last origin, do some additional deletion. |
| 674 if (m_quotaMap->isEmpty()) { | 734 if (m_quotaMap->isEmpty()) { |
| 675 if (m_database.isOpen()) | 735 if (m_database.isOpen()) |
| 676 m_database.close(); | 736 m_database.close(); |
| 677 SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); | 737 SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); |
| 678 SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectoryPat
h); | 738 SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectoryPat
h); |
| 679 } | 739 } |
| 680 } | |
| 681 | 740 |
| 682 if (m_client) { | 741 if (m_client) { |
| 683 m_client->dispatchDidModifyOrigin(origin); | 742 m_client->dispatchDidModifyOrigin(origin); |
| 684 for (unsigned i = 0; i < databaseNames.size(); ++i) | 743 for (unsigned i = 0; i < databaseNames.size(); ++i) |
| 685 m_client->dispatchDidModifyDatabase(origin, databaseNames[i]); | 744 m_client->dispatchDidModifyDatabase(origin, databaseNames[i]); |
| 745 } |
| 686 } | 746 } |
| 687 } | 747 } |
| 688 | 748 |
| 689 void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name) | 749 void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name) |
| 690 { | 750 { |
| 691 ASSERT(currentThread() == m_thread); | 751 { |
| 692 openTrackerDatabase(false); | 752 MutexLocker lockDatabase(m_databaseGuard); |
| 693 if (!m_database.isOpen()) | 753 openTrackerDatabase(false); |
| 694 return; | 754 if (!m_database.isOpen()) |
| 755 return; |
| 756 } |
| 695 | 757 |
| 758 // We drop the lock here because holding locks during a call to deleteDataba
seFile will deadlock. |
| 696 if (!deleteDatabaseFile(origin, name)) { | 759 if (!deleteDatabaseFile(origin, name)) { |
| 697 LOG_ERROR("Unable to delete file for database %s in origin %s", name.asc
ii().data(), origin->databaseIdentifier().ascii().data()); | 760 LOG_ERROR("Unable to delete file for database %s in origin %s", name.asc
ii().data(), origin->databaseIdentifier().ascii().data()); |
| 698 return; | 761 return; |
| 699 } | 762 } |
| 700 | 763 |
| 764 // To satisfy the lock hierarchy, we have to lock the originQuotaManager bef
ore m_databaseGuard if there's any chance we'll to lock both. |
| 765 Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); |
| 766 MutexLocker lockDatabase(m_databaseGuard); |
| 767 |
| 701 SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?
AND name=?"); | 768 SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?
AND name=?"); |
| 702 if (statement.prepare() != SQLResultOk) { | 769 if (statement.prepare() != SQLResultOk) { |
| 703 LOG_ERROR("Unable to prepare deletion of database %s from origin %s from
tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data()); | 770 LOG_ERROR("Unable to prepare deletion of database %s from origin %s from
tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data()); |
| 704 return; | 771 return; |
| 705 } | 772 } |
| 706 | 773 |
| 707 statement.bindText(1, origin->databaseIdentifier()); | 774 statement.bindText(1, origin->databaseIdentifier()); |
| 708 statement.bindText(2, name); | 775 statement.bindText(2, name); |
| 709 | 776 |
| 710 if (!statement.executeCommand()) { | 777 if (!statement.executeCommand()) { |
| 711 LOG_ERROR("Unable to execute deletion of database %s from origin %s from
tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data()); | 778 LOG_ERROR("Unable to execute deletion of database %s from origin %s from
tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data()); |
| 712 return; | 779 return; |
| 713 } | 780 } |
| 714 | 781 |
| 715 { | 782 originQuotaManagerNoLock().removeDatabase(origin, name); |
| 716 Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager()); | |
| 717 originQuotaManager().removeDatabase(origin, name); | |
| 718 } | |
| 719 | 783 |
| 720 if (m_client) { | 784 if (m_client) { |
| 721 m_client->dispatchDidModifyOrigin(origin); | 785 m_client->dispatchDidModifyOrigin(origin); |
| 722 m_client->dispatchDidModifyDatabase(origin, name); | 786 m_client->dispatchDidModifyDatabase(origin, name); |
| 723 } | 787 } |
| 724 } | 788 } |
| 725 | 789 |
| 790 // deleteDatabaseFile has to release locks between looking up the list of databa
ses to close and closing them. While this is in progress, the caller |
| 791 // is responsible for making sure no new databases are opened in the file to be
deleted. |
| 726 bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& n
ame) | 792 bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& n
ame) |
| 727 { | 793 { |
| 728 ASSERT(currentThread() == m_thread); | 794 LOG_ERROR("in deleteDatabaseFile(%s,%s)", |
| 795 origin->databaseIdentifier().ascii().data(), name.ascii().data()); |
| 729 String fullPath = fullPathForDatabase(origin, name, false); | 796 String fullPath = fullPathForDatabase(origin, name, false); |
| 730 if (fullPath.isEmpty()) | 797 if (fullPath.isEmpty()) { |
| 798 LOG_ERROR("out [empty] deleteDatabaseFile(%s,%s)", |
| 799 origin->databaseIdentifier().ascii().data(), name.ascii().data()); |
| 731 return true; | 800 return true; |
| 801 } |
| 732 | 802 |
| 733 Vector<RefPtr<Database> > deletedDatabases; | 803 Vector<RefPtr<Database> > deletedDatabases; |
| 734 | 804 |
| 735 // Make sure not to hold the m_openDatabaseMapGuard mutex when calling | 805 // Make sure not to hold the any locks when calling |
| 736 // Database::markAsDeletedAndClose(), since that can cause a deadlock | 806 // Database::markAsDeletedAndClose(), since that can cause a deadlock |
| 737 // during the synchronous DatabaseThread call it triggers. | 807 // during the synchronous DatabaseThread call it triggers. |
| 738 | |
| 739 { | 808 { |
| 740 MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); | 809 MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); |
| 741 if (m_openDatabaseMap) { | 810 if (m_openDatabaseMap) { |
| 742 // There are some open databases, lets check if they are for this or
igin. | 811 // There are some open databases, lets check if they are for this or
igin. |
| 743 DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin); | 812 DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin); |
| 744 if (nameMap && nameMap->size()) { | 813 if (nameMap && nameMap->size()) { |
| 745 // There are some open databases for this origin, lets check | 814 // There are some open databases for this origin, let's check |
| 746 // if they are this database by name. | 815 // if they are this database by name. |
| 747 DatabaseSet* databaseSet = nameMap->get(name); | 816 DatabaseSet* databaseSet = nameMap->get(name); |
| 748 if (databaseSet && databaseSet->size()) { | 817 if (databaseSet && databaseSet->size()) { |
| 749 // We have some database open with this name. Mark them as d
eleted. | 818 // We have some database open with this name. Mark them as d
eleted. |
| 750 DatabaseSet::const_iterator end = databaseSet->end(); | 819 DatabaseSet::const_iterator end = databaseSet->end(); |
| 751 for (DatabaseSet::const_iterator it = databaseSet->begin();
it != end; ++it) | 820 for (DatabaseSet::const_iterator it = databaseSet->begin();
it != end; ++it) |
| 752 deletedDatabases.append(*it); | 821 deletedDatabases.append(*it); |
| 753 } | 822 } |
| 754 } | 823 } |
| 755 } | 824 } |
| 756 } | 825 } |
| 757 | 826 |
| 758 for (unsigned i = 0; i < deletedDatabases.size(); ++i) | 827 for (unsigned i = 0; i < deletedDatabases.size(); ++i) |
| 759 deletedDatabases[i]->markAsDeletedAndClose(); | 828 deletedDatabases[i]->markAsDeletedAndClose(); |
| 760 | 829 |
| 830 LOG_ERROR("out [full] deleteDatabaseFile(%s,%s)", |
| 831 origin->databaseIdentifier().ascii().data(), name.ascii().data()); |
| 761 return SQLiteFileSystem::deleteDatabaseFile(fullPath); | 832 return SQLiteFileSystem::deleteDatabaseFile(fullPath); |
| 762 } | 833 } |
| 763 | 834 |
| 764 void DatabaseTracker::setClient(DatabaseTrackerClient* client) | 835 void DatabaseTracker::setClient(DatabaseTrackerClient* client) |
| 765 { | 836 { |
| 766 ASSERT(currentThread() == m_thread); | |
| 767 m_client = client; | 837 m_client = client; |
| 768 } | 838 } |
| 769 | 839 |
| 770 static Mutex& notificationMutex() | 840 static Mutex& notificationMutex() |
| 771 { | 841 { |
| 772 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); | 842 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); |
| 773 return mutex; | 843 return mutex; |
| 774 } | 844 } |
| 775 | 845 |
| 776 typedef Vector<pair<SecurityOrigin*, String> > NotificationQueue; | 846 typedef Vector<pair<SecurityOrigin*, String> > NotificationQueue; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 819 if (!theTracker.m_client) | 889 if (!theTracker.m_client) |
| 820 return; | 890 return; |
| 821 | 891 |
| 822 for (unsigned i = 0; i < notifications.size(); ++i) | 892 for (unsigned i = 0; i < notifications.size(); ++i) |
| 823 theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first, n
otifications[i].second); | 893 theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first, n
otifications[i].second); |
| 824 } | 894 } |
| 825 | 895 |
| 826 | 896 |
| 827 } // namespace WebCore | 897 } // namespace WebCore |
| 828 #endif | 898 #endif |
| OLD | NEW |