void DatabaseTracker::removeOpenDatabase(AbstractDatabase* database) { if (!database->scriptExecutionContext()->isContextThread()) { database->scriptExecutionContext()->postTask(TrackerRemoveOpenDatabaseTask::create(database)); return; } MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); ASSERT(m_openDatabaseMap); DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()); ASSERT(nameMap); String name(database->stringIdentifier()); DatabaseSet* databaseSet = nameMap->get(name); ASSERT(databaseSet); databaseSet->remove(database); if (databaseSet->isEmpty()) { nameMap->remove(name); delete databaseSet; if (nameMap->isEmpty()) { m_openDatabaseMap->remove(database->securityOrigin()); delete nameMap; } } DatabaseObserver::databaseClosed(database); }
void DatabaseTracker::interruptAllDatabasesForContext(const DatabaseBackendContext* context) { Vector<RefPtr<DatabaseBackendBase>> openDatabases; { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) return; DatabaseNameMap* nameMap = m_openDatabaseMap->get(context->securityOrigin()); if (!nameMap) return; DatabaseNameMap::const_iterator dbNameMapEndIt = nameMap->end(); for (DatabaseNameMap::const_iterator dbNameMapIt = nameMap->begin(); dbNameMapIt != dbNameMapEndIt; ++dbNameMapIt) { DatabaseSet* databaseSet = dbNameMapIt->value; DatabaseSet::const_iterator dbSetEndIt = databaseSet->end(); for (DatabaseSet::const_iterator dbSetIt = databaseSet->begin(); dbSetIt != dbSetEndIt; ++dbSetIt) { if ((*dbSetIt)->databaseContext() == context) openDatabases.append(*dbSetIt); } } } Vector<RefPtr<DatabaseBackendBase>>::const_iterator openDatabasesEndIt = openDatabases.end(); for (Vector<RefPtr<DatabaseBackendBase>>::const_iterator openDatabasesIt = openDatabases.begin(); openDatabasesIt != openDatabasesEndIt; ++openDatabasesIt) (*openDatabasesIt)->interrupt(); }
void DatabaseTracker::removeOpenDatabase(Database* database) { { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); String originString = database->getSecurityOrigin()->toRawString(); ASSERT(m_openDatabaseMap); DatabaseNameMap* nameMap = m_openDatabaseMap->get(originString); if (!nameMap) return; String name(database->stringIdentifier()); DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) return; DatabaseSet::iterator found = databaseSet->find(database); if (found == databaseSet->end()) return; databaseSet->remove(found); if (databaseSet->isEmpty()) { nameMap->remove(name); delete databaseSet; if (nameMap->isEmpty()) { m_openDatabaseMap->remove(originString); delete nameMap; } } } databaseClosed(database); }
void DatabaseTracker::addOpenDatabase(DatabaseBackendBase* database) { if (!database) return; { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) m_openDatabaseMap = adoptPtr(new DatabaseOriginMap); String name(database->stringIdentifier()); DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()); if (!nameMap) { nameMap = new DatabaseNameMap; m_openDatabaseMap->set(database->securityOrigin()->isolatedCopy(), nameMap); } DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) { databaseSet = new DatabaseSet; nameMap->set(name.isolatedCopy(), databaseSet); } databaseSet->add(database); LOG(StorageAPI, "Added open Database %s (%p)\n", database->stringIdentifier().ascii().data(), database); } }
void DatabaseTracker::addOpenDatabase(AbstractDatabase* database) { ASSERT(database->scriptExecutionContext()->isContextThread()); MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) m_openDatabaseMap = adoptPtr(new DatabaseOriginMap); String originIdentifier = database->securityOrigin()->databaseIdentifier(); DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier); if (!nameMap) { nameMap = new DatabaseNameMap(); m_openDatabaseMap->set(originIdentifier, nameMap); } String name(database->stringIdentifier()); DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) { databaseSet = new DatabaseSet(); nameMap->set(name, databaseSet); } databaseSet->add(database); DatabaseObserver::databaseOpened(database); }
void DatabaseTracker::removeOpenDatabase(AbstractDatabase* database) { String originIdentifier = database->securityOrigin()->databaseIdentifier(); MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); ASSERT(m_openDatabaseMap); DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier); if (!nameMap) return; String name(database->stringIdentifier()); DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) return; DatabaseSet::iterator found = databaseSet->find(database); if (found == databaseSet->end()) return; databaseSet->remove(found); if (databaseSet->isEmpty()) { nameMap->remove(name); delete databaseSet; if (nameMap->isEmpty()) { m_openDatabaseMap->remove(originIdentifier); delete nameMap; } } if (!database->scriptExecutionContext()->isContextThread()) database->scriptExecutionContext()->postTask(NotifyDatabaseObserverOnCloseTask::create(database)); else DatabaseObserver::databaseClosed(database); }
// deleteDatabaseFile has to release locks between looking up the list of databases to close and closing them. While this is in progress, the caller // is responsible for making sure no new databases are opened in the file to be deleted. bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& name, DeletionMode deletionMode) { String fullPath = fullPathForDatabase(origin, name, false); if (fullPath.isEmpty()) return true; #ifndef NDEBUG { LockHolder lockDatabase(m_databaseGuard); ASSERT(isDeletingDatabaseOrOriginFor(origin, name)); } #endif Vector<RefPtr<Database>> deletedDatabases; // Make sure not to hold the any locks when calling // Database::markAsDeletedAndClose(), since that can cause a deadlock // during the synchronous DatabaseThread call it triggers. { LockHolder 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, let's 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. for (auto& database : *databaseSet) deletedDatabases.append(database); } } } } for (auto& database : deletedDatabases) database->markAsDeletedAndClose(); #if PLATFORM(IOS) if (deletionMode == DeletionMode::Deferred) { // On the phone, other background processes may still be accessing this database. Deleting the database directly // would nuke the POSIX file locks, potentially causing Safari/WebApp to corrupt the new db if it's running in the background. // We'll instead truncate the database file to 0 bytes. If another process is operating on this same database file after // the truncation, it should get an error since the database file is no longer valid. When Safari is launched // next time, it'll go through the database files and clean up any zero-bytes ones. SQLiteDatabase database; if (!database.open(fullPath)) return false; return SQLiteFileSystem::truncateDatabaseFile(database.sqlite3Handle()); } #else UNUSED_PARAM(deletionMode); #endif return SQLiteFileSystem::deleteDatabaseFile(fullPath); }
void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<AbstractDatabase> >* databases) { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) return; DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin); if (!nameMap) return; DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) return; for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it) databases->add(*it); }
void DatabaseTracker::getOpenDatabases(SecurityOrigin* origin, const String& name, HashSet<RefPtr<Database>>* databases) { LockHolder openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) return; DatabaseNameMap* nameMap = m_openDatabaseMap->get(origin); if (!nameMap) return; DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) return; for (auto& database : *databaseSet) databases->add(database); }
void DatabaseTracker::closeDatabasesImmediately(const String& originIdentifier, const String& name) { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) return; DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier); if (!nameMap) return; DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) return; // We have to call closeImmediately() on the context thread and we cannot safely add a reference to // the database in our collection when not on the context thread (which is always the case given // current usage). for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it) (*it)->scriptExecutionContext()->postTask(CloseOneDatabaseImmediatelyTask::create(originIdentifier, name, *it)); }
void DatabaseTracker::closeDatabasesImmediately(SecurityOrigin* origin, const String& name) { String originString = origin->toRawString(); MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) return; DatabaseNameMap* nameMap = m_openDatabaseMap->get(originString); if (!nameMap) return; DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) return; // We have to call closeImmediately() on the context thread. for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it) (*it)->getDatabaseContext()->getExecutionContext()->postTask(BLINK_FROM_HERE, createCrossThreadTask(&DatabaseTracker::closeOneDatabaseImmediately, crossThreadUnretained(this), originString, name, *it)); }
void DatabaseTracker::removeOpenDatabase(DatabaseBackendBase* database) { if (!database) return; { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) { ASSERT_NOT_REACHED(); return; } String name(database->stringIdentifier()); DatabaseNameMap* nameMap = m_openDatabaseMap->get(database->securityOrigin()); 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(database->securityOrigin()); delete nameMap; } }
// deleteDatabaseFile has to release locks between looking up the list of databases to close and closing them. While this is in progress, the caller // is responsible for making sure no new databases are opened in the file to be deleted. bool DatabaseTracker::deleteDatabaseFile(SecurityOrigin* origin, const String& name) { String fullPath = fullPathForDatabase(origin, name, false); if (fullPath.isEmpty()) return true; #ifndef NDEBUG { MutexLocker lockDatabase(m_databaseGuard); ASSERT(isDeletingDatabaseOrOriginFor(origin, name)); } #endif Vector<RefPtr<DatabaseBackendBase>> deletedDatabases; // Make sure not to hold the any locks 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, let's 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 SQLiteFileSystem::deleteDatabaseFile(fullPath); }
void DatabaseTracker::interruptAllDatabasesForContext(const ScriptExecutionContext* context) { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) return; DatabaseNameMap* nameMap = m_openDatabaseMap->get(context->securityOrigin()->databaseIdentifier()); if (!nameMap) return; DatabaseNameMap::const_iterator dbNameMapEndIt = nameMap->end(); for (DatabaseNameMap::const_iterator dbNameMapIt = nameMap->begin(); dbNameMapIt != dbNameMapEndIt; ++dbNameMapIt) { DatabaseSet* databaseSet = dbNameMapIt->value; DatabaseSet::const_iterator end = databaseSet->end(); for (DatabaseSet::const_iterator it = databaseSet->begin(); it != end; ++it) { if ((*it)->scriptExecutionContext() == context) (*it)->interrupt(); } } }
void DatabaseTracker::addOpenDatabase(Database* database) { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) m_openDatabaseMap = wrapUnique(new DatabaseOriginMap); String originString = database->getSecurityOrigin()->toRawString(); DatabaseNameMap* nameMap = m_openDatabaseMap->get(originString); if (!nameMap) { nameMap = new DatabaseNameMap(); m_openDatabaseMap->set(originString, nameMap); } String name(database->stringIdentifier()); DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) { databaseSet = new DatabaseSet(); nameMap->set(name, databaseSet); } databaseSet->add(database); }
void DatabaseTracker::closeOneDatabaseImmediately(const String& originIdentifier, const String& name, DatabaseBackend* database) { // First we have to confirm the 'database' is still in our collection. { MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); if (!m_openDatabaseMap) return; DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier); if (!nameMap) return; DatabaseSet* databaseSet = nameMap->get(name); if (!databaseSet) return; DatabaseSet::iterator found = databaseSet->find(database); if (found == databaseSet->end()) return; } // And we have to call closeImmediately() without our collection lock being held. database->closeImmediately(); }