📄 databasetracker.cpp
字号:
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(){ DEFINE_STATIC_LOCAL(Mutex, mutex, ()); return mutex;}typedef Vector<pair<SecurityOrigin*, String> > NotificationQueue;static NotificationQueue& notificationQueue(){ DEFINE_STATIC_LOCAL(NotificationQueue, 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()); NotificationQueue 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -