Bug 1032254 - Provide a way to pin resources in the http cache r=honzab

This commit is contained in:
Valentin Gosu 2015-07-30 11:40:00 +02:00
parent 49c394e147
commit aefe552c95
27 changed files with 707 additions and 163 deletions

View File

@ -17,7 +17,7 @@ interface nsIFile;
* 3) Support for uniquely identifying cached data in cases when the URL
* is insufficient (e.g., HTTP form submission).
*/
[scriptable, uuid(436b939d-e391-48e5-ba64-ab0e496e3400)]
[scriptable, uuid(dd1d6122-5ecf-4fe4-8f0f-995e7ab3121a)]
interface nsICachingChannel : nsICacheInfoChannel
{
/**
@ -53,6 +53,11 @@ interface nsICachingChannel : nsICacheInfoChannel
*/
attribute boolean cacheOnlyMetadata;
/**
* Tells the channel to use the pinning storage.
*/
attribute boolean pin;
/**************************************************************************
* Caching channel specific load flags:
*/

View File

@ -163,7 +163,8 @@ NS_IMPL_ISUPPORTS(CacheEntry,
CacheEntry::CacheEntry(const nsACString& aStorageID,
nsIURI* aURI,
const nsACString& aEnhanceID,
bool aUseDisk)
bool aUseDisk,
uint32_t aPinningAppId)
: mFrecency(0)
, mSortingExpirationTime(uint32_t(-1))
, mLock("CacheEntry")
@ -172,6 +173,7 @@ CacheEntry::CacheEntry(const nsACString& aStorageID,
, mEnhanceID(aEnhanceID)
, mStorageID(aStorageID)
, mUseDisk(aUseDisk)
, mPinningAppId(aPinningAppId)
, mIsDoomed(false)
, mSecurityInfoLoaded(false)
, mPreventCallbacks(false)
@ -341,7 +343,8 @@ bool CacheEntry::Load(bool aTruncate, bool aPriority)
// as a new one.
// 2. When this is a memory-only entry, check there is a disk file.
// If there is or could be, doom that file.
if ((!aTruncate || !mUseDisk) && NS_SUCCEEDED(rv)) {
if ((!aTruncate || !mUseDisk) && NS_SUCCEEDED(rv) &&
!mPinningAppId) {
// Check the index right now to know we have or have not the entry
// as soon as possible.
CacheIndex::EntryStatus status;
@ -391,6 +394,7 @@ bool CacheEntry::Load(bool aTruncate, bool aPriority)
rv = mFile->Init(fileKey,
aTruncate,
!mUseDisk,
mPinningAppId,
aPriority,
directLoad ? nullptr : this);
}
@ -486,6 +490,7 @@ already_AddRefed<CacheEntryHandle> CacheEntry::ReopenTruncated(bool aMemoryOnly,
nsresult rv = CacheStorageService::Self()->AddStorageEntry(
GetStorageID(), GetURI(), GetEnhanceID(),
mUseDisk && !aMemoryOnly,
mPinningAppId,
true, // always create
true, // truncate existing (this one)
getter_AddRefs(handle));

View File

@ -55,7 +55,7 @@ public:
NS_DECL_NSIRUNNABLE
CacheEntry(const nsACString& aStorageID, nsIURI* aURI, const nsACString& aEnhanceID,
bool aUseDisk);
bool aUseDisk, uint32_t aPinningAppId);
void AsyncOpen(nsICacheEntryOpenCallback* aCallback, uint32_t aFlags);
@ -276,6 +276,9 @@ private:
// Whether it's allowed to persist the data to disk
bool const mUseDisk;
// AppId of an app that wants this entry be pinned
uint32_t const mPinningAppId;
// Set when entry is doomed with AsyncDoom() or DoomAlreadyRemoved().
// Left as a standalone flag to not bother with locking (there is no need).
bool mIsDoomed;

View File

@ -212,6 +212,7 @@ nsresult
CacheFile::Init(const nsACString &aKey,
bool aCreateNew,
bool aMemoryOnly,
uint32_t aPinningAppID,
bool aPriority,
CacheFileListener *aCallback)
{
@ -266,7 +267,7 @@ CacheFile::Init(const nsACString &aKey,
mOpeningFile = true;
mListener = aCallback;
rv = CacheFileIOManager::OpenFile(mKey, flags, this);
rv = CacheFileIOManager::OpenFile(mKey, aPinningAppID, flags, this);
if (NS_FAILED(rv)) {
mListener = nullptr;
mOpeningFile = false;

View File

@ -56,6 +56,7 @@ public:
nsresult Init(const nsACString &aKey,
bool aCreateNew,
bool aMemoryOnly,
uint32_t aPinningAppID,
bool aPriority,
CacheFileListener *aCallback);
@ -103,6 +104,10 @@ public:
void Key(nsACString& aKey) { aKey = mKey; }
bool IsDoomed();
bool IsWriteInProgress();
CacheFileIOManager* Manager()
{
return mHandle ? mHandle->Manager() : nullptr;
}
// Memory reporting
size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;

View File

@ -398,7 +398,7 @@ CacheFileContextEvictor::GetContextFile(nsILoadContextInfo *aLoadContextInfo,
leafName.AssignLiteral(CONTEXT_EVICTION_PREFIX);
nsAutoCString keyPrefix;
CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, keyPrefix);
CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, false, keyPrefix);
nsAutoCString data64;
rv = Base64Encode(keyPrefix, data64);

View File

@ -108,8 +108,9 @@ NS_INTERFACE_MAP_BEGIN(CacheFileHandle)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END_THREADSAFE
CacheFileHandle::CacheFileHandle(const SHA1Sum::Hash *aHash, bool aPriority)
: mHash(aHash)
CacheFileHandle::CacheFileHandle(CacheFileIOManager* aManager, const SHA1Sum::Hash *aHash, bool aPriority)
: mManager(aManager)
, mHash(aHash)
, mIsDoomed(false)
, mPriority(aPriority)
, mClosed(false)
@ -123,8 +124,9 @@ CacheFileHandle::CacheFileHandle(const SHA1Sum::Hash *aHash, bool aPriority)
, this, LOGSHA1(aHash)));
}
CacheFileHandle::CacheFileHandle(const nsACString &aKey, bool aPriority)
: mHash(nullptr)
CacheFileHandle::CacheFileHandle(CacheFileIOManager* aManager, const nsACString &aKey, bool aPriority)
: mManager(aManager)
, mHash(nullptr)
, mIsDoomed(false)
, mPriority(aPriority)
, mClosed(false)
@ -145,9 +147,8 @@ CacheFileHandle::~CacheFileHandle()
MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased());
nsRefPtr<CacheFileIOManager> ioMan = CacheFileIOManager::gInstance;
if (!IsClosed() && ioMan) {
ioMan->CloseHandleInternal(this);
if (!IsClosed() && mManager) {
mManager->CloseHandleInternal(this);
}
}
@ -295,7 +296,8 @@ CacheFileHandles::HandleHashKey::SizeOfExcludingThis(mozilla::MallocSizeOf mallo
* CacheFileHandles
*****************************************************************************/
CacheFileHandles::CacheFileHandles()
CacheFileHandles::CacheFileHandles(CacheFileIOManager* aManager)
: mManager(aManager)
{
LOG(("CacheFileHandles::CacheFileHandles() [this=%p]", this));
MOZ_COUNT_CTOR(CacheFileHandles);
@ -376,7 +378,7 @@ CacheFileHandles::NewHandle(const SHA1Sum::Hash *aHash,
entry->AssertHandlesState();
#endif
nsRefPtr<CacheFileHandle> handle = new CacheFileHandle(entry->Hash(), aPriority);
nsRefPtr<CacheFileHandle> handle = new CacheFileHandle(mManager, entry->Hash(), aPriority);
entry->AddHandle(handle);
LOG(("CacheFileHandles::NewHandle() hash=%08x%08x%08x%08x%08x "
@ -544,14 +546,15 @@ protected:
class OpenFileEvent : public nsRunnable {
public:
OpenFileEvent(const nsACString &aKey, uint32_t aFlags,
OpenFileEvent(CacheFileIOManager *aIOMan,
const nsACString &aKey, uint32_t aFlags,
CacheFileIOListener *aCallback)
: mFlags(aFlags)
, mCallback(aCallback)
, mIOMan(aIOMan)
, mKey(aKey)
{
MOZ_COUNT_CTOR(OpenFileEvent);
mIOMan = CacheFileIOManager::gInstance;
}
protected:
@ -629,7 +632,7 @@ public:
if (mHandle->IsClosed()) {
rv = NS_ERROR_NOT_INITIALIZED;
} else {
rv = CacheFileIOManager::gInstance->ReadInternal(
rv = mHandle->Manager()->ReadInternal(
mHandle, mOffset, mBuf, mCount);
}
@ -679,11 +682,11 @@ public:
if (mHandle->IsClosed()) {
rv = NS_ERROR_NOT_INITIALIZED;
} else {
rv = CacheFileIOManager::gInstance->WriteInternal(
rv = mHandle->Manager()->WriteInternal(
mHandle, mOffset, mBuf, mCount, mValidate, mTruncate);
if (NS_FAILED(rv) && !mCallback) {
// No listener is going to handle the error, doom the file
CacheFileIOManager::gInstance->DoomFileInternal(mHandle);
mHandle->Manager()->DoomFileInternal(mHandle);
}
}
if (mCallback) {
@ -730,7 +733,7 @@ public:
if (mHandle->IsClosed()) {
rv = NS_ERROR_NOT_INITIALIZED;
} else {
rv = CacheFileIOManager::gInstance->DoomFileInternal(mHandle);
rv = mHandle->Manager()->DoomFileInternal(mHandle);
}
if (mCallback) {
@ -749,8 +752,10 @@ protected:
class DoomFileByKeyEvent : public nsRunnable {
public:
DoomFileByKeyEvent(const nsACString &aKey,
CacheFileIOManager *aManager,
CacheFileIOListener *aCallback)
: mCallback(aCallback)
, mIOMan(aManager)
{
MOZ_COUNT_CTOR(DoomFileByKeyEvent);
@ -758,7 +763,7 @@ public:
sum.update(aKey.BeginReading(), aKey.Length());
sum.finish(mHash);
mIOMan = CacheFileIOManager::gInstance;
mIOMan = aManager;
}
protected:
@ -810,7 +815,7 @@ public:
NS_IMETHOD Run()
{
if (mHandle->mFD && !mHandle->IsClosed()) {
CacheFileIOManager::gInstance->ReleaseNSPRHandleInternal(mHandle);
mHandle->Manager()->ReleaseNSPRHandleInternal(mHandle);
}
return NS_OK;
@ -846,7 +851,7 @@ public:
if (mHandle->IsClosed()) {
rv = NS_ERROR_NOT_INITIALIZED;
} else {
rv = CacheFileIOManager::gInstance->TruncateSeekSetEOFInternal(
rv = mHandle->Manager()->TruncateSeekSetEOFInternal(
mHandle, mTruncatePos, mEOFPos);
}
@ -889,8 +894,7 @@ public:
if (mHandle->IsClosed()) {
rv = NS_ERROR_NOT_INITIALIZED;
} else {
rv = CacheFileIOManager::gInstance->RenameFileInternal(mHandle,
mNewName);
rv = mHandle->Manager()->RenameFileInternal(mHandle, mNewName);
}
if (mCallback) {
@ -1021,8 +1025,7 @@ public:
NS_IMETHOD Run()
{
nsRefPtr<CacheFileIOManager> ioMan = CacheFileIOManager::gInstance;
if (!ioMan) {
if (!mIOMan) {
NS_WARNING("CacheFileIOManager already gone in MetadataWriteScheduleEvent::Run()");
return NS_OK;
}
@ -1030,13 +1033,13 @@ public:
switch (mMode)
{
case SCHEDULE:
ioMan->ScheduleMetadataWriteInternal(mFile);
mIOMan->ScheduleMetadataWriteInternal(mFile);
break;
case UNSCHEDULE:
ioMan->UnscheduleMetadataWriteInternal(mFile);
mIOMan->UnscheduleMetadataWriteInternal(mFile);
break;
case SHUTDOWN:
ioMan->ShutdownMetadataWriteSchedulingInternal();
mIOMan->ShutdownMetadataWriteSchedulingInternal();
break;
}
return NS_OK;
@ -1048,20 +1051,19 @@ CacheFileIOManager * CacheFileIOManager::gInstance = nullptr;
NS_IMPL_ISUPPORTS(CacheFileIOManager, nsITimerCallback)
CacheFileIOManager::CacheFileIOManager()
: mShuttingDown(false)
: mKind(UNKNOWN)
, mShuttingDown(false)
, mTreeCreated(false)
, mHandles(this)
, mOverLimitEvicting(false)
, mRemovingTrashDirs(false)
{
LOG(("CacheFileIOManager::CacheFileIOManager [this=%p]", this));
MOZ_COUNT_CTOR(CacheFileIOManager);
MOZ_ASSERT(!gInstance, "multiple CacheFileIOManager instances!");
}
CacheFileIOManager::~CacheFileIOManager()
{
LOG(("CacheFileIOManager::~CacheFileIOManager [this=%p]", this));
MOZ_COUNT_DTOR(CacheFileIOManager);
}
// static
@ -1082,6 +1084,10 @@ CacheFileIOManager::Init()
NS_ENSURE_SUCCESS(rv, rv);
ioMan.swap(gInstance);
// Ensure pinning managers static to avoid concurrent thread initiation.
Pinning::Self();
return NS_OK;
}
@ -1090,6 +1096,7 @@ CacheFileIOManager::InitInternal()
{
nsresult rv;
mKind = GENERAL;
mIOThread = new CacheIOThread();
rv = mIOThread->Init();
@ -1101,6 +1108,38 @@ CacheFileIOManager::InitInternal()
return NS_OK;
}
nsresult
CacheFileIOManager::InitAsPinning(uint32_t aAppId, nsIFile* aProfileDir)
{
if (!aProfileDir || !gInstance) {
return NS_ERROR_NOT_INITIALIZED;
}
mKind = PINNING;
MOZ_ASSERT(!mCacheDirectory);
MOZ_ASSERT(!mIOThread);
nsresult rv;
rv = aProfileDir->Clone(getter_AddRefs(mCacheDirectory));
NS_ENSURE_SUCCESS(rv, rv);
rv = mCacheDirectory->Append(NS_LITERAL_STRING("cache2"));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString appIdString;
appIdString.AppendInt(aAppId);
rv = mCacheDirectory->Append(appIdString);
NS_ENSURE_SUCCESS(rv, rv);
mIOThread = gInstance->mIOThread;
mStartTime = TimeStamp::NowLoRes();
return NS_OK;
}
// static
nsresult
CacheFileIOManager::Shutdown()
@ -1133,6 +1172,7 @@ CacheFileIOManager::Shutdown()
MOZ_ASSERT(gInstance->mHandles.HandleCount() == 0);
MOZ_ASSERT(gInstance->mHandlesByLastUsed.Length() == 0);
MOZ_ASSERT(Pinning::Self()->Length() == 0);
if (gInstance->mIOThread) {
gInstance->mIOThread->Shutdown();
@ -1143,11 +1183,14 @@ CacheFileIOManager::Shutdown()
if (CacheObserver::ClearCacheOnShutdown()) {
Telemetry::AutoTimer<Telemetry::NETWORK_DISK_CACHE2_SHUTDOWN_CLEAR_PRIVATE> totalTimer;
gInstance->SyncRemoveAllCacheFiles();
// mayhemer: should this apply to pinning apps as well? followup sufficient...
}
nsRefPtr<CacheFileIOManager> ioMan;
ioMan.swap(gInstance);
Pinning::Self()->Destroy();
return NS_OK;
}
@ -1184,7 +1227,8 @@ CacheFileIOManager::ShutdownInternal()
}
if (!h->IsSpecialFile() && !h->mIsDoomed &&
(h->mInvalid || !h->mFileExists)) {
(h->mInvalid || !h->mFileExists) &&
mKind != PINNING) {
CacheIndex::RemoveEntry(h->Hash());
}
@ -1215,6 +1259,8 @@ CacheFileIOManager::ShutdownInternal()
mTrashDirEnumerator = nullptr;
}
Pinning::Self()->ShutdownInternal();
return NS_OK;
}
@ -1299,6 +1345,8 @@ CacheFileIOManager::OnProfile()
CacheIndex::Init(ioMan->mCacheDirectory);
}
Pinning::Self()->OnProfile();
return NS_OK;
}
@ -1365,9 +1413,11 @@ CacheFileIOManager::IsShutdown()
nsresult
CacheFileIOManager::ScheduleMetadataWrite(CacheFile * aFile)
{
// This can freely go to the global IO manager, no need for distinction
// since the timer code calls on the file that delegates to its handle
// which is already correctly bound to the correct manager.
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
NS_ENSURE_TRUE(ioMan, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(!ioMan->mShuttingDown, NS_ERROR_NOT_INITIALIZED);
nsRefPtr<MetadataWriteScheduleEvent> event = new MetadataWriteScheduleEvent(
@ -1409,7 +1459,6 @@ CacheFileIOManager::UnscheduleMetadataWrite(CacheFile * aFile)
{
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
NS_ENSURE_TRUE(ioMan, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(!ioMan->mShuttingDown, NS_ERROR_NOT_INITIALIZED);
nsRefPtr<MetadataWriteScheduleEvent> event = new MetadataWriteScheduleEvent(
@ -1472,38 +1521,63 @@ CacheFileIOManager::ShutdownMetadataWriteSchedulingInternal()
NS_IMETHODIMP
CacheFileIOManager::Notify(nsITimer * aTimer)
{
MOZ_ASSERT(IsOnIOThreadOrCeased());
MOZ_ASSERT(mMetadataWritesTimer == aTimer);
if (mTrashTimer == aTimer) {
LOG(("CacheFileIOManager, trash timer [this=%p]", this));
mMetadataWritesTimer = nullptr;
mTrashTimer = nullptr;
StartRemovingTrash();
nsTArray<nsRefPtr<CacheFile> > files;
files.SwapElements(mScheduledMetadataWrites);
for (uint32_t i = 0; i < files.Length(); ++i) {
CacheFile * file = files[i];
file->WriteMetadataIfNeeded();
return NS_OK;
}
return NS_OK;
if (mMetadataWritesTimer == aTimer) {
LOG(("CacheFileIOManager, metadata write timer [this=%p]", this));
MOZ_ASSERT(IsOnIOThreadOrCeased());
mMetadataWritesTimer = nullptr;
nsTArray<nsRefPtr<CacheFile> > files;
files.SwapElements(mScheduledMetadataWrites);
for (uint32_t i = 0; i < files.Length(); ++i) {
CacheFile * file = files[i];
file->WriteMetadataIfNeeded();
}
return NS_OK;
}
MOZ_ASSERT(false, "Unexpected timer in CacheFileIOManager::Notify()!");
return NS_ERROR_UNEXPECTED;
}
// static
nsresult
CacheFileIOManager::OpenFile(const nsACString &aKey,
uint32_t aFlags, CacheFileIOListener *aCallback)
{
return OpenFile(aKey, nsILoadContextInfo::NO_APP_ID, aFlags, aCallback);
}
// static
nsresult
CacheFileIOManager::OpenFile(const nsACString &aKey, uint32_t aPinningAppId,
uint32_t aFlags, CacheFileIOListener *aCallback)
{
LOG(("CacheFileIOManager::OpenFile() [key=%s, flags=%d, listener=%p]",
PromiseFlatCString(aKey).get(), aFlags, aCallback));
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
if (aPinningAppId != nsILoadContextInfo::NO_APP_ID && ioMan) {
ioMan = Pinning::Self()->Get(aPinningAppId);
}
if (!ioMan) {
return NS_ERROR_NOT_INITIALIZED;
}
bool priority = aFlags & CacheFileIOManager::PRIORITY;
nsRefPtr<OpenFileEvent> ev = new OpenFileEvent(aKey, aFlags, aCallback);
nsRefPtr<OpenFileEvent> ev = new OpenFileEvent(ioMan, aKey, aFlags, aCallback);
rv = ioMan->mIOThread->Dispatch(ev, priority
? CacheIOThread::OPEN_PRIORITY
: CacheIOThread::OPEN);
@ -1557,7 +1631,9 @@ CacheFileIOManager::OpenFileInternal(const SHA1Sum::Hash *aHash,
NS_ENSURE_SUCCESS(rv, rv);
if (exists) {
CacheIndex::RemoveEntry(aHash);
if (mKind != PINNING) {
CacheIndex::RemoveEntry(aHash);
}
LOG(("CacheFileIOManager::OpenFileInternal() - Removing old file from "
"disk"));
@ -1569,7 +1645,10 @@ CacheFileIOManager::OpenFileInternal(const SHA1Sum::Hash *aHash,
}
}
CacheIndex::AddEntry(aHash);
if (mKind != PINNING) {
CacheIndex::AddEntry(aHash);
}
handle->mFile.swap(file);
handle->mFileSize = 0;
}
@ -1594,7 +1673,10 @@ CacheFileIOManager::OpenFileInternal(const SHA1Sum::Hash *aHash,
"entry was evicted by EvictByContext()"));
exists = false;
file->Remove(false);
CacheIndex::RemoveEntry(aHash);
if (mKind != PINNING) {
CacheIndex::RemoveEntry(aHash);
}
}
}
}
@ -1612,11 +1694,15 @@ CacheFileIOManager::OpenFileInternal(const SHA1Sum::Hash *aHash,
handle->mFileExists = true;
CacheIndex::EnsureEntryExists(aHash);
if (mKind != PINNING) {
CacheIndex::EnsureEntryExists(aHash);
}
} else {
handle->mFileSize = 0;
CacheIndex::AddEntry(aHash);
if (mKind != PINNING) {
CacheIndex::AddEntry(aHash);
}
}
handle->mFile.swap(file);
@ -1664,7 +1750,7 @@ CacheFileIOManager::OpenSpecialFileInternal(const nsACString &aKey,
handle = nullptr;
}
handle = new CacheFileHandle(aKey, aFlags & PRIORITY);
handle = new CacheFileHandle(this, aKey, aFlags & PRIORITY);
mSpecialHandles.AppendElement(handle);
bool exists;
@ -1699,7 +1785,7 @@ CacheFileIOManager::OpenSpecialFileInternal(const nsACString &aKey,
return NS_ERROR_NOT_AVAILABLE;
}
handle = new CacheFileHandle(aKey, aFlags & PRIORITY);
handle = new CacheFileHandle(this, aKey, aFlags & PRIORITY);
mSpecialHandles.AppendElement(handle);
if (exists) {
@ -1740,7 +1826,8 @@ CacheFileIOManager::CloseHandleInternal(CacheFileHandle *aHandle)
}
if (!aHandle->IsSpecialFile() && !aHandle->mIsDoomed &&
(aHandle->mInvalid || !aHandle->mFileExists)) {
(aHandle->mInvalid || !aHandle->mFileExists) &&
mKind != PINNING) {
CacheIndex::RemoveEntry(aHandle->Hash());
}
@ -1766,7 +1853,7 @@ CacheFileIOManager::Read(CacheFileHandle *aHandle, int64_t aOffset,
"listener=%p]", aHandle, aOffset, aCount, aCallback));
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
nsRefPtr<CacheFileIOManager> ioMan = aHandle->Manager();
if (aHandle->IsClosed() || !ioMan) {
return NS_ERROR_NOT_INITIALIZED;
@ -1833,7 +1920,7 @@ CacheFileIOManager::Write(CacheFileHandle *aHandle, int64_t aOffset,
aValidate, aTruncate, aCallback));
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
nsRefPtr<CacheFileIOManager> ioMan = aHandle->Manager();
if (aHandle->IsClosed() || !ioMan) {
if (!aCallback) {
@ -1950,7 +2037,7 @@ CacheFileIOManager::WriteInternal(CacheFileHandle *aHandle, int64_t aOffset,
uint32_t newSizeInK = aHandle->FileSizeInK();
if (oldSizeInK != newSizeInK && !aHandle->IsDoomed() &&
!aHandle->IsSpecialFile()) {
!aHandle->IsSpecialFile() && mKind != PINNING) {
CacheIndex::UpdateEntry(aHandle->Hash(), nullptr, nullptr, &newSizeInK);
if (oldSizeInK < newSizeInK) {
@ -1980,7 +2067,7 @@ CacheFileIOManager::DoomFile(CacheFileHandle *aHandle,
aHandle, aCallback));
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
nsRefPtr<CacheFileIOManager> ioMan = aHandle->Manager();
if (aHandle->IsClosed() || !ioMan) {
return NS_ERROR_NOT_INITIALIZED;
@ -2037,7 +2124,7 @@ CacheFileIOManager::DoomFileInternal(CacheFileHandle *aHandle)
}
}
if (!aHandle->IsSpecialFile()) {
if (!aHandle->IsSpecialFile() && mKind != PINNING) {
CacheIndex::RemoveEntry(aHandle->Hash());
}
@ -2046,12 +2133,12 @@ CacheFileIOManager::DoomFileInternal(CacheFileHandle *aHandle)
if (!aHandle->IsSpecialFile()) {
nsRefPtr<CacheStorageService> storageService = CacheStorageService::Self();
if (storageService) {
nsAutoCString idExtension, url;
CacheFileUtils::KeyInfo keyInfo;
nsCOMPtr<nsILoadContextInfo> info =
CacheFileUtils::ParseKey(aHandle->Key(), &idExtension, &url);
CacheFileUtils::ParseKey(aHandle->Key(), &keyInfo);
MOZ_ASSERT(info);
if (info) {
storageService->CacheFileDoomed(info, idExtension, url);
storageService->CacheFileDoomed(info, &keyInfo);
}
}
}
@ -2067,14 +2154,21 @@ CacheFileIOManager::DoomFileByKey(const nsACString &aKey,
LOG(("CacheFileIOManager::DoomFileByKey() [key=%s, listener=%p]",
PromiseFlatCString(aKey).get(), aCallback));
CacheFileUtils::KeyInfo keyInfo;
nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(aKey, &keyInfo);
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
if (keyInfo.mPinningStorage && ioMan) {
ioMan = Pinning::Self()->Get(info->AppId());
}
if (!ioMan) {
return NS_ERROR_NOT_INITIALIZED;
}
nsRefPtr<DoomFileByKeyEvent> ev = new DoomFileByKeyEvent(aKey, aCallback);
nsRefPtr<DoomFileByKeyEvent> ev = new DoomFileByKeyEvent(aKey, ioMan, aCallback);
rv = ioMan->mIOThread->DispatchAfterPendingOpens(ev);
NS_ENSURE_SUCCESS(rv, rv);
@ -2131,7 +2225,9 @@ CacheFileIOManager::DoomFileByKeyInternal(const SHA1Sum::Hash *aHash)
"[rv=0x%08x]", rv));
}
CacheIndex::RemoveEntry(aHash);
if (mKind != PINNING) {
CacheIndex::RemoveEntry(aHash);
}
return NS_OK;
}
@ -2143,7 +2239,7 @@ CacheFileIOManager::ReleaseNSPRHandle(CacheFileHandle *aHandle)
LOG(("CacheFileIOManager::ReleaseNSPRHandle() [handle=%p]", aHandle));
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
nsRefPtr<CacheFileIOManager> ioMan = aHandle->Manager();
if (aHandle->IsClosed() || !ioMan) {
return NS_ERROR_NOT_INITIALIZED;
@ -2165,7 +2261,7 @@ CacheFileIOManager::ReleaseNSPRHandleInternal(CacheFileHandle *aHandle)
MOZ_ASSERT(aHandle->mFD);
DebugOnly<bool> found;
found = mHandlesByLastUsed.RemoveElement(aHandle);
found = gInstance->mHandlesByLastUsed.RemoveElement(aHandle);
MOZ_ASSERT(found);
PR_Close(aHandle->mFD);
@ -2184,7 +2280,7 @@ CacheFileIOManager::TruncateSeekSetEOF(CacheFileHandle *aHandle,
"EOFPos=%lld, listener=%p]", aHandle, aTruncatePos, aEOFPos, aCallback));
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
nsRefPtr<CacheFileIOManager> ioMan = aHandle->Manager();
if (aHandle->IsClosed() || !ioMan) {
return NS_ERROR_NOT_INITIALIZED;
@ -2238,19 +2334,19 @@ CacheFileIOManager::GetEntryInfo(const SHA1Sum::Hash *aHash,
nsresult rv;
// mayhemer: This method should take aPinningAppId argument.
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
if (!ioMan) {
return NS_ERROR_NOT_INITIALIZED;
}
nsAutoCString enhanceId;
nsAutoCString uriSpec;
CacheFileUtils::KeyInfo keyInfo;
nsRefPtr<CacheFileHandle> handle;
ioMan->mHandles.GetHandle(aHash, getter_AddRefs(handle));
if (handle) {
nsRefPtr<nsILoadContextInfo> info =
CacheFileUtils::ParseKey(handle->Key(), &enhanceId, &uriSpec);
CacheFileUtils::ParseKey(handle->Key(), &keyInfo);
MOZ_ASSERT(info);
if (!info) {
@ -2263,7 +2359,7 @@ CacheFileIOManager::GetEntryInfo(const SHA1Sum::Hash *aHash,
}
// Invokes OnCacheEntryInfo when an existing entry is found
if (service->GetCacheEntryInfo(info, enhanceId, uriSpec, aCallback)) {
if (service->GetCacheEntryInfo(info, &keyInfo, aCallback)) {
return NS_OK;
}
@ -2287,7 +2383,7 @@ CacheFileIOManager::GetEntryInfo(const SHA1Sum::Hash *aHash,
metadata->GetKey(key);
nsRefPtr<nsILoadContextInfo> info =
CacheFileUtils::ParseKey(key, &enhanceId, &uriSpec);
CacheFileUtils::ParseKey(key, &keyInfo);
MOZ_ASSERT(info);
if (!info) {
return NS_OK;
@ -2309,8 +2405,8 @@ CacheFileIOManager::GetEntryInfo(const SHA1Sum::Hash *aHash,
}
// Call directly on the callback.
aCallback->OnEntryInfo(uriSpec, enhanceId, dataSize, fetchCount,
lastModified, expirationTime);
aCallback->OnEntryInfo(keyInfo.mURISpec, keyInfo.mIdEnhance,
dataSize, fetchCount, lastModified, expirationTime);
return NS_OK;
}
@ -2397,7 +2493,7 @@ CacheFileIOManager::RenameFile(CacheFileHandle *aHandle,
aHandle, PromiseFlatCString(aNewName).get(), aCallback));
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
nsRefPtr<CacheFileIOManager> ioMan = aHandle->Manager();
if (aHandle->IsClosed() || !ioMan) {
return NS_ERROR_NOT_INITIALIZED;
@ -2508,6 +2604,10 @@ CacheFileIOManager::EvictIfOverLimitInternal()
MOZ_ASSERT(mIOThread->IsCurrentThread());
if (mKind == PINNING) {
return NS_ERROR_NOT_IMPLEMENTED;
}
if (mShuttingDown) {
return NS_ERROR_NOT_INITIALIZED;
}
@ -2569,6 +2669,7 @@ CacheFileIOManager::OverLimitEvictionInternal()
nsresult rv;
MOZ_ASSERT(mIOThread->IsCurrentThread());
MOZ_ASSERT(mKind != PINNING);
// mOverLimitEvicting is accessed only on IO thread, so we can set it to false
// here and set it to true again once we dispatch another event that will
@ -2701,6 +2802,31 @@ CacheFileIOManager::EvictAll()
return NS_OK;
}
// static
nsresult
CacheFileIOManager::EvictPinned(uint32_t aPinningAppId)
{
LOG(("CacheFileIOManager::EvictPinned(appId=%d)", aPinningAppId));
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
if (ioMan) {
ioMan = Pinning::Self()->Get(aPinningAppId);
}
if (!ioMan) {
return NS_ERROR_NOT_INITIALIZED;
}
nsCOMPtr<nsIRunnable> ev;
ev = NS_NewRunnableMethod(ioMan, &CacheFileIOManager::EvictAllInternal);
nsresult rv = ioMan->mIOThread->DispatchAfterPendingOpens(ev);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
namespace {
class EvictionNotifierRunnable : public nsRunnable
@ -2724,7 +2850,7 @@ EvictionNotifierRunnable::Run()
nsresult
CacheFileIOManager::EvictAllInternal()
{
LOG(("CacheFileIOManager::EvictAllInternal()"));
LOG(("CacheFileIOManager::EvictAllInternal(), this=%p", this));
nsresult rv;
@ -2789,18 +2915,29 @@ CacheFileIOManager::EvictAllInternal()
return rv;
}
CacheIndex::RemoveAll();
if (mKind != PINNING) {
CacheIndex::RemoveAll();
}
return NS_OK;
}
// static
nsresult
CacheFileIOManager::EvictByContext(nsILoadContextInfo *aLoadContextInfo)
CacheFileIOManager::EvictByContext(nsILoadContextInfo *aLoadContextInfo,
bool aIsPinning)
{
LOG(("CacheFileIOManager::EvictByContext() [loadContextInfo=%p]",
aLoadContextInfo));
if (aIsPinning) {
// This is a kinda hacky workaround, we simply delete everything that
// the app has pinned with disrespect to the load context separation.
// This API is dependent on the index, but index is global and only
// works for the general manager.
return CacheFileIOManager::EvictPinned(aLoadContextInfo->AppId());
}
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
@ -2937,7 +3074,7 @@ CacheFileIOManager::TrashDirectory(nsIFile *aFile)
{
nsAutoCString path;
aFile->GetNativePath(path);
LOG(("CacheFileIOManager::TrashDirectory() [file=%s]", path.get()));
LOG(("CacheFileIOManager::TrashDirectory() [this=%p, file=%s]", this, path.get()));
nsresult rv;
@ -3001,23 +3138,6 @@ CacheFileIOManager::TrashDirectory(nsIFile *aFile)
return NS_OK;
}
// static
void
CacheFileIOManager::OnTrashTimer(nsITimer *aTimer, void *aClosure)
{
LOG(("CacheFileIOManager::OnTrashTimer() [timer=%p, closure=%p]", aTimer,
aClosure));
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
if (!ioMan) {
return;
}
ioMan->mTrashTimer = nullptr;
ioMan->StartRemovingTrash();
}
nsresult
CacheFileIOManager::StartRemovingTrash()
{
@ -3057,9 +3177,8 @@ CacheFileIOManager::StartRemovingTrash()
rv = timer->SetTarget(ioTarget);
NS_ENSURE_SUCCESS(rv, rv);
rv = timer->InitWithFuncCallback(CacheFileIOManager::OnTrashTimer, nullptr,
kRemoveTrashStartDelay - elapsed,
nsITimer::TYPE_ONE_SHOT);
rv = timer->InitWithCallback(this, kRemoveTrashStartDelay - elapsed,
nsITimer::TYPE_ONE_SHOT);
NS_ENSURE_SUCCESS(rv, rv);
mTrashTimer.swap(timer);
@ -3260,12 +3379,16 @@ CacheFileIOManager::InitIndexEntry(CacheFileHandle *aHandle,
", inBrowser=%d]", aHandle, aAppId, aAnonymous, aInBrowser));
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
nsRefPtr<CacheFileIOManager> ioMan = aHandle->Manager();
if (aHandle->IsClosed() || !ioMan) {
return NS_ERROR_NOT_INITIALIZED;
}
if (ioMan->Kind() == PINNING) {
return NS_ERROR_NOT_IMPLEMENTED;
}
if (aHandle->IsSpecialFile()) {
return NS_ERROR_UNEXPECTED;
}
@ -3290,12 +3413,16 @@ CacheFileIOManager::UpdateIndexEntry(CacheFileHandle *aHandle,
aExpirationTime ? nsPrintfCString("%u", *aExpirationTime).get() : ""));
nsresult rv;
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
nsRefPtr<CacheFileIOManager> ioMan = aHandle->Manager();
if (aHandle->IsClosed() || !ioMan) {
return NS_ERROR_NOT_INITIALIZED;
}
if (ioMan->Kind() == PINNING) {
return NS_ERROR_NOT_IMPLEMENTED;
}
if (aHandle->IsSpecialFile()) {
return NS_ERROR_UNEXPECTED;
}
@ -3623,16 +3750,16 @@ CacheFileIOManager::OpenNSPRHandle(CacheFileHandle *aHandle, bool aCreate)
{
MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased());
MOZ_ASSERT(!aHandle->mFD);
MOZ_ASSERT(mHandlesByLastUsed.IndexOf(aHandle) == mHandlesByLastUsed.NoIndex);
MOZ_ASSERT(mHandlesByLastUsed.Length() <= kOpenHandlesLimit);
MOZ_ASSERT(gInstance->mHandlesByLastUsed.IndexOf(aHandle) == gInstance->mHandlesByLastUsed.NoIndex);
MOZ_ASSERT(gInstance->mHandlesByLastUsed.Length() <= kOpenHandlesLimit);
MOZ_ASSERT((aCreate && !aHandle->mFileExists) ||
(!aCreate && aHandle->mFileExists));
nsresult rv;
if (mHandlesByLastUsed.Length() == kOpenHandlesLimit) {
if (gInstance->mHandlesByLastUsed.Length() == kOpenHandlesLimit) {
// close handle that hasn't been used for the longest time
rv = ReleaseNSPRHandleInternal(mHandlesByLastUsed[0]);
rv = ReleaseNSPRHandleInternal(gInstance->mHandlesByLastUsed[0]);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -3689,7 +3816,7 @@ CacheFileIOManager::OpenNSPRHandle(CacheFileHandle *aHandle, bool aCreate)
NS_ENSURE_SUCCESS(rv, rv);
}
mHandlesByLastUsed.AppendElement(aHandle);
gInstance->mHandlesByLastUsed.AppendElement(aHandle);
return NS_OK;
}
@ -3700,10 +3827,10 @@ CacheFileIOManager::NSPRHandleUsed(CacheFileHandle *aHandle)
MOZ_ASSERT(aHandle->mFD);
DebugOnly<bool> found;
found = mHandlesByLastUsed.RemoveElement(aHandle);
found = gInstance->mHandlesByLastUsed.RemoveElement(aHandle);
MOZ_ASSERT(found);
mHandlesByLastUsed.AppendElement(aHandle);
gInstance->mHandlesByLastUsed.AppendElement(aHandle);
}
nsresult
@ -3843,6 +3970,10 @@ CacheFileIOManager::UpdateSmartCacheSize(int64_t aFreeSpace)
return NS_ERROR_NOT_AVAILABLE;
}
if (mKind == PINNING) {
return NS_ERROR_NOT_AVAILABLE;
}
// Wait at least kSmartSizeUpdateInterval before recomputing smart size.
static const TimeDuration kUpdateLimit =
TimeDuration::FromMilliseconds(kSmartSizeUpdateInterval);
@ -3984,9 +4115,19 @@ CacheFileIOManager::SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSize
n += mFailedTrashDirs[i].SizeOfExcludingThisIfUnshared(mallocSizeOf);
}
if (mKind == GENERAL) {
Pinning::Self()->SizeOfIncludingThis(mallocSizeOf);
}
return n;
}
size_t
CacheFileIOManager::SizeOfIncludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(this) + SizeOfExcludingThisInternal(mallocSizeOf);
}
// static
size_t
CacheFileIOManager::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
@ -4004,5 +4145,128 @@ CacheFileIOManager::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
return mallocSizeOf(gInstance) + SizeOfExcludingThis(mallocSizeOf);
}
// CacheFileIOManager::Pinning
CacheFileIOManager::Pinning*
CacheFileIOManager::Pinning::sSelf = nullptr;
bool
CacheFileIOManager::Pinning::sDestroyed = false;
CacheFileIOManager::Pinning::Pinning()
: mLock("CacheFileIOManager::Pinning")
{
MOZ_ASSERT(!sSelf);
sSelf = this;
MOZ_COUNT_CTOR(CacheFileIOManager::Pinning);
}
CacheFileIOManager::Pinning::~Pinning()
{
MOZ_ASSERT(sSelf);
sSelf = nullptr;
MOZ_COUNT_DTOR(CacheFileIOManager::Pinning);
}
// static
CacheFileIOManager::Pinning*
CacheFileIOManager::Pinning::Self()
{
MOZ_ASSERT(!sDestroyed);
if (!sSelf) {
sSelf = new Pinning();
}
return sSelf;
}
void
CacheFileIOManager::Pinning::Destroy()
{
delete sSelf;
sDestroyed = true;
}
nsresult
CacheFileIOManager::Pinning::OnProfile()
{
nsresult rv;
rv = NS_GetSpecialDirectory(
NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mRoamingProfileDir));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
already_AddRefed<CacheFileIOManager>
CacheFileIOManager::Pinning::Get(uint32_t aAppId)
{
mozilla::MutexAutoLock lock(mLock);
nsRefPtr<CacheFileIOManager> pinningIOMan;
if (!mTable.Get(aAppId, getter_AddRefs(pinningIOMan))) {
pinningIOMan = new CacheFileIOManager();
LOG(("CacheFileIOManager::Pinning::Get, new manager %p for appid=%u",
pinningIOMan.get(), aAppId));
nsresult rv = pinningIOMan->InitAsPinning(aAppId, mRoamingProfileDir);
if (NS_FAILED(rv)) {
return nullptr;
}
mTable.Put(aAppId, pinningIOMan);
}
return pinningIOMan.forget();
}
// static
PLDHashOperator
CacheFileIOManager::Pinning::Collect(uint32_t const& aAppId,
nsRefPtr<CacheFileIOManager>& aIoMan,
void* aClosure)
{
nsTArray<nsRefPtr<CacheFileIOManager> >* managers =
static_cast<nsTArray<nsRefPtr<CacheFileIOManager> >*>(aClosure);
managers->AppendElement()->swap(aIoMan);
return PL_DHASH_REMOVE;
}
void
CacheFileIOManager::Pinning::ShutdownInternal()
{
nsTArray<nsRefPtr<CacheFileIOManager> > managers;
{
mozilla::MutexAutoLock lock(mLock);
mTable.Enumerate(&Pinning::Collect, &managers);
}
for (uint32_t i = 0; i < managers.Length(); ++i) {
CacheFileIOManager* ioMan = managers[i];
ioMan->ShutdownInternal();
}
}
static
size_t CollectManagerMemory(uint32_t const & aAppId,
nsRefPtr<mozilla::net::CacheFileIOManager> const & aManager,
mozilla::MallocSizeOf mallocSizeOf,
void * aClosure)
{
return aManager->SizeOfIncludingThisInternal(mallocSizeOf);
}
size_t
CacheFileIOManager::Pinning::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
return mTable.SizeOfExcludingThis(&CollectManagerMemory, mallocSizeOf, nullptr);
}
size_t
CacheFileIOManager::Pinning::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
}
} // namespace net
} // namespace mozilla

View File

@ -15,6 +15,7 @@
#include "nsTArray.h"
#include "nsString.h"
#include "nsTHashtable.h"
#include "nsRefPtrHashtable.h"
#include "prio.h"
//#define DEBUG_HANDLES 1
@ -28,6 +29,7 @@ namespace mozilla {
namespace net {
class CacheFile;
class CacheFileIOManager;
#ifdef DEBUG_HANDLES
class CacheFileHandlesEntry;
#endif
@ -43,8 +45,8 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
bool DispatchRelease();
CacheFileHandle(const SHA1Sum::Hash *aHash, bool aPriority);
CacheFileHandle(const nsACString &aKey, bool aPriority);
CacheFileHandle(CacheFileIOManager* aManager, const SHA1Sum::Hash *aHash, bool aPriority);
CacheFileHandle(CacheFileIOManager* aManager, const nsACString &aKey, bool aPriority);
CacheFileHandle(const CacheFileHandle &aOther);
void Log();
bool IsDoomed() const { return mIsDoomed; }
@ -56,6 +58,7 @@ public:
bool IsClosed() const { return mClosed; }
bool IsSpecialFile() const { return mSpecialFile; }
nsCString & Key() { return mKey; }
CacheFileIOManager* Manager() const { return mManager; }
// Memory reporting
size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
@ -68,6 +71,8 @@ private:
virtual ~CacheFileHandle();
nsRefPtr<CacheFileIOManager> mManager;
const SHA1Sum::Hash *mHash;
bool mIsDoomed;
bool mPriority;
@ -86,7 +91,7 @@ private:
class CacheFileHandles {
public:
CacheFileHandles();
CacheFileHandles(CacheFileIOManager* aManager);
~CacheFileHandles();
nsresult GetHandle(const SHA1Sum::Hash *aHash, CacheFileHandle **_retval);
@ -168,6 +173,7 @@ public:
private:
nsTHashtable<HandleHashKey> mTable;
CacheFileIOManager* mManager;
};
////////////////////////////////////////////////////////////////////////////////
@ -218,6 +224,12 @@ public:
SPECIAL_FILE = 8U
};
enum EKind {
UNKNOWN,
GENERAL,
PINNING
};
CacheFileIOManager();
static nsresult Init();
@ -229,6 +241,8 @@ public:
static bool IsOnIOThreadOrCeased();
static bool IsShutdown();
EKind Kind() const { return mKind; }
// Make aFile's WriteMetadataIfNeeded be called automatically after
// a short interval.
static nsresult ScheduleMetadataWrite(CacheFile * aFile);
@ -240,6 +254,8 @@ public:
static nsresult OpenFile(const nsACString &aKey,
uint32_t aFlags, CacheFileIOListener *aCallback);
static nsresult OpenFile(const nsACString &aKey, uint32_t aPinningAppId,
uint32_t aFlags, CacheFileIOListener *aCallback);
static nsresult Read(CacheFileHandle *aHandle, int64_t aOffset,
char *aBuf, int32_t aCount,
CacheFileIOListener *aCallback);
@ -259,7 +275,9 @@ public:
CacheFileIOListener *aCallback);
static nsresult EvictIfOverLimit();
static nsresult EvictAll();
static nsresult EvictByContext(nsILoadContextInfo *aLoadContextInfo);
static nsresult EvictPinned(uint32_t aPinningAppId);
static nsresult EvictByContext(nsILoadContextInfo *aLoadContextInfo,
bool aIsPinning);
static nsresult InitIndexEntry(CacheFileHandle *aHandle,
uint32_t aAppId,
@ -292,6 +310,9 @@ public:
static size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
static size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
size_t SizeOfIncludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const;
size_t SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const;
private:
friend class CacheFileHandle;
friend class CacheFileChunk;
@ -313,6 +334,8 @@ private:
virtual ~CacheFileIOManager();
nsresult InitInternal();
nsresult InitAsPinning(uint32_t aAppId, nsIFile* aProfileDir);
nsresult ShutdownInternal();
nsresult OpenFileInternal(const SHA1Sum::Hash *aHash,
@ -376,10 +399,44 @@ private:
// before we start an eviction loop.
nsresult UpdateSmartCacheSize(int64_t aFreeSpace);
// Memory reporting (private part)
size_t SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const;
static CacheFileIOManager *gInstance;
// Each pinning app has its own intance of an IO manager setup to point to
// the roaming part of the profile plus identification by the appid.
class Pinning
{
nsRefPtrHashtable<nsUint32HashKey, CacheFileIOManager> mTable;
mozilla::Mutex mLock;
nsCOMPtr<nsIFile> mRoamingProfileDir;
static Pinning* sSelf;
static bool sDestroyed;
static PLDHashOperator Collect(uint32_t const& aAppId,
nsRefPtr<CacheFileIOManager>& aIoMan,
void* aClosure);
static PLDHashOperator Copy(uint32_t const& aAppId,
nsRefPtr<CacheFileIOManager>& aIoMan,
void* aClosure);
public:
Pinning();
~Pinning();
static Pinning* Self();
static void Destroy();
nsresult OnProfile();
already_AddRefed<CacheFileIOManager> Get(uint32_t aPinningAppId);
void ShutdownInternal();
#ifdef DEBUG
uint32_t Length() { return mTable.Count(); }
#endif
size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
};
EKind mKind;
TimeStamp mStartTime;
bool mShuttingDown;
nsRefPtr<CacheIOThread> mIOThread;
@ -393,7 +450,7 @@ private:
#endif
bool mTreeCreated;
CacheFileHandles mHandles;
nsTArray<CacheFileHandle *> mHandlesByLastUsed;
nsTArray<CacheFileHandle *> mHandlesByLastUsed;
nsTArray<CacheFileHandle *> mSpecialHandles;
nsTArray<nsRefPtr<CacheFile> > mScheduledMetadataWrites;
nsCOMPtr<nsITimer> mMetadataWritesTimer;

View File

@ -4,6 +4,7 @@
#include "CacheLog.h"
#include "CacheFileUtils.h"
#include "CacheStorage.h"
#include "LoadContextInfo.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
@ -27,6 +28,7 @@ public:
: caret(aCaret)
, end(aEnd)
// Initialize attributes to their default values
, pinningStorage(false)
, appId(nsILoadContextInfo::NO_APP_ID)
, isPrivate(false)
, isInBrowser(false)
@ -44,6 +46,7 @@ private:
nsACString::const_iterator const end;
// Results
bool pinningStorage;
uint32_t appId;
bool isPrivate;
bool isInBrowser;
@ -76,6 +79,9 @@ private:
cacheKey = caret;
caret = end;
return true;
case 'P':
pinningStorage = true;
break;
case 'p':
isPrivate = true;
break;
@ -194,14 +200,18 @@ public:
{
result.Assign(idEnhance);
}
void PinningStorage(bool &result)
{
result = pinningStorage;
}
};
} // namespace
already_AddRefed<nsILoadContextInfo>
ParseKey(const nsCSubstring &aKey,
nsCSubstring *aIdEnhance,
nsCSubstring *aURISpec)
KeyInfo* aKeyInfo)
{
nsACString::const_iterator caret, end;
aKey.BeginReading(caret);
@ -210,18 +220,25 @@ ParseKey(const nsCSubstring &aKey,
KeyParser parser(caret, end);
nsRefPtr<LoadContextInfo> info = parser.Parse();
if (info) {
if (aIdEnhance)
parser.IdEnhance(*aIdEnhance);
if (aURISpec)
parser.URISpec(*aURISpec);
if (info && aKeyInfo) {
parser.IdEnhance(aKeyInfo->mIdEnhance);
parser.URISpec(aKeyInfo->mURISpec);
parser.PinningStorage(aKeyInfo->mPinningStorage);
}
return info.forget();
}
void
AppendKeyPrefix(nsILoadContextInfo* aInfo, nsACString &_retval)
AppendKeyPrefix(CacheStorage const* aStorage, nsACString &_retval)
{
AppendKeyPrefix(aStorage->LoadInfo(), aStorage->IsPinning(), _retval);
}
void
AppendKeyPrefix(nsILoadContextInfo* aInfo,
bool aPin,
nsACString &_retval)
{
/**
* This key is used to salt file hashes. When form of the key is changed
@ -231,6 +248,10 @@ AppendKeyPrefix(nsILoadContextInfo* aInfo, nsACString &_retval)
* Keep the attributes list sorted according their ASCII code.
*/
if (aPin) {
_retval.AppendLiteral("P,");
}
if (aInfo->IsAnonymous()) {
_retval.AppendLiteral("a,");
}

View File

@ -11,21 +11,26 @@
#include "nsTArray.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/TimeStamp.h"
#include "CacheStorageService.h"
class nsILoadContextInfo;
class nsACString;
namespace mozilla {
namespace net {
class CacheStorage;
namespace CacheFileUtils {
already_AddRefed<nsILoadContextInfo>
ParseKey(const nsCSubstring &aKey,
nsCSubstring *aIdEnhance = nullptr,
nsCSubstring *aURISpec = nullptr);
KeyInfo* aKeyInfo = nullptr);
void
AppendKeyPrefix(nsILoadContextInfo *aInfo, nsACString &_retval);
AppendKeyPrefix(CacheStorage const* aStorage, nsACString &_retval);
void
AppendKeyPrefix(nsILoadContextInfo *aInfo, bool aPin, nsACString &_retval);
void
AppendTagWithValue(nsACString & aTarget, char const aTag, nsCSubstring const & aValue);

View File

@ -429,6 +429,10 @@ CacheStorageEvictHelper::Run(mozIApplicationClearPrivateDataParams* aParams)
rv = ClearStorage(true, aBrowserOnly, true);
NS_ENSURE_SUCCESS(rv, rv);
// And finally evict everything that this app has stored as pinned
rv = CacheFileIOManager::EvictPinned(mAppId);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

View File

@ -54,6 +54,11 @@ public:
bool aAllowDisk,
bool aLookupAppCache);
virtual bool IsPinning() const
{
return false;
}
protected:
virtual ~CacheStorage();

View File

@ -9,6 +9,7 @@
#include "CacheIndex.h"
#include "CacheIndexIterator.h"
#include "CacheStorage.h"
#include "PinningCacheStorage.h"
#include "AppCacheStorage.h"
#include "CacheEntry.h"
#include "CacheFileUtils.h"
@ -209,12 +210,12 @@ protected:
class WalkMemoryCacheRunnable : public WalkCacheRunnable
{
public:
WalkMemoryCacheRunnable(nsILoadContextInfo *aLoadInfo,
WalkMemoryCacheRunnable(CacheStorage const *aStorage,
bool aVisitEntries,
nsICacheStorageVisitor* aVisitor)
: WalkCacheRunnable(aVisitor, aVisitEntries)
{
CacheFileUtils::AppendKeyPrefix(aLoadInfo, mContextKey);
CacheFileUtils::AppendKeyPrefix(aStorage, mContextKey);
MOZ_ASSERT(NS_IsMainThread());
}
@ -535,8 +536,9 @@ void CacheStorageService::DropPrivateBrowsingEntries()
nsTArray<nsCString> keys;
sGlobalEntryTables->EnumerateRead(&CollectPrivateContexts, &keys);
for (uint32_t i = 0; i < keys.Length(); ++i)
DoomStorageEntries(keys[i], nullptr, true, nullptr);
for (uint32_t i = 0; i < keys.Length(); ++i) {
DoomStorageEntries(keys[i], nullptr, true, false, nullptr);
}
}
namespace {
@ -716,6 +718,23 @@ NS_IMETHODIMP CacheStorageService::DiskCacheStorage(nsILoadContextInfo *aLoadCon
return NS_OK;
}
NS_IMETHODIMP CacheStorageService::PinningCacheStorage(nsILoadContextInfo *aLoadContextInfo,
nsICacheStorage * *_retval)
{
NS_ENSURE_ARG(aLoadContextInfo);
NS_ENSURE_ARG(_retval);
if (!CacheObserver::UseNewCache()) {
return NS_ERROR_NOT_IMPLEMENTED;
}
nsCOMPtr<nsICacheStorage> storage =
new mozilla::net::PinningCacheStorage(aLoadContextInfo);
storage.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP CacheStorageService::AppCacheStorage(nsILoadContextInfo *aLoadContextInfo,
nsIApplicationCache *aApplicationCache,
nsICacheStorage * *_retval)
@ -751,7 +770,7 @@ NS_IMETHODIMP CacheStorageService::Clear()
sGlobalEntryTables->EnumerateRead(&CollectContexts, &keys);
for (uint32_t i = 0; i < keys.Length(); ++i)
DoomStorageEntries(keys[i], nullptr, true, nullptr);
DoomStorageEntries(keys[i], nullptr, true, false, nullptr);
}
rv = CacheFileIOManager::EvictAll();
@ -1336,10 +1355,15 @@ CacheStorageService::AddStorageEntry(CacheStorage const* aStorage,
NS_ENSURE_ARG(aStorage);
nsAutoCString contextKey;
CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
CacheFileUtils::AppendKeyPrefix(aStorage, contextKey);
uint32_t pinningAppId = aStorage->IsPinning()
? aStorage->LoadInfo()->AppId()
: nsILoadContextInfo::NO_APP_ID;
return AddStorageEntry(contextKey, aURI, aIdExtension,
aStorage->WriteToDisk(), aCreateIfNotExist, aReplace,
aStorage->WriteToDisk(), pinningAppId,
aCreateIfNotExist, aReplace,
aResult);
}
@ -1348,6 +1372,7 @@ CacheStorageService::AddStorageEntry(nsCSubstring const& aContextKey,
nsIURI* aURI,
const nsACString & aIdExtension,
bool aWriteToDisk,
uint32_t aPinningAppId,
bool aCreateIfNotExist,
bool aReplace,
CacheEntryHandle** aResult)
@ -1410,7 +1435,7 @@ CacheStorageService::AddStorageEntry(nsCSubstring const& aContextKey,
// 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);
entry = new CacheEntry(aContextKey, aURI, aIdExtension, aWriteToDisk, aPinningAppId);
entries->Put(entryKey, entry);
LOG((" new entry %p for %s", entry.get(), entryKey.get()));
}
@ -1435,7 +1460,7 @@ CacheStorageService::CheckStorageEntry(CacheStorage const* aStorage,
nsresult rv;
nsAutoCString contextKey;
CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
CacheFileUtils::AppendKeyPrefix(aStorage, contextKey);
if (!aStorage->WriteToDisk()) {
AppendMemoryStorageID(contextKey);
@ -1471,6 +1496,11 @@ CacheStorageService::CheckStorageEntry(CacheStorage const* aStorage,
return NS_OK;
}
if (aStorage->IsPinning()) {
LOG((" not implemented for pinning entries"));
return NS_ERROR_NOT_AVAILABLE;
}
// Disk entry, not found in the hashtable, check the index.
nsAutoCString fileKey;
rv = CacheEntry::HashingKey(contextKey, aIdExtension, aURI, fileKey);
@ -1557,7 +1587,7 @@ CacheStorageService::DoomStorageEntry(CacheStorage const* aStorage,
NS_ENSURE_ARG(aURI);
nsAutoCString contextKey;
CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
CacheFileUtils::AppendKeyPrefix(aStorage, contextKey);
nsAutoCString entryKey;
nsresult rv = CacheEntry::HashingKey(EmptyCString(), aIdExtension, aURI, entryKey);
@ -1598,7 +1628,7 @@ CacheStorageService::DoomStorageEntry(CacheStorage const* aStorage,
if (aStorage->WriteToDisk()) {
nsAutoCString contextKey;
CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
CacheFileUtils::AppendKeyPrefix(aStorage, contextKey);
rv = CacheEntry::HashingKey(contextKey, aIdExtension, aURI, entryKey);
NS_ENSURE_SUCCESS(rv, rv);
@ -1643,18 +1673,20 @@ CacheStorageService::DoomStorageEntries(CacheStorage const* aStorage,
NS_ENSURE_ARG(aStorage);
nsAutoCString contextKey;
CacheFileUtils::AppendKeyPrefix(aStorage->LoadInfo(), contextKey);
CacheFileUtils::AppendKeyPrefix(aStorage, contextKey);
mozilla::MutexAutoLock lock(mLock);
return DoomStorageEntries(contextKey, aStorage->LoadInfo(),
aStorage->WriteToDisk(), aCallback);
aStorage->WriteToDisk(),
aStorage->IsPinning(), aCallback);
}
nsresult
CacheStorageService::DoomStorageEntries(nsCSubstring const& aContextKey,
nsILoadContextInfo* aContext,
bool aDiskStorage,
bool aPinningStorage,
nsICacheEntryDoomCallback* aCallback)
{
mLock.AssertCurrentThreadOwns();
@ -1673,7 +1705,7 @@ CacheStorageService::DoomStorageEntries(nsCSubstring const& aContextKey,
if (aContext && !aContext->IsPrivate()) {
LOG((" dooming disk entries"));
CacheFileIOManager::EvictByContext(aContext);
CacheFileIOManager::EvictByContext(aContext, aPinningStorage);
}
} else {
LOG((" dooming memory-only storage of %s", aContextKey.BeginReading()));
@ -1740,6 +1772,10 @@ CacheStorageService::WalkStorageEntries(CacheStorage const* aStorage,
NS_ENSURE_ARG(aStorage);
if (aStorage->IsPinning()) {
return NS_ERROR_NOT_AVAILABLE;
}
if (aStorage->WriteToDisk()) {
nsRefPtr<WalkDiskCacheRunnable> event =
new WalkDiskCacheRunnable(aStorage->LoadInfo(), aVisitEntries, aVisitor);
@ -1747,20 +1783,20 @@ CacheStorageService::WalkStorageEntries(CacheStorage const* aStorage,
}
nsRefPtr<WalkMemoryCacheRunnable> event =
new WalkMemoryCacheRunnable(aStorage->LoadInfo(), aVisitEntries, aVisitor);
new WalkMemoryCacheRunnable(aStorage, aVisitEntries, aVisitor);
return event->Walk();
}
void
CacheStorageService::CacheFileDoomed(nsILoadContextInfo* aLoadContextInfo,
const nsACString & aIdExtension,
const nsACString & aURISpec)
CacheFileUtils::KeyInfo* aKeyInfo)
{
nsAutoCString contextKey;
CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, contextKey);
CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, aKeyInfo->mPinningStorage, contextKey);
nsAutoCString entryKey;
CacheEntry::HashingKey(EmptyCString(), aIdExtension, aURISpec, entryKey);
CacheEntry::HashingKey(EmptyCString(),
aKeyInfo->mIdEnhance, aKeyInfo->mURISpec, entryKey);
mozilla::MutexAutoLock lock(mLock);
@ -1789,15 +1825,15 @@ CacheStorageService::CacheFileDoomed(nsILoadContextInfo* aLoadContextInfo,
bool
CacheStorageService::GetCacheEntryInfo(nsILoadContextInfo* aLoadContextInfo,
const nsACString & aIdExtension,
const nsACString & aURISpec,
CacheFileUtils::KeyInfo* aKeyInfo,
EntryInfoCallback *aCallback)
{
nsAutoCString contextKey;
CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, contextKey);
CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, aKeyInfo->mPinningStorage, contextKey);
nsAutoCString entryKey;
CacheEntry::HashingKey(EmptyCString(), aIdExtension, aURISpec, entryKey);
CacheEntry::HashingKey(EmptyCString(),
aKeyInfo->mIdEnhance, aKeyInfo->mURISpec, entryKey);
nsRefPtr<CacheEntry> entry;
{

View File

@ -29,6 +29,17 @@ class nsIEventTarget;
namespace mozilla {
namespace net {
namespace CacheFileUtils {
class KeyInfo {
public:
bool mPinningStorage;
nsCString mIdEnhance;
nsCString mURISpec;
};
} // CacheFileUtils
class CacheStorageService;
class CacheStorage;
class CacheEntry;
@ -229,20 +240,18 @@ private:
* removal was originated by CacheStorageService.
*/
void CacheFileDoomed(nsILoadContextInfo* aLoadContextInfo,
const nsACString & aIdExtension,
const nsACString & aURISpec);
CacheFileUtils::KeyInfo* aKeyInfo);
/**
* Tries to find an existing entry in the hashtables and synchronously call
* OnCacheEntryInfo of the aVisitor callback when found.
* @retuns
* true, when the entry has been found that also implies the callbacks has
* beem invoked
* been invoked
* false, when an entry has not been found
*/
bool GetCacheEntryInfo(nsILoadContextInfo* aLoadContextInfo,
const nsACString & aIdExtension,
const nsACString & aURISpec,
CacheFileUtils::KeyInfo* aKeyInfo,
EntryInfoCallback *aCallback);
private:
@ -273,11 +282,13 @@ private:
nsresult DoomStorageEntries(nsCSubstring const& aContextKey,
nsILoadContextInfo* aContext,
bool aDiskStorage,
bool aPinningStorage,
nsICacheEntryDoomCallback* aCallback);
nsresult AddStorageEntry(nsCSubstring const& aContextKey,
nsIURI* aURI,
const nsACString & aIdExtension,
bool aWriteToDisk,
uint32_t aPinningAppId,
bool aCreateIfNotExist,
bool aReplace,
CacheEntryHandle** aResult);

View File

@ -0,0 +1,25 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PinningCacheStorage.h"
namespace mozilla {
namespace net {
bool PinningCacheStorage::IsPinning() const
{
if (LoadInfo()->AppId() == nsILoadContextInfo::NO_APP_ID) {
return false;
}
if (LoadInfo()->IsPrivate()) {
return false;
}
// We are a non-private app load, pin!
return true;
}
} // net
} // mozilla

View File

@ -0,0 +1,27 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PinninCacheStorage__h__
#define PinninCacheStorage__h__
#include "CacheStorage.h"
namespace mozilla {
namespace net {
class PinningCacheStorage : public CacheStorage
{
public:
PinningCacheStorage(nsILoadContextInfo* aInfo)
: CacheStorage(aInfo, true, false)
{
}
virtual bool IsPinning() const override;
};
} // net
} // mozilla
#endif

View File

@ -40,6 +40,7 @@ UNIFIED_SOURCES += [
'CacheStorage.cpp',
'CacheStorageService.cpp',
'OldWrappers.cpp',
'PinningCacheStorage.cpp',
]
# AppCacheStorage.cpp cannot be built in unified mode because it uses plarena.h.

View File

@ -13,7 +13,7 @@ interface nsICacheStorageConsumptionObserver;
/**
* Provides access to particual cache storages of the network URI cache.
*/
[scriptable, uuid(44de2fa4-1b0e-4cd3-9e32-211e936f721e)]
[scriptable, uuid(6764d6a5-af42-4655-aef2-81d9efe72ae6)]
interface nsICacheStorageService : nsISupports
{
/**
@ -42,6 +42,14 @@ interface nsICacheStorageService : nsISupports
nsICacheStorage diskCacheStorage(in nsILoadContextInfo aLoadContextInfo,
in bool aLookupAppCache);
/**
* Entries bound to an app will be persisted in a roaming part of the profile
* and won't unpersist until the app goes away. Common web content will use
* disk cache storage, when under the private browsing mode, entries will be
* held in memory and evicted on limit.
*/
nsICacheStorage pinningCacheStorage(in nsILoadContextInfo aLoadContextInfo);
/**
* Get storage for a specified application cache obtained using some different
* mechanism.

View File

@ -42,7 +42,7 @@ LogURI(const char *aFunctionName, void *self, nsIURI *aURI, nsILoadContextInfo *
nsAutoCString prefix;
if (aInfo) {
CacheFileUtils::AppendKeyPrefix(aInfo, prefix);
CacheFileUtils::AppendKeyPrefix(aInfo, false, prefix);
prefix += ":";
}
@ -627,7 +627,7 @@ PackagedAppService::RequestURI(nsIURI *aURI,
}
nsAutoCString key;
CacheFileUtils::AppendKeyPrefix(aInfo, key);
CacheFileUtils::AppendKeyPrefix(aInfo, false, key);
{
nsAutoCString spec;

View File

@ -260,6 +260,7 @@ nsHttpChannel::nsHttpChannel()
, mConcurentCacheAccess(0)
, mIsPartialRequest(0)
, mHasAutoRedirectVetoNotifier(0)
, mPinCacheContent(0)
, mIsPackagedAppResource(0)
, mPushedStream(nullptr)
, mLocalBlocklist(false)
@ -2847,6 +2848,10 @@ nsHttpChannel::OpenCacheEntry(bool isHttps)
rv = cacheStorageService->MemoryCacheStorage(info, // ? choose app cache as well...
getter_AddRefs(cacheStorage));
}
else if (mPinCacheContent) {
rv = cacheStorageService->PinningCacheStorage(info,
getter_AddRefs(cacheStorage));
}
else {
rv = cacheStorageService->DiskCacheStorage(info,
!mPostID && (mChooseApplicationCache || (mLoadFlags & LOAD_CHECK_OFFLINE_CACHE)),
@ -6271,6 +6276,26 @@ nsHttpChannel::SetCacheOnlyMetadata(bool aOnlyMetadata)
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::GetPin(bool *aPin)
{
NS_ENSURE_ARG(aPin);
*aPin = mPinCacheContent;
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::SetPin(bool aPin)
{
LOG(("nsHttpChannel::SetPin [this=%p pin=%d]\n",
this, aPin));
ENSURE_CALLED_BEFORE_ASYNC_OPEN();
mPinCacheContent = aPin;
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsIResumableChannel
//-----------------------------------------------------------------------------

View File

@ -479,6 +479,9 @@ private:
uint32_t mIsPartialRequest : 1;
// true iff there is AutoRedirectVetoNotifier on the stack
uint32_t mHasAutoRedirectVetoNotifier : 1;
// consumers set this to true to use cache pinning, this has effect
// only when the channel is in an app context (load context has an appid)
uint32_t mPinCacheContent : 1;
// Whether fetching the content is meant to be handled by the
// packaged app service, which behaves like a caching layer.
// Upon successfully fetching the package, the resource will be placed in

View File

@ -50,6 +50,7 @@ function getCacheStorage(where, lci, appcache)
case "disk": return svc.diskCacheStorage(lci, false);
case "memory": return svc.memoryCacheStorage(lci);
case "appcache": return svc.appCacheStorage(lci, appcache);
case "pin": return svc.pinningCacheStorage(lci);
}
return null;
}

View File

@ -0,0 +1,30 @@
function run_test()
{
do_get_profile();
var applci = LoadContextInfo.custom(false, false, 1001, false);
// Open for write, write
asyncOpenCacheEntry("http://a/", "pin", Ci.nsICacheStorage.OPEN_NORMALLY, applci,
new OpenCallback(NEW|WAITFORWRITE, "a1m", "a1d", function(entry) {
// Open for read and check
asyncOpenCacheEntry("http://a/", "pin", Ci.nsICacheStorage.OPEN_NORMALLY, applci,
new OpenCallback(NORMAL, "a1m", "a1d", function(entry) {
// Now clear the whole cache
get_cache_service().clear();
// The pinned entry should be intact
asyncOpenCacheEntry("http://a/", "pin", Ci.nsICacheStorage.OPEN_NORMALLY, applci,
new OpenCallback(NORMAL, "a1m", "a1d", function(entry) {
finish_cache2_test();
})
);
})
);
})
);
do_test_pending();
}

View File

@ -101,7 +101,8 @@ function run_test() {
function doneFirstLoad(req, buffer, expected) {
// Load it again, make sure it hits the cache
var chan = makeChan(URL, 0, false);
var nc = req.notificationCallbacks.getInterface(Ci.nsILoadContext);
var chan = makeChan(URL, nc.appId, nc.isInBrowserElement);
chan.asyncOpen(new ChannelListener(doneSecondLoad, expected), null);
}

View File

@ -68,8 +68,9 @@ skip-if = true
[test_cache2-28a-OPEN_SECRETLY.js]
# This test will be fixed in bug 1067931
skip-if = true
[test_cache2-28-concurrent_read_resumable_entry_size_zero.js]
[test_cache2-29-concurrent_read_non-resumable_entry_size_zero.js]
[test_cache2-29a-concurrent_read_resumable_entry_size_zero.js]
[test_cache2-29b-concurrent_read_non-resumable_entry_size_zero.js]
[test_cache2-30-app-pinning.js]
[test_partial_response_entry_size_smart_shrink.js]
[test_304_responses.js]
[test_421.js]