mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 968106 - HTTP cache v2: implementation of the eviction of the whole disk cache, r=honzab
This commit is contained in:
parent
72173a705a
commit
6d22e72788
@ -1,96 +0,0 @@
|
||||
/* 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 "CacheEntriesEnumerator.h"
|
||||
|
||||
#include "CacheFileIOManager.h"
|
||||
#include "CacheFile.h"
|
||||
|
||||
#include "nsIDirectoryEnumerator.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
CacheEntriesEnumerator::CacheEntriesEnumerator(nsIFile* aEntriesDirectory)
|
||||
: mEntriesDirectory(aEntriesDirectory)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CacheEntriesEnumerator);
|
||||
}
|
||||
|
||||
CacheEntriesEnumerator::~CacheEntriesEnumerator()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CacheEntriesEnumerator);
|
||||
|
||||
if (mEnumerator) {
|
||||
mEnumerator->Close();
|
||||
ProxyReleaseMainThread(mEnumerator);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult CacheEntriesEnumerator::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> e;
|
||||
rv = mEntriesDirectory->GetDirectoryEntries(getter_AddRefs(e));
|
||||
|
||||
if (NS_ERROR_FILE_NOT_FOUND == rv || NS_ERROR_FILE_TARGET_DOES_NOT_EXIST == rv) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mEnumerator = do_QueryInterface(e, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool CacheEntriesEnumerator::HasMore()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!mThreadCheck)
|
||||
mThreadCheck = NS_GetCurrentThread();
|
||||
else
|
||||
MOZ_ASSERT(mThreadCheck == NS_GetCurrentThread());
|
||||
#endif
|
||||
|
||||
if (!mEnumerator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mCurrentFile)
|
||||
return true;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
rv = mEnumerator->GetNextFile(getter_AddRefs(mCurrentFile));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mEnumerator->Close();
|
||||
mEnumerator = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!mCurrentFile;
|
||||
}
|
||||
|
||||
nsresult CacheEntriesEnumerator::GetNextFile(nsIFile** aFile)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(mThreadCheck == NS_GetCurrentThread());
|
||||
#endif
|
||||
|
||||
NS_ENSURE_TRUE(mCurrentFile, NS_ERROR_UNEXPECTED);
|
||||
|
||||
mCurrentFile.forget(aFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // net
|
||||
} // mozilla
|
@ -1,53 +0,0 @@
|
||||
/* 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 CacheEntriesEnumerator__h__
|
||||
#define CacheEntriesEnumerator__h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIFile;
|
||||
class nsIDirectoryEnumerator;
|
||||
class nsIThread;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class CacheFileIOManager;
|
||||
class CacheFileListener;
|
||||
class CacheFile;
|
||||
|
||||
class CacheEntriesEnumeratorCallback : public nsISupports
|
||||
{
|
||||
public:
|
||||
virtual void OnFile(CacheFile* aFile) = 0;
|
||||
};
|
||||
|
||||
class CacheEntriesEnumerator
|
||||
{
|
||||
public:
|
||||
~CacheEntriesEnumerator();
|
||||
|
||||
bool HasMore();
|
||||
nsresult GetNextFile(nsIFile** aFile);
|
||||
|
||||
protected:
|
||||
friend class CacheFileIOManager;
|
||||
CacheEntriesEnumerator(nsIFile* aEntriesDirectory);
|
||||
nsresult Init();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDirectoryEnumerator> mEnumerator;
|
||||
nsCOMPtr<nsIFile> mEntriesDirectory;
|
||||
nsCOMPtr<nsIFile> mCurrentFile;
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIThread> mThreadCheck;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // net
|
||||
} // mozilla
|
||||
|
||||
#endif
|
@ -17,9 +17,11 @@
|
||||
#include "nsITimer.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsIDirectoryEnumerator.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsISizeOf.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "private/pprio.h"
|
||||
@ -437,6 +439,30 @@ CacheFileHandles::GetAllHandles(nsTArray<nsRefPtr<CacheFileHandle> > *_retval)
|
||||
mTable.EnumerateEntries(&GetAllHandlesEnum, _retval);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
GetActiveHandlesEnum(CacheFileHandles::HandleHashKey* aEntry, void *aClosure)
|
||||
{
|
||||
nsTArray<nsRefPtr<CacheFileHandle> > *array =
|
||||
static_cast<nsTArray<nsRefPtr<CacheFileHandle> > *>(aClosure);
|
||||
|
||||
nsRefPtr<CacheFileHandle> handle = aEntry->GetNewestHandle();
|
||||
MOZ_ASSERT(handle);
|
||||
|
||||
if (!handle->IsDoomed()) {
|
||||
array->AppendElement(handle);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
CacheFileHandles::GetActiveHandles(
|
||||
nsTArray<nsRefPtr<CacheFileHandle> > *_retval)
|
||||
{
|
||||
MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased());
|
||||
mTable.EnumerateEntries(&GetActiveHandlesEnum, _retval);
|
||||
}
|
||||
|
||||
void
|
||||
CacheFileHandles::ClearAll()
|
||||
{
|
||||
@ -1111,6 +1137,7 @@ CacheFileIOManager::~CacheFileIOManager()
|
||||
MOZ_COUNT_DTOR(CacheFileIOManager);
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::Init()
|
||||
{
|
||||
@ -1147,6 +1174,7 @@ CacheFileIOManager::InitInternal()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::Shutdown()
|
||||
{
|
||||
@ -1251,6 +1279,7 @@ CacheFileIOManager::ShutdownInternal()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::OnProfile()
|
||||
{
|
||||
@ -1487,6 +1516,7 @@ CacheFileIOManager::Notify(nsITimer * aTimer)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::OpenFile(const nsACString &aKey,
|
||||
uint32_t aFlags,
|
||||
@ -1733,6 +1763,7 @@ CacheFileIOManager::CloseHandleInternal(CacheFileHandle *aHandle)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::Read(CacheFileHandle *aHandle, int64_t aOffset,
|
||||
char *aBuf, int32_t aCount,
|
||||
@ -1798,6 +1829,7 @@ CacheFileIOManager::ReadInternal(CacheFileHandle *aHandle, int64_t aOffset,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::Write(CacheFileHandle *aHandle, int64_t aOffset,
|
||||
const char *aBuf, int32_t aCount, bool aValidate,
|
||||
@ -1881,6 +1913,7 @@ CacheFileIOManager::WriteInternal(CacheFileHandle *aHandle, int64_t aOffset,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::DoomFile(CacheFileHandle *aHandle,
|
||||
CacheFileIOListener *aCallback)
|
||||
@ -1968,6 +2001,7 @@ CacheFileIOManager::DoomFileInternal(CacheFileHandle *aHandle)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::DoomFileByKey(const nsACString &aKey,
|
||||
CacheFileIOListener *aCallback)
|
||||
@ -2048,6 +2082,7 @@ CacheFileIOManager::DoomFileByKeyInternal(const SHA1Sum::Hash *aHash)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::ReleaseNSPRHandle(CacheFileHandle *aHandle)
|
||||
{
|
||||
@ -2085,6 +2120,7 @@ CacheFileIOManager::ReleaseNSPRHandleInternal(CacheFileHandle *aHandle)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::TruncateSeekSetEOF(CacheFileHandle *aHandle,
|
||||
int64_t aTruncatePos, int64_t aEOFPos,
|
||||
@ -2186,6 +2222,7 @@ CacheFileIOManager::TruncateSeekSetEOFInternal(CacheFileHandle *aHandle,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::RenameFile(CacheFileHandle *aHandle,
|
||||
const nsACString &aNewName,
|
||||
@ -2274,6 +2311,7 @@ CacheFileIOManager::RenameFileInternal(CacheFileHandle *aHandle,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::EvictIfOverLimit()
|
||||
{
|
||||
@ -2439,6 +2477,122 @@ CacheFileIOManager::OverLimitEvictionInternal()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::EvictAll()
|
||||
{
|
||||
LOG(("CacheFileIOManager::EvictAll()"));
|
||||
|
||||
nsresult rv;
|
||||
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
|
||||
|
||||
if (!ioMan) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> ev;
|
||||
ev = NS_NewRunnableMethod(ioMan, &CacheFileIOManager::EvictAllInternal);
|
||||
|
||||
rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::OPEN_PRIORITY);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class EvictionNotifierRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
EvictionNotifierRunnable::Run()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
|
||||
if (obsSvc) {
|
||||
obsSvc->NotifyObservers(nullptr, "cacheservice:empty-cache", nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
nsresult
|
||||
CacheFileIOManager::EvictAllInternal()
|
||||
{
|
||||
LOG(("CacheFileIOManager::EvictAllInternal()"));
|
||||
|
||||
nsresult rv;
|
||||
|
||||
MOZ_ASSERT(mIOThread->IsCurrentThread());
|
||||
|
||||
nsRefPtr<EvictionNotifierRunnable> r = new EvictionNotifierRunnable();
|
||||
|
||||
if (!mCacheDirectory) {
|
||||
// This is a kind of hack. Somebody called EvictAll() without a profile.
|
||||
// This happens in xpcshell tests that use cache without profile. We need
|
||||
// to notify observers in this case since the tests are waiting for it.
|
||||
NS_DispatchToMainThread(r);
|
||||
return NS_ERROR_FILE_INVALID_PATH;
|
||||
}
|
||||
|
||||
if (mShuttingDown) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (!mTreeCreated) {
|
||||
rv = CreateCacheTree();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Doom all active handles
|
||||
nsTArray<nsRefPtr<CacheFileHandle> > handles;
|
||||
mHandles.GetActiveHandles(&handles);
|
||||
|
||||
for (uint32_t i = 0; i < handles.Length(); ++i) {
|
||||
rv = DoomFileInternal(handles[i]);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = mCacheDirectory->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->AppendNative(NS_LITERAL_CSTRING(kEntriesDir));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Trash current entries directory
|
||||
rv = TrashDirectory(file);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Files are now inaccessible in entries directory, notify observers.
|
||||
NS_DispatchToMainThread(r);
|
||||
|
||||
// Create a new empty entries directory
|
||||
rv = CheckAndCreateDir(mCacheDirectory, kEntriesDir, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
CacheIndex::RemoveAll();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheFileIOManager::TrashDirectory(nsIFile *aFile)
|
||||
{
|
||||
@ -2510,6 +2664,7 @@ CacheFileIOManager::TrashDirectory(nsIFile *aFile)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
CacheFileIOManager::OnTrashTimer(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
@ -2755,6 +2910,7 @@ CacheFileIOManager::FindTrashDirToRemove()
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::InitIndexEntry(CacheFileHandle *aHandle,
|
||||
uint32_t aAppId,
|
||||
@ -2783,6 +2939,7 @@ CacheFileIOManager::InitIndexEntry(CacheFileHandle *aHandle,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::UpdateIndexEntry(CacheFileHandle *aHandle,
|
||||
const uint32_t *aFrecency,
|
||||
@ -2812,54 +2969,6 @@ CacheFileIOManager::UpdateIndexEntry(CacheFileHandle *aHandle,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheFileIOManager::EnumerateEntryFiles(EEnumerateMode aMode,
|
||||
CacheEntriesEnumerator** aEnumerator)
|
||||
{
|
||||
LOG(("CacheFileIOManager::EnumerateEntryFiles(%d)", aMode));
|
||||
|
||||
nsresult rv;
|
||||
nsRefPtr<CacheFileIOManager> ioMan = gInstance;
|
||||
|
||||
if (!ioMan) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (!ioMan->mCacheDirectory) {
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = ioMan->mCacheDirectory->Clone(getter_AddRefs(file));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
switch (aMode) {
|
||||
case ENTRIES:
|
||||
rv = file->AppendNative(NS_LITERAL_CSTRING(kEntriesDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
break;
|
||||
|
||||
case DOOMED:
|
||||
rv = file->AppendNative(NS_LITERAL_CSTRING(kDoomedDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsAutoPtr<CacheEntriesEnumerator> enumerator(
|
||||
new CacheEntriesEnumerator(file));
|
||||
|
||||
rv = enumerator->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aEnumerator = enumerator.forget();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheFileIOManager::CreateFile(CacheFileHandle *aHandle)
|
||||
{
|
||||
@ -2889,6 +2998,7 @@ CacheFileIOManager::CreateFile(CacheFileHandle *aHandle)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
CacheFileIOManager::HashToStr(const SHA1Sum::Hash *aHash, nsACString &_retval)
|
||||
{
|
||||
@ -2901,6 +3011,7 @@ CacheFileIOManager::HashToStr(const SHA1Sum::Hash *aHash, nsACString &_retval)
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheFileIOManager::StrToHash(const nsACString &aHash, SHA1Sum::Hash *_retval)
|
||||
{
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define CacheFileIOManager__h__
|
||||
|
||||
#include "CacheIOThread.h"
|
||||
#include "CacheEntriesEnumerator.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@ -26,6 +25,7 @@ class nsIDirectoryEnumerator;
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class CacheFile;
|
||||
#ifdef DEBUG_HANDLES
|
||||
class CacheFileHandlesEntry;
|
||||
#endif
|
||||
@ -90,6 +90,7 @@ public:
|
||||
nsresult NewHandle(const SHA1Sum::Hash *aHash, bool aPriority, CacheFileHandle **_retval);
|
||||
void RemoveHandle(CacheFileHandle *aHandlle);
|
||||
void GetAllHandles(nsTArray<nsRefPtr<CacheFileHandle> > *_retval);
|
||||
void GetActiveHandles(nsTArray<nsRefPtr<CacheFileHandle> > *_retval);
|
||||
void ClearAll();
|
||||
uint32_t HandleCount();
|
||||
|
||||
@ -255,6 +256,7 @@ public:
|
||||
const nsACString &aNewName,
|
||||
CacheFileIOListener *aCallback);
|
||||
static nsresult EvictIfOverLimit();
|
||||
static nsresult EvictAll();
|
||||
|
||||
static nsresult InitIndexEntry(CacheFileHandle *aHandle,
|
||||
uint32_t aAppId,
|
||||
@ -271,9 +273,6 @@ public:
|
||||
DOOMED
|
||||
};
|
||||
|
||||
static nsresult EnumerateEntryFiles(EEnumerateMode aMode,
|
||||
CacheEntriesEnumerator** aEnumerator);
|
||||
|
||||
static void GetCacheDirectory(nsIFile** result);
|
||||
|
||||
// Memory reporting
|
||||
@ -322,6 +321,7 @@ private:
|
||||
const nsACString &aNewName);
|
||||
nsresult EvictIfOverLimitInternal();
|
||||
nsresult OverLimitEvictionInternal();
|
||||
nsresult EvictAllInternal();
|
||||
|
||||
nsresult TrashDirectory(nsIFile *aFile);
|
||||
static void OnTrashTimer(nsITimer *aTimer, void *aClosure);
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
WRITE,
|
||||
MANAGEMENT,
|
||||
CLOSE,
|
||||
BUILD_OR_UPDATE_INDEX,
|
||||
INDEX,
|
||||
EVICT,
|
||||
LAST_LEVEL,
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "prinrval.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsITimer.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
@ -221,6 +222,72 @@ private:
|
||||
bool mLocked;
|
||||
};
|
||||
|
||||
class FileOpenHelper : public CacheFileIOListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
FileOpenHelper(CacheIndex* aIndex)
|
||||
: mIndex(aIndex)
|
||||
, mCanceled(false)
|
||||
{}
|
||||
|
||||
virtual ~FileOpenHelper() {}
|
||||
|
||||
void Cancel() {
|
||||
mIndex->AssertOwnsLock();
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
private:
|
||||
NS_IMETHOD OnFileOpened(CacheFileHandle *aHandle, nsresult aResult);
|
||||
NS_IMETHOD OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
|
||||
nsresult aResult) {
|
||||
MOZ_CRASH("FileOpenHelper::OnDataWritten should not be called!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf,
|
||||
nsresult aResult) {
|
||||
MOZ_CRASH("FileOpenHelper::OnDataRead should not be called!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
NS_IMETHOD OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult) {
|
||||
MOZ_CRASH("FileOpenHelper::OnFileDoomed should not be called!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
NS_IMETHOD OnEOFSet(CacheFileHandle *aHandle, nsresult aResult) {
|
||||
MOZ_CRASH("FileOpenHelper::OnEOFSet should not be called!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) {
|
||||
MOZ_CRASH("FileOpenHelper::OnFileRenamed should not be called!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsRefPtr<CacheIndex> mIndex;
|
||||
bool mCanceled;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP FileOpenHelper::OnFileOpened(CacheFileHandle *aHandle,
|
||||
nsresult aResult)
|
||||
{
|
||||
CacheIndexAutoLock lock(mIndex);
|
||||
|
||||
if (mCanceled) {
|
||||
if (aHandle) {
|
||||
CacheFileIOManager::DoomFile(aHandle, nullptr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mIndex->OnFileOpenedInternal(this, aHandle, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(FileOpenHelper, CacheFileIOListener);
|
||||
|
||||
|
||||
CacheIndex * CacheIndex::gInstance = nullptr;
|
||||
|
||||
@ -239,16 +306,16 @@ CacheIndex::CacheIndex()
|
||||
, mState(INITIAL)
|
||||
, mShuttingDown(false)
|
||||
, mIndexNeedsUpdate(false)
|
||||
, mRemovingAll(false)
|
||||
, mIndexOnDiskIsValid(false)
|
||||
, mDontMarkIndexClean(false)
|
||||
, mIndexTimeStamp(0)
|
||||
, mUpdateEventPending(false)
|
||||
, mSkipEntries(0)
|
||||
, mProcessEntries(0)
|
||||
, mRWBuf(nullptr)
|
||||
, mRWBufSize(0)
|
||||
, mRWBufPos(0)
|
||||
, mReadOpenCount(0)
|
||||
, mReadFailed(false)
|
||||
, mJournalReadSuccessfully(false)
|
||||
{
|
||||
LOG(("CacheIndex::CacheIndex [this=%p]", this));
|
||||
@ -300,6 +367,8 @@ CacheIndex::Init(nsIFile *aCacheDirectory)
|
||||
|
||||
nsRefPtr<CacheIndex> idx = new CacheIndex();
|
||||
|
||||
CacheIndexAutoLock lock(idx);
|
||||
|
||||
nsresult rv = idx->InitInternal(aCacheDirectory);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -315,20 +384,9 @@ CacheIndex::InitInternal(nsIFile *aCacheDirectory)
|
||||
rv = aCacheDirectory->Clone(getter_AddRefs(mCacheDirectory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ChangeState(READING);
|
||||
|
||||
mStartTime = TimeStamp::NowLoRes();
|
||||
|
||||
// dispatch an event since IO manager's path is not initialized yet
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
event = NS_NewRunnableMethod(this, &CacheIndex::ReadIndexFromDisk);
|
||||
|
||||
rv = NS_DispatchToCurrentThread(event);
|
||||
if (NS_FAILED(rv)) {
|
||||
ChangeState(INITIAL);
|
||||
LOG(("CacheIndex::InitInternal() - Cannot dispatch event"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
ReadIndexFromDisk();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -390,8 +448,8 @@ CacheIndex::PreShutdownInternal()
|
||||
|
||||
MOZ_ASSERT(mShuttingDown);
|
||||
|
||||
if (mTimer) {
|
||||
mTimer = nullptr;
|
||||
if (mUpdateTimer) {
|
||||
mUpdateTimer = nullptr;
|
||||
}
|
||||
|
||||
switch (mState) {
|
||||
@ -405,8 +463,6 @@ CacheIndex::PreShutdownInternal()
|
||||
FinishRead(false);
|
||||
break;
|
||||
case BUILDING:
|
||||
FinishBuild(false);
|
||||
break;
|
||||
case UPDATING:
|
||||
FinishUpdate(false);
|
||||
break;
|
||||
@ -466,8 +522,6 @@ CacheIndex::Shutdown()
|
||||
index->FinishRead(false);
|
||||
break;
|
||||
case BUILDING:
|
||||
index->FinishBuild(false);
|
||||
break;
|
||||
case UPDATING:
|
||||
index->FinishUpdate(false);
|
||||
break;
|
||||
@ -978,6 +1032,90 @@ CacheIndex::UpdateEntry(const SHA1Sum::Hash *aHash,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheIndex::RemoveAll()
|
||||
{
|
||||
LOG(("CacheIndex::RemoveAll()"));
|
||||
|
||||
nsRefPtr<CacheIndex> index = gInstance;
|
||||
|
||||
if (!index) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
|
||||
{
|
||||
CacheIndexAutoLock lock(index);
|
||||
|
||||
MOZ_ASSERT(!index->mRemovingAll);
|
||||
|
||||
if (!index->IsIndexUsable()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
AutoRestore<bool> saveRemovingAll(index->mRemovingAll);
|
||||
index->mRemovingAll = true;
|
||||
|
||||
// Doom index and journal handles but don't null them out since this will be
|
||||
// done in FinishWrite/FinishRead methods.
|
||||
if (index->mIndexHandle) {
|
||||
CacheFileIOManager::DoomFile(index->mIndexHandle, nullptr);
|
||||
} else {
|
||||
// We don't have a handle to index file, so get the file here, but delete
|
||||
// it outside the lock. Ignore the result since this is not fatal.
|
||||
index->GetFile(NS_LITERAL_CSTRING(kIndexName), getter_AddRefs(file));
|
||||
}
|
||||
|
||||
if (index->mJournalHandle) {
|
||||
CacheFileIOManager::DoomFile(index->mJournalHandle, nullptr);
|
||||
}
|
||||
|
||||
switch (index->mState) {
|
||||
case WRITING:
|
||||
index->FinishWrite(false);
|
||||
break;
|
||||
case READY:
|
||||
// nothing to do
|
||||
break;
|
||||
case READING:
|
||||
index->FinishRead(false);
|
||||
break;
|
||||
case BUILDING:
|
||||
case UPDATING:
|
||||
index->FinishUpdate(false);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unexpected state!");
|
||||
}
|
||||
|
||||
// We should end up in READY state
|
||||
MOZ_ASSERT(index->mState == READY);
|
||||
|
||||
// There should not be any handle
|
||||
MOZ_ASSERT(!index->mIndexHandle);
|
||||
MOZ_ASSERT(!index->mJournalHandle);
|
||||
|
||||
index->mIndexOnDiskIsValid = false;
|
||||
index->mIndexNeedsUpdate = false;
|
||||
|
||||
index->mIndexStats.Clear();
|
||||
index->mFrecencyArray.Clear();
|
||||
index->mExpirationArray.Clear();
|
||||
index->mIndex.Clear();
|
||||
}
|
||||
|
||||
if (file) {
|
||||
// Ignore the result. The file might not exist and the failure is not fatal.
|
||||
file->Remove(false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
CacheIndex::HasEntry(const nsACString &aKey, EntryStatus *_retval)
|
||||
@ -1274,10 +1412,11 @@ CacheIndex::WriteIndexToDisk()
|
||||
|
||||
mProcessEntries = mIndexStats.ActiveEntriesCount();
|
||||
|
||||
mIndexFileOpener = new FileOpenHelper(this);
|
||||
rv = CacheFileIOManager::OpenFile(NS_LITERAL_CSTRING(kTempIndexName),
|
||||
CacheFileIOManager::SPECIAL_FILE |
|
||||
CacheFileIOManager::CREATE,
|
||||
this);
|
||||
mIndexFileOpener);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("CacheIndex::WriteIndexToDisk() - Can't open file [rv=0x%08x]", rv));
|
||||
FinishWrite(false);
|
||||
@ -1396,8 +1535,19 @@ CacheIndex::FinishWrite(bool aSucceeded)
|
||||
ReleaseBuffer();
|
||||
|
||||
if (aSucceeded) {
|
||||
// Opening of the file must not be in progress if writing succeeded.
|
||||
MOZ_ASSERT(!mIndexFileOpener);
|
||||
|
||||
mIndex.EnumerateEntries(&CacheIndex::ApplyIndexChanges, this);
|
||||
mIndexOnDiskIsValid = true;
|
||||
} else {
|
||||
if (mIndexFileOpener) {
|
||||
// If opening of the file is still in progress (e.g. WRITE process was
|
||||
// canceled by RemoveAll()) then we need to cancel the opener to make sure
|
||||
// that OnFileOpenedInternal() won't be called.
|
||||
mIndexFileOpener->Cancel();
|
||||
mIndexFileOpener = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ProcessPendingOperations();
|
||||
@ -1702,50 +1852,42 @@ CacheIndex::ReadIndexFromDisk()
|
||||
|
||||
nsresult rv;
|
||||
|
||||
CacheIndexAutoLock lock(this);
|
||||
AssertOwnsLock();
|
||||
MOZ_ASSERT(mState == INITIAL);
|
||||
|
||||
MOZ_ASSERT(mState == READING);
|
||||
|
||||
mReadFailed = false;
|
||||
mReadOpenCount = 0;
|
||||
ChangeState(READING);
|
||||
|
||||
mIndexFileOpener = new FileOpenHelper(this);
|
||||
rv = CacheFileIOManager::OpenFile(NS_LITERAL_CSTRING(kIndexName),
|
||||
CacheFileIOManager::SPECIAL_FILE |
|
||||
CacheFileIOManager::OPEN,
|
||||
this);
|
||||
mIndexFileOpener);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("CacheIndex::ReadIndexFromDisk() - CacheFileIOManager::OpenFile() "
|
||||
"failed [rv=0x%08x, file=%s]", rv, kIndexName));
|
||||
mReadFailed = true;
|
||||
} else {
|
||||
mReadOpenCount++;
|
||||
FinishRead(false);
|
||||
return;
|
||||
}
|
||||
|
||||
mJournalFileOpener = new FileOpenHelper(this);
|
||||
rv = CacheFileIOManager::OpenFile(NS_LITERAL_CSTRING(kJournalName),
|
||||
CacheFileIOManager::SPECIAL_FILE |
|
||||
CacheFileIOManager::OPEN,
|
||||
this);
|
||||
mJournalFileOpener);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("CacheIndex::ReadIndexFromDisk() - CacheFileIOManager::OpenFile() "
|
||||
"failed [rv=0x%08x, file=%s]", rv, kJournalName));
|
||||
mReadFailed = true;
|
||||
} else {
|
||||
mReadOpenCount++;
|
||||
FinishRead(false);
|
||||
}
|
||||
|
||||
mTmpFileOpener = new FileOpenHelper(this);
|
||||
rv = CacheFileIOManager::OpenFile(NS_LITERAL_CSTRING(kTempIndexName),
|
||||
CacheFileIOManager::SPECIAL_FILE |
|
||||
CacheFileIOManager::OPEN,
|
||||
this);
|
||||
mTmpFileOpener);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("CacheIndex::ReadIndexFromDisk() - CacheFileIOManager::OpenFile() "
|
||||
"failed [rv=0x%08x, file=%s]", rv, kTempIndexName));
|
||||
mReadFailed = true;
|
||||
} else {
|
||||
mReadOpenCount++;
|
||||
}
|
||||
|
||||
if (mReadOpenCount == 0) {
|
||||
FinishRead(false);
|
||||
}
|
||||
}
|
||||
@ -2133,6 +2275,19 @@ CacheIndex::FinishRead(bool aSucceeded)
|
||||
}
|
||||
}
|
||||
|
||||
if (mIndexFileOpener) {
|
||||
mIndexFileOpener->Cancel();
|
||||
mIndexFileOpener = nullptr;
|
||||
}
|
||||
if (mJournalFileOpener) {
|
||||
mJournalFileOpener->Cancel();
|
||||
mJournalFileOpener = nullptr;
|
||||
}
|
||||
if (mTmpFileOpener) {
|
||||
mTmpFileOpener->Cancel();
|
||||
mTmpFileOpener = nullptr;
|
||||
}
|
||||
|
||||
mIndexHandle = nullptr;
|
||||
mJournalHandle = nullptr;
|
||||
mRWHash = nullptr;
|
||||
@ -2148,7 +2303,7 @@ CacheIndex::FinishRead(bool aSucceeded)
|
||||
ProcessPendingOperations();
|
||||
// Remove all entries that we haven't seen during this session
|
||||
mIndex.EnumerateEntries(&CacheIndex::RemoveNonFreshEntries, this);
|
||||
StartBuildingIndex();
|
||||
StartUpdatingIndex(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2156,7 +2311,7 @@ CacheIndex::FinishRead(bool aSucceeded)
|
||||
mTmpJournal.Clear();
|
||||
EnsureNoFreshEntry();
|
||||
ProcessPendingOperations();
|
||||
StartUpdatingIndex();
|
||||
StartUpdatingIndex(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2171,9 +2326,9 @@ CacheIndex::FinishRead(bool aSucceeded)
|
||||
|
||||
// static
|
||||
void
|
||||
CacheIndex::DelayedBuildUpdate(nsITimer *aTimer, void *aClosure)
|
||||
CacheIndex::DelayedUpdate(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
LOG(("CacheIndex::DelayedBuildUpdate()"));
|
||||
LOG(("CacheIndex::DelayedUpdate()"));
|
||||
|
||||
nsresult rv;
|
||||
nsRefPtr<CacheIndex> index = gInstance;
|
||||
@ -2184,7 +2339,7 @@ CacheIndex::DelayedBuildUpdate(nsITimer *aTimer, void *aClosure)
|
||||
|
||||
CacheIndexAutoLock lock(index);
|
||||
|
||||
index->mTimer = nullptr;
|
||||
index->mUpdateTimer = nullptr;
|
||||
|
||||
if (!index->IsIndexUsable()) {
|
||||
return;
|
||||
@ -2194,30 +2349,34 @@ CacheIndex::DelayedBuildUpdate(nsITimer *aTimer, void *aClosure)
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(index->mState == BUILDING || index->mState == UPDATING);
|
||||
// mUpdateEventPending must be false here since StartUpdatingIndex() won't
|
||||
// schedule timer if it is true.
|
||||
MOZ_ASSERT(!index->mUpdateEventPending);
|
||||
if (index->mState != BUILDING && index->mState != UPDATING) {
|
||||
LOG(("CacheIndex::DelayedUpdate() - Update was canceled"));
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to redispatch to run with lower priority
|
||||
nsRefPtr<CacheIOThread> ioThread = CacheFileIOManager::IOThread();
|
||||
MOZ_ASSERT(ioThread);
|
||||
|
||||
rv = ioThread->Dispatch(index, CacheIOThread::BUILD_OR_UPDATE_INDEX);
|
||||
index->mUpdateEventPending = true;
|
||||
rv = ioThread->Dispatch(index, CacheIOThread::INDEX);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CacheIndex::DelayedBuildUpdate() - Can't dispatch event");
|
||||
LOG(("CacheIndex::DelayedBuildUpdate() - Can't dispatch event" ));
|
||||
if (index->mState == BUILDING) {
|
||||
index->FinishBuild(false);
|
||||
} else {
|
||||
index->FinishUpdate(false);
|
||||
}
|
||||
index->mUpdateEventPending = false;
|
||||
NS_WARNING("CacheIndex::DelayedUpdate() - Can't dispatch event");
|
||||
LOG(("CacheIndex::DelayedUpdate() - Can't dispatch event" ));
|
||||
index->FinishUpdate(false);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheIndex::ScheduleBuildUpdateTimer(uint32_t aDelay)
|
||||
CacheIndex::ScheduleUpdateTimer(uint32_t aDelay)
|
||||
{
|
||||
LOG(("CacheIndex::ScheduleBuildUpdateTimer() [delay=%u]", aDelay));
|
||||
LOG(("CacheIndex::ScheduleUpdateTimer() [delay=%u]", aDelay));
|
||||
|
||||
MOZ_ASSERT(!mTimer);
|
||||
MOZ_ASSERT(!mUpdateTimer);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
@ -2230,11 +2389,11 @@ CacheIndex::ScheduleBuildUpdateTimer(uint32_t aDelay)
|
||||
rv = timer->SetTarget(ioTarget);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = timer->InitWithFuncCallback(CacheIndex::DelayedBuildUpdate, nullptr,
|
||||
rv = timer->InitWithFuncCallback(CacheIndex::DelayedUpdate, nullptr,
|
||||
aDelay, nsITimer::TYPE_ONE_SHOT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mTimer.swap(timer);
|
||||
mUpdateTimer.swap(timer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2299,43 +2458,16 @@ CacheIndex::InitEntryFromDiskData(CacheIndexEntry *aEntry,
|
||||
(aFileSize + 0x3FF) >> 10)));
|
||||
}
|
||||
|
||||
void
|
||||
CacheIndex::StartBuildingIndex()
|
||||
bool
|
||||
CacheIndex::IsUpdatePending()
|
||||
{
|
||||
LOG(("CacheIndex::StartBuildingIndex()"));
|
||||
AssertOwnsLock();
|
||||
|
||||
nsresult rv;
|
||||
|
||||
ChangeState(BUILDING);
|
||||
mDontMarkIndexClean = false;
|
||||
|
||||
if (mShuttingDown) {
|
||||
FinishBuild(false);
|
||||
return;
|
||||
if (mUpdateTimer || mUpdateEventPending) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t elapsed = (TimeStamp::NowLoRes() - mStartTime).ToMilliseconds();
|
||||
if (elapsed < kBuildIndexStartDelay) {
|
||||
rv = ScheduleBuildUpdateTimer(kBuildIndexStartDelay - elapsed);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(("CacheIndex::StartBuildingIndex() - ScheduleBuildUpdateTimer() failed."
|
||||
" Starting build immediately."));
|
||||
}
|
||||
|
||||
nsRefPtr<CacheIOThread> ioThread = CacheFileIOManager::IOThread();
|
||||
MOZ_ASSERT(ioThread);
|
||||
|
||||
// We need to dispatch an event even if we are on IO thread since we need to
|
||||
// build the inde with the correct priority.
|
||||
rv = ioThread->Dispatch(this, CacheIOThread::BUILD_OR_UPDATE_INDEX);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CacheIndex::StartBuildingIndex() - Can't dispatch event");
|
||||
LOG(("CacheIndex::StartBuildingIndex() - Can't dispatch event" ));
|
||||
FinishBuild(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -2356,13 +2488,13 @@ CacheIndex::BuildIndex()
|
||||
rv = SetupDirectoryEnumerator();
|
||||
}
|
||||
if (mState == SHUTDOWN) {
|
||||
// The index was shut down while we released the lock. FinishBuild() was
|
||||
// The index was shut down while we released the lock. FinishUpdate() was
|
||||
// already called from Shutdown(), so just simply return here.
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
FinishBuild(false);
|
||||
FinishUpdate(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2370,6 +2502,7 @@ CacheIndex::BuildIndex()
|
||||
while (true) {
|
||||
if (CacheIOThread::YieldAndRerun()) {
|
||||
LOG(("CacheIndex::BuildIndex() - Breaking loop for higher level events."));
|
||||
mUpdateEventPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2383,7 +2516,7 @@ CacheIndex::BuildIndex()
|
||||
return;
|
||||
}
|
||||
if (!file) {
|
||||
FinishBuild(NS_SUCCEEDED(rv));
|
||||
FinishUpdate(NS_SUCCEEDED(rv));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2475,54 +2608,17 @@ CacheIndex::BuildIndex()
|
||||
NS_NOTREACHED("We should never get here");
|
||||
}
|
||||
|
||||
void
|
||||
CacheIndex::FinishBuild(bool aSucceeded)
|
||||
{
|
||||
LOG(("CacheIndex::FinishBuild() [succeeded=%d]", aSucceeded));
|
||||
|
||||
MOZ_ASSERT((!aSucceeded && mState == SHUTDOWN) || mState == BUILDING);
|
||||
|
||||
AssertOwnsLock();
|
||||
|
||||
if (mDirEnumerator) {
|
||||
if (NS_IsMainThread()) {
|
||||
LOG(("CacheIndex::FinishBuild() - posting of PreShutdownInternal failed? "
|
||||
"Cannot safely release mDirEnumerator, leaking it!"));
|
||||
NS_WARNING(("CacheIndex::FinishBuild() - Leaking mDirEnumerator!"));
|
||||
// This can happen only in case dispatching event to IO thread failed in
|
||||
// CacheIndex::PreShutdown().
|
||||
mDirEnumerator.forget(); // Leak it since dir enumerator is not threadsafe
|
||||
} else {
|
||||
mDirEnumerator->Close();
|
||||
mDirEnumerator = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aSucceeded) {
|
||||
mDontMarkIndexClean = true;
|
||||
}
|
||||
|
||||
if (mState == BUILDING) {
|
||||
// Make sure we won't start update. Index should be up to date, if build
|
||||
// was successful. If the build failed, there is no reason to believe that
|
||||
// the update will succeed.
|
||||
mIndexNeedsUpdate = false;
|
||||
|
||||
ChangeState(READY);
|
||||
mLastDumpTime = TimeStamp::NowLoRes(); // Do not dump new index immediately
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIndex::StartUpdatingIndexIfNeeded(bool aSwitchingToReadyState)
|
||||
{
|
||||
// Start updating process when we are in or we are switching to READY state
|
||||
// and index needs update, but not during shutdown.
|
||||
// and index needs update, but not during shutdown or when removing all
|
||||
// entries.
|
||||
if ((mState == READY || aSwitchingToReadyState) && mIndexNeedsUpdate &&
|
||||
!mShuttingDown) {
|
||||
!mShuttingDown && !mRemovingAll) {
|
||||
LOG(("CacheIndex::StartUpdatingIndexIfNeeded() - starting update process"));
|
||||
mIndexNeedsUpdate = false;
|
||||
StartUpdatingIndex();
|
||||
StartUpdatingIndex(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2530,31 +2626,38 @@ CacheIndex::StartUpdatingIndexIfNeeded(bool aSwitchingToReadyState)
|
||||
}
|
||||
|
||||
void
|
||||
CacheIndex::StartUpdatingIndex()
|
||||
CacheIndex::StartUpdatingIndex(bool aRebuild)
|
||||
{
|
||||
LOG(("CacheIndex::StartUpdatingIndex()"));
|
||||
LOG(("CacheIndex::StartUpdatingIndex() [rebuild=%d]", aRebuild));
|
||||
|
||||
AssertOwnsLock();
|
||||
|
||||
nsresult rv;
|
||||
|
||||
mIndexStats.Log();
|
||||
|
||||
ChangeState(UPDATING);
|
||||
ChangeState(aRebuild ? BUILDING : UPDATING);
|
||||
mDontMarkIndexClean = false;
|
||||
|
||||
if (mShuttingDown) {
|
||||
if (mShuttingDown || mRemovingAll) {
|
||||
FinishUpdate(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsUpdatePending()) {
|
||||
LOG(("CacheIndex::StartUpdatingIndex() - Update is already pending"));
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t elapsed = (TimeStamp::NowLoRes() - mStartTime).ToMilliseconds();
|
||||
if (elapsed < kUpdateIndexStartDelay) {
|
||||
rv = ScheduleBuildUpdateTimer(kUpdateIndexStartDelay - elapsed);
|
||||
rv = ScheduleUpdateTimer(kUpdateIndexStartDelay - elapsed);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(("CacheIndex::StartUpdatingIndex() - ScheduleBuildUpdateTimer() failed."
|
||||
" Starting update immediately."));
|
||||
LOG(("CacheIndex::StartUpdatingIndex() - ScheduleUpdateTimer() failed. "
|
||||
"Starting update immediately."));
|
||||
}
|
||||
|
||||
nsRefPtr<CacheIOThread> ioThread = CacheFileIOManager::IOThread();
|
||||
@ -2562,8 +2665,10 @@ CacheIndex::StartUpdatingIndex()
|
||||
|
||||
// We need to dispatch an event even if we are on IO thread since we need to
|
||||
// update the index with the correct priority.
|
||||
rv = ioThread->Dispatch(this, CacheIOThread::BUILD_OR_UPDATE_INDEX);
|
||||
mUpdateEventPending = true;
|
||||
rv = ioThread->Dispatch(this, CacheIOThread::INDEX);
|
||||
if (NS_FAILED(rv)) {
|
||||
mUpdateEventPending = false;
|
||||
NS_WARNING("CacheIndex::StartUpdatingIndex() - Can't dispatch event");
|
||||
LOG(("CacheIndex::StartUpdatingIndex() - Can't dispatch event" ));
|
||||
FinishUpdate(false);
|
||||
@ -2588,7 +2693,7 @@ CacheIndex::UpdateIndex()
|
||||
rv = SetupDirectoryEnumerator();
|
||||
}
|
||||
if (mState == SHUTDOWN) {
|
||||
// The index was shut down while we released the lock. FinishBuild() was
|
||||
// The index was shut down while we released the lock. FinishUpdate() was
|
||||
// already called from Shutdown(), so just simply return here.
|
||||
return;
|
||||
}
|
||||
@ -2603,6 +2708,7 @@ CacheIndex::UpdateIndex()
|
||||
if (CacheIOThread::YieldAndRerun()) {
|
||||
LOG(("CacheIndex::UpdateIndex() - Breaking loop for higher level "
|
||||
"events."));
|
||||
mUpdateEventPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2747,7 +2853,8 @@ CacheIndex::FinishUpdate(bool aSucceeded)
|
||||
{
|
||||
LOG(("CacheIndex::FinishUpdate() [succeeded=%d]", aSucceeded));
|
||||
|
||||
MOZ_ASSERT((!aSucceeded && mState == SHUTDOWN) || mState == UPDATING);
|
||||
MOZ_ASSERT(mState == UPDATING || mState == BUILDING ||
|
||||
(!aSucceeded && mState == SHUTDOWN));
|
||||
|
||||
AssertOwnsLock();
|
||||
|
||||
@ -2769,21 +2876,23 @@ CacheIndex::FinishUpdate(bool aSucceeded)
|
||||
mDontMarkIndexClean = true;
|
||||
}
|
||||
|
||||
if (mState == UPDATING) {
|
||||
if (aSucceeded) {
|
||||
// If we've iterated over all entries successfully then all entries that
|
||||
// really exist on the disk are now marked as fresh. All non-fresh entries
|
||||
// don't exist anymore and must be removed from the index.
|
||||
mIndex.EnumerateEntries(&CacheIndex::RemoveNonFreshEntries, this);
|
||||
}
|
||||
|
||||
// Make sure we won't start update again. If the update failed, there is no
|
||||
// reason to believe that it will succeed next time.
|
||||
mIndexNeedsUpdate = false;
|
||||
|
||||
ChangeState(READY);
|
||||
mLastDumpTime = TimeStamp::NowLoRes(); // Do not dump new index immediately
|
||||
if (mState == SHUTDOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mState == UPDATING && aSucceeded) {
|
||||
// If we've iterated over all entries successfully then all entries that
|
||||
// really exist on the disk are now marked as fresh. All non-fresh entries
|
||||
// don't exist anymore and must be removed from the index.
|
||||
mIndex.EnumerateEntries(&CacheIndex::RemoveNonFreshEntries, this);
|
||||
}
|
||||
|
||||
// Make sure we won't start update. If the build or update failed, there is no
|
||||
// reason to believe that it will succeed next time.
|
||||
mIndexNeedsUpdate = false;
|
||||
|
||||
ChangeState(READY);
|
||||
mLastDumpTime = TimeStamp::NowLoRes(); // Do not dump new index immediately
|
||||
}
|
||||
|
||||
// static
|
||||
@ -2845,8 +2954,9 @@ CacheIndex::ChangeState(EState aNewState)
|
||||
}
|
||||
|
||||
// Try to evict entries over limit everytime we're leaving state READING,
|
||||
// BUILDING or UPDATING, but not during shutdown.
|
||||
if (!mShuttingDown && aNewState != SHUTDOWN &&
|
||||
// BUILDING or UPDATING, but not during shutdown or when removing all
|
||||
// entries.
|
||||
if (!mShuttingDown && !mRemovingAll && aNewState != SHUTDOWN &&
|
||||
(mState == READING || mState == BUILDING || mState == UPDATING)) {
|
||||
CacheFileIOManager::EvictIfOverLimit();
|
||||
}
|
||||
@ -2976,6 +3086,8 @@ CacheIndex::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mUpdateEventPending = false;
|
||||
|
||||
switch (mState) {
|
||||
case BUILDING:
|
||||
BuildIndex();
|
||||
@ -2984,21 +3096,22 @@ CacheIndex::Run()
|
||||
UpdateIndex();
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unexpected state!");
|
||||
LOG(("CacheIndex::Run() - Update/Build was canceled"));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheIndex::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
|
||||
CacheIndex::OnFileOpenedInternal(FileOpenHelper *aOpener,
|
||||
CacheFileHandle *aHandle, nsresult aResult)
|
||||
{
|
||||
LOG(("CacheIndex::OnFileOpened() [handle=%p, result=0x%08x]", aHandle,
|
||||
aResult));
|
||||
LOG(("CacheIndex::OnFileOpenedInternal() [opener=%p, handle=%p, "
|
||||
"result=0x%08x]", aOpener, aHandle, aResult));
|
||||
|
||||
nsresult rv;
|
||||
|
||||
CacheIndexAutoLock lock(this);
|
||||
AssertOwnsLock();
|
||||
|
||||
if (!IsIndexUsable()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
@ -3010,9 +3123,12 @@ CacheIndex::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
|
||||
|
||||
switch (mState) {
|
||||
case WRITING:
|
||||
MOZ_ASSERT(aOpener == mIndexFileOpener);
|
||||
mIndexFileOpener = nullptr;
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
LOG(("CacheIndex::OnFileOpened() - Can't open index file for writing "
|
||||
"[rv=0x%08x]", aResult));
|
||||
LOG(("CacheIndex::OnFileOpenedInternal() - Can't open index file for "
|
||||
"writing [rv=0x%08x]", aResult));
|
||||
FinishWrite(false);
|
||||
} else {
|
||||
mIndexHandle = aHandle;
|
||||
@ -3020,74 +3136,67 @@ CacheIndex::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
|
||||
}
|
||||
break;
|
||||
case READING:
|
||||
mReadOpenCount--;
|
||||
if (aOpener == mIndexFileOpener) {
|
||||
mIndexFileOpener = nullptr;
|
||||
|
||||
if (mReadFailed) {
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
CacheFileIOManager::DoomFile(aHandle, nullptr);
|
||||
}
|
||||
|
||||
if (mReadOpenCount == 0) {
|
||||
FinishRead(false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
switch (mReadOpenCount) {
|
||||
case 2: // kIndexName
|
||||
if (NS_FAILED(aResult)) {
|
||||
mReadFailed = true;
|
||||
} else {
|
||||
MOZ_ASSERT(aHandle->Key() == kIndexName);
|
||||
if (aHandle->FileSize() == 0) {
|
||||
mReadFailed = true;
|
||||
CacheFileIOManager::DoomFile(aHandle, nullptr);
|
||||
} else {
|
||||
mIndexHandle = aHandle;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: // kJournalName
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
MOZ_ASSERT(aHandle->Key() == kJournalName);
|
||||
if (aHandle->FileSize() == 0) {
|
||||
CacheFileIOManager::DoomFile(aHandle, nullptr);
|
||||
} else {
|
||||
mJournalHandle = aHandle;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0: // kTempIndexName
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
MOZ_ASSERT(aHandle->Key() == kTempIndexName);
|
||||
if (aHandle->FileSize() == 0) {
|
||||
FinishRead(false);
|
||||
CacheFileIOManager::DoomFile(aHandle, nullptr);
|
||||
|
||||
if (mJournalHandle) { // this should never happen
|
||||
LOG(("CacheIndex::OnFileOpened() - Unexpected state, all files "
|
||||
"[%s, %s, %s] should never exist. Removing whole index.",
|
||||
kIndexName, kJournalName, kTempIndexName));
|
||||
FinishRead(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mJournalHandle) {
|
||||
// Rename journal to make sure we update index on next start in case
|
||||
// firefox crashes
|
||||
rv = CacheFileIOManager::RenameFile(
|
||||
mJournalHandle, NS_LITERAL_CSTRING(kTempIndexName), this);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("CacheIndex::OnFileOpened() - CacheFileIOManager::RenameFile"
|
||||
"() failed synchronously [rv=0x%08x]", rv));
|
||||
FinishRead(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
mIndexHandle = aHandle;
|
||||
}
|
||||
|
||||
StartReadingIndex();
|
||||
} else {
|
||||
FinishRead(false);
|
||||
break;
|
||||
}
|
||||
} else if (aOpener == mJournalFileOpener) {
|
||||
mJournalFileOpener = nullptr;
|
||||
mJournalHandle = aHandle;
|
||||
} else if (aOpener == mTmpFileOpener) {
|
||||
mTmpFileOpener = nullptr;
|
||||
mTmpHandle = aHandle;
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Unexpected state!");
|
||||
}
|
||||
|
||||
if (mIndexFileOpener || mJournalFileOpener || mTmpFileOpener) {
|
||||
// Some opener still didn't finish
|
||||
break;
|
||||
}
|
||||
|
||||
// We fail and cancel all other openers when we opening index file fails.
|
||||
MOZ_ASSERT(mIndexHandle);
|
||||
|
||||
if (mTmpHandle) {
|
||||
CacheFileIOManager::DoomFile(mTmpHandle, nullptr);
|
||||
mTmpHandle = nullptr;
|
||||
|
||||
if (mJournalHandle) { // this shouldn't normally happen
|
||||
LOG(("CacheIndex::OnFileOpenedInternal() - Unexpected state, all "
|
||||
"files [%s, %s, %s] should never exist. Removing whole index.",
|
||||
kIndexName, kJournalName, kTempIndexName));
|
||||
FinishRead(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mJournalHandle) {
|
||||
// Rename journal to make sure we update index on next start in case
|
||||
// firefox crashes
|
||||
rv = CacheFileIOManager::RenameFile(
|
||||
mJournalHandle, NS_LITERAL_CSTRING(kTempIndexName), this);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("CacheIndex::OnFileOpenedInternal() - CacheFileIOManager::"
|
||||
"RenameFile() failed synchronously [rv=0x%08x]", rv));
|
||||
FinishRead(false);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
StartReadingIndex();
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unexpected state!");
|
||||
@ -3096,6 +3205,13 @@ CacheIndex::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheIndex::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
|
||||
{
|
||||
MOZ_CRASH("CacheIndex::OnFileOpened should not be called!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheIndex::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
|
||||
nsresult aResult)
|
||||
@ -3117,6 +3233,12 @@ CacheIndex::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
|
||||
|
||||
switch (mState) {
|
||||
case WRITING:
|
||||
if (mIndexHandle != aHandle) {
|
||||
LOG(("CacheIndex::OnDataWritten() - ignoring notification since it "
|
||||
"belongs to previously canceled operation [state=%d]", mState));
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
FinishWrite(false);
|
||||
} else {
|
||||
@ -3135,7 +3257,9 @@ CacheIndex::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unexpected state!");
|
||||
// Writing was canceled.
|
||||
LOG(("CacheIndex::OnDataWritten() - ignoring notification since the "
|
||||
"operation was previously canceled [state=%d]", mState));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -3153,12 +3277,10 @@ CacheIndex::OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (mState == READY && mShuttingDown) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
switch (mState) {
|
||||
case READING:
|
||||
MOZ_ASSERT(mIndexHandle == aHandle || mJournalHandle == aHandle);
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
FinishRead(false);
|
||||
} else {
|
||||
@ -3170,7 +3292,9 @@ CacheIndex::OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unexpected state!");
|
||||
// Reading was canceled.
|
||||
LOG(("CacheIndex::OnDataRead() - ignoring notification since the "
|
||||
"operation was previously canceled [state=%d]", mState));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -3211,12 +3335,26 @@ CacheIndex::OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult)
|
||||
// This is a result of renaming the new index written to tmpfile to index
|
||||
// file. This is the last step when writing the index and the whole
|
||||
// writing process is successful iff renaming was successful.
|
||||
|
||||
if (mIndexHandle != aHandle) {
|
||||
LOG(("CacheIndex::OnFileRenamed() - ignoring notification since it "
|
||||
"belongs to previously canceled operation [state=%d]", mState));
|
||||
break;
|
||||
}
|
||||
|
||||
FinishWrite(NS_SUCCEEDED(aResult));
|
||||
break;
|
||||
case READING:
|
||||
// This is a result of renaming journal file to tmpfile. It is renamed
|
||||
// before we start reading index and journal file and it should normally
|
||||
// succeed. If it fails give up reading of index.
|
||||
|
||||
if (mJournalHandle != aHandle) {
|
||||
LOG(("CacheIndex::OnFileRenamed() - ignoring notification since it "
|
||||
"belongs to previously canceled operation [state=%d]", mState));
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
FinishRead(false);
|
||||
} else {
|
||||
@ -3224,7 +3362,9 @@ CacheIndex::OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unexpected state!");
|
||||
// Reading/writing was canceled.
|
||||
LOG(("CacheIndex::OnFileRenamed() - ignoring notification since the "
|
||||
"operation was previously canceled [state=%d]", mState));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -3261,7 +3401,7 @@ CacheIndex::SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) cons
|
||||
n += sizeOf->SizeOfIncludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
sizeOf = do_QueryInterface(mTimer);
|
||||
sizeOf = do_QueryInterface(mUpdateTimer);
|
||||
if (sizeOf) {
|
||||
n += sizeOf->SizeOfIncludingThis(mallocSizeOf);
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class CacheFileMetadata;
|
||||
class FileOpenHelper;
|
||||
|
||||
typedef struct {
|
||||
// Version of the index. The index must be ignored and deleted when the file
|
||||
@ -327,10 +328,22 @@ public:
|
||||
|
||||
void Log() {
|
||||
LOG(("CacheIndexStats::Log() [count=%u, notInitialized=%u, removed=%u, "
|
||||
"dirty=%u, fresh=%u, empty=%u, size=%lld]", mCount, mNotInitialized,
|
||||
"dirty=%u, fresh=%u, empty=%u, size=%u]", mCount, mNotInitialized,
|
||||
mRemoved, mDirty, mFresh, mEmpty, mSize));
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
MOZ_ASSERT(!mStateLogged, "CacheIndexStats::Clear() - state logged!");
|
||||
|
||||
mCount = 0;
|
||||
mNotInitialized = 0;
|
||||
mRemoved = 0;
|
||||
mDirty = 0;
|
||||
mFresh = 0;
|
||||
mEmpty = 0;
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool StateLogged() {
|
||||
return mStateLogged;
|
||||
@ -512,6 +525,9 @@ public:
|
||||
const uint32_t *aExpirationTime,
|
||||
const uint32_t *aSize);
|
||||
|
||||
// Remove all entries from the index. Called when clearing the whole cache.
|
||||
static nsresult RemoveAll();
|
||||
|
||||
enum EntryStatus {
|
||||
EXISTS = 0,
|
||||
DOES_NOT_EXIST = 1,
|
||||
@ -538,10 +554,13 @@ private:
|
||||
friend class CacheIndexEntryAutoManage;
|
||||
friend class CacheIndexAutoLock;
|
||||
friend class CacheIndexAutoUnlock;
|
||||
friend class FileOpenHelper;
|
||||
|
||||
virtual ~CacheIndex();
|
||||
|
||||
NS_IMETHOD OnFileOpened(CacheFileHandle *aHandle, nsresult aResult);
|
||||
nsresult OnFileOpenedInternal(FileOpenHelper *aOpener,
|
||||
CacheFileHandle *aHandle, nsresult aResult);
|
||||
NS_IMETHOD OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
|
||||
nsresult aResult);
|
||||
NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult);
|
||||
@ -682,29 +701,28 @@ private:
|
||||
|
||||
// Following methods perform updating and building of the index.
|
||||
// Timer callback that starts update or build process.
|
||||
static void DelayedBuildUpdate(nsITimer *aTimer, void *aClosure);
|
||||
static void DelayedUpdate(nsITimer *aTimer, void *aClosure);
|
||||
// Posts timer event that start update or build process.
|
||||
nsresult ScheduleBuildUpdateTimer(uint32_t aDelay);
|
||||
nsresult ScheduleUpdateTimer(uint32_t aDelay);
|
||||
nsresult SetupDirectoryEnumerator();
|
||||
void InitEntryFromDiskData(CacheIndexEntry *aEntry,
|
||||
CacheFileMetadata *aMetaData,
|
||||
int64_t aFileSize);
|
||||
// Starts build process or fires a timer when it is too early after startup.
|
||||
void StartBuildingIndex();
|
||||
// Returns true when either a timer is scheduled or event is posted.
|
||||
bool IsUpdatePending();
|
||||
// Iterates through all files in entries directory that we didn't create/open
|
||||
// during this session, parses them and adds the entries to the index.
|
||||
void BuildIndex();
|
||||
// Finalizes build process.
|
||||
void FinishBuild(bool aSucceeded);
|
||||
|
||||
bool StartUpdatingIndexIfNeeded(bool aSwitchingToReadyState = false);
|
||||
// Starts update process or fires a timer when it is too early after startup.
|
||||
void StartUpdatingIndex();
|
||||
// Starts update or build process or fires a timer when it is too early after
|
||||
// startup.
|
||||
void StartUpdatingIndex(bool aRebuild);
|
||||
// Iterates through all files in entries directory that we didn't create/open
|
||||
// during this session and theirs last modified time is newer than timestamp
|
||||
// in the index header. Parses the files and adds the entries to the index.
|
||||
void UpdateIndex();
|
||||
// Finalizes update process.
|
||||
// Finalizes update or build process.
|
||||
void FinishUpdate(bool aSucceeded);
|
||||
|
||||
static PLDHashOperator RemoveNonFreshEntries(CacheIndexEntry *aEntry,
|
||||
@ -797,6 +815,12 @@ private:
|
||||
// set this flag should also call StartUpdatingIndexIfNeeded() to cover the
|
||||
// case when we are currently in READY state.
|
||||
bool mIndexNeedsUpdate;
|
||||
// Set at the beginning of RemoveAll() which clears the whole index. When
|
||||
// removing all entries we must stop any pending reading, writing, updating or
|
||||
// building operation. This flag is checked at various places and it prevents
|
||||
// we won't start another operation (e.g. canceling reading of the index would
|
||||
// normally start update or build process)
|
||||
bool mRemovingAll;
|
||||
// Whether the index file on disk exists and is valid.
|
||||
bool mIndexOnDiskIsValid;
|
||||
// When something goes wrong during updating or building process, we don't
|
||||
@ -812,7 +836,9 @@ private:
|
||||
TimeStamp mLastDumpTime;
|
||||
|
||||
// Timer of delayed update/build.
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsCOMPtr<nsITimer> mUpdateTimer;
|
||||
// True when build or update event is posted
|
||||
bool mUpdateEventPending;
|
||||
|
||||
// Helper members used when reading/writing index from/to disk.
|
||||
// Contains number of entries that should be skipped:
|
||||
@ -828,12 +854,6 @@ private:
|
||||
uint32_t mRWBufPos;
|
||||
nsRefPtr<CacheHash> mRWHash;
|
||||
|
||||
// When reading index from disk, we open index, journal and tmpindex files at
|
||||
// the same time. This value tell us how many times CacheIndex::OnFileOpened()
|
||||
// will be called and identifies the handle.
|
||||
uint32_t mReadOpenCount;
|
||||
// Reading of index failed completely if true.
|
||||
bool mReadFailed;
|
||||
// Reading of journal succeeded if true.
|
||||
bool mJournalReadSuccessfully;
|
||||
|
||||
@ -841,6 +861,12 @@ private:
|
||||
nsRefPtr<CacheFileHandle> mIndexHandle;
|
||||
// Handle used for reading journal file.
|
||||
nsRefPtr<CacheFileHandle> mJournalHandle;
|
||||
// Used to check the existence of the file during reading process.
|
||||
nsRefPtr<CacheFileHandle> mTmpHandle;
|
||||
|
||||
nsRefPtr<FileOpenHelper> mIndexFileOpener;
|
||||
nsRefPtr<FileOpenHelper> mJournalFileOpener;
|
||||
nsRefPtr<FileOpenHelper> mTmpFileOpener;
|
||||
|
||||
// Directory enumerator used when building and updating index.
|
||||
nsCOMPtr<nsIDirectoryEnumerator> mDirEnumerator;
|
||||
|
@ -489,223 +489,6 @@ NS_IMETHODIMP CacheStorageService::AppCacheStorage(nsILoadContextInfo *aLoadCont
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
namespace { // anon
|
||||
|
||||
class CacheFilesDeletor : public nsRunnable
|
||||
, public CacheEntriesEnumeratorCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
CacheFilesDeletor(nsICacheEntryDoomCallback* aCallback);
|
||||
~CacheFilesDeletor();
|
||||
|
||||
nsresult DeleteAll();
|
||||
nsresult DeleteDoomed();
|
||||
|
||||
private:
|
||||
nsresult Init(CacheFileIOManager::EEnumerateMode aMode);
|
||||
NS_IMETHOD Run();
|
||||
NS_IMETHOD Execute();
|
||||
void Callback();
|
||||
virtual void OnFile(CacheFile* aFile);
|
||||
|
||||
nsCOMPtr<nsICacheEntryDoomCallback> mCallback;
|
||||
nsAutoPtr<CacheEntriesEnumerator> mEnumerator;
|
||||
nsRefPtr<CacheIOThread> mIOThread;
|
||||
|
||||
uint32_t mRunning;
|
||||
enum {
|
||||
ALL,
|
||||
DOOMED
|
||||
} mMode;
|
||||
nsresult mRv;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(CacheFilesDeletor, nsRunnable);
|
||||
|
||||
CacheFilesDeletor::CacheFilesDeletor(nsICacheEntryDoomCallback* aCallback)
|
||||
: mCallback(aCallback)
|
||||
, mRunning(0)
|
||||
, mRv(NS_OK)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CacheFilesDeletor);
|
||||
MOZ_EVENT_TRACER_WAIT(static_cast<nsRunnable*>(this), "net::cache::deletor");
|
||||
}
|
||||
|
||||
CacheFilesDeletor::~CacheFilesDeletor()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CacheFilesDeletor);
|
||||
MOZ_EVENT_TRACER_DONE(static_cast<nsRunnable*>(this), "net::cache::deletor");
|
||||
|
||||
if (mMode == ALL) {
|
||||
// Now delete the doomed entries if some left.
|
||||
nsRefPtr<CacheFilesDeletor> deletor = new CacheFilesDeletor(mCallback);
|
||||
|
||||
nsRefPtr<nsRunnableMethod<CacheFilesDeletor, nsresult> > event =
|
||||
NS_NewRunnableMethod(deletor.get(), &CacheFilesDeletor::DeleteDoomed);
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult CacheFilesDeletor::DeleteAll()
|
||||
{
|
||||
mMode = ALL;
|
||||
return Init(CacheFileIOManager::ENTRIES);
|
||||
}
|
||||
|
||||
nsresult CacheFilesDeletor::DeleteDoomed()
|
||||
{
|
||||
mMode = DOOMED;
|
||||
return Init(CacheFileIOManager::DOOMED);
|
||||
}
|
||||
|
||||
nsresult CacheFilesDeletor::Init(CacheFileIOManager::EEnumerateMode aMode)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = CacheFileIOManager::EnumerateEntryFiles(
|
||||
aMode, getter_Transfers(mEnumerator));
|
||||
|
||||
if (NS_ERROR_FILE_NOT_FOUND == rv || NS_ERROR_FILE_TARGET_DOES_NOT_EXIST == rv) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mIOThread = CacheFileIOManager::IOThread();
|
||||
NS_ENSURE_TRUE(mIOThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
rv = mIOThread->Dispatch(this, CacheIOThread::EVICT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void CacheFilesDeletor::Callback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
|
||||
if (obsSvc) {
|
||||
obsSvc->NotifyObservers(CacheStorageService::SelfISupports(),
|
||||
"cacheservice:empty-cache",
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (!mCallback)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsICacheEntryDoomCallback> callback;
|
||||
callback.swap(mCallback);
|
||||
callback->OnCacheEntryDoomed(mRv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP CacheFilesDeletor::Run()
|
||||
{
|
||||
if (!mRunning) {
|
||||
MOZ_EVENT_TRACER_EXEC(static_cast<nsRunnable*>(this), "net::cache::deletor");
|
||||
}
|
||||
|
||||
MOZ_EVENT_TRACER_EXEC(static_cast<nsRunnable*>(this), "net::cache::deletor::exec");
|
||||
|
||||
nsresult rv = Execute();
|
||||
if (NS_SUCCEEDED(mRv))
|
||||
mRv = rv;
|
||||
|
||||
if (!mEnumerator || !mEnumerator->HasMore()) {
|
||||
// No enumerator or no more elements means the job is done.
|
||||
mEnumerator = nullptr;
|
||||
|
||||
if (mMode != ALL) {
|
||||
nsRefPtr<nsRunnableMethod<CacheFilesDeletor> > event =
|
||||
NS_NewRunnableMethod(this, &CacheFilesDeletor::Callback);
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_EVENT_TRACER_DONE(static_cast<nsRunnable*>(this), "net::cache::deletor::exec");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult CacheFilesDeletor::Execute()
|
||||
{
|
||||
LOG(("CacheFilesDeletor::Execute [this=%p]", this));
|
||||
|
||||
if (!mEnumerator) {
|
||||
// No enumerator means the job is done.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
switch (mMode) {
|
||||
case ALL:
|
||||
case DOOMED:
|
||||
// Simply delete all files, don't doom then though the backend
|
||||
|
||||
while (mEnumerator->HasMore()) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = mEnumerator->GetNextFile(getter_AddRefs(file));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
#ifdef PR_LOG
|
||||
nsAutoCString key;
|
||||
file->GetNativeLeafName(key);
|
||||
LOG((" deleting file with key=%s", key.get()));
|
||||
#endif
|
||||
|
||||
rv = file->Remove(false);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG((" could not remove the file, probably doomed, rv=0x%08x", rv));
|
||||
}
|
||||
|
||||
++mRunning;
|
||||
|
||||
if (CacheIOThread::YieldAndRerun()) {
|
||||
LOG((" deleted %u files, breaking loop for higher level events."));
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void CacheFilesDeletor::OnFile(CacheFile* aFile)
|
||||
{
|
||||
LOG(("CacheFilesDeletor::OnFile [this=%p, file=%p]", this, aFile));
|
||||
|
||||
if (!aFile)
|
||||
return;
|
||||
|
||||
MOZ_EVENT_TRACER_EXEC(static_cast<nsRunnable*>(this), "net::cache::deletor::file");
|
||||
|
||||
#ifdef PR_LOG
|
||||
nsAutoCString key;
|
||||
aFile->Key(key);
|
||||
#endif
|
||||
|
||||
switch (mMode) {
|
||||
case ALL:
|
||||
case DOOMED:
|
||||
LOG((" dooming file with key=%s", key.get()));
|
||||
// Uncompromisely delete the file!
|
||||
aFile->Doom(nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_EVENT_TRACER_DONE(static_cast<nsRunnable*>(this), "net::cache::deletor::file");
|
||||
}
|
||||
|
||||
} // anon
|
||||
|
||||
NS_IMETHODIMP CacheStorageService::Clear()
|
||||
{
|
||||
nsresult rv;
|
||||
@ -723,12 +506,9 @@ NS_IMETHODIMP CacheStorageService::Clear()
|
||||
DoomStorageEntries(keys[i], true, nullptr);
|
||||
}
|
||||
|
||||
// TODO - Callback can be provided!
|
||||
nsRefPtr<CacheFilesDeletor> deletor = new CacheFilesDeletor(nullptr);
|
||||
rv = deletor->DeleteAll();
|
||||
rv = CacheFileIOManager::EvictAll();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
nsCOMPtr<nsICacheService> serv =
|
||||
do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -21,7 +21,6 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'CacheEntriesEnumerator.cpp',
|
||||
'CacheHashUtils.cpp',
|
||||
'CacheIOThread.cpp',
|
||||
'CacheObserver.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user