Use StaticLock instead of NeverDestroyed<Lock>
[WebKit-https.git] / Source / WebCore / Modules / webdatabase / DatabaseTracker.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2012, 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "DatabaseTracker.h"
31
32 #include "Database.h"
33 #include "DatabaseContext.h"
34 #include "DatabaseManager.h"
35 #include "DatabaseManagerClient.h"
36 #include "DatabaseThread.h"
37 #include "FileSystem.h"
38 #include "Logging.h"
39 #include "OriginLock.h"
40 #include "SecurityOrigin.h"
41 #include "SecurityOriginData.h"
42 #include "SecurityOriginHash.h"
43 #include "SQLiteFileSystem.h"
44 #include "SQLiteStatement.h"
45 #include "SQLiteTransaction.h"
46 #include <wtf/MainThread.h>
47 #include <wtf/NeverDestroyed.h>
48 #include <wtf/StdLibExtras.h>
49 #include <wtf/UUID.h>
50 #include <wtf/text/CString.h>
51 #include <wtf/text/StringBuilder.h>
52
53 #if PLATFORM(IOS)
54 #include "WebCoreThread.h"
55 #endif
56
57 namespace WebCore {
58
59 static Vector<String> isolatedCopy(const Vector<String>& original)
60 {
61     Vector<String> copy;
62     copy.reserveInitialCapacity(original.size());
63     for (auto& string : original)
64         copy.uncheckedAppend(string.isolatedCopy());
65     return copy;
66 }
67
68 std::unique_ptr<DatabaseTracker> DatabaseTracker::trackerWithDatabasePath(const String& databasePath)
69 {
70     return std::unique_ptr<DatabaseTracker>(new DatabaseTracker(databasePath));
71 }
72
73 static DatabaseTracker* staticTracker = nullptr;
74
75 void DatabaseTracker::initializeTracker(const String& databasePath)
76 {
77     ASSERT(!staticTracker);
78     if (staticTracker)
79         return;
80     staticTracker = new DatabaseTracker(databasePath);
81 }
82
83 DatabaseTracker& DatabaseTracker::singleton()
84 {
85     if (!staticTracker)
86         staticTracker = new DatabaseTracker(emptyString());
87     return *staticTracker;
88 }
89
90 DatabaseTracker::DatabaseTracker(const String& databasePath)
91     : m_databaseDirectoryPath(databasePath.isolatedCopy())
92 {
93 }
94
95 String DatabaseTracker::trackerDatabasePath() const
96 {
97     return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath.isolatedCopy(), "Databases.db");
98 }
99
100 void DatabaseTracker::openTrackerDatabase(TrackerCreationAction createAction)
101 {
102     ASSERT(!m_databaseGuard.tryLock());
103
104     if (m_database.isOpen())
105         return;
106
107     // If createIfDoesNotExist is false, SQLiteFileSystem::ensureDatabaseFileExists()
108     // will return false if the database file does not exist.
109     // If createIfDoesNotExist is true, SQLiteFileSystem::ensureDatabaseFileExists()
110     // will attempt to create the path to the database file if it does not
111     // exists yet. It'll return true if the path already exists, or if it
112     // successfully creates the path. Else, it will return false.
113     String databasePath = trackerDatabasePath();
114     if (!SQLiteFileSystem::ensureDatabaseFileExists(databasePath, createAction == CreateIfDoesNotExist))
115         return;
116
117     if (!m_database.open(databasePath)) {
118         // FIXME: What do do here?
119         LOG_ERROR("Failed to open databasePath %s.", databasePath.utf8().data());
120         return;
121     }
122     m_database.disableThreadingChecks();
123
124     if (!m_database.tableExists("Origins")) {
125         if (!m_database.executeCommand("CREATE TABLE Origins (origin TEXT UNIQUE ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);")) {
126             // FIXME: and here
127             LOG_ERROR("Failed to create Origins table");
128         }
129     }
130
131     if (!m_database.tableExists("Databases")) {
132         if (!m_database.executeCommand("CREATE TABLE Databases (guid INTEGER PRIMARY KEY AUTOINCREMENT, origin TEXT, name TEXT, displayName TEXT, estimatedSize INTEGER, path TEXT);")) {
133             // FIXME: and here
134             LOG_ERROR("Failed to create Databases table");
135         }
136     }
137 }
138
139 ExceptionOr<void> DatabaseTracker::hasAdequateQuotaForOrigin(const SecurityOriginData& origin, unsigned estimatedSize)
140 {
141     ASSERT(!m_databaseGuard.tryLock());
142     auto usage = this->usage(origin);
143
144     // If the database will fit, allow its creation.
145     auto requirement = usage + std::max<unsigned long long>(1, estimatedSize);
146     if (requirement < usage) {
147         // The estimated size is so big it causes an overflow; don't allow creation.
148         return Exception { SecurityError };
149     }
150     if (requirement > quotaNoLock(origin))
151         return Exception { QuotaExceededError };
152     return { };
153 }
154
155 ExceptionOr<void> DatabaseTracker::canEstablishDatabase(DatabaseContext& context, const String& name, unsigned estimatedSize)
156 {
157     LockHolder lockDatabase(m_databaseGuard);
158
159     // FIXME: What guarantees this context.securityOrigin() is non-null?
160     auto origin = context.securityOrigin();
161
162     if (isDeletingDatabaseOrOriginFor(origin, name))
163         return Exception { SecurityError };
164
165     recordCreatingDatabase(origin, name);
166
167     // If a database already exists, ignore the passed-in estimated size and say it's OK.
168     if (hasEntryForDatabase(origin, name))
169         return { };
170
171     auto result = hasAdequateQuotaForOrigin(origin, estimatedSize);
172     if (!result.hasException())
173         return { };
174
175     // If we get here, then we do not have enough quota for one of the
176     // following reasons as indicated by the set error:
177     //
178     // If the error is DatabaseSizeOverflowed, then this means the requested
179     // estimatedSize if so unreasonably large that it can cause an overflow in
180     // the usage budget computation. In that case, there's nothing more we can
181     // do, and there's no need for a retry. Hence, we should indicate that
182     // we're done with our attempt to create the database.
183     //
184     // If the error is DatabaseSizeExceededQuota, then we'll give the client
185     // a chance to update the quota and call retryCanEstablishDatabase() to try
186     // again. Hence, we don't call doneCreatingDatabase() yet in that case.
187
188     auto exception = result.releaseException();
189     if (exception.code() != QuotaExceededError)
190         doneCreatingDatabase(origin, name);
191
192     return WTFMove(exception);
193 }
194
195 // Note: a thought about performance: hasAdequateQuotaForOrigin() was also
196 // called in canEstablishDatabase(), and hence, we're repeating some work within
197 // hasAdequateQuotaForOrigin(). However, retryCanEstablishDatabase() should only
198 // be called in the rare even if canEstablishDatabase() fails. Since it is rare,
199 // we should not bother optimizing it. It is more beneficial to keep
200 // hasAdequateQuotaForOrigin() simple and correct (i.e. bug free), and just
201 // re-use it. Also note that the path for opening a database involves IO, and
202 // hence should not be a performance critical path anyway. 
203 ExceptionOr<void> DatabaseTracker::retryCanEstablishDatabase(DatabaseContext& context, const String& name, unsigned estimatedSize)
204 {
205     LockHolder lockDatabase(m_databaseGuard);
206
207     // FIXME: What guarantees context.securityOrigin() is non-null?
208     auto origin = context.securityOrigin();
209
210     // We have already eliminated other types of errors in canEstablishDatabase().
211     // The only reason we're in retryCanEstablishDatabase() is because we gave
212     // the client a chance to update the quota and are rechecking it here.
213     // If we fail this check, the only possible reason this time should be due
214     // to inadequate quota.
215     auto result = hasAdequateQuotaForOrigin(origin, estimatedSize);
216     if (!result.hasException())
217         return { };
218
219     auto exception = result.releaseException();
220     ASSERT(exception.code() == QuotaExceededError);
221     doneCreatingDatabase(origin, name);
222
223     return WTFMove(exception);
224 }
225
226 bool DatabaseTracker::hasEntryForOriginNoLock(const SecurityOriginData& origin)
227 {
228     ASSERT(!m_databaseGuard.tryLock());
229     openTrackerDatabase(DontCreateIfDoesNotExist);
230     if (!m_database.isOpen())
231         return false;
232
233     SQLiteStatement statement(m_database, "SELECT origin FROM Origins where origin=?;");
234     if (statement.prepare() != SQLITE_OK) {
235         LOG_ERROR("Failed to prepare statement.");
236         return false;
237     }
238
239     statement.bindText(1, origin.databaseIdentifier());
240
241     return statement.step() == SQLITE_ROW;
242 }
243
244 bool DatabaseTracker::hasEntryForDatabase(const SecurityOriginData& origin, const String& databaseIdentifier)
245 {
246     ASSERT(!m_databaseGuard.tryLock());
247     openTrackerDatabase(DontCreateIfDoesNotExist);
248     if (!m_database.isOpen()) {
249         // No "tracker database". Hence, no entry for the database of interest.
250         return false;
251     }
252
253     // We've got a tracker database. Set up a query to ask for the db of interest:
254     SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?;");
255
256     if (statement.prepare() != SQLITE_OK)
257         return false;
258
259     statement.bindText(1, origin.databaseIdentifier());
260     statement.bindText(2, databaseIdentifier);
261
262     return statement.step() == SQLITE_ROW;
263 }
264
265 unsigned long long DatabaseTracker::maximumSize(Database& database)
266 {
267     // The maximum size for a database is the full quota for its origin, minus the current usage within the origin,
268     // plus the current usage of the given database
269     LockHolder lockDatabase(m_databaseGuard);
270     auto origin = database.securityOrigin();
271
272     unsigned long long quota = quotaNoLock(origin);
273     unsigned long long diskUsage = usage(origin);
274     unsigned long long databaseFileSize = SQLiteFileSystem::getDatabaseFileSize(database.fileName());
275     ASSERT(databaseFileSize <= diskUsage);
276
277     if (diskUsage > quota)
278         return databaseFileSize;
279
280     // A previous error may have allowed the origin to exceed its quota, or may
281     // have allowed this database to exceed our cached estimate of the origin
282     // disk usage. Don't multiply that error through integer underflow, or the
283     // effective quota will permanently become 2^64.
284     unsigned long long maxSize = quota - diskUsage + databaseFileSize;
285     if (maxSize > quota)
286         maxSize = databaseFileSize;
287     return maxSize;
288 }
289
290 void DatabaseTracker::closeAllDatabases(CurrentQueryBehavior currentQueryBehavior)
291 {
292     Vector<Ref<Database>> openDatabases;
293     {
294         LockHolder openDatabaseMapLock(m_openDatabaseMapGuard);
295         if (!m_openDatabaseMap)
296             return;
297         for (auto& nameMap : m_openDatabaseMap->values()) {
298             for (auto& set : nameMap->values()) {
299                 for (auto& database : *set)
300                     openDatabases.append(*database);
301             }
302         }
303     }
304     for (auto& database : openDatabases) {
305         if (currentQueryBehavior == CurrentQueryBehavior::Interrupt)
306             database->interrupt();
307         database->close();
308     }
309 }
310
311 String DatabaseTracker::originPath(const SecurityOriginData& origin) const
312 {
313     return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath.isolatedCopy(), origin.databaseIdentifier());
314 }
315
316 static String generateDatabaseFileName()
317 {
318     StringBuilder stringBuilder;
319
320     stringBuilder.append(createCanonicalUUIDString());
321     stringBuilder.appendLiteral(".db");
322
323     return stringBuilder.toString();
324 }
325
326 String DatabaseTracker::fullPathForDatabaseNoLock(const SecurityOriginData& origin, const String& name, bool createIfNotExists)
327 {
328     ASSERT(!m_databaseGuard.tryLock());
329
330     String originIdentifier = origin.databaseIdentifier();
331     String originPath = this->originPath(origin);
332
333     // Make sure the path for this SecurityOrigin exists
334     if (createIfNotExists && !SQLiteFileSystem::ensureDatabaseDirectoryExists(originPath))
335         return String();
336
337     // See if we have a path for this database yet
338     if (!m_database.isOpen())
339         return String();
340     SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
341
342     if (statement.prepare() != SQLITE_OK)
343         return String();
344
345     statement.bindText(1, originIdentifier);
346     statement.bindText(2, name);
347
348     int result = statement.step();
349
350     if (result == SQLITE_ROW)
351         return SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, statement.getColumnText(0));
352     if (!createIfNotExists)
353         return String();
354
355     if (result != SQLITE_DONE) {
356         LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", originIdentifier.utf8().data(), name.utf8().data());
357         return String();
358     }
359     statement.finalize();
360
361     String fileName = generateDatabaseFileName();
362
363     if (!addDatabase(origin, name, fileName))
364         return String();
365
366     // If this origin's quota is being tracked (open handle to a database in this origin), add this new database
367     // to the quota manager now
368     String fullFilePath = SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, fileName);
369
370     return fullFilePath;
371 }
372
373 String DatabaseTracker::fullPathForDatabase(const SecurityOriginData& origin, const String& name, bool createIfNotExists)
374 {
375     LockHolder lockDatabase(m_databaseGuard);
376     return fullPathForDatabaseNoLock(origin, name, createIfNotExists).isolatedCopy();
377 }
378
379 Vector<SecurityOriginData> DatabaseTracker::origins()
380 {
381     LockHolder lockDatabase(m_databaseGuard);
382
383     openTrackerDatabase(DontCreateIfDoesNotExist);
384     if (!m_database.isOpen())
385         return { };
386
387     SQLiteStatement statement(m_database, "SELECT origin FROM Origins");
388     if (statement.prepare() != SQLITE_OK) {
389         LOG_ERROR("Failed to prepare statement.");
390         return { };
391     }
392
393     Vector<SecurityOriginData> origins;
394     int stepResult;
395     while ((stepResult = statement.step()) == SQLITE_ROW)
396         origins.append(SecurityOriginData::fromDatabaseIdentifier(statement.getColumnText(0))->isolatedCopy());
397     origins.shrinkToFit();
398
399     if (stepResult != SQLITE_DONE)
400         LOG_ERROR("Failed to read in all origins from the database.");
401
402     return origins;
403 }
404
405 Vector<String> DatabaseTracker::databaseNamesNoLock(const SecurityOriginData& origin)
406 {
407     ASSERT(!m_databaseGuard.tryLock());
408     openTrackerDatabase(DontCreateIfDoesNotExist);
409     if (!m_database.isOpen())
410         return { };
411
412     SQLiteStatement statement(m_database, "SELECT name FROM Databases where origin=?;");
413     if (statement.prepare() != SQLITE_OK)
414         return { };
415
416     statement.bindText(1, origin.databaseIdentifier());
417
418     Vector<String> names;
419     int result;
420     while ((result = statement.step()) == SQLITE_ROW)
421         names.append(statement.getColumnText(0));
422     names.shrinkToFit();
423
424     if (result != SQLITE_DONE) {
425         LOG_ERROR("Failed to retrieve all database names for origin %s", origin.databaseIdentifier().utf8().data());
426         return { };
427     }
428
429     return names;
430 }
431
432 Vector<String> DatabaseTracker::databaseNames(const SecurityOriginData& origin)
433 {
434     Vector<String> names;
435     {
436         LockHolder lockDatabase(m_databaseGuard);
437         names = databaseNamesNoLock(origin);
438     }
439     return isolatedCopy(names);
440 }
441
442 DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, const SecurityOriginData& origin)
443 {
444     String originIdentifier = origin.databaseIdentifier();
445     String displayName;
446     int64_t expectedUsage;
447
448     {
449         LockHolder lockDatabase(m_databaseGuard);
450
451         openTrackerDatabase(DontCreateIfDoesNotExist);
452         if (!m_database.isOpen())
453             return DatabaseDetails();
454         SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?");
455         if (statement.prepare() != SQLITE_OK)
456             return DatabaseDetails();
457
458         statement.bindText(1, originIdentifier);
459         statement.bindText(2, name);
460
461         int result = statement.step();
462         if (result == SQLITE_DONE)
463             return DatabaseDetails();
464
465         if (result != SQLITE_ROW) {
466             LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.utf8().data(), originIdentifier.utf8().data());
467             return DatabaseDetails();
468         }
469         displayName = statement.getColumnText(0);
470         expectedUsage = statement.getColumnInt64(1);
471     }
472
473     String path = fullPathForDatabase(origin, name, false);
474     if (path.isEmpty())
475         return DatabaseDetails(name, displayName, expectedUsage, 0, 0, 0);
476     return DatabaseDetails(name, displayName, expectedUsage, SQLiteFileSystem::getDatabaseFileSize(path), SQLiteFileSystem::databaseCreationTime(path), SQLiteFileSystem::databaseModificationTime(path));
477 }
478
479 void DatabaseTracker::setDatabaseDetails(const SecurityOriginData& origin, const String& name, const String& displayName, unsigned estimatedSize)
480 {
481     String originIdentifier = origin.databaseIdentifier();
482     int64_t guid = 0;
483
484     LockHolder lockDatabase(m_databaseGuard);
485
486     openTrackerDatabase(CreateIfDoesNotExist);
487     if (!m_database.isOpen())
488         return;
489     SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?");
490     if (statement.prepare() != SQLITE_OK)
491         return;
492
493     statement.bindText(1, originIdentifier);
494     statement.bindText(2, name);
495
496     int result = statement.step();
497     if (result == SQLITE_ROW)
498         guid = statement.getColumnInt64(0);
499     statement.finalize();
500
501     if (guid == 0) {
502         if (result != SQLITE_DONE)
503             LOG_ERROR("Error to determing existence of database %s in origin %s in tracker database", name.utf8().data(), originIdentifier.utf8().data());
504         else {
505             // This case should never occur - we should never be setting database details for a database that doesn't already exist in the tracker
506             // But since the tracker file is an external resource not under complete control of our code, it's somewhat invalid to make this an ASSERT case
507             // So we'll print an error instead
508             LOG_ERROR("Could not retrieve guid for database %s in origin %s from the tracker database - it is invalid to set database details on a database that doesn't already exist in the tracker", name.utf8().data(), originIdentifier.utf8().data());
509         }
510         return;
511     }
512
513     SQLiteStatement updateStatement(m_database, "UPDATE Databases SET displayName=?, estimatedSize=? WHERE guid=?");
514     if (updateStatement.prepare() != SQLITE_OK)
515         return;
516
517     updateStatement.bindText(1, displayName);
518     updateStatement.bindInt64(2, estimatedSize);
519     updateStatement.bindInt64(3, guid);
520
521     if (updateStatement.step() != SQLITE_DONE) {
522         LOG_ERROR("Failed to update details for database %s in origin %s", name.utf8().data(), originIdentifier.utf8().data());
523         return;
524     }
525
526     if (m_client)
527         m_client->dispatchDidModifyDatabase(origin, name);
528 }
529
530 void DatabaseTracker::doneCreatingDatabase(Database& database)
531 {
532     LockHolder lockDatabase(m_databaseGuard);
533     doneCreatingDatabase(database.securityOrigin(), database.stringIdentifier());
534 }
535
536 void DatabaseTracker::addOpenDatabase(Database& database)
537 {
538     LockHolder openDatabaseMapLock(m_openDatabaseMapGuard);
539
540     if (!m_openDatabaseMap)
541         m_openDatabaseMap = std::make_unique<DatabaseOriginMap>();
542
543     auto origin = database.securityOrigin();
544
545     auto* nameMap = m_openDatabaseMap->get(origin);
546     if (!nameMap) {
547         nameMap = new DatabaseNameMap;
548         m_openDatabaseMap->add(origin.isolatedCopy(), nameMap);
549     }
550
551     String name = database.stringIdentifier();
552     auto* databaseSet = nameMap->get(name);
553     if (!databaseSet) {
554         databaseSet = new DatabaseSet;
555         nameMap->set(name.isolatedCopy(), databaseSet);
556     }
557
558     databaseSet->add(&database);
559
560     LOG(StorageAPI, "Added open Database %s (%p)\n", database.stringIdentifier().utf8().data(), &database);
561 }
562
563 void DatabaseTracker::removeOpenDatabase(Database& database)
564 {
565     LockHolder openDatabaseMapLock(m_openDatabaseMapGuard);
566
567     if (!m_openDatabaseMap) {
568         ASSERT_NOT_REACHED();
569         return;
570     }
571
572     DatabaseNameMap* nameMap = m_openDatabaseMap->get(database.securityOrigin());
573     if (!nameMap) {
574         ASSERT_NOT_REACHED();
575         return;
576     }
577
578     String name = database.stringIdentifier();
579     auto* databaseSet = nameMap->get(name);
580     if (!databaseSet) {
581         ASSERT_NOT_REACHED();
582         return;
583     }
584
585     databaseSet->remove(&database);
586
587     LOG(StorageAPI, "Removed open Database %s (%p)\n", database.stringIdentifier().utf8().data(), &database);
588
589     if (!databaseSet->isEmpty())
590         return;
591
592     nameMap->remove(name);
593     delete databaseSet;
594
595     if (!nameMap->isEmpty())
596         return;
597
598     m_openDatabaseMap->remove(database.securityOrigin());
599     delete nameMap;
600 }
601
602 RefPtr<OriginLock> DatabaseTracker::originLockFor(const SecurityOriginData& origin)
603 {
604     LockHolder lockDatabase(m_databaseGuard);
605     String databaseIdentifier = origin.databaseIdentifier();
606
607     // The originLockMap is accessed from multiple DatabaseThreads since
608     // different script contexts can be writing to different databases from
609     // the same origin. Hence, the databaseIdentifier key needs to be an
610     // isolated copy. An isolated copy gives us a value whose refCounting is
611     // thread-safe, since our copy is guarded by the m_databaseGuard mutex.
612     databaseIdentifier = databaseIdentifier.isolatedCopy();
613
614     OriginLockMap::AddResult addResult =
615         m_originLockMap.add(databaseIdentifier, RefPtr<OriginLock>());
616     if (!addResult.isNewEntry)
617         return addResult.iterator->value;
618
619     String path = originPath(origin);
620     RefPtr<OriginLock> lock = adoptRef(*new OriginLock(path));
621     ASSERT(lock);
622     addResult.iterator->value = lock;
623
624     return lock;
625 }
626
627 void DatabaseTracker::deleteOriginLockFor(const SecurityOriginData& origin)
628 {
629     ASSERT(!m_databaseGuard.tryLock());
630
631     // There is not always an instance of an OriginLock associated with an origin.
632     // For example, if the OriginLock lock file was created by a previous run of
633     // the browser which has now terminated, and the current browser process
634     // has not executed any database transactions from this origin that would
635     // have created the OriginLock instance in memory. In this case, we will have
636     // a lock file but not an OriginLock instance in memory.
637
638     // This function is only called if we are already deleting all the database
639     // files in this origin. We'll give the OriginLock one chance to do an
640     // orderly clean up first when we remove its ref from the m_originLockMap.
641     // This may or may not be possible depending on whether other threads are
642     // also using the OriginLock at the same time. After that, we will delete the lock file.
643
644     m_originLockMap.remove(origin.databaseIdentifier());
645     OriginLock::deleteLockFile(originPath(origin));
646 }
647
648 unsigned long long DatabaseTracker::usage(const SecurityOriginData& origin)
649 {
650     String originPath = this->originPath(origin);
651     unsigned long long diskUsage = 0;
652     for (auto& fileName : FileSystem::listDirectory(originPath, ASCIILiteral("*.db"))) {
653         long long size;
654         FileSystem::getFileSize(fileName, size);
655         diskUsage += size;
656     }
657     return diskUsage;
658 }
659
660 unsigned long long DatabaseTracker::quotaNoLock(const SecurityOriginData& origin)
661 {
662     ASSERT(!m_databaseGuard.tryLock());
663     unsigned long long quota = 0;
664
665     openTrackerDatabase(DontCreateIfDoesNotExist);
666     if (!m_database.isOpen())
667         return quota;
668
669     SQLiteStatement statement(m_database, "SELECT quota FROM Origins where origin=?;");
670     if (statement.prepare() != SQLITE_OK) {
671         LOG_ERROR("Failed to prepare statement.");
672         return quota;
673     }
674     statement.bindText(1, origin.databaseIdentifier());
675
676     if (statement.step() == SQLITE_ROW)
677         quota = statement.getColumnInt64(0);
678
679     return quota;
680 }
681
682 unsigned long long DatabaseTracker::quota(const SecurityOriginData& origin)
683 {
684     LockHolder lockDatabase(m_databaseGuard);
685     return quotaNoLock(origin);
686 }
687
688 void DatabaseTracker::setQuota(const SecurityOriginData& origin, unsigned long long quota)
689 {
690     LockHolder lockDatabase(m_databaseGuard);
691
692     if (quotaNoLock(origin) == quota)
693         return;
694
695     openTrackerDatabase(CreateIfDoesNotExist);
696     if (!m_database.isOpen())
697         return;
698     
699     bool insertedNewOrigin = false;
700
701     bool originEntryExists = hasEntryForOriginNoLock(origin);
702     if (!originEntryExists) {
703         SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
704         if (statement.prepare() != SQLITE_OK) {
705             LOG_ERROR("Unable to establish origin %s in the tracker", origin.databaseIdentifier().utf8().data());
706         } else {
707             statement.bindText(1, origin.databaseIdentifier());
708             statement.bindInt64(2, quota);
709
710             if (statement.step() != SQLITE_DONE)
711                 LOG_ERROR("Unable to establish origin %s in the tracker", origin.databaseIdentifier().utf8().data());
712             else
713                 insertedNewOrigin = true;
714         }
715     } else {
716         SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
717         bool error = statement.prepare() != SQLITE_OK;
718         if (!error) {
719             statement.bindInt64(1, quota);
720             statement.bindText(2, origin.databaseIdentifier());
721
722             error = !statement.executeCommand();
723         }
724
725         if (error)
726             LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin.databaseIdentifier().utf8().data());
727     }
728
729     if (m_client) {
730         if (insertedNewOrigin)
731             m_client->dispatchDidAddNewOrigin();
732         m_client->dispatchDidModifyOrigin(origin);
733     }
734 }
735
736 bool DatabaseTracker::addDatabase(const SecurityOriginData& origin, const String& name, const String& path)
737 {
738     ASSERT(!m_databaseGuard.tryLock());
739     openTrackerDatabase(CreateIfDoesNotExist);
740     if (!m_database.isOpen())
741         return false;
742
743     // New database should never be added until the origin has been established
744     ASSERT(hasEntryForOriginNoLock(origin));
745
746     SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
747
748     if (statement.prepare() != SQLITE_OK)
749         return false;
750
751     statement.bindText(1, origin.databaseIdentifier());
752     statement.bindText(2, name);
753     statement.bindText(3, path);
754
755     if (!statement.executeCommand()) {
756         LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.utf8().data(), origin.databaseIdentifier().utf8().data(), m_database.lastErrorMsg());
757         return false;
758     }
759
760     if (m_client)
761         m_client->dispatchDidModifyOrigin(origin);
762
763     return true;
764 }
765
766 void DatabaseTracker::deleteAllDatabasesImmediately()
767 {
768     // This method is only intended for use by DumpRenderTree / WebKitTestRunner.
769     // Actually deleting the databases is necessary to reset to a known state before running
770     // each test case, but may be unsafe in deployment use cases (where multiple applications
771     // may be accessing the same databases concurrently).
772     for (auto& origin : origins())
773         deleteOrigin(origin, DeletionMode::Immediate);
774 }
775
776 void DatabaseTracker::deleteDatabasesModifiedSince(std::chrono::system_clock::time_point time)
777 {
778     for (auto& origin : origins()) {
779         Vector<String> databaseNames = this->databaseNames(origin);
780         Vector<String> databaseNamesToDelete;
781         databaseNamesToDelete.reserveInitialCapacity(databaseNames.size());
782         for (const auto& databaseName : databaseNames) {
783             auto fullPath = fullPathForDatabase(origin, databaseName, false);
784
785             // If the file doesn't exist, we previously deleted it but failed to remove the information
786             // from the tracker database. We want to delete all of the information associated with this
787             // database from the tracker database, so still add its name to databaseNamesToDelete.
788             if (FileSystem::fileExists(fullPath)) {
789                 time_t modificationTime;
790                 if (!FileSystem::getFileModificationTime(fullPath, modificationTime))
791                     continue;
792
793                 if (modificationTime < std::chrono::system_clock::to_time_t(time))
794                     continue;
795             }
796
797             databaseNamesToDelete.uncheckedAppend(databaseName);
798         }
799
800         if (databaseNames.size() == databaseNamesToDelete.size())
801             deleteOrigin(origin);
802         else {
803             for (const auto& databaseName : databaseNamesToDelete)
804                 deleteDatabase(origin, databaseName);
805         }
806     }
807 }
808
809 // It is the caller's responsibility to make sure that nobody is trying to create, delete, open, or close databases in this origin while the deletion is
810 // taking place.
811 bool DatabaseTracker::deleteOrigin(const SecurityOriginData& origin)
812 {
813     return deleteOrigin(origin, DeletionMode::Default);
814 }
815
816 bool DatabaseTracker::deleteOrigin(const SecurityOriginData& origin, DeletionMode deletionMode)
817 {
818     Vector<String> databaseNames;
819     {
820         LockHolder lockDatabase(m_databaseGuard);
821         openTrackerDatabase(DontCreateIfDoesNotExist);
822         if (!m_database.isOpen())
823             return false;
824
825         databaseNames = databaseNamesNoLock(origin);
826         if (databaseNames.isEmpty())
827             LOG_ERROR("Unable to retrieve list of database names for origin %s", origin.databaseIdentifier().utf8().data());
828
829         if (!canDeleteOrigin(origin)) {
830             LOG_ERROR("Tried to delete an origin (%s) while either creating database in it or already deleting it", origin.databaseIdentifier().utf8().data());
831             ASSERT_NOT_REACHED();
832             return false;
833         }
834         recordDeletingOrigin(origin);
835     }
836
837     // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
838     bool failedToDeleteAnyDatabaseFile = false;
839     for (auto& name : databaseNames) {
840         if (FileSystem::fileExists(fullPathForDatabase(origin, name, false)) && !deleteDatabaseFile(origin, name, deletionMode)) {
841             // Even if the file can't be deleted, we want to try and delete the rest, don't return early here.
842             LOG_ERROR("Unable to delete file for database %s in origin %s", name.utf8().data(), origin.databaseIdentifier().utf8().data());
843             failedToDeleteAnyDatabaseFile = true;
844         }
845     }
846
847     // If databaseNames is empty, delete everything in the directory containing the databases for this origin.
848     // This condition indicates that we previously tried to remove the origin but didn't get all of the way
849     // through the deletion process. Because we have lost track of the databases for this origin,
850     // we can assume that no other process is accessing them. This means it should be safe to delete them outright.
851     if (databaseNames.isEmpty()) {
852 #if PLATFORM(COCOA)
853         RELEASE_LOG_ERROR(DatabaseTracker, "Unable to retrieve list of database names for origin");
854 #endif
855         for (const auto& file : FileSystem::listDirectory(originPath(origin), "*")) {
856             if (!FileSystem::deleteFile(file))
857                 failedToDeleteAnyDatabaseFile = true;
858         }
859     }
860
861     // If we failed to delete any database file, don't remove the origin from the tracker
862     // database because we didn't successfully remove all of its data.
863     if (failedToDeleteAnyDatabaseFile) {
864 #if PLATFORM(COCOA)
865         RELEASE_LOG_ERROR(DatabaseTracker, "Failed to delete database for origin");
866 #endif
867         return false;
868     }
869
870     {
871         LockHolder lockDatabase(m_databaseGuard);
872         deleteOriginLockFor(origin);
873         doneDeletingOrigin(origin);
874
875         SQLiteTransaction transaction(m_database);
876         transaction.begin();
877
878         SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
879         if (statement.prepare() != SQLITE_OK) {
880             LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin.databaseIdentifier().utf8().data());
881             return false;
882         }
883
884         statement.bindText(1, origin.databaseIdentifier());
885
886         if (!statement.executeCommand()) {
887             LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin.databaseIdentifier().utf8().data());
888             return false;
889         }
890
891         SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
892         if (originStatement.prepare() != SQLITE_OK) {
893             LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin.databaseIdentifier().utf8().data());
894             return false;
895         }
896
897         originStatement.bindText(1, origin.databaseIdentifier());
898
899         if (!originStatement.executeCommand()) {
900             LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin.databaseIdentifier().utf8().data());
901             return false;
902         }
903
904         transaction.commit();
905
906         SQLiteFileSystem::deleteEmptyDatabaseDirectory(originPath(origin));
907
908         bool isEmpty = true;
909
910         openTrackerDatabase(DontCreateIfDoesNotExist);
911         if (m_database.isOpen()) {
912             SQLiteStatement statement(m_database, "SELECT origin FROM Origins");
913             if (statement.prepare() != SQLITE_OK)
914                 LOG_ERROR("Failed to prepare statement.");
915             else if (statement.step() == SQLITE_ROW)
916                 isEmpty = false;
917         }
918
919         // If we removed the last origin, do some additional deletion.
920         if (isEmpty) {
921             if (m_database.isOpen())
922                 m_database.close();
923            SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath());
924            SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectoryPath);
925         }
926
927         if (m_client) {
928             m_client->dispatchDidModifyOrigin(origin);
929             m_client->dispatchDidDeleteDatabaseOrigin();
930             for (auto& name : databaseNames)
931                 m_client->dispatchDidModifyDatabase(origin, name);
932         }
933     }
934     return true;
935 }
936
937 bool DatabaseTracker::isDeletingDatabaseOrOriginFor(const SecurityOriginData& origin, const String& name)
938 {
939     ASSERT(!m_databaseGuard.tryLock());
940     // Can't create a database while someone else is deleting it; there's a risk of leaving untracked database debris on the disk.
941     return isDeletingDatabase(origin, name) || isDeletingOrigin(origin);
942 }
943
944 void DatabaseTracker::recordCreatingDatabase(const SecurityOriginData& origin, const String& name)
945 {
946     ASSERT(!m_databaseGuard.tryLock());
947
948     // We don't use HashMap::ensure here to avoid making an isolated copy of the origin every time.
949     auto* nameSet = m_beingCreated.get(origin);
950     if (!nameSet) {
951         auto ownedSet = std::make_unique<HashCountedSet<String>>();
952         nameSet = ownedSet.get();
953         m_beingCreated.add(origin.isolatedCopy(), WTFMove(ownedSet));
954     }
955     nameSet->add(name.isolatedCopy());
956 }
957
958 void DatabaseTracker::doneCreatingDatabase(const SecurityOriginData& origin, const String& name)
959 {
960     ASSERT(!m_databaseGuard.tryLock());
961
962     ASSERT(m_beingCreated.contains(origin));
963
964     auto iterator = m_beingCreated.find(origin);
965     if (iterator == m_beingCreated.end())
966         return;
967
968     auto& countedSet = *iterator->value;
969     ASSERT(countedSet.contains(name));
970
971     if (countedSet.remove(name) && countedSet.isEmpty())
972         m_beingCreated.remove(iterator);
973 }
974
975 bool DatabaseTracker::creatingDatabase(const SecurityOriginData& origin, const String& name)
976 {
977     ASSERT(!m_databaseGuard.tryLock());
978
979     auto iterator = m_beingCreated.find(origin);
980     return iterator != m_beingCreated.end() && iterator->value->contains(name);
981 }
982
983 bool DatabaseTracker::canDeleteDatabase(const SecurityOriginData& origin, const String& name)
984 {
985     ASSERT(!m_databaseGuard.tryLock());
986     return !creatingDatabase(origin, name) && !isDeletingDatabase(origin, name);
987 }
988
989 void DatabaseTracker::recordDeletingDatabase(const SecurityOriginData& origin, const String& name)
990 {
991     ASSERT(!m_databaseGuard.tryLock());
992     ASSERT(canDeleteDatabase(origin, name));
993
994     // We don't use HashMap::ensure here to avoid making an isolated copy of the origin every time.
995     auto* nameSet = m_beingDeleted.get(origin);
996     if (!nameSet) {
997         auto ownedSet = std::make_unique<HashSet<String>>();
998         nameSet = ownedSet.get();
999         m_beingDeleted.add(origin.isolatedCopy(), WTFMove(ownedSet));
1000     }
1001     ASSERT(!nameSet->contains(name));
1002     nameSet->add(name.isolatedCopy());
1003 }
1004
1005 void DatabaseTracker::doneDeletingDatabase(const SecurityOriginData& origin, const String& name)
1006 {
1007     ASSERT(!m_databaseGuard.tryLock());
1008     ASSERT(m_beingDeleted.contains(origin));
1009
1010     auto iterator = m_beingDeleted.find(origin);
1011     if (iterator == m_beingDeleted.end())
1012         return;
1013
1014     ASSERT(iterator->value->contains(name));
1015     iterator->value->remove(name);
1016     if (iterator->value->isEmpty())
1017         m_beingDeleted.remove(iterator);
1018 }
1019
1020 bool DatabaseTracker::isDeletingDatabase(const SecurityOriginData& origin, const String& name)
1021 {
1022     ASSERT(!m_databaseGuard.tryLock());
1023     auto* nameSet = m_beingDeleted.get(origin);
1024     return nameSet && nameSet->contains(name);
1025 }
1026
1027 bool DatabaseTracker::canDeleteOrigin(const SecurityOriginData& origin)
1028 {
1029     ASSERT(!m_databaseGuard.tryLock());
1030     return !(isDeletingOrigin(origin) || m_beingCreated.get(origin));
1031 }
1032
1033 bool DatabaseTracker::isDeletingOrigin(const SecurityOriginData& origin)
1034 {
1035     ASSERT(!m_databaseGuard.tryLock());
1036     return m_originsBeingDeleted.contains(origin);
1037 }
1038
1039 void DatabaseTracker::recordDeletingOrigin(const SecurityOriginData& origin)
1040 {
1041     ASSERT(!m_databaseGuard.tryLock());
1042     ASSERT(!isDeletingOrigin(origin));
1043     m_originsBeingDeleted.add(origin.isolatedCopy());
1044 }
1045
1046 void DatabaseTracker::doneDeletingOrigin(const SecurityOriginData& origin)
1047 {
1048     ASSERT(!m_databaseGuard.tryLock());
1049     ASSERT(isDeletingOrigin(origin));
1050     m_originsBeingDeleted.remove(origin);
1051 }
1052
1053 bool DatabaseTracker::deleteDatabase(const SecurityOriginData& origin, const String& name)
1054 {
1055     {
1056         LockHolder lockDatabase(m_databaseGuard);
1057         openTrackerDatabase(DontCreateIfDoesNotExist);
1058         if (!m_database.isOpen())
1059             return false;
1060
1061         if (!canDeleteDatabase(origin, name)) {
1062             ASSERT_NOT_REACHED();
1063             return false;
1064         }
1065         recordDeletingDatabase(origin, name);
1066     }
1067
1068     // We drop the lock here because holding locks during a call to deleteDatabaseFile will deadlock.
1069     if (FileSystem::fileExists(fullPathForDatabase(origin, name, false)) && !deleteDatabaseFile(origin, name, DeletionMode::Default)) {
1070         LOG_ERROR("Unable to delete file for database %s in origin %s", name.utf8().data(), origin.databaseIdentifier().utf8().data());
1071         LockHolder lockDatabase(m_databaseGuard);
1072         doneDeletingDatabase(origin, name);
1073         return false;
1074     }
1075
1076     LockHolder lockDatabase(m_databaseGuard);
1077
1078     SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?");
1079     if (statement.prepare() != SQLITE_OK) {
1080         LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.utf8().data(), origin.databaseIdentifier().utf8().data());
1081         doneDeletingDatabase(origin, name);
1082         return false;
1083     }
1084
1085     statement.bindText(1, origin.databaseIdentifier());
1086     statement.bindText(2, name);
1087
1088     if (!statement.executeCommand()) {
1089         LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.utf8().data(), origin.databaseIdentifier().utf8().data());
1090         doneDeletingDatabase(origin, name);
1091         return false;
1092     }
1093
1094     if (m_client) {
1095         m_client->dispatchDidModifyOrigin(origin);
1096         m_client->dispatchDidModifyDatabase(origin, name);
1097         m_client->dispatchDidDeleteDatabase();
1098     }
1099     doneDeletingDatabase(origin, name);
1100     
1101     return true;
1102 }
1103
1104 // deleteDatabaseFile has to release locks between looking up the list of databases to close and closing them.  While this is in progress, the caller
1105 // is responsible for making sure no new databases are opened in the file to be deleted.
1106 bool DatabaseTracker::deleteDatabaseFile(const SecurityOriginData& origin, const String& name, DeletionMode deletionMode)
1107 {
1108     String fullPath = fullPathForDatabase(origin, name, false);
1109     if (fullPath.isEmpty())
1110         return true;
1111
1112 #ifndef NDEBUG
1113     {
1114         LockHolder lockDatabase(m_databaseGuard);
1115         ASSERT(isDeletingDatabaseOrOriginFor(origin, name));
1116     }
1117 #endif
1118
1119     Vector<Ref<Database>> deletedDatabases;
1120
1121     // Make sure not to hold the any locks when calling
1122     // Database::markAsDeletedAndClose(), since that can cause a deadlock
1123     // during the synchronous DatabaseThread call it triggers.
1124     {
1125         LockHolder openDatabaseMapLock(m_openDatabaseMapGuard);
1126         if (m_openDatabaseMap) {
1127             if (auto* nameMap = m_openDatabaseMap->get(origin)) {
1128                 if (auto* databaseSet = nameMap->get(name)) {
1129                     for (auto& database : *databaseSet)
1130                         deletedDatabases.append(*database);
1131                 }
1132             }
1133         }
1134     }
1135
1136     for (auto& database : deletedDatabases)
1137         database->markAsDeletedAndClose();
1138
1139 #if PLATFORM(IOS)
1140     if (deletionMode == DeletionMode::Deferred) {
1141         // Other background processes may still be accessing this database. Deleting the database directly
1142         // would nuke the POSIX file locks, potentially causing Safari/WebApp to corrupt the new db if it's running in the background.
1143         // We'll instead truncate the database file to 0 bytes. If another process is operating on this same database file after
1144         // the truncation, it should get an error since the database file is no longer valid. When Safari is launched
1145         // next time, it'll go through the database files and clean up any zero-bytes ones.
1146         SQLiteDatabase database;
1147         if (!database.open(fullPath))
1148             return false;
1149         return SQLiteFileSystem::truncateDatabaseFile(database.sqlite3Handle());
1150     }
1151 #else
1152     UNUSED_PARAM(deletionMode);
1153 #endif
1154
1155     return SQLiteFileSystem::deleteDatabaseFile(fullPath);
1156 }
1157     
1158 #if PLATFORM(IOS)
1159
1160 void DatabaseTracker::removeDeletedOpenedDatabases()
1161 {
1162     // This is called when another app has deleted a database.  Go through all opened databases in this
1163     // tracker and close any that's no longer being tracked in the database.
1164     
1165     {
1166         // Acquire the lock before calling openTrackerDatabase.
1167         LockHolder lockDatabase(m_databaseGuard);
1168         openTrackerDatabase(DontCreateIfDoesNotExist);
1169     }
1170
1171     if (!m_database.isOpen())
1172         return;
1173     
1174     // Keep track of which opened databases have been deleted.
1175     Vector<RefPtr<Database>> deletedDatabases;
1176     Vector<std::pair<SecurityOriginData, Vector<String>>> deletedDatabaseNames;
1177
1178     // Make sure not to hold the m_openDatabaseMapGuard mutex when calling
1179     // Database::markAsDeletedAndClose(), since that can cause a deadlock
1180     // during the synchronous DatabaseThread call it triggers.
1181     {
1182         LockHolder openDatabaseMapLock(m_openDatabaseMapGuard);
1183         if (m_openDatabaseMap) {
1184             for (auto& openDatabase : *m_openDatabaseMap) {
1185                 auto& origin = openDatabase.key;
1186                 DatabaseNameMap* databaseNameMap = openDatabase.value;
1187                 Vector<String> deletedDatabaseNamesForThisOrigin;
1188
1189                 // Loop through all opened databases in this origin.  Get the current database file path of each database and see if
1190                 // it still matches the path stored in the opened database object.
1191                 for (auto& databases : *databaseNameMap) {
1192                     String databaseName = databases.key;
1193                     String databaseFileName;
1194                     SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
1195                     if (statement.prepare() == SQLITE_OK) {
1196                         statement.bindText(1, origin.databaseIdentifier());
1197                         statement.bindText(2, databaseName);
1198                         if (statement.step() == SQLITE_ROW)
1199                             databaseFileName = statement.getColumnText(0);
1200                         statement.finalize();
1201                     }
1202                     
1203                     bool foundDeletedDatabase = false;
1204                     for (auto& db : *databases.value) {
1205                         // We are done if this database has already been marked as deleted.
1206                         if (db->deleted())
1207                             continue;
1208                         
1209                         // If this database has been deleted or if its database file no longer matches the current version, this database is no longer valid and it should be marked as deleted.
1210                         if (databaseFileName.isNull() || databaseFileName != FileSystem::pathGetFileName(db->fileName())) {
1211                             deletedDatabases.append(db);
1212                             foundDeletedDatabase = true;
1213                         }
1214                     }
1215                     
1216                     // If the database no longer exists, we should remember to send that information to the client later.
1217                     if (m_client && foundDeletedDatabase && databaseFileName.isNull())
1218                         deletedDatabaseNamesForThisOrigin.append(databaseName);
1219                 }
1220                 
1221                 if (!deletedDatabaseNamesForThisOrigin.isEmpty())
1222                     deletedDatabaseNames.append({ origin, WTFMove(deletedDatabaseNamesForThisOrigin) });
1223             }
1224         }
1225     }
1226     
1227     for (auto& deletedDatabase : deletedDatabases)
1228         deletedDatabase->markAsDeletedAndClose();
1229
1230     for (auto& deletedDatabase : deletedDatabaseNames) {
1231         auto& origin = deletedDatabase.first;
1232         m_client->dispatchDidModifyOrigin(origin);
1233         for (auto& databaseName : deletedDatabase.second)
1234             m_client->dispatchDidModifyDatabase(origin, databaseName);
1235     }
1236 }
1237     
1238 static bool isZeroByteFile(const String& path)
1239 {
1240     long long size = 0;
1241     return FileSystem::getFileSize(path, size) && !size;
1242 }
1243     
1244 bool DatabaseTracker::deleteDatabaseFileIfEmpty(const String& path)
1245 {
1246     if (!isZeroByteFile(path))
1247         return false;
1248     
1249     SQLiteDatabase database;
1250     if (!database.open(path))
1251         return false;
1252     
1253     // Specify that we want the exclusive locking mode, so after the next write,
1254     // we'll be holding the lock to this database file.
1255     SQLiteStatement lockStatement(database, "PRAGMA locking_mode=EXCLUSIVE;");
1256     if (lockStatement.prepare() != SQLITE_OK)
1257         return false;
1258     int result = lockStatement.step();
1259     if (result != SQLITE_ROW && result != SQLITE_DONE)
1260         return false;
1261     lockStatement.finalize();
1262
1263     if (!database.executeCommand("BEGIN EXCLUSIVE TRANSACTION;"))
1264         return false;
1265
1266     // At this point, we hold the exclusive lock to this file.
1267     // Check that the database doesn't contain any tables.
1268     if (!database.executeCommand("SELECT name FROM sqlite_master WHERE type='table';"))
1269         return false;
1270
1271     database.executeCommand("COMMIT TRANSACTION;");
1272
1273     database.close();
1274
1275     return SQLiteFileSystem::deleteDatabaseFile(path);
1276 }
1277
1278 static StaticLock openDatabaseLock;
1279 StaticLock& DatabaseTracker::openDatabaseMutex()
1280 {
1281     return openDatabaseLock;
1282 }
1283
1284 void DatabaseTracker::emptyDatabaseFilesRemovalTaskWillBeScheduled()
1285 {
1286     // Lock the database from opening any database until we are done with scanning the file system for
1287     // zero byte database files to remove.
1288     openDatabaseLock.lock();
1289 }
1290
1291 void DatabaseTracker::emptyDatabaseFilesRemovalTaskDidFinish()
1292 {
1293     openDatabaseLock.unlock();
1294 }
1295
1296 #endif
1297
1298 void DatabaseTracker::setClient(DatabaseManagerClient* client)
1299 {
1300     m_client = client;
1301 }
1302
1303 static StaticLock notificationLock;
1304
1305 using NotificationQueue = Vector<std::pair<SecurityOriginData, String>>;
1306
1307 static NotificationQueue& notificationQueue()
1308 {
1309     static NeverDestroyed<NotificationQueue> queue;
1310     return queue;
1311 }
1312
1313 void DatabaseTracker::scheduleNotifyDatabaseChanged(const SecurityOriginData& origin, const String& name)
1314 {
1315     auto locker = holdLock(notificationLock);
1316     notificationQueue().append(std::make_pair(origin.isolatedCopy(), name.isolatedCopy()));
1317     scheduleForNotification();
1318 }
1319
1320 static bool notificationScheduled = false;
1321
1322 void DatabaseTracker::scheduleForNotification()
1323 {
1324     ASSERT(!notificationLock.tryLock());
1325
1326     if (!notificationScheduled) {
1327         callOnMainThread([] {
1328             notifyDatabasesChanged();
1329         });
1330         notificationScheduled = true;
1331     }
1332 }
1333
1334 void DatabaseTracker::notifyDatabasesChanged()
1335 {
1336     // Note that if DatabaseTracker ever becomes non-singleton, we'll have to amend this notification
1337     // mechanism to include which tracker the notification goes out on as well.
1338     auto& tracker = DatabaseTracker::singleton();
1339
1340     NotificationQueue notifications;
1341     {
1342         auto locker = holdLock(notificationLock);
1343         notifications.swap(notificationQueue());
1344         notificationScheduled = false;
1345     }
1346
1347     if (!tracker.m_client)
1348         return;
1349
1350     for (auto& notification : notifications)
1351         tracker.m_client->dispatchDidModifyDatabase(notification.first, notification.second);
1352 }
1353
1354
1355 } // namespace WebCore