summaryrefslogtreecommitdiffstats
path: root/WebCore/storage/DatabaseTracker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/storage/DatabaseTracker.cpp')
-rw-r--r--WebCore/storage/DatabaseTracker.cpp827
1 files changed, 0 insertions, 827 deletions
diff --git a/WebCore/storage/DatabaseTracker.cpp b/WebCore/storage/DatabaseTracker.cpp
deleted file mode 100644
index 9a78dc8..0000000
--- a/WebCore/storage/DatabaseTracker.cpp
+++ /dev/null
@@ -1,827 +0,0 @@
-/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "DatabaseTracker.h"
-
-#include "ChromeClient.h"
-#include "Database.h"
-#include "DatabaseTrackerClient.h"
-#include "Document.h"
-#include "FileSystem.h"
-#include "Logging.h"
-#include "OriginQuotaManager.h"
-#include "Page.h"
-#include "SecurityOrigin.h"
-#include "SecurityOriginHash.h"
-#include "SQLiteStatement.h"
-#include <wtf/MainThread.h>
-
-using namespace std;
-
-namespace WebCore {
-
-OriginQuotaManager& DatabaseTracker::originQuotaManager()
-{
- populateOrigins();
- ASSERT(m_quotaManager);
- return *m_quotaManager;
-}
-
-DatabaseTracker& DatabaseTracker::tracker()
-{
- static DatabaseTracker tracker;
- return tracker;
-}
-
-DatabaseTracker::DatabaseTracker()
- : m_client(0)
- , m_proposedDatabase(0)
-#ifndef NDEBUG
- , m_thread(currentThread())
-#endif
-{
-}
-
-void DatabaseTracker::setDatabaseDirectoryPath(const String& path)
-{
- ASSERT(currentThread() == m_thread);
- ASSERT(!m_database.isOpen());
- m_databaseDirectoryPath = path;
-}
-
-const String& DatabaseTracker::databaseDirectoryPath() const
-{
- ASSERT(currentThread() == m_thread);
- return m_databaseDirectoryPath;
-}
-
-String DatabaseTracker::trackerDatabasePath() const
-{
- ASSERT(currentThread() == m_thread);
- if (m_databaseDirectoryPath.isEmpty())
- return String();
- return pathByAppendingComponent(m_databaseDirectoryPath, "Databases.db");
-}
-
-void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist)
-{
- ASSERT(currentThread() == m_thread);
-
- if (m_database.isOpen())
- return;
-
- String databasePath = trackerDatabasePath();
- if (databasePath.isEmpty())
- return;
-
- if (!createIfDoesNotExist && !fileExists(databasePath))
- return;
-
- makeAllDirectories(m_databaseDirectoryPath);
- if (!m_database.open(databasePath)) {
- // FIXME: What do do here?
- return;
- }
- if (!m_database.tableExists("Origins")) {
- if (!m_database.executeCommand("CREATE TABLE Origins (origin TEXT UNIQUE ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);")) {
- // FIXME: and here
- }
- }
- if (!m_database.tableExists("Databases")) {
- if (!m_database.executeCommand("CREATE TABLE Databases (guid INTEGER PRIMARY KEY AUTOINCREMENT, origin TEXT, name TEXT, displayName TEXT, estimatedSize INTEGER, path TEXT);")) {
- // FIXME: and here
- }
- }
-}
-
-bool DatabaseTracker::canEstablishDatabase(Document* document, const String& name, const String& displayName, unsigned long estimatedSize)
-{
- ASSERT(currentThread() == m_thread);
-
- // Populate the origins before we establish a database; this guarantees that quotaForOrigin
- // can run on the database thread later.
- populateOrigins();
-
- SecurityOrigin* origin = document->securityOrigin();
-
- // Since we're imminently opening a database within this Document's origin, make sure this origin is being tracked by the QuotaTracker
- // by fetching it's current usage now
- unsigned long long usage = usageForOrigin(origin);
-
- // If a database already exists, ignore the passed-in estimated size and say it's OK.
- if (hasEntryForDatabase(origin, name))
- return true;
-
- // If the database will fit, allow its creation.
- unsigned long long requirement = usage + max(1UL, estimatedSize);
- if (requirement < usage)
- return false; // If the estimated size is so big it causes an overflow, don't allow creation.
- if (requirement <= quotaForOrigin(origin))
- return true;
-
- // Give the chrome client a chance to increase the quota.
- // Temporarily make the details of the proposed database available, so the client can get at them.
- Page* page = document->page();
- if (!page)
- return false;
- pair<SecurityOrigin*, DatabaseDetails> details(origin, DatabaseDetails(name, displayName, estimatedSize, 0));
- m_proposedDatabase = &details;
- page->chrome()->client()->exceededDatabaseQuota(document->frame(), name);
- m_proposedDatabase = 0;
-
- // If the database will fit now, allow its creation.
- return requirement <= quotaForOrigin(origin);
-}
-
-bool DatabaseTracker::hasEntryForOrigin(SecurityOrigin* origin)
-{
- ASSERT(currentThread() == m_thread);
- populateOrigins();
- MutexLocker lockQuotaMap(m_quotaMapGuard);
- return m_quotaMap->contains(origin);
-}
-
-bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String& databaseIdentifier)
-{
- ASSERT(currentThread() == m_thread);
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return false;
- SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?;");
-
- if (statement.prepare() != SQLResultOk)
- return false;
-
- statement.bindText(1, origin->databaseIdentifier());
- statement.bindText(2, databaseIdentifier);
-
- return statement.step() == SQLResultRow;
-}
-
-String DatabaseTracker::originPath(SecurityOrigin* origin) const
-{
- ASSERT(currentThread() == m_thread);
- if (m_databaseDirectoryPath.isEmpty())
- return String();
- return pathByAppendingComponent(m_databaseDirectoryPath, origin->databaseIdentifier());
-}
-
-String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfNotExists)
-{
- ASSERT(currentThread() == m_thread);
-
- if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name)
- return String();
-
- String originIdentifier = origin->databaseIdentifier();
- String originPath = this->originPath(origin);
-
- // Make sure the path for this SecurityOrigin exists
- if (createIfNotExists && !makeAllDirectories(originPath))
- return String();
-
- // See if we have a path for this database yet
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return String();
- SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
-
- if (statement.prepare() != SQLResultOk)
- return String();
-
- statement.bindText(1, originIdentifier);
- statement.bindText(2, name);
-
- int result = statement.step();
-
- if (result == SQLResultRow)
- return pathByAppendingComponent(originPath, statement.getColumnText(0));
- if (!createIfNotExists)
- return String();
-
- if (result != SQLResultDone) {
- LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", origin->databaseIdentifier().ascii().data(), name.ascii().data());
- return String();
- }
- statement.finalize();
-
- SQLiteStatement sequenceStatement(m_database, "SELECT seq FROM sqlite_sequence WHERE name='Databases';");
-
- // FIXME: More informative error handling here, even though these steps should never fail
- if (sequenceStatement.prepare() != SQLResultOk)
- return String();
- result = sequenceStatement.step();
-
- // This has a range of 2^63 and starts at 0 for every time a user resets Safari -
- // I can't imagine it'd over overflow
- int64_t seq = 0;
- if (result == SQLResultRow) {
- seq = sequenceStatement.getColumnInt64(0);
- } else if (result != SQLResultDone)
- return String();
- sequenceStatement.finalize();
-
- String filename;
- do {
- ++seq;
- filename = pathByAppendingComponent(originPath, String::format("%016llx.db", seq));
- } while (fileExists(filename));
-
- if (!addDatabase(origin, name, String::format("%016llx.db", seq)))
- return String();
-
- // If this origin's quota is being tracked (open handle to a database in this origin), add this new database
- // to the quota manager now
- {
- Locker<OriginQuotaManager> locker(originQuotaManager());
- if (originQuotaManager().tracksOrigin(origin))
- originQuotaManager().addDatabase(origin, name, filename);
- }
-
- return filename;
-}
-
-void DatabaseTracker::populateOrigins()
-{
- if (m_quotaMap)
- return;
-
- ASSERT(currentThread() == m_thread);
-
- m_quotaMap.set(new QuotaMap);
- m_quotaManager.set(new OriginQuotaManager);
-
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return;
-
- SQLiteStatement statement(m_database, "SELECT origin, quota FROM Origins");
-
- if (statement.prepare() != SQLResultOk)
- return;
-
- int result;
- while ((result = statement.step()) == SQLResultRow) {
- RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromDatabaseIdentifier(statement.getColumnText(0));
- m_quotaMap->set(origin.get(), statement.getColumnInt64(1));
- }
-
- if (result != SQLResultDone)
- LOG_ERROR("Failed to read in all origins from the database");
-}
-
-void DatabaseTracker::origins(Vector<RefPtr<SecurityOrigin> >& result)
-{
- ASSERT(currentThread() == m_thread);
- populateOrigins();
- MutexLocker lockQuotaMap(m_quotaMapGuard);
- copyKeysToVector(*m_quotaMap, result);
-}
-
-bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<String>& resultVector)
-{
- ASSERT(currentThread() == m_thread);
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return false;
-
- SQLiteStatement statement(m_database, "SELECT name FROM Databases where origin=?;");
-
- if (statement.prepare() != SQLResultOk)
- return false;
-
- statement.bindText(1, origin->databaseIdentifier());
-
- int result;
- while ((result = statement.step()) == SQLResultRow)
- resultVector.append(statement.getColumnText(0));
-
- if (result != SQLResultDone) {
- LOG_ERROR("Failed to retrieve all database names for origin %s", origin->databaseIdentifier().ascii().data());
- return false;
- }
-
- return true;
-}
-
-DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, SecurityOrigin* origin)
-{
- ASSERT(currentThread() == m_thread);
-
- if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name)
- return m_proposedDatabase->second;
-
- String originIdentifier = origin->databaseIdentifier();
-
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return DatabaseDetails();
- SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?");
- if (statement.prepare() != SQLResultOk)
- return DatabaseDetails();
-
- statement.bindText(1, originIdentifier);
- statement.bindText(2, name);
-
- int result = statement.step();
- if (result == SQLResultDone)
- return DatabaseDetails();
-
- if (result != SQLResultRow) {
- LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.ascii().data(), originIdentifier.ascii().data());
- return DatabaseDetails();
- }
-
- return DatabaseDetails(name, statement.getColumnText(0), statement.getColumnInt64(1), usageForDatabase(name, origin));
-}
-
-void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& name, const String& displayName, unsigned long estimatedSize)
-{
- ASSERT(currentThread() == m_thread);
-
- String originIdentifier = origin->databaseIdentifier();
- int64_t guid = 0;
-
- openTrackerDatabase(true);
- if (!m_database.isOpen())
- return;
- SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?");
- if (statement.prepare() != SQLResultOk)
- return;
-
- statement.bindText(1, originIdentifier);
- statement.bindText(2, name);
-
- int result = statement.step();
- if (result == SQLResultRow)
- guid = statement.getColumnInt64(0);
- statement.finalize();
-
- if (guid == 0) {
- if (result != SQLResultDone)
- LOG_ERROR("Error to determing existence of database %s in origin %s in tracker database", name.ascii().data(), originIdentifier.ascii().data());
- else {
- // This case should never occur - we should never be setting database details for a database that doesn't already exist in the tracker
- // 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
- // So we'll print an error instead
- 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.ascii().data(), originIdentifier.ascii().data());
- }
- return;
- }
-
- SQLiteStatement updateStatement(m_database, "UPDATE Databases SET displayName=?, estimatedSize=? WHERE guid=?");
- if (updateStatement.prepare() != SQLResultOk)
- return;
-
- updateStatement.bindText(1, displayName);
- updateStatement.bindInt64(2, estimatedSize);
- updateStatement.bindInt64(3, guid);
-
- if (updateStatement.step() != SQLResultDone) {
- LOG_ERROR("Failed to update details for database %s in origin %s", name.ascii().data(), originIdentifier.ascii().data());
- return;
- }
-
- if (m_client)
- m_client->dispatchDidModifyDatabase(origin, name);
-}
-
-unsigned long long DatabaseTracker::usageForDatabase(const String& name, SecurityOrigin* origin)
-{
- ASSERT(currentThread() == m_thread);
- String path = fullPathForDatabase(origin, name, false);
- if (path.isEmpty())
- return 0;
-
- long long size;
- return getFileSize(path, size) ? size : 0;
-}
-
-void DatabaseTracker::addOpenDatabase(Database* database)
-{
- if (!database)
- return;
-
- MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
-
- if (!m_openDatabaseMap)
- m_openDatabaseMap.set(new DatabaseOriginMap);
-
- RefPtr<SecurityOrigin> origin(database->securityOriginCopy());
- String name(database->stringIdentifier());
-
- DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
- if (!nameMap) {
- nameMap = new DatabaseNameMap;
- m_openDatabaseMap->set(origin, nameMap);
- }
-
- DatabaseSet* databaseSet = nameMap->get(name);
- if (!databaseSet) {
- databaseSet = new DatabaseSet;
- nameMap->set(name, databaseSet);
- }
-
- databaseSet->add(database);
-
- LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
-}
-
-void DatabaseTracker::removeOpenDatabase(Database* database)
-{
- if (!database)
- return;
-
- MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
-
- if (!m_openDatabaseMap) {
- ASSERT_NOT_REACHED();
- return;
- }
-
- RefPtr<SecurityOrigin> origin(database->securityOriginCopy());
- String name(database->stringIdentifier());
-
- DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
- if (!nameMap) {
- ASSERT_NOT_REACHED();
- return;
- }
-
- DatabaseSet* databaseSet = nameMap->get(name);
- if (!databaseSet) {
- ASSERT_NOT_REACHED();
- return;
- }
-
- databaseSet->remove(database);
-
- LOG(StorageAPI, "Removed open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database);
-
- if (!databaseSet->isEmpty())
- return;
-
- nameMap->remove(name);
- delete databaseSet;
-
- if (!nameMap->isEmpty())
- return;
-
- m_openDatabaseMap->remove(origin);
- delete nameMap;
-}
-
-unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin)
-{
- ASSERT(currentThread() == m_thread);
- Locker<OriginQuotaManager> locker(originQuotaManager());
-
- // Use the OriginQuotaManager mechanism to calculate the usage
- if (originQuotaManager().tracksOrigin(origin))
- return originQuotaManager().diskUsage(origin);
-
- // If the OriginQuotaManager doesn't track this origin already, prime it to do so
- originQuotaManager().trackOrigin(origin);
-
- Vector<String> names;
- databaseNamesForOrigin(origin, names);
-
- for (unsigned i = 0; i < names.size(); ++i)
- originQuotaManager().addDatabase(origin, names[i], fullPathForDatabase(origin, names[i], false));
-
- if (!originQuotaManager().tracksOrigin(origin))
- return 0;
- return originQuotaManager().diskUsage(origin);
-}
-
-unsigned long long DatabaseTracker::quotaForOrigin(SecurityOrigin* origin)
-{
- ASSERT(currentThread() == m_thread || m_quotaMap);
- populateOrigins();
- MutexLocker lockQuotaMap(m_quotaMapGuard);
- return m_quotaMap->get(origin);
-}
-
-void DatabaseTracker::setQuota(SecurityOrigin* origin, unsigned long long quota)
-{
- ASSERT(currentThread() == m_thread);
- if (quotaForOrigin(origin) == quota)
- return;
-
- openTrackerDatabase(true);
- if (!m_database.isOpen())
- return;
-
- {
- MutexLocker lockQuotaMap(m_quotaMapGuard);
-
- if (!m_quotaMap->contains(origin)) {
- SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
- if (statement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
- } else {
- statement.bindText(1, origin->databaseIdentifier());
- statement.bindInt64(2, quota);
-
- if (statement.step() != SQLResultDone)
- LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
- }
- } else {
- SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
- bool error = statement.prepare() != SQLResultOk;
- if (!error) {
- statement.bindInt64(1, quota);
- statement.bindText(2, origin->databaseIdentifier());
-
- error = !statement.executeCommand();
- }
-
- if (error)
- LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data());
- }
-
- // FIXME: Is it really OK to update the quota in memory if we failed to update it on disk?
- m_quotaMap->set(origin, quota);
- }
-
- if (m_client)
- m_client->dispatchDidModifyOrigin(origin);
-}
-
-bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, const String& path)
-{
- ASSERT(currentThread() == m_thread);
- openTrackerDatabase(true);
- if (!m_database.isOpen())
- return false;
-
- // New database should never be added until the origin has been established
- ASSERT(hasEntryForOrigin(origin));
-
- SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
-
- if (statement.prepare() != SQLResultOk)
- return false;
-
- statement.bindText(1, origin->databaseIdentifier());
- statement.bindText(2, name);
- statement.bindText(3, path);
-
- if (!statement.executeCommand()) {
- LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.ascii().data(), origin->databaseIdentifier().ascii().data(), m_database.lastErrorMsg());
- return false;
- }
-
- if (m_client)
- m_client->dispatchDidModifyOrigin(origin);
-
- return true;
-}
-
-void DatabaseTracker::deleteAllDatabases()
-{
- ASSERT(currentThread() == m_thread);
-
- Vector<RefPtr<SecurityOrigin> > originsCopy;
- origins(originsCopy);
-
- for (unsigned i = 0; i < originsCopy.size(); ++i)
- deleteOrigin(originsCopy[i].get());
-}
-
-void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
-{
- ASSERT(currentThread() == m_thread);
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return;
-
- Vector<String> databaseNames;
- if (!databaseNamesForOrigin(origin, databaseNames)) {
- LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data());
- return;
- }
-
- for (unsigned i = 0; i < databaseNames.size(); ++i) {
- if (!deleteDatabaseFile(origin, databaseNames[i])) {
- LOG_ERROR("Unable to delete file for database %s in origin %s", databaseNames[i].ascii().data(), origin->databaseIdentifier().ascii().data());
- return;
- }
- }
-
- SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
- if (statement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
-
- statement.bindText(1, origin->databaseIdentifier());
-
- if (!statement.executeCommand()) {
- LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
-
- SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
- if (originStatement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
-
- originStatement.bindText(1, origin->databaseIdentifier());
-
- if (!originStatement.executeCommand()) {
- LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
- return;
- }
-
- deleteEmptyDirectory(originPath(origin));
-
- RefPtr<SecurityOrigin> originPossiblyLastReference = origin;
- {
- MutexLocker lockQuotaMap(m_quotaMapGuard);
- m_quotaMap->remove(origin);
-
- Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
- originQuotaManager().removeOrigin(origin);
-
- // If we removed the last origin, do some additional deletion.
- if (m_quotaMap->isEmpty()) {
- if (m_database.isOpen())
- m_database.close();
- deleteFile(trackerDatabasePath());
- deleteEmptyDirectory(m_databaseDirectoryPath);
- }
- }
-
- if (m_client) {
- m_client->dispatchDidModifyOrigin(origin);
- for (unsigned i = 0; i < databaseNames.size(); ++i)
- m_client->dispatchDidModifyDatabase(origin, databaseNames[i]);
- }
-}
-
-void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
-{
- ASSERT(currentThread() == m_thread);
- openTrackerDatabase(false);
- if (!m_database.isOpen())
- return;
-
- if (!deleteDatabaseFile(origin, name)) {
- LOG_ERROR("Unable to delete file for database %s in origin %s", name.ascii().data(), origin->databaseIdentifier().ascii().data());
- return;
- }
-
- SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?");
- if (statement.prepare() != SQLResultOk) {
- LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
- return;
- }
-
- statement.bindText(1, origin->databaseIdentifier());
- statement.bindText(2, name);
-
- if (!statement.executeCommand()) {
- LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
- return;
- }
-
- {
- Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
- originQuotaManager().removeDatabase(origin, name);
- }
-
- if (m_client) {
- m_client->dispatchDidModifyOrigin(origin);
- m_client->dispatchDidModifyDatabase(origin, name);
- }
-}
-
-bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& name)
-{
- ASSERT(currentThread() == m_thread);
- String fullPath = fullPathForDatabase(origin, name, false);
- if (fullPath.isEmpty())
- return true;
-
- Vector<RefPtr<Database> > deletedDatabases;
-
- // Make sure not to hold the m_openDatabaseMapGuard mutex when calling
- // Database::markAsDeletedAndClose(), since that can cause a deadlock
- // during the synchronous DatabaseThread call it triggers.
-
- {
- MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
- if (m_openDatabaseMap) {
- // There are some open databases, lets check if they are for this origin.
- DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin);
- if (nameMap && nameMap->size()) {
- // There are some open databases for this origin, lets check
- // if they are this database by name.
- DatabaseSet* databaseSet = nameMap->get(name);
- if (databaseSet && databaseSet->size()) {
- // We have some database open with this name. Mark them as deleted.
- DatabaseSet::const_iterator end = databaseSet->end();
- for (DatabaseSet::const_iterator it = databaseSet->begin(); it != end; ++it)
- deletedDatabases.append(*it);
- }
- }
- }
- }
-
- for (unsigned i = 0; i < deletedDatabases.size(); ++i)
- deletedDatabases[i]->markAsDeletedAndClose();
-
- return deleteFile(fullPath);
-}
-
-void DatabaseTracker::setClient(DatabaseTrackerClient* client)
-{
- ASSERT(currentThread() == m_thread);
- m_client = client;
-}
-
-static Mutex& notificationMutex()
-{
- static Mutex mutex;
- return mutex;
-}
-
-static Vector<pair<SecurityOrigin*, String> >& notificationQueue()
-{
- static Vector<pair<SecurityOrigin*, String> > queue;
- return queue;
-}
-
-void DatabaseTracker::scheduleNotifyDatabaseChanged(SecurityOrigin* origin, const String& name)
-{
- MutexLocker locker(notificationMutex());
-
- notificationQueue().append(pair<SecurityOrigin*, String>(origin, name.copy()));
- scheduleForNotification();
-}
-
-static bool notificationScheduled = false;
-
-void DatabaseTracker::scheduleForNotification()
-{
- ASSERT(!notificationMutex().tryLock());
-
- if (!notificationScheduled) {
- callOnMainThread(DatabaseTracker::notifyDatabasesChanged, 0);
- notificationScheduled = true;
- }
-}
-
-void DatabaseTracker::notifyDatabasesChanged(void*)
-{
- // Note that if DatabaseTracker ever becomes non-singleton, we'll have to amend this notification
- // mechanism to include which tracker the notification goes out on as well.
- DatabaseTracker& theTracker(tracker());
-
- Vector<pair<SecurityOrigin*, String> > notifications;
- {
- MutexLocker locker(notificationMutex());
-
- notifications.swap(notificationQueue());
-
- notificationScheduled = false;
- }
-
- if (!theTracker.m_client)
- return;
-
- for (unsigned i = 0; i < notifications.size(); ++i)
- theTracker.m_client->dispatchDidModifyDatabase(notifications[i].first, notifications[i].second);
-}
-
-
-} // namespace WebCore