mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
d457251529
- Bug 1120715 - Part 6: Remove the dom.requestcache.enabled pref; r=bkelly (800c996a96) - Bug 1143222 - Put the DOM Cache tests in sequential mode again until we fix the rest of the intermittent failures; a=RyanVM (2ebdd659a1) - Bug 1255636 - Give a better error message when the Request constructor fails because of a cross-origin referrer URL; r=bkelly (d81a21c0bb) - Bug 1265056 - don't needlessly construct nsAutoCString temporaries in dom/; r=baku (3be49ca3fc) - Bug 1243849 - Restore support for accessing the Cache API from app:// URLs and also for storing requests/responses with app:// URLs within it; r=bkelly (eb56fa564c) - Bug 1263235, part 1 - Move PBrowser::AsyncMessage's data argument last. r=smaug (6852b87c22) - Bug 1263235, part 2 - Make PContent::AsyncMessage and PContentBridge::AsyncMessage's data argument last. r=smaug (9e8cd94461) - Bug 1263028 - send HTTP data to the content process in smaller chunks, r=michal (c0da548157) - Bug 1263235, part 3 - Move PHttpChannel::OnTransportAndData's data argument last. r=mayhemer (e1bf4f430f) - Bug 1263235, part 4 - Make PBrowserStream::Write's data argument last. r=jimm (8bcec4d541) - Bug 1260876 - Remove process switch code for signed package code (added by Bug 1186290). r=valentin. (cef270b44c) - Bug 1234575 - Empty fragment is ignored in URI of location header r=mcmanus (db68f102d8) - Bug 1262506 - Unused variable in a runnable in BackgroundParentImpl, r=ehsan (9288f0a111) - bug 1239166 - platform work to support Microsoft Family Safety functionality r=froydnj,mgoodwin,mhowell,rbarnes,vladan (adc357f3b3) - Bug 842818 - Make Crypto::GetRandomValues() work off the main thread r=baku,keeler,mt (533f8942c4) - Bug 1247089 - Add a mode to ReportToConsoleNonLocalized that ignores the calling location. r=bkelly (4be23e0869) - Bug 1258883 - Add a way to replace the entire Push service in tests. r=wchen (06a5f27016) - Bug 1243856 - Remove alarms from the Push H2 backend. r=dragana (60d146dc73) - Bug 1246066 - Clear PushService timeout tasks on uninitialization. r=itcambridge (461276a972) - Bug 1214338 - Implement Android GCM-based PushService protocol. r=rnewman r=kitcambridge (f2bb78994a) - Bug 1257821 - Support the new aesgcm content encoding scheme. r=mt (1da653c14a) - Bug 1243856 - Remove alarms from the Push WebSocket backend. r=dragana (43f74c4999) - Bug 1258145 - Remove waitForPromise from the xpcshell tests. r=wchen (cdd1aff2f6) - Bug 1253831 - Don't check actual intervals in the Push backoff test. r=wchen (859fa0bba3) - Bug 1246341 - Include status codes in "ack" and "unregister" requests. r=dragana (a62d0daf9b) - Bug 1246341 - Add a test for push event error reporting. r=dragana (013bc814e4) - Bug 1247089 - Log Web Push decryption errors. r=bkelly (ffc093dc2f) - Bug 1258221 - patch 2 - Port FileSystem API and DeviceStorage API to PBackground, r=smaug (c1c0e08bc0) - Bug 1258221 - patch 3 - Rename FileSystemTaskBase to FileSystemTaskChildBase, r=smaug (867a0e65fd) - Bug 1251032 - Don't return layersId or textureFactoryIdentifier as outparams in RenderFrameParent constructor. r=kanru (198ddff7fc) - Bug 1251032 - Send RenderFrame info down to child in CreateWindow message. r=kanru (87e9001088) - Bug 1251032 - Make it possible to assign a frameloader to RenderFrameParent after construction. r=kanru (96483d1282) - Bug 1254865 - Send disableglobalhistory state down to TabChild after construction asynchronously. r=smaug (3949285b62) - Bug 1238707 Release the window immediately in TabParent::Destroy() to avoid leaks. r=smaug (fc612485d7) - Bug 1256589 part.1 Move the implementation of StopPropagation() from dom::Event to WidgetEvent r=smaug (181721b64c) - Bug 1256589 part.2 Move the implementation of StopImmediatePropagation() from dom::Event to WidgetEvent r=smaug (554a0dc5b5) - Bug 1203059 part.1 nsXBLWincowKeyHandler mark WidgetEvent::mFlags if it's reserved by chrome before the event is dispatched into the content r=smaug (9162dd68cb) - Bug 1203059 part.2 When an event is reserved by chrome, it should be fired only on chrome r=smaug (35f082ca5f) - Bug 1203059 part.3 Installing and removing keyboard event listeners of nsXBLWindowKeyHandler should be done by the class itself r=smaug (1e06c2d0bc) - Bug 1203059 part.4 Update test_keycodes.xul for the new behavior r=smaug (3014d21c75) - Bug 1256589 part.3 Move the implementation of StopCrossProcessForwarding() from dom::Event to WidgetEvent r=smaug (96db915b51) - Bug 1257180 - patch 1 - Directory clonable to workers, r=smaug (5634acb08d) - Bug 1257180 - patch 2 - Directory can be sent via postMessage(), r=smaug (82ada39ae3) - Bug 1263311: Part 3 - s/nsCancelableRunnable/CancelableRunnable/g. r=froydnj (79d0a6c81f) - Bug 1253198: add WebRtcIce prefix to all ICE unit tests. r=bwc (9c18f5fd56) - Bug 1244926: added TCP socket filter to only allow outgoing STUN. r=jesup (75debfdc84) - Bug 1257405 - Increase auth secret length to 16 octets. r=mt (b1e000c331) - Bug 1257401 - Remove the worker descriptor for PushSubscription. r=khuey (5791fb69ef) - Bug 1257401 - Remove the worker descriptor for PushManager. r=khuey (e2c75903a9) - Bug 1257821 - Remove the authenticated aesgcm128 content coding scheme. r=mt,marco (64a2917910) - Bug 1256488 - Add a Base64 URL-decoder for C++ and chrome JS callers. r=mt,baku (0bbb250298) - Bug 1247685 - Validate and store app server keys in the Push service. r=mt (c3c026ccb1) - Bug 1252650 - Support loading PushService immediately on Android; r=kitcambridge (d59a37fec4) - Bug 1258595 - Shut down the Push service if errors occur at startup. r=wchen (eef1805652) - Bug 1258595 - Wait for the Push service to shut down between tests. r=wchen (c30cf92ce6) - Bug 1262618 - Fix an unchained promise and a couple of non-promise returns in the push service. r=wchen (8eadab5706) - Bug 1263747 - Log error messages when stringifying errors. r=bgrins (edffd0074e) - Bug 1265705 - Silence startup JavaScript strict warning in resource://gre/modules/PushService.jsm. r=kitcambridge (e7e210fb61) - Bug 1264062 - Don't bother checking which accelerated layer types are available if they're all disabled by pref r=milan (0d3208ad59) - Bug 1263346. Remove wrong Ivy Bridge device id. r=Bas (7e39e7f370) - fix misspatch (a67a111b2c) - Bug 1251334 - Create a disposable pref to force-disable e10s in an emergency. r=jimm (ef892d4474) - Bug 1254774 - error: member access into incomplete type 'nsIUUIDGenerator' after bug 1237847. r=aklotz (c1f334609f) - Bug 1257242 - Split the ::BrowserTabsRemoteAutostart() function into two parts, to allow for the blocking policies to be checked independently from the prefs checks. r=jimm (1babda578f) - Bug 1260190 - Disable e10s for accessibility users on OS X. r=jimm (219e5b1f19) - Bug 1237769 - Disable e10s on Windows XP if layers acceleration is requested r=milan (60f2434e9f) - Bug 1232911 - [3.2] Block VPX support in ADM on unsupported devices. r=snorp (6924aa073a) - Bug 1263249 - Bubble up unique failureId in GetFeatureStatus. r=mconley,milan (cd56eeab3c) - Bug 1219296 - Split fields not needed for repaints out from FrameMetrics. r=kats (9003ca634a) - Bug 1219296 - Factor out scroll snap information into a form that's usable by the compositor. r=kats (23d3e619a1) - Bug 1219296 - Make ScrollMetadata::sNullMetadata a StaticAutoPtr so that ScrollMetadata can admit nsTArray members. r=kats (1729ff7d93) - Bug 1257641 - Replace the mUpdateScrollOffset bool with an enum, needed in the next patch. r=botond (f9d546f8e8) - Bug 1257641 - Use empty transactions to carry scroll offset updates to APZ that don't require a repaint. r=mattwoodrow,mstange,botond (ba4a8a8c29) - Bug 1246290 - Add a bit to FrameMetrics to indicate if APZ-scrolling should be disabled on that APZC. r=botond (af2067137f) - Bug 1256589 part.4 Move the implementation of PreventDefault() and add PreventDefaultBeforeDispatch() from dom::Event to WidgetEvent r=smaug (e7828f2d8f) - Bug 1256589 part.5 Add DefaultPrevented() and DefaultPreventedByContent() to WidgetEvent r=smaug (e65cdd9127) - Bug 1249915 - Fix missing MOZ_COUNT_CTOR and some misc cleanup. r=karlt (d2f26cf971) - Bug 1154183 part.1 Move shortcut/access key candidate list creators from nsContentUtils to WidgetKeyboardEvent r=smaug (40b0b11a5a) - Bug 1154183 part.2 eKeyDown event should have charCode value of following keypress event r=smaug (28c1443ba3) - Bug 1154183 part.3 Clean up some variable names in nsXBLWindowKeyHandler::WalkHandlersAndExecute() r=smaug (81e25023d8) - Bug 1154183 part.4 Implement nsXBLWindowKeyHandler::GetElementForHandler() r=smaug (b5605d5c83) - Bug 1154183 part.5 Make nsXBLWindowKeyHandler::GetElementForHandler() use early return style r=smaug (017467204f) - Bug 1154183 part.6 Add nsXBLWindowKeyHandler::IsExecuteableElement() r=smaug (1fda349113) - Bug 1154183 part.7 Don't dispatch preceding keydown events of reserved keypress events on content in the default event group r=smaug (15b9e8c9d2) - Bug 1256589 part.6 Move the implementation of IsTrusted() from dom::Event to WidgetEvent r=smaug (ec79520fd3) - Bug 1253044. Fix fall through of observer topics when other conditions aren't met in PresShell::Observe. r=dholbert (dcc36884aa) - Bug 1157546 - Replace the image visibility API with a more general API that tracks visibility for any kind of frame. r=mstange (d6ea061614) - Bug 1219296 - Factor out the algorithm that computes a scroll snap destination into a reusable form. r=kats (296cbe9e49) - Bug 1254275 - Inspect the event queue to find out whether momentum events are following. r=kats (b2bb8a26b9) - Bug 1219296 - Scroll snap directly in APZ instead of going through the main thread. r=kats (0a30b550f9) - Bug 1219296 - Fix an include-what-you-use error. r=kats (4a128ae98e) - Bug 1260588 - C++ APZ should only allow handoff to ancestor APZC r=botond (9856ab5160) - Bug 1257269 - Panning up in a scrollable element should not hide the toolbar r=kats,jchen (1036ffc9e3) - Bug 1219296 - Ship scroll snap information to the compositor. r=kats (0e920f02a1) - Bug 1219296 - Move the layout.css.scroll-snap.proximity-threshold pref to gfxPrefs, so it can be queried on the compositor thread. r=kats (2e3e1ec16e) - Bug 1219296 - Remove StartSmoothScroll()'s argument, which is no longer used. r=kats (12efcd9c79) - Bug 1219296 - Light refactoring to how a smooth scroll is launched inside APZC. r=kats (ba6a9ed9a2) - Bug 1219296 - Followup to fix stale code comments. r=me and DONTBUILD (fec5f65988) - Bug 1257641 - Remove now-unused code for the lightweight scroll offset update message. r=botond (d449e45d6d) - Bug 1236680 Part 1: Add new WinUtils function to Resolve moved Users folder. r=jimm (51d12f856c) - Bug 1236680 Part 2: Resolve GMP path for moved Users folder. r=cpearce (e568217b78) - Bug 1236680 Part 3: Add #ifs to include to fix bustage. r=me (40c38680ea) - Bug 1240315: Add startup crash report annotation for AppInit_DLLs; r=jimm (aa2040baae) - Bug 1253446 - patch 2 - Return the proper scaling factor when querying the primary screen on Windows. r=emk (9765e4f7ca) - Bug 1251624 - patch 1 - The desktop to device scaling in WinUtils::MonitorFromRect should not depend on custom CSS pixel scaling (devPixelsPerPx setting). r=emk (788b4ad5db) - Bug 1251624 - patch 2 - Check for scaling override (devPixelsPerPx setting) in nsScreenWin::GetDefaultCSSScaleFactor, for proper window positioning when a custom scale factor is used. r=emk (2843a3fe70) - Bug 1222149 - delete unused fields from AsyncEncodeAndWriteIcon; r=roc clang-cl says these are unused, so let's delete them. (62cf7f8f47) - Bug 1204809 - Notify (don't hang) third party windows when adding shortcut icon. r=jmathies (7e4058a0f8) - Bug 1253566 - Deal with char16_t/wchar_t mismatch. r=aklotz (1c6cf160c7) - Bug 1211941 - Let nsICacheStorage.openTruncate impl return an HTTP cache entry write handle, r=michal (6a5796fb93) - Bug 1050613 - Make sure force-valid for HTTP cache entries is removed when entries are removed, r=michal (9efb91eefc) - Bug 1248389 - Cache index causing CPU loops, r=honzab (175b5b27f2) - Bug 1066970 - Show 'calculating' during HTTP cache cleaning process in preferences window, r=michal (db722000d8) - Bug 1248958 - CacheIndex mRWBuf ownership too fragile, read-after-free, r=honzab (66ee3d1d0d) - Bug 1248003 - Purge from HTTP cache memory pool only in reasonable intervals, r=michal (1cd6cb5983) - Bug 1068674 - Don't turn off e10s if hardware acceleration is disabled. r=jimm (dfbef44278)
1087 lines
37 KiB
C++
1087 lines
37 KiB
C++
/* 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 CacheIndex__h__
|
|
#define CacheIndex__h__
|
|
|
|
#include "CacheLog.h"
|
|
#include "CacheFileIOManager.h"
|
|
#include "nsIRunnable.h"
|
|
#include "CacheHashUtils.h"
|
|
#include "nsICacheStorageService.h"
|
|
#include "nsICacheEntry.h"
|
|
#include "nsILoadContextInfo.h"
|
|
#include "nsTHashtable.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsWeakReference.h"
|
|
#include "mozilla/SHA1.h"
|
|
#include "mozilla/StaticMutex.h"
|
|
#include "mozilla/Endian.h"
|
|
#include "mozilla/TimeStamp.h"
|
|
|
|
class nsIFile;
|
|
class nsIDirectoryEnumerator;
|
|
class nsITimer;
|
|
|
|
|
|
#ifdef DEBUG
|
|
#define DEBUG_STATS 1
|
|
#endif
|
|
|
|
namespace mozilla {
|
|
namespace net {
|
|
|
|
class CacheFileMetadata;
|
|
class FileOpenHelper;
|
|
class CacheIndexIterator;
|
|
|
|
typedef struct {
|
|
// Version of the index. The index must be ignored and deleted when the file
|
|
// on disk was written with a newer version.
|
|
uint32_t mVersion;
|
|
|
|
// Timestamp of time when the last successful write of the index started.
|
|
// During update process we use this timestamp for a quick validation of entry
|
|
// files. If last modified time of the file is lower than this timestamp, we
|
|
// skip parsing of such file since the information in index should be up to
|
|
// date.
|
|
uint32_t mTimeStamp;
|
|
|
|
// We set this flag as soon as possible after parsing index during startup
|
|
// and clean it after we write journal to disk during shutdown. We ignore the
|
|
// journal and start update process whenever this flag is set during index
|
|
// parsing.
|
|
uint32_t mIsDirty;
|
|
} CacheIndexHeader;
|
|
|
|
struct CacheIndexRecord {
|
|
SHA1Sum::Hash mHash;
|
|
uint32_t mFrecency;
|
|
uint32_t mExpirationTime;
|
|
uint32_t mAppId;
|
|
|
|
/*
|
|
* 1000 0000 0000 0000 0000 0000 0000 0000 : initialized
|
|
* 0100 0000 0000 0000 0000 0000 0000 0000 : anonymous
|
|
* 0010 0000 0000 0000 0000 0000 0000 0000 : inBrowser
|
|
* 0001 0000 0000 0000 0000 0000 0000 0000 : removed
|
|
* 0000 1000 0000 0000 0000 0000 0000 0000 : dirty
|
|
* 0000 0100 0000 0000 0000 0000 0000 0000 : fresh
|
|
* 0000 0011 0000 0000 0000 0000 0000 0000 : reserved
|
|
* 0000 0000 1111 1111 1111 1111 1111 1111 : file size (in kB)
|
|
*/
|
|
uint32_t mFlags;
|
|
|
|
CacheIndexRecord()
|
|
: mFrecency(0)
|
|
, mExpirationTime(nsICacheEntry::NO_EXPIRATION_TIME)
|
|
, mAppId(nsILoadContextInfo::NO_APP_ID)
|
|
, mFlags(0)
|
|
{}
|
|
};
|
|
|
|
class CacheIndexEntry : public PLDHashEntryHdr
|
|
{
|
|
public:
|
|
typedef const SHA1Sum::Hash& KeyType;
|
|
typedef const SHA1Sum::Hash* KeyTypePointer;
|
|
|
|
explicit CacheIndexEntry(KeyTypePointer aKey)
|
|
{
|
|
MOZ_COUNT_CTOR(CacheIndexEntry);
|
|
mRec = new CacheIndexRecord();
|
|
LOG(("CacheIndexEntry::CacheIndexEntry() - Created record [rec=%p]", mRec.get()));
|
|
memcpy(&mRec->mHash, aKey, sizeof(SHA1Sum::Hash));
|
|
}
|
|
CacheIndexEntry(const CacheIndexEntry& aOther)
|
|
{
|
|
NS_NOTREACHED("CacheIndexEntry copy constructor is forbidden!");
|
|
}
|
|
~CacheIndexEntry()
|
|
{
|
|
MOZ_COUNT_DTOR(CacheIndexEntry);
|
|
LOG(("CacheIndexEntry::~CacheIndexEntry() - Deleting record [rec=%p]",
|
|
mRec.get()));
|
|
}
|
|
|
|
// KeyEquals(): does this entry match this key?
|
|
bool KeyEquals(KeyTypePointer aKey) const
|
|
{
|
|
return memcmp(&mRec->mHash, aKey, sizeof(SHA1Sum::Hash)) == 0;
|
|
}
|
|
|
|
// KeyToPointer(): Convert KeyType to KeyTypePointer
|
|
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
|
|
|
|
// HashKey(): calculate the hash number
|
|
static PLDHashNumber HashKey(KeyTypePointer aKey)
|
|
{
|
|
return (reinterpret_cast<const uint32_t *>(aKey))[0];
|
|
}
|
|
|
|
// ALLOW_MEMMOVE can we move this class with memmove(), or do we have
|
|
// to use the copy constructor?
|
|
enum { ALLOW_MEMMOVE = true };
|
|
|
|
bool operator==(const CacheIndexEntry& aOther) const
|
|
{
|
|
return KeyEquals(&aOther.mRec->mHash);
|
|
}
|
|
|
|
CacheIndexEntry& operator=(const CacheIndexEntry& aOther)
|
|
{
|
|
MOZ_ASSERT(memcmp(&mRec->mHash, &aOther.mRec->mHash,
|
|
sizeof(SHA1Sum::Hash)) == 0);
|
|
mRec->mFrecency = aOther.mRec->mFrecency;
|
|
mRec->mExpirationTime = aOther.mRec->mExpirationTime;
|
|
mRec->mAppId = aOther.mRec->mAppId;
|
|
mRec->mFlags = aOther.mRec->mFlags;
|
|
return *this;
|
|
}
|
|
|
|
void InitNew()
|
|
{
|
|
mRec->mFrecency = 0;
|
|
mRec->mExpirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
|
|
mRec->mAppId = nsILoadContextInfo::NO_APP_ID;
|
|
mRec->mFlags = 0;
|
|
}
|
|
|
|
void Init(uint32_t aAppId, bool aAnonymous, bool aInBrowser, bool aPinned)
|
|
{
|
|
MOZ_ASSERT(mRec->mFrecency == 0);
|
|
MOZ_ASSERT(mRec->mExpirationTime == nsICacheEntry::NO_EXPIRATION_TIME);
|
|
MOZ_ASSERT(mRec->mAppId == nsILoadContextInfo::NO_APP_ID);
|
|
// When we init the entry it must be fresh and may be dirty
|
|
MOZ_ASSERT((mRec->mFlags & ~kDirtyMask) == kFreshMask);
|
|
|
|
mRec->mAppId = aAppId;
|
|
mRec->mFlags |= kInitializedMask;
|
|
if (aAnonymous) {
|
|
mRec->mFlags |= kAnonymousMask;
|
|
}
|
|
if (aInBrowser) {
|
|
mRec->mFlags |= kInBrowserMask;
|
|
}
|
|
if (aPinned) {
|
|
mRec->mFlags |= kPinnedMask;
|
|
}
|
|
}
|
|
|
|
const SHA1Sum::Hash * Hash() const { return &mRec->mHash; }
|
|
|
|
bool IsInitialized() const { return !!(mRec->mFlags & kInitializedMask); }
|
|
|
|
uint32_t AppId() const { return mRec->mAppId; }
|
|
bool Anonymous() const { return !!(mRec->mFlags & kAnonymousMask); }
|
|
bool InBrowser() const { return !!(mRec->mFlags & kInBrowserMask); }
|
|
|
|
bool IsRemoved() const { return !!(mRec->mFlags & kRemovedMask); }
|
|
void MarkRemoved() { mRec->mFlags |= kRemovedMask; }
|
|
|
|
bool IsDirty() const { return !!(mRec->mFlags & kDirtyMask); }
|
|
void MarkDirty() { mRec->mFlags |= kDirtyMask; }
|
|
void ClearDirty() { mRec->mFlags &= ~kDirtyMask; }
|
|
|
|
bool IsFresh() const { return !!(mRec->mFlags & kFreshMask); }
|
|
void MarkFresh() { mRec->mFlags |= kFreshMask; }
|
|
|
|
bool IsPinned() const { return !!(mRec->mFlags & kPinnedMask); }
|
|
|
|
void SetFrecency(uint32_t aFrecency) { mRec->mFrecency = aFrecency; }
|
|
uint32_t GetFrecency() const { return mRec->mFrecency; }
|
|
|
|
void SetExpirationTime(uint32_t aExpirationTime)
|
|
{
|
|
mRec->mExpirationTime = aExpirationTime;
|
|
}
|
|
uint32_t GetExpirationTime() const { return mRec->mExpirationTime; }
|
|
|
|
// Sets filesize in kilobytes.
|
|
void SetFileSize(uint32_t aFileSize)
|
|
{
|
|
if (aFileSize > kFileSizeMask) {
|
|
LOG(("CacheIndexEntry::SetFileSize() - FileSize is too large, "
|
|
"truncating to %u", kFileSizeMask));
|
|
aFileSize = kFileSizeMask;
|
|
}
|
|
mRec->mFlags &= ~kFileSizeMask;
|
|
mRec->mFlags |= aFileSize;
|
|
}
|
|
// Returns filesize in kilobytes.
|
|
uint32_t GetFileSize() const { return GetFileSize(mRec); }
|
|
static uint32_t GetFileSize(CacheIndexRecord *aRec)
|
|
{
|
|
return aRec->mFlags & kFileSizeMask;
|
|
}
|
|
static uint32_t IsPinned(CacheIndexRecord *aRec)
|
|
{
|
|
return aRec->mFlags & kPinnedMask;
|
|
}
|
|
bool IsFileEmpty() const { return GetFileSize() == 0; }
|
|
|
|
void WriteToBuf(void *aBuf)
|
|
{
|
|
CacheIndexRecord *dst = reinterpret_cast<CacheIndexRecord *>(aBuf);
|
|
|
|
// Copy the whole record to the buffer.
|
|
memcpy(aBuf, mRec, sizeof(CacheIndexRecord));
|
|
|
|
// Dirty and fresh flags should never go to disk, since they make sense only
|
|
// during current session.
|
|
dst->mFlags &= ~kDirtyMask;
|
|
dst->mFlags &= ~kFreshMask;
|
|
|
|
#if defined(IS_LITTLE_ENDIAN)
|
|
// Data in the buffer are in machine byte order and we want them in network
|
|
// byte order.
|
|
NetworkEndian::writeUint32(&dst->mFrecency, dst->mFrecency);
|
|
NetworkEndian::writeUint32(&dst->mExpirationTime, dst->mExpirationTime);
|
|
NetworkEndian::writeUint32(&dst->mAppId, dst->mAppId);
|
|
NetworkEndian::writeUint32(&dst->mFlags, dst->mFlags);
|
|
#endif
|
|
}
|
|
|
|
void ReadFromBuf(void *aBuf)
|
|
{
|
|
CacheIndexRecord *src= reinterpret_cast<CacheIndexRecord *>(aBuf);
|
|
MOZ_ASSERT(memcmp(&mRec->mHash, &src->mHash,
|
|
sizeof(SHA1Sum::Hash)) == 0);
|
|
|
|
mRec->mFrecency = NetworkEndian::readUint32(&src->mFrecency);
|
|
mRec->mExpirationTime = NetworkEndian::readUint32(&src->mExpirationTime);
|
|
mRec->mAppId = NetworkEndian::readUint32(&src->mAppId);
|
|
mRec->mFlags = NetworkEndian::readUint32(&src->mFlags);
|
|
}
|
|
|
|
void Log() const {
|
|
LOG(("CacheIndexEntry::Log() [this=%p, hash=%08x%08x%08x%08x%08x, fresh=%u,"
|
|
" initialized=%u, removed=%u, dirty=%u, anonymous=%u, inBrowser=%u, "
|
|
"appId=%u, frecency=%u, expirationTime=%u, size=%u]",
|
|
this, LOGSHA1(mRec->mHash), IsFresh(), IsInitialized(), IsRemoved(),
|
|
IsDirty(), Anonymous(), InBrowser(), AppId(), GetFrecency(),
|
|
GetExpirationTime(), GetFileSize()));
|
|
}
|
|
|
|
static bool RecordMatchesLoadContextInfo(CacheIndexRecord *aRec,
|
|
nsILoadContextInfo *aInfo)
|
|
{
|
|
if (!aInfo->IsPrivate() &&
|
|
aInfo->OriginAttributesPtr()->mAppId == aRec->mAppId &&
|
|
aInfo->IsAnonymous() == !!(aRec->mFlags & kAnonymousMask) &&
|
|
aInfo->OriginAttributesPtr()->mInBrowser == !!(aRec->mFlags & kInBrowserMask)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Memory reporting
|
|
size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
|
{
|
|
return mallocSizeOf(mRec.get());
|
|
}
|
|
|
|
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
|
{
|
|
return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
|
|
}
|
|
|
|
private:
|
|
friend class CacheIndexEntryUpdate;
|
|
friend class CacheIndex;
|
|
friend class CacheIndexEntryAutoManage;
|
|
|
|
static const uint32_t kInitializedMask = 0x80000000;
|
|
static const uint32_t kAnonymousMask = 0x40000000;
|
|
static const uint32_t kInBrowserMask = 0x20000000;
|
|
|
|
// This flag is set when the entry was removed. We need to keep this
|
|
// information in memory until we write the index file.
|
|
static const uint32_t kRemovedMask = 0x10000000;
|
|
|
|
// This flag is set when the information in memory is not in sync with the
|
|
// information in index file on disk.
|
|
static const uint32_t kDirtyMask = 0x08000000;
|
|
|
|
// This flag is set when the information about the entry is fresh, i.e.
|
|
// we've created or opened this entry during this session, or we've seen
|
|
// this entry during update or build process.
|
|
static const uint32_t kFreshMask = 0x04000000;
|
|
|
|
// Indicates a pinned entry.
|
|
static const uint32_t kPinnedMask = 0x02000000;
|
|
|
|
static const uint32_t kReservedMask = 0x01000000;
|
|
|
|
// FileSize in kilobytes
|
|
static const uint32_t kFileSizeMask = 0x00FFFFFF;
|
|
|
|
nsAutoPtr<CacheIndexRecord> mRec;
|
|
};
|
|
|
|
class CacheIndexEntryUpdate : public CacheIndexEntry
|
|
{
|
|
public:
|
|
explicit CacheIndexEntryUpdate(CacheIndexEntry::KeyTypePointer aKey)
|
|
: CacheIndexEntry(aKey)
|
|
, mUpdateFlags(0)
|
|
{
|
|
MOZ_COUNT_CTOR(CacheIndexEntryUpdate);
|
|
LOG(("CacheIndexEntryUpdate::CacheIndexEntryUpdate()"));
|
|
}
|
|
~CacheIndexEntryUpdate()
|
|
{
|
|
MOZ_COUNT_DTOR(CacheIndexEntryUpdate);
|
|
LOG(("CacheIndexEntryUpdate::~CacheIndexEntryUpdate()"));
|
|
}
|
|
|
|
CacheIndexEntryUpdate& operator=(const CacheIndexEntry& aOther)
|
|
{
|
|
MOZ_ASSERT(memcmp(&mRec->mHash, &aOther.mRec->mHash,
|
|
sizeof(SHA1Sum::Hash)) == 0);
|
|
mUpdateFlags = 0;
|
|
*(static_cast<CacheIndexEntry *>(this)) = aOther;
|
|
return *this;
|
|
}
|
|
|
|
void InitNew()
|
|
{
|
|
mUpdateFlags = kFrecencyUpdatedMask | kExpirationUpdatedMask |
|
|
kFileSizeUpdatedMask;
|
|
CacheIndexEntry::InitNew();
|
|
}
|
|
|
|
void SetFrecency(uint32_t aFrecency)
|
|
{
|
|
mUpdateFlags |= kFrecencyUpdatedMask;
|
|
CacheIndexEntry::SetFrecency(aFrecency);
|
|
}
|
|
|
|
void SetExpirationTime(uint32_t aExpirationTime)
|
|
{
|
|
mUpdateFlags |= kExpirationUpdatedMask;
|
|
CacheIndexEntry::SetExpirationTime(aExpirationTime);
|
|
}
|
|
|
|
void SetFileSize(uint32_t aFileSize)
|
|
{
|
|
mUpdateFlags |= kFileSizeUpdatedMask;
|
|
CacheIndexEntry::SetFileSize(aFileSize);
|
|
}
|
|
|
|
void ApplyUpdate(CacheIndexEntry *aDst) {
|
|
MOZ_ASSERT(memcmp(&mRec->mHash, &aDst->mRec->mHash,
|
|
sizeof(SHA1Sum::Hash)) == 0);
|
|
if (mUpdateFlags & kFrecencyUpdatedMask) {
|
|
aDst->mRec->mFrecency = mRec->mFrecency;
|
|
}
|
|
if (mUpdateFlags & kExpirationUpdatedMask) {
|
|
aDst->mRec->mExpirationTime = mRec->mExpirationTime;
|
|
}
|
|
aDst->mRec->mAppId = mRec->mAppId;
|
|
if (mUpdateFlags & kFileSizeUpdatedMask) {
|
|
aDst->mRec->mFlags = mRec->mFlags;
|
|
} else {
|
|
// Copy all flags except file size.
|
|
aDst->mRec->mFlags &= kFileSizeMask;
|
|
aDst->mRec->mFlags |= (mRec->mFlags & ~kFileSizeMask);
|
|
}
|
|
}
|
|
|
|
private:
|
|
static const uint32_t kFrecencyUpdatedMask = 0x00000001;
|
|
static const uint32_t kExpirationUpdatedMask = 0x00000002;
|
|
static const uint32_t kFileSizeUpdatedMask = 0x00000004;
|
|
|
|
uint32_t mUpdateFlags;
|
|
};
|
|
|
|
class CacheIndexStats
|
|
{
|
|
public:
|
|
CacheIndexStats()
|
|
: mCount(0)
|
|
, mNotInitialized(0)
|
|
, mRemoved(0)
|
|
, mDirty(0)
|
|
, mFresh(0)
|
|
, mEmpty(0)
|
|
, mSize(0)
|
|
#ifdef DEBUG
|
|
, mStateLogged(false)
|
|
, mDisableLogging(false)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
bool operator==(const CacheIndexStats& aOther) const
|
|
{
|
|
return
|
|
#ifdef DEBUG
|
|
aOther.mStateLogged == mStateLogged &&
|
|
#endif
|
|
aOther.mCount == mCount &&
|
|
aOther.mNotInitialized == mNotInitialized &&
|
|
aOther.mRemoved == mRemoved &&
|
|
aOther.mDirty == mDirty &&
|
|
aOther.mFresh == mFresh &&
|
|
aOther.mEmpty == mEmpty &&
|
|
aOther.mSize == mSize;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void DisableLogging() {
|
|
mDisableLogging = true;
|
|
}
|
|
#endif
|
|
|
|
void Log() {
|
|
LOG(("CacheIndexStats::Log() [count=%u, notInitialized=%u, removed=%u, "
|
|
"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;
|
|
}
|
|
#endif
|
|
|
|
uint32_t Count() {
|
|
MOZ_ASSERT(!mStateLogged, "CacheIndexStats::Count() - state logged!");
|
|
return mCount;
|
|
}
|
|
|
|
uint32_t Dirty() {
|
|
MOZ_ASSERT(!mStateLogged, "CacheIndexStats::Dirty() - state logged!");
|
|
return mDirty;
|
|
}
|
|
|
|
uint32_t Fresh() {
|
|
MOZ_ASSERT(!mStateLogged, "CacheIndexStats::Fresh() - state logged!");
|
|
return mFresh;
|
|
}
|
|
|
|
uint32_t ActiveEntriesCount() {
|
|
MOZ_ASSERT(!mStateLogged, "CacheIndexStats::ActiveEntriesCount() - state "
|
|
"logged!");
|
|
return mCount - mRemoved - mNotInitialized - mEmpty;
|
|
}
|
|
|
|
uint32_t Size() {
|
|
MOZ_ASSERT(!mStateLogged, "CacheIndexStats::Size() - state logged!");
|
|
return mSize;
|
|
}
|
|
|
|
void BeforeChange(const CacheIndexEntry *aEntry) {
|
|
#ifdef DEBUG_STATS
|
|
if (!mDisableLogging) {
|
|
LOG(("CacheIndexStats::BeforeChange()"));
|
|
Log();
|
|
}
|
|
#endif
|
|
|
|
MOZ_ASSERT(!mStateLogged, "CacheIndexStats::BeforeChange() - state "
|
|
"logged!");
|
|
#ifdef DEBUG
|
|
mStateLogged = true;
|
|
#endif
|
|
if (aEntry) {
|
|
MOZ_ASSERT(mCount);
|
|
mCount--;
|
|
if (aEntry->IsDirty()) {
|
|
MOZ_ASSERT(mDirty);
|
|
mDirty--;
|
|
}
|
|
if (aEntry->IsFresh()) {
|
|
MOZ_ASSERT(mFresh);
|
|
mFresh--;
|
|
}
|
|
if (aEntry->IsRemoved()) {
|
|
MOZ_ASSERT(mRemoved);
|
|
mRemoved--;
|
|
} else {
|
|
if (!aEntry->IsInitialized()) {
|
|
MOZ_ASSERT(mNotInitialized);
|
|
mNotInitialized--;
|
|
} else {
|
|
if (aEntry->IsFileEmpty()) {
|
|
MOZ_ASSERT(mEmpty);
|
|
mEmpty--;
|
|
} else {
|
|
MOZ_ASSERT(mSize >= aEntry->GetFileSize());
|
|
mSize -= aEntry->GetFileSize();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AfterChange(const CacheIndexEntry *aEntry) {
|
|
MOZ_ASSERT(mStateLogged, "CacheIndexStats::AfterChange() - state not "
|
|
"logged!");
|
|
#ifdef DEBUG
|
|
mStateLogged = false;
|
|
#endif
|
|
if (aEntry) {
|
|
++mCount;
|
|
if (aEntry->IsDirty()) {
|
|
mDirty++;
|
|
}
|
|
if (aEntry->IsFresh()) {
|
|
mFresh++;
|
|
}
|
|
if (aEntry->IsRemoved()) {
|
|
mRemoved++;
|
|
} else {
|
|
if (!aEntry->IsInitialized()) {
|
|
mNotInitialized++;
|
|
} else {
|
|
if (aEntry->IsFileEmpty()) {
|
|
mEmpty++;
|
|
} else {
|
|
mSize += aEntry->GetFileSize();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_STATS
|
|
if (!mDisableLogging) {
|
|
LOG(("CacheIndexStats::AfterChange()"));
|
|
Log();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
private:
|
|
uint32_t mCount;
|
|
uint32_t mNotInitialized;
|
|
uint32_t mRemoved;
|
|
uint32_t mDirty;
|
|
uint32_t mFresh;
|
|
uint32_t mEmpty;
|
|
uint32_t mSize;
|
|
#ifdef DEBUG
|
|
// We completely remove the data about an entry from the stats in
|
|
// BeforeChange() and set this flag to true. The entry is then modified,
|
|
// deleted or created and the data is again put into the stats and this flag
|
|
// set to false. Statistics must not be read during this time since the
|
|
// information is not correct.
|
|
bool mStateLogged;
|
|
|
|
// Disables logging in this instance of CacheIndexStats
|
|
bool mDisableLogging;
|
|
#endif
|
|
};
|
|
|
|
class CacheIndex : public CacheFileIOListener
|
|
, public nsIRunnable
|
|
{
|
|
public:
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
NS_DECL_NSIRUNNABLE
|
|
|
|
CacheIndex();
|
|
|
|
static nsresult Init(nsIFile *aCacheDirectory);
|
|
static nsresult PreShutdown();
|
|
static nsresult Shutdown();
|
|
|
|
// Following methods can be called only on IO thread.
|
|
|
|
// Add entry to the index. The entry shouldn't be present in index. This
|
|
// method is called whenever a new handle for a new entry file is created. The
|
|
// newly created entry is not initialized and it must be either initialized
|
|
// with InitEntry() or removed with RemoveEntry().
|
|
static nsresult AddEntry(const SHA1Sum::Hash *aHash);
|
|
|
|
// Inform index about an existing entry that should be present in index. This
|
|
// method is called whenever a new handle for an existing entry file is
|
|
// created. Like in case of AddEntry(), either InitEntry() or RemoveEntry()
|
|
// must be called on the entry, since the entry is not initizlized if the
|
|
// index is outdated.
|
|
static nsresult EnsureEntryExists(const SHA1Sum::Hash *aHash);
|
|
|
|
// Initialize the entry. It MUST be present in index. Call to AddEntry() or
|
|
// EnsureEntryExists() must precede the call to this method.
|
|
static nsresult InitEntry(const SHA1Sum::Hash *aHash,
|
|
uint32_t aAppId,
|
|
bool aAnonymous,
|
|
bool aInBrowser,
|
|
bool aPinned);
|
|
|
|
// Remove entry from index. The entry should be present in index.
|
|
static nsresult RemoveEntry(const SHA1Sum::Hash *aHash);
|
|
|
|
// Update some information in entry. The entry MUST be present in index and
|
|
// MUST be initialized. Call to AddEntry() or EnsureEntryExists() and to
|
|
// InitEntry() must precede the call to this method.
|
|
// Pass nullptr if the value didn't change.
|
|
static nsresult UpdateEntry(const SHA1Sum::Hash *aHash,
|
|
const uint32_t *aFrecency,
|
|
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,
|
|
DO_NOT_KNOW = 2
|
|
};
|
|
|
|
// Returns status of the entry in index for the given key. It can be called
|
|
// on any thread.
|
|
// If _pinned is non-null, it's filled with pinning status of the entry.
|
|
static nsresult HasEntry(const nsACString &aKey, EntryStatus *_retval,
|
|
bool *_pinned = nullptr);
|
|
static nsresult HasEntry(const SHA1Sum::Hash &hash, EntryStatus *_retval,
|
|
bool *_pinned = nullptr);
|
|
|
|
// Returns a hash of the least important entry that should be evicted if the
|
|
// cache size is over limit and also returns a total number of all entries in
|
|
// the index minus the number of forced valid entries and unpinned entries
|
|
// that we encounter when searching (see below)
|
|
static nsresult GetEntryForEviction(bool aIgnoreEmptyEntries, SHA1Sum::Hash *aHash, uint32_t *aCnt);
|
|
|
|
// Checks if a cache entry is currently forced valid. Used to prevent an entry
|
|
// (that has been forced valid) from being evicted when the cache size reaches
|
|
// its limit.
|
|
static bool IsForcedValidEntry(const SHA1Sum::Hash *aHash);
|
|
|
|
// Returns cache size in kB.
|
|
static nsresult GetCacheSize(uint32_t *_retval);
|
|
|
|
// Synchronously returns the disk occupation and number of entries per-context.
|
|
// Callable on any thread.
|
|
static nsresult GetCacheStats(nsILoadContextInfo *aInfo, uint32_t *aSize, uint32_t *aCount);
|
|
|
|
// Asynchronously gets the disk cache size, used for display in the UI.
|
|
static nsresult AsyncGetDiskConsumption(nsICacheStorageConsumptionObserver* aObserver);
|
|
|
|
// Returns an iterator that returns entries matching a given context that were
|
|
// present in the index at the time this method was called. If aAddNew is true
|
|
// then the iterator will also return entries created after this call.
|
|
// NOTE: When some entry is removed from index it is removed also from the
|
|
// iterator regardless what aAddNew was passed.
|
|
static nsresult GetIterator(nsILoadContextInfo *aInfo, bool aAddNew,
|
|
CacheIndexIterator **_retval);
|
|
|
|
// Returns true if we _think_ that the index is up to date. I.e. the state is
|
|
// READY or WRITING and mIndexNeedsUpdate as well as mShuttingDown is false.
|
|
static nsresult IsUpToDate(bool *_retval);
|
|
|
|
// Called from CacheStorageService::Clear() and CacheFileContextEvictor::EvictEntries(),
|
|
// sets a flag that blocks notification to AsyncGetDiskConsumption.
|
|
static void OnAsyncEviction(bool aEvicting);
|
|
|
|
// Memory reporting
|
|
static size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
|
static size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
|
|
|
private:
|
|
friend class CacheIndexEntryAutoManage;
|
|
friend class FileOpenHelper;
|
|
friend class CacheIndexIterator;
|
|
|
|
virtual ~CacheIndex();
|
|
|
|
NS_IMETHOD OnFileOpened(CacheFileHandle *aHandle, nsresult aResult) override;
|
|
nsresult OnFileOpenedInternal(FileOpenHelper *aOpener,
|
|
CacheFileHandle *aHandle, nsresult aResult);
|
|
NS_IMETHOD OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
|
|
nsresult aResult) override;
|
|
NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult) override;
|
|
NS_IMETHOD OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult) override;
|
|
NS_IMETHOD OnEOFSet(CacheFileHandle *aHandle, nsresult aResult) override;
|
|
NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) override;
|
|
|
|
nsresult InitInternal(nsIFile *aCacheDirectory);
|
|
void PreShutdownInternal();
|
|
|
|
// This method returns false when index is not initialized or is shut down.
|
|
bool IsIndexUsable();
|
|
|
|
// This method checks whether the entry has the same values of appId,
|
|
// isAnonymous and isInBrowser. We don't expect to find a collision since
|
|
// these values are part of the key that we hash and we use a strong hash
|
|
// function.
|
|
static bool IsCollision(CacheIndexEntry *aEntry,
|
|
uint32_t aAppId,
|
|
bool aAnonymous,
|
|
bool aInBrowser);
|
|
|
|
// Checks whether any of the information about the entry has changed.
|
|
static bool HasEntryChanged(CacheIndexEntry *aEntry,
|
|
const uint32_t *aFrecency,
|
|
const uint32_t *aExpirationTime,
|
|
const uint32_t *aSize);
|
|
|
|
// Merge all pending operations from mPendingUpdates into mIndex.
|
|
void ProcessPendingOperations();
|
|
|
|
// Following methods perform writing of the index file.
|
|
//
|
|
// The index is written periodically, but not earlier than once in
|
|
// kMinDumpInterval and there must be at least kMinUnwrittenChanges
|
|
// differences between index on disk and in memory. Index is always first
|
|
// written to a temporary file and the old index file is replaced when the
|
|
// writing process succeeds.
|
|
//
|
|
// Starts writing of index when both limits (minimal delay between writes and
|
|
// minimum number of changes in index) were exceeded.
|
|
bool WriteIndexToDiskIfNeeded();
|
|
// Starts writing of index file.
|
|
void WriteIndexToDisk();
|
|
// Serializes part of mIndex hashtable to the write buffer a writes the buffer
|
|
// to the file.
|
|
void WriteRecords();
|
|
// Finalizes writing process.
|
|
void FinishWrite(bool aSucceeded);
|
|
|
|
// Following methods perform writing of the journal during shutdown. All these
|
|
// methods must be called only during shutdown since they write/delete files
|
|
// directly on the main thread instead of using CacheFileIOManager that does
|
|
// it asynchronously on IO thread. Journal contains only entries that are
|
|
// dirty, i.e. changes that are not present in the index file on the disk.
|
|
// When the log is written successfully, the dirty flag in index file is
|
|
// cleared.
|
|
nsresult GetFile(const nsACString &aName, nsIFile **_retval);
|
|
nsresult RemoveFile(const nsACString &aName);
|
|
void RemoveIndexFromDisk();
|
|
// Writes journal to the disk and clears dirty flag in index header.
|
|
nsresult WriteLogToDisk();
|
|
|
|
// Following methods perform reading of the index from the disk.
|
|
//
|
|
// Index is read at startup just after initializing the CacheIndex. There are
|
|
// 3 files used when manipulating with index: index file, journal file and
|
|
// a temporary file. All files contain the hash of the data, so we can check
|
|
// whether the content is valid and complete. Index file contains also a dirty
|
|
// flag in the index header which is unset on a clean shutdown. During opening
|
|
// and reading of the files we determine the status of the whole index from
|
|
// the states of the separate files. Following table shows all possible
|
|
// combinations:
|
|
//
|
|
// index, journal, tmpfile
|
|
// M * * - index is missing -> BUILD
|
|
// I * * - index is invalid -> BUILD
|
|
// D * * - index is dirty -> UPDATE
|
|
// C M * - index is dirty -> UPDATE
|
|
// C I * - unexpected state -> UPDATE
|
|
// C V E - unexpected state -> UPDATE
|
|
// C V M - index is up to date -> READY
|
|
//
|
|
// where the letters mean:
|
|
// * - any state
|
|
// E - file exists
|
|
// M - file is missing
|
|
// I - data is invalid (parsing failed or hash didn't match)
|
|
// D - dirty (data in index file is correct, but dirty flag is set)
|
|
// C - clean (index file is clean)
|
|
// V - valid (data in journal file is correct)
|
|
//
|
|
// Note: We accept the data from journal only when the index is up to date as
|
|
// a whole (i.e. C,V,M state).
|
|
//
|
|
// We rename the journal file to the temporary file as soon as possible after
|
|
// initial test to ensure that we start update process on the next startup if
|
|
// FF crashes during parsing of the index.
|
|
//
|
|
// Initiates reading index from disk.
|
|
void ReadIndexFromDisk();
|
|
// Starts reading data from index file.
|
|
void StartReadingIndex();
|
|
// Parses data read from index file.
|
|
void ParseRecords();
|
|
// Starts reading data from journal file.
|
|
void StartReadingJournal();
|
|
// Parses data read from journal file.
|
|
void ParseJournal();
|
|
// Merges entries from journal into mIndex.
|
|
void MergeJournal();
|
|
// In debug build this method checks that we have no fresh entry in mIndex
|
|
// after we finish reading index and before we process pending operations.
|
|
void EnsureNoFreshEntry();
|
|
// In debug build this method is called after processing pending operations
|
|
// to make sure mIndexStats contains correct information.
|
|
void EnsureCorrectStats();
|
|
// Finalizes reading process.
|
|
void FinishRead(bool aSucceeded);
|
|
|
|
// Following methods perform updating and building of the index.
|
|
// Timer callback that starts update or build process.
|
|
static void DelayedUpdate(nsITimer *aTimer, void *aClosure);
|
|
// Posts timer event that start update or build process.
|
|
nsresult ScheduleUpdateTimer(uint32_t aDelay);
|
|
nsresult SetupDirectoryEnumerator();
|
|
void InitEntryFromDiskData(CacheIndexEntry *aEntry,
|
|
CacheFileMetadata *aMetaData,
|
|
int64_t aFileSize);
|
|
// 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();
|
|
|
|
bool StartUpdatingIndexIfNeeded(bool aSwitchingToReadyState = false);
|
|
// 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 or build process.
|
|
void FinishUpdate(bool aSucceeded);
|
|
|
|
void RemoveNonFreshEntries();
|
|
|
|
enum EState {
|
|
// Initial state in which the index is not usable
|
|
// Possible transitions:
|
|
// -> READING
|
|
INITIAL = 0,
|
|
|
|
// Index is being read from the disk.
|
|
// Possible transitions:
|
|
// -> INITIAL - We failed to dispatch a read event.
|
|
// -> BUILDING - No or corrupted index file was found.
|
|
// -> UPDATING - No or corrupted journal file was found.
|
|
// - Dirty flag was set in index header.
|
|
// -> READY - Index was read successfully or was interrupted by
|
|
// pre-shutdown.
|
|
// -> SHUTDOWN - This could happen only in case of pre-shutdown failure.
|
|
READING = 1,
|
|
|
|
// Index is being written to the disk.
|
|
// Possible transitions:
|
|
// -> READY - Writing of index finished or was interrupted by
|
|
// pre-shutdown..
|
|
// -> UPDATING - Writing of index finished, but index was found outdated
|
|
// during writing.
|
|
// -> SHUTDOWN - This could happen only in case of pre-shutdown failure.
|
|
WRITING = 2,
|
|
|
|
// Index is being build.
|
|
// Possible transitions:
|
|
// -> READY - Building of index finished or was interrupted by
|
|
// pre-shutdown.
|
|
// -> SHUTDOWN - This could happen only in case of pre-shutdown failure.
|
|
BUILDING = 3,
|
|
|
|
// Index is being updated.
|
|
// Possible transitions:
|
|
// -> READY - Updating of index finished or was interrupted by
|
|
// pre-shutdown.
|
|
// -> SHUTDOWN - This could happen only in case of pre-shutdown failure.
|
|
UPDATING = 4,
|
|
|
|
// Index is ready.
|
|
// Possible transitions:
|
|
// -> UPDATING - Index was found outdated.
|
|
// -> SHUTDOWN - Index is shutting down.
|
|
READY = 5,
|
|
|
|
// Index is shutting down.
|
|
SHUTDOWN = 6
|
|
};
|
|
|
|
static char const * StateString(EState aState);
|
|
void ChangeState(EState aNewState);
|
|
void NotifyAsyncGetDiskConsumptionCallbacks();
|
|
|
|
// Allocates and releases buffer used for reading and writing index.
|
|
void AllocBuffer();
|
|
void ReleaseBuffer();
|
|
|
|
// Methods used by CacheIndexEntryAutoManage to keep the arrays up to date.
|
|
void InsertRecordToFrecencyArray(CacheIndexRecord *aRecord);
|
|
void RemoveRecordFromFrecencyArray(CacheIndexRecord *aRecord);
|
|
|
|
// Methods used by CacheIndexEntryAutoManage to keep the iterators up to date.
|
|
void AddRecordToIterators(CacheIndexRecord *aRecord);
|
|
void RemoveRecordFromIterators(CacheIndexRecord *aRecord);
|
|
void ReplaceRecordInIterators(CacheIndexRecord *aOldRecord,
|
|
CacheIndexRecord *aNewRecord);
|
|
|
|
// Memory reporting (private part)
|
|
size_t SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const;
|
|
|
|
static CacheIndex *gInstance;
|
|
static StaticMutex sLock;
|
|
|
|
nsCOMPtr<nsIFile> mCacheDirectory;
|
|
|
|
EState mState;
|
|
// Timestamp of time when the index was initialized. We use it to delay
|
|
// initial update or build of index.
|
|
TimeStamp mStartTime;
|
|
// Set to true in PreShutdown(), it is checked on variaous places to prevent
|
|
// starting any process (write, update, etc.) during shutdown.
|
|
bool mShuttingDown;
|
|
// When set to true, update process should start as soon as possible. This
|
|
// flag is set whenever we find some inconsistency which would be fixed by
|
|
// update process. The flag is checked always when switching to READY state.
|
|
// To make sure we start the update process as soon as possible, methods that
|
|
// 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
|
|
// mark index clean (and also don't write journal) to ensure that update or
|
|
// build will be initiated on the next start.
|
|
bool mDontMarkIndexClean;
|
|
// Timestamp value from index file. It is used during update process to skip
|
|
// entries that were last modified before this timestamp.
|
|
uint32_t mIndexTimeStamp;
|
|
// Timestamp of last time the index was dumped to disk.
|
|
// NOTE: The index might not be necessarily dumped at this time. The value
|
|
// is used to schedule next dump of the index.
|
|
TimeStamp mLastDumpTime;
|
|
|
|
// Timer of delayed update/build.
|
|
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:
|
|
// - in hashtable when writing index because they were already written
|
|
// - in index file when reading index because they were already read
|
|
uint32_t mSkipEntries;
|
|
// Number of entries that should be written to disk. This is number of entries
|
|
// in hashtable that are initialized and are not marked as removed when writing
|
|
// begins.
|
|
uint32_t mProcessEntries;
|
|
char *mRWBuf;
|
|
uint32_t mRWBufSize;
|
|
uint32_t mRWBufPos;
|
|
RefPtr<CacheHash> mRWHash;
|
|
|
|
// Reading of journal succeeded if true.
|
|
bool mJournalReadSuccessfully;
|
|
|
|
// Handle used for writing and reading index file.
|
|
RefPtr<CacheFileHandle> mIndexHandle;
|
|
// Handle used for reading journal file.
|
|
RefPtr<CacheFileHandle> mJournalHandle;
|
|
// Used to check the existence of the file during reading process.
|
|
RefPtr<CacheFileHandle> mTmpHandle;
|
|
|
|
RefPtr<FileOpenHelper> mIndexFileOpener;
|
|
RefPtr<FileOpenHelper> mJournalFileOpener;
|
|
RefPtr<FileOpenHelper> mTmpFileOpener;
|
|
|
|
// Directory enumerator used when building and updating index.
|
|
nsCOMPtr<nsIDirectoryEnumerator> mDirEnumerator;
|
|
|
|
// Main index hashtable.
|
|
nsTHashtable<CacheIndexEntry> mIndex;
|
|
|
|
// We cannot add, remove or change any entry in mIndex in states READING and
|
|
// WRITING. We track all changes in mPendingUpdates during these states.
|
|
nsTHashtable<CacheIndexEntryUpdate> mPendingUpdates;
|
|
|
|
// Contains information statistics for mIndex + mPendingUpdates.
|
|
CacheIndexStats mIndexStats;
|
|
|
|
// When reading journal, we must first parse the whole file and apply the
|
|
// changes iff the journal was read successfully. mTmpJournal is used to store
|
|
// entries from the journal file. We throw away all these entries if parsing
|
|
// of the journal fails or the hash does not match.
|
|
nsTHashtable<CacheIndexEntry> mTmpJournal;
|
|
|
|
// An array that keeps entry records ordered by eviction preference; we take
|
|
// the entry with lowest valid frecency. Zero frecency is an initial value
|
|
// and such entries are stored at the end of the array. Uninitialized entries
|
|
// and entries marked as deleted are not present in this array.
|
|
nsTArray<CacheIndexRecord *> mFrecencyArray;
|
|
bool mFrecencyArraySorted;
|
|
|
|
nsTArray<CacheIndexIterator *> mIterators;
|
|
|
|
// This flag is true iff we are between CacheStorageService:Clear() and processing
|
|
// all contexts to be evicted. It will make UI to show "calculating" instead of
|
|
// any intermediate cache size.
|
|
bool mAsyncGetDiskConsumptionBlocked;
|
|
|
|
class DiskConsumptionObserver : public nsRunnable
|
|
{
|
|
public:
|
|
static DiskConsumptionObserver* Init(nsICacheStorageConsumptionObserver* aObserver)
|
|
{
|
|
nsWeakPtr observer = do_GetWeakReference(aObserver);
|
|
if (!observer)
|
|
return nullptr;
|
|
|
|
return new DiskConsumptionObserver(observer);
|
|
}
|
|
|
|
void OnDiskConsumption(int64_t aSize)
|
|
{
|
|
mSize = aSize;
|
|
NS_DispatchToMainThread(this);
|
|
}
|
|
|
|
private:
|
|
explicit DiskConsumptionObserver(nsWeakPtr const &aWeakObserver)
|
|
: mObserver(aWeakObserver) { }
|
|
virtual ~DiskConsumptionObserver() {
|
|
if (mObserver && !NS_IsMainThread()) {
|
|
NS_ReleaseOnMainThread(mObserver.forget());
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP Run()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
nsCOMPtr<nsICacheStorageConsumptionObserver> observer =
|
|
do_QueryReferent(mObserver);
|
|
|
|
mObserver = nullptr;
|
|
|
|
if (observer) {
|
|
observer->OnNetworkCacheDiskConsumption(mSize);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsWeakPtr mObserver;
|
|
int64_t mSize;
|
|
};
|
|
|
|
// List of async observers that want to get disk consumption information
|
|
nsTArray<RefPtr<DiskConsumptionObserver> > mDiskConsumptionObservers;
|
|
};
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|
|
|
|
#endif
|