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 |