nsresult CacheStorageService::DoomStorageEntries(nsCSubstring const& aContextKey, bool aDiskStorage, nsICacheEntryDoomCallback* aCallback) { mLock.AssertCurrentThreadOwns(); NS_ENSURE_TRUE(!mShutdown, NS_ERROR_NOT_INITIALIZED); nsAutoCString memoryStorageID(aContextKey); AppendMemoryStorageID(memoryStorageID); nsAutoPtr<CacheEntryTable> entries; if (aDiskStorage) { LOG((" dooming disk+memory storage of %s", aContextKey.BeginReading())); // Grab all entries in this storage sGlobalEntryTables->RemoveAndForget(aContextKey, entries); // Just remove the memory-only records table sGlobalEntryTables->Remove(memoryStorageID); } else { LOG((" dooming memory-only storage of %s", aContextKey.BeginReading())); // Grab the memory-only records table, EvictionRunnable will safely remove // entries one by one from the master hashtable on the background management // thread. Code at AddStorageEntry ensures a new entry will always replace // memory only entries that EvictionRunnable yet didn't manage to remove. sGlobalEntryTables->RemoveAndForget(memoryStorageID, entries); } nsRefPtr<EvictionRunnable> evict = new EvictionRunnable( aContextKey, entries.forget(), aDiskStorage, aCallback); return Dispatch(evict); }
void CacheStorageService::RemoveEntry(CacheEntry* aEntry) { LOG(("CacheStorageService::RemoveEntry [entry=%p]", aEntry)); nsAutoCString entryKey; nsresult rv = aEntry->HashingKey(entryKey); if (NS_FAILED(rv)) { NS_ERROR("aEntry->HashingKey() failed?"); return; } mozilla::MutexAutoLock lock(mLock); if (mShutdown) { LOG((" after shutdown")); return; } CacheEntryTable* entries; if (sGlobalEntryTables->Get(aEntry->GetStorageID(), &entries)) RemoveExactEntry(entries, entryKey, aEntry, false /* don't overwrite */); nsAutoCString memoryStorageID(aEntry->GetStorageID()); AppendMemoryStorageID(memoryStorageID); if (sGlobalEntryTables->Get(memoryStorageID, &entries)) RemoveExactEntry(entries, entryKey, aEntry, false /* don't overwrite */); }
void CacheStorageService::RecordMemoryOnlyEntry(CacheEntry* aEntry, bool aOnlyInMemory, bool aOverwrite) { LOG(("CacheStorageService::RecordMemoryOnlyEntry [entry=%p, memory=%d, overwrite=%d]", aEntry, aOnlyInMemory, aOverwrite)); // This method is responsible to put this entry to a special record hashtable // that contains only entries that are stored in memory. // Keep in mind that every entry, regardless of whether is in-memory-only or not // is always recorded in the storage master hash table, the one identified by // CacheEntry.StorageID(). mLock.AssertCurrentThreadOwns(); if (mShutdown) { LOG((" after shutdown")); return; } nsresult rv; nsAutoCString entryKey; rv = aEntry->HashingKey(entryKey); if (NS_FAILED(rv)) { NS_ERROR("aEntry->HashingKey() failed?"); return; } CacheEntryTable* entries = nullptr; nsAutoCString memoryStorageID(aEntry->GetStorageID()); AppendMemoryStorageID(memoryStorageID); if (!sGlobalEntryTables->Get(memoryStorageID, &entries)) { if (!aOnlyInMemory) { LOG((" not recorded as memory only")); return; } entries = new CacheEntryTable(CacheEntryTable::MEMORY_ONLY); sGlobalEntryTables->Put(memoryStorageID, entries); LOG((" new memory-only storage table for %s", memoryStorageID.get())); } if (aOnlyInMemory) { AddExactEntry(entries, entryKey, aEntry, aOverwrite); } else { RemoveExactEntry(entries, entryKey, aEntry, aOverwrite); } }
nsresult CacheStorageService::DoomStorageEntries(nsCSubstring const& aContextKey, nsILoadContextInfo* aContext, bool aDiskStorage, nsICacheEntryDoomCallback* aCallback) { mLock.AssertCurrentThreadOwns(); NS_ENSURE_TRUE(!mShutdown, NS_ERROR_NOT_INITIALIZED); nsAutoCString memoryStorageID(aContextKey); AppendMemoryStorageID(memoryStorageID); if (aDiskStorage) { LOG((" dooming disk+memory storage of %s", aContextKey.BeginReading())); // Just remove all entries, CacheFileIOManager will take care of the files. sGlobalEntryTables->Remove(aContextKey); sGlobalEntryTables->Remove(memoryStorageID); if (aContext && !aContext->IsPrivate()) { LOG((" dooming disk entries")); CacheFileIOManager::EvictByContext(aContext); } } else { LOG((" dooming memory-only storage of %s", aContextKey.BeginReading())); class MemoryEntriesRemoval { public: static PLDHashOperator EvictEntry(const nsACString& aKey, CacheEntry* aEntry, void* aClosure) { CacheEntryTable* entries = static_cast<CacheEntryTable*>(aClosure); nsCString key(aKey); RemoveExactEntry(entries, key, aEntry, false); return PL_DHASH_NEXT; } }; // Remove the memory entries table from the global tables. // Since we store memory entries also in the disk entries table // we need to remove the memory entries from the disk table one // by one manually. nsAutoPtr<CacheEntryTable> memoryEntries; sGlobalEntryTables->RemoveAndForget(memoryStorageID, memoryEntries); CacheEntryTable* entries; sGlobalEntryTables->Get(aContextKey, &entries); if (memoryEntries && entries) memoryEntries->EnumerateRead(&MemoryEntriesRemoval::EvictEntry, entries); } // An artificial callback. This is a candidate for removal tho. In the new // cache any 'doom' or 'evict' function ensures that the entry or entries // being doomed is/are not accessible after the function returns. So there is // probably no need for a callback - has no meaning. But for compatibility // with the old cache that is still in the tree we keep the API similar to be // able to make tests as well as other consumers work for now. class Callback : public nsRunnable { public: Callback(nsICacheEntryDoomCallback* aCallback) : mCallback(aCallback) { } NS_IMETHODIMP Run() { mCallback->OnCacheEntryDoomed(NS_OK); return NS_OK; } nsCOMPtr<nsICacheEntryDoomCallback> mCallback; }; if (aCallback) { nsRefPtr<nsRunnable> callback = new Callback(aCallback); return NS_DispatchToCurrentThread(callback); } return NS_OK; }
nsresult CacheStorageService::AddStorageEntry(nsCSubstring const& aContextKey, nsIURI* aURI, const nsACString & aIdExtension, bool aWriteToDisk, bool aCreateIfNotExist, bool aReplace, CacheEntry** aResult) { NS_ENSURE_ARG(aURI); nsresult rv; nsAutoCString entryKey; rv = CacheEntry::HashingKey(EmptyCString(), aIdExtension, aURI, entryKey); NS_ENSURE_SUCCESS(rv, rv); LOG(("CacheStorageService::AddStorageEntry [entryKey=%s, contextKey=%s]", entryKey.get(), aContextKey.BeginReading())); nsRefPtr<CacheEntry> entry; { mozilla::MutexAutoLock lock(mLock); NS_ENSURE_FALSE(mShutdown, NS_ERROR_NOT_INITIALIZED); // Ensure storage table CacheEntryTable* entries; if (!sGlobalEntryTables->Get(aContextKey, &entries)) { entries = new CacheEntryTable(); sGlobalEntryTables->Put(aContextKey, entries); LOG((" new storage entries table for context %s", aContextKey.BeginReading())); } bool entryExists = entries->Get(entryKey, getter_AddRefs(entry)); // Check entry that is memory-only is also in related memory-only hashtable. // If not, it has been evicted and we will truncate it ; doom is pending for it, // this consumer just made it sooner then the entry has actually been removed // from the master hash table. // (This can be bypassed when entry is about to be replaced anyway.) if (entryExists && !entry->UsingDisk() && !aReplace) { nsAutoCString memoryStorageID(aContextKey); AppendMemoryStorageID(memoryStorageID); CacheEntryTable* memoryEntries; aReplace = sGlobalEntryTables->Get(memoryStorageID, &memoryEntries) && memoryEntries->GetWeak(entryKey) != entry; #ifdef MOZ_LOGGING if (aReplace) { LOG((" memory-only entry %p for %s already doomed, replacing", entry.get(), entryKey.get())); } #endif } // If truncate is demanded, delete and doom the current entry if (entryExists && aReplace) { entries->Remove(entryKey); LOG((" dooming entry %p for %s because of OPEN_TRUNCATE", entry.get(), entryKey.get())); // On purpose called under the lock to prevent races of doom and open on I/O thread entry->DoomAlreadyRemoved(); entry = nullptr; entryExists = false; } if (entryExists && entry->SetUsingDisk(aWriteToDisk)) { RecordMemoryOnlyEntry(entry, !aWriteToDisk, true /* overwrite */); } // Ensure entry for the particular URL, if not read/only if (!entryExists && (aCreateIfNotExist || aReplace)) { // Entry is not in the hashtable or has just been truncated... entry = new CacheEntry(aContextKey, aURI, aIdExtension, aWriteToDisk); entries->Put(entryKey, entry); LOG((" new entry %p for %s", entry.get(), entryKey.get())); } } entry.forget(aResult); return NS_OK; }