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