Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(240)

Side by Side Diff: WebCore/storage/DatabaseTracker.cpp

Issue 596028: Make the DatabaseTracker thread-safe. (Closed) Base URL: http://svn.webkit.org/repository/webkit/trunk/
Patch Set: '' Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « WebCore/storage/DatabaseTracker.h ('k') | WebCore/storage/OriginQuotaManager.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « WebCore/storage/DatabaseTracker.h ('k') | WebCore/storage/OriginQuotaManager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698