LCOV - code coverage report
Current view: top level - netwerk/cache2 - CacheEntry.h (source / functions) Hit Total Coverage
Test: output.info Lines: 19 39 48.7 %
Date: 2017-07-14 16:53:18 Functions: 32 60 53.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #ifndef CacheEntry__h__
       6             : #define CacheEntry__h__
       7             : 
       8             : #include "nsICacheEntry.h"
       9             : #include "CacheFile.h"
      10             : 
      11             : #include "nsIRunnable.h"
      12             : #include "nsIOutputStream.h"
      13             : #include "nsICacheEntryOpenCallback.h"
      14             : #include "nsICacheEntryDoomCallback.h"
      15             : 
      16             : #include "nsCOMPtr.h"
      17             : #include "nsRefPtrHashtable.h"
      18             : #include "nsDataHashtable.h"
      19             : #include "nsHashKeys.h"
      20             : #include "nsString.h"
      21             : #include "nsCOMArray.h"
      22             : #include "nsThreadUtils.h"
      23             : #include "mozilla/Attributes.h"
      24             : #include "mozilla/Mutex.h"
      25             : #include "mozilla/TimeStamp.h"
      26             : 
      27             : static inline uint32_t
      28           0 : PRTimeToSeconds(PRTime t_usec)
      29             : {
      30           0 :   PRTime usec_per_sec = PR_USEC_PER_SEC;
      31           0 :   return uint32_t(t_usec /= usec_per_sec);
      32             : }
      33             : 
      34             : #define NowInSeconds() PRTimeToSeconds(PR_Now())
      35             : 
      36             : class nsIOutputStream;
      37             : class nsIURI;
      38             : class nsIThread;
      39             : 
      40             : namespace mozilla {
      41             : namespace net {
      42             : 
      43             : class CacheStorageService;
      44             : class CacheStorage;
      45             : class CacheOutputCloseListener;
      46             : class CacheEntryHandle;
      47             : 
      48             : class CacheEntry final : public nsICacheEntry
      49             :                        , public nsIRunnable
      50             :                        , public CacheFileListener
      51             : {
      52             : public:
      53             :   NS_DECL_THREADSAFE_ISUPPORTS
      54             :   NS_DECL_NSICACHEENTRY
      55             :   NS_DECL_NSIRUNNABLE
      56             : 
      57             :   CacheEntry(const nsACString& aStorageID, const nsACString& aURI, const nsACString& aEnhanceID,
      58             :              bool aUseDisk, bool aSkipSizeCheck, bool aPin);
      59             : 
      60             :   void AsyncOpen(nsICacheEntryOpenCallback* aCallback, uint32_t aFlags);
      61             : 
      62             :   CacheEntryHandle* NewHandle();
      63             :   // For a new and recreated entry w/o a callback, we need to wrap it
      64             :   // with a handle to detect writing consumer is gone.
      65             :   CacheEntryHandle* NewWriteHandle();
      66             : 
      67             : public:
      68             :   uint32_t GetMetadataMemoryConsumption();
      69          10 :   nsCString const &GetStorageID() const { return mStorageID; }
      70           0 :   nsCString const &GetEnhanceID() const { return mEnhanceID; }
      71           0 :   nsCString const &GetURI() const { return mURI; }
      72             :   // Accessible at any time
      73           5 :   bool IsUsingDisk() const { return mUseDisk; }
      74             :   bool IsReferenced() const;
      75             :   bool IsFileDoomed();
      76          28 :   bool IsDoomed() const { return mIsDoomed; }
      77           0 :   bool IsPinned() const { return mPinned; }
      78             : 
      79             :   // Methods for entry management (eviction from memory),
      80             :   // called only on the management thread.
      81             : 
      82             :   // TODO make these inline
      83             :   double GetFrecency() const;
      84             :   uint32_t GetExpirationTime() const;
      85           0 :   uint32_t UseCount() const { return mUseCount; }
      86             : 
      87             :   bool IsRegistered() const;
      88             :   bool CanRegister() const;
      89             :   void SetRegistered(bool aRegistered);
      90             : 
      91           0 :   TimeStamp const& LoadStart() const { return mLoadStart; }
      92             : 
      93             :   enum EPurge {
      94             :     PURGE_DATA_ONLY_DISK_BACKED,
      95             :     PURGE_WHOLE_ONLY_DISK_BACKED,
      96             :     PURGE_WHOLE,
      97             :   };
      98             : 
      99             :   bool DeferOrBypassRemovalOnPinStatus(bool aPinned);
     100             :   bool Purge(uint32_t aWhat);
     101             :   void PurgeAndDoom();
     102             :   void DoomAlreadyRemoved();
     103             : 
     104             :   nsresult HashingKeyWithStorage(nsACString &aResult) const;
     105             :   nsresult HashingKey(nsACString &aResult) const;
     106             : 
     107             :   static nsresult HashingKey(const nsACString& aStorageID,
     108             :                              const nsACString& aEnhanceID,
     109             :                              nsIURI* aURI,
     110             :                              nsACString &aResult);
     111             : 
     112             :   static nsresult HashingKey(const nsACString& aStorageID,
     113             :                              const nsACString& aEnhanceID,
     114             :                              const nsACString& aURISpec,
     115             :                              nsACString &aResult);
     116             : 
     117             :   // Accessed only on the service management thread
     118             :   double mFrecency;
     119             :   ::mozilla::Atomic<uint32_t, ::mozilla::Relaxed> mSortingExpirationTime;
     120             : 
     121             :   // Memory reporting
     122             :   size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
     123             :   size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
     124             : 
     125             : private:
     126             :   virtual ~CacheEntry();
     127             : 
     128             :   // CacheFileListener
     129             :   NS_IMETHOD OnFileReady(nsresult aResult, bool aIsNew) override;
     130             :   NS_IMETHOD OnFileDoomed(nsresult aResult) override;
     131             : 
     132             :   // Keep the service alive during life-time of an entry
     133             :   RefPtr<CacheStorageService> mService;
     134             : 
     135             :   // We must monitor when a cache entry whose consumer is responsible
     136             :   // for writing it the first time gets released.  We must then invoke
     137             :   // waiting callbacks to not break the chain.
     138             :   class Callback
     139             :   {
     140             :   public:
     141             :     Callback(CacheEntry* aEntry,
     142             :              nsICacheEntryOpenCallback *aCallback,
     143             :              bool aReadOnly, bool aCheckOnAnyThread, bool aSecret);
     144             :     // Special constructor for Callback objects added to the chain
     145             :     // just to ensure proper defer dooming (recreation) of this entry.
     146             :     Callback(CacheEntry* aEntry, bool aDoomWhenFoundInPinStatus);
     147             :     Callback(Callback const &aThat);
     148             :     ~Callback();
     149             : 
     150             :     // Called when this callback record changes it's owning entry,
     151             :     // mainly during recreation.
     152             :     void ExchangeEntry(CacheEntry* aEntry);
     153             : 
     154             :     // Returns true when an entry is about to be "defer" doomed and this is
     155             :     // a "defer" callback.
     156             :     bool DeferDoom(bool *aDoom) const;
     157             : 
     158             :     // We are raising reference count here to take into account the pending
     159             :     // callback (that virtually holds a ref to this entry before it gets
     160             :     // it's pointer).
     161             :     RefPtr<CacheEntry> mEntry;
     162             :     nsCOMPtr<nsICacheEntryOpenCallback> mCallback;
     163             :     nsCOMPtr<nsIEventTarget> mTarget;
     164             :     bool mReadOnly : 1;
     165             :     bool mRevalidating : 1;
     166             :     bool mCheckOnAnyThread : 1;
     167             :     bool mRecheckAfterWrite : 1;
     168             :     bool mNotWanted : 1;
     169             :     bool mSecret : 1;
     170             : 
     171             :     // These are set only for the defer-doomer Callback instance inserted
     172             :     // to the callback chain.  When any of these is set and also any of
     173             :     // the corressponding flags on the entry is set, this callback will
     174             :     // indicate (via DeferDoom()) the entry have to be recreated/doomed.
     175             :     bool mDoomWhenFoundPinned : 1;
     176             :     bool mDoomWhenFoundNonPinned : 1;
     177             : 
     178             :     nsresult OnCheckThread(bool *aOnCheckThread) const;
     179             :     nsresult OnAvailThread(bool *aOnAvailThread) const;
     180             :   };
     181             : 
     182             :   // Since OnCacheEntryAvailable must be invoked on the main thread
     183             :   // we need a runnable for it...
     184          18 :   class AvailableCallbackRunnable : public Runnable
     185             :   {
     186             :   public:
     187           6 :     AvailableCallbackRunnable(CacheEntry* aEntry,
     188             :                               Callback const &aCallback)
     189           6 :       : Runnable("CacheEntry::AvailableCallbackRunnable")
     190             :       , mEntry(aEntry)
     191           6 :       , mCallback(aCallback)
     192           6 :     {}
     193             : 
     194             :   private:
     195           6 :     NS_IMETHOD Run() override
     196             :     {
     197           6 :       mEntry->InvokeAvailableCallback(mCallback);
     198           6 :       return NS_OK;
     199             :     }
     200             : 
     201             :     RefPtr<CacheEntry> mEntry;
     202             :     Callback mCallback;
     203             :   };
     204             : 
     205             :   // Since OnCacheEntryDoomed must be invoked on the main thread
     206             :   // we need a runnable for it...
     207           0 :   class DoomCallbackRunnable : public Runnable
     208             :   {
     209             :   public:
     210           0 :     DoomCallbackRunnable(CacheEntry* aEntry, nsresult aRv)
     211           0 :       : Runnable("net::CacheEntry::DoomCallbackRunnable")
     212             :       , mEntry(aEntry)
     213           0 :       , mRv(aRv)
     214             :     {
     215           0 :     }
     216             : 
     217             :   private:
     218           0 :     NS_IMETHOD Run() override
     219             :     {
     220           0 :       nsCOMPtr<nsICacheEntryDoomCallback> callback;
     221             :       {
     222           0 :         mozilla::MutexAutoLock lock(mEntry->mLock);
     223           0 :         mEntry->mDoomCallback.swap(callback);
     224             :       }
     225             : 
     226           0 :       if (callback)
     227           0 :         callback->OnCacheEntryDoomed(mRv);
     228           0 :       return NS_OK;
     229             :     }
     230             : 
     231             :     RefPtr<CacheEntry> mEntry;
     232             :     nsresult mRv;
     233             :   };
     234             : 
     235             :   // Starts the load or just invokes the callback, bypasses (when required)
     236             :   // if busy.  Returns true on job done, false on bypass.
     237             :   bool Open(Callback & aCallback, bool aTruncate, bool aPriority, bool aBypassIfBusy);
     238             :   // Loads from disk asynchronously
     239             :   bool Load(bool aTruncate, bool aPriority);
     240             : 
     241             :   void RememberCallback(Callback & aCallback);
     242             :   void InvokeCallbacksLock();
     243             :   void InvokeCallbacks();
     244             :   bool InvokeCallbacks(bool aReadOnly);
     245             :   bool InvokeCallback(Callback & aCallback);
     246             :   void InvokeAvailableCallback(Callback const & aCallback);
     247             :   void OnFetched(Callback const & aCallback);
     248             : 
     249             :   nsresult OpenOutputStreamInternal(int64_t offset, nsIOutputStream * *_retval);
     250             :   nsresult OpenInputStreamInternal(int64_t offset, const char *aAltDataType, nsIInputStream * *_retval);
     251             : 
     252             :   void OnHandleClosed(CacheEntryHandle const* aHandle);
     253             : 
     254             : private:
     255             :   friend class CacheEntryHandle;
     256             :   // Increment/decrements the number of handles keeping this entry.
     257          77 :   void AddHandleRef() { ++mHandlesCount; }
     258          77 :   void ReleaseHandleRef() { --mHandlesCount; }
     259             :   // Current number of handles keeping this entry.
     260          77 :   uint32_t HandlesCount() const { return mHandlesCount; }
     261             : 
     262             : private:
     263             :   friend class CacheOutputCloseListener;
     264             :   void OnOutputClosed();
     265             : 
     266             : private:
     267             :   // Schedules a background operation on the management thread.
     268             :   // When executed on the management thread directly, the operation(s)
     269             :   // is (are) executed immediately.
     270             :   void BackgroundOp(uint32_t aOperation, bool aForceAsync = false);
     271             :   void StoreFrecency(double aFrecency);
     272             : 
     273             :   // Called only from DoomAlreadyRemoved()
     274             :   void DoomFile();
     275             :   // When this entry is doomed the first time, this method removes
     276             :   // any force-valid timing info for this entry.
     277             :   void RemoveForcedValidity();
     278             : 
     279             :   already_AddRefed<CacheEntryHandle> ReopenTruncated(bool aMemoryOnly,
     280             :                                                      nsICacheEntryOpenCallback* aCallback);
     281             :   void TransferCallbacks(CacheEntry & aFromEntry);
     282             : 
     283             :   mozilla::Mutex mLock;
     284             : 
     285             :   // Reflects the number of existing handles for this entry
     286             :   ::mozilla::ThreadSafeAutoRefCnt mHandlesCount;
     287             : 
     288             :   nsTArray<Callback> mCallbacks;
     289             :   nsCOMPtr<nsICacheEntryDoomCallback> mDoomCallback;
     290             : 
     291             :   RefPtr<CacheFile> mFile;
     292             : 
     293             :   // Using ReleaseAcquire since we only control access to mFile with this.
     294             :   // When mFileStatus is read and found success it is ensured there is mFile and
     295             :   // that it is after a successful call to Init().
     296             :   ::mozilla::Atomic<nsresult, ::mozilla::ReleaseAcquire> mFileStatus;
     297             :   nsCString mURI;
     298             :   nsCString mEnhanceID;
     299             :   nsCString mStorageID;
     300             : 
     301             :   // mUseDisk, mSkipSizeCheck, mIsDoomed are plain "bool", not "bool:1",
     302             :   // so as to avoid bitfield races with the byte containing
     303             :   // mSecurityInfoLoaded et al.  See bug 1278524.
     304             :   //
     305             :   // Whether it's allowed to persist the data to disk
     306             :   bool const mUseDisk;
     307             :   // Whether it should skip max size check.
     308             :   bool const mSkipSizeCheck;
     309             :   // Set when entry is doomed with AsyncDoom() or DoomAlreadyRemoved().
     310             :   bool mIsDoomed;
     311             : 
     312             :   // Following flags are all synchronized with the cache entry lock.
     313             : 
     314             :   // Whether security info has already been looked up in metadata.
     315             :   bool mSecurityInfoLoaded : 1;
     316             :   // Prevents any callback invocation
     317             :   bool mPreventCallbacks : 1;
     318             :   // true: after load and an existing file, or after output stream has been opened.
     319             :   //       note - when opening an input stream, and this flag is false, output stream
     320             :   //       is open along ; this makes input streams on new entries behave correctly
     321             :   //       when EOF is reached (WOULD_BLOCK is returned).
     322             :   // false: after load and a new file, or dropped to back to false when a writer
     323             :   //        fails to open an output stream.
     324             :   bool mHasData : 1;
     325             :   // The indication of pinning this entry was open with
     326             :   bool mPinned : 1;
     327             :   // Whether the pinning state of the entry is known (equals to the actual state
     328             :   // of the cache file)
     329             :   bool mPinningKnown : 1;
     330             : 
     331             :   static char const * StateString(uint32_t aState);
     332             : 
     333             :   enum EState {      // transiting to:
     334             :     NOTLOADED = 0,   // -> LOADING | EMPTY
     335             :     LOADING = 1,     // -> EMPTY | READY
     336             :     EMPTY = 2,       // -> WRITING
     337             :     WRITING = 3,     // -> EMPTY | READY
     338             :     READY = 4,       // -> REVALIDATING
     339             :     REVALIDATING = 5 // -> READY
     340             :   };
     341             : 
     342             :   // State of this entry.
     343             :   EState mState;
     344             : 
     345             :   enum ERegistration {
     346             :     NEVERREGISTERED = 0, // The entry has never been registered
     347             :     REGISTERED = 1,      // The entry is stored in the memory pool index
     348             :     DEREGISTERED = 2     // The entry has been removed from the pool
     349             :   };
     350             : 
     351             :   // Accessed only on the management thread.  Records the state of registration
     352             :   // this entry in the memory pool intermediate cache.
     353             :   ERegistration mRegistration;
     354             : 
     355             :   // If a new (empty) entry is requested to open an input stream before
     356             :   // output stream has been opened, we must open output stream internally
     357             :   // on CacheFile and hold until writer releases the entry or opens the output
     358             :   // stream for read (then we trade him mOutputStream).
     359             :   nsCOMPtr<nsIOutputStream> mOutputStream;
     360             : 
     361             :   // Weak reference to the current writter.  There can be more then one
     362             :   // writer at a time and OnHandleClosed() must be processed only for the
     363             :   // current one.
     364             :   CacheEntryHandle* mWriter;
     365             : 
     366             :   // Background thread scheduled operation.  Set (under the lock) one
     367             :   // of this flags to tell the background thread what to do.
     368             :   class Ops {
     369             :   public:
     370             :     static uint32_t const REGISTER =          1 << 0;
     371             :     static uint32_t const FRECENCYUPDATE =    1 << 1;
     372             :     static uint32_t const CALLBACKS =         1 << 2;
     373             :     static uint32_t const UNREGISTER =        1 << 3;
     374             : 
     375           5 :     Ops() : mFlags(0) { }
     376          13 :     uint32_t Grab() { uint32_t flags = mFlags; mFlags = 0; return flags; }
     377          13 :     bool Set(uint32_t aFlags) { if (mFlags & aFlags) return false; mFlags |= aFlags; return true; }
     378             :   private:
     379             :     uint32_t mFlags;
     380             :   } mBackgroundOperations;
     381             : 
     382             :   nsCOMPtr<nsISupports> mSecurityInfo;
     383             :   int64_t mPredictedDataSize;
     384             :   mozilla::TimeStamp mLoadStart;
     385             :   uint32_t mUseCount;
     386             : };
     387             : 
     388             : 
     389             : class CacheEntryHandle : public nsICacheEntry
     390             : {
     391             : public:
     392             :   explicit CacheEntryHandle(CacheEntry* aEntry);
     393          13 :   CacheEntry* Entry() const { return mEntry; }
     394             : 
     395             :   NS_DECL_THREADSAFE_ISUPPORTS
     396          76 :   NS_FORWARD_NSICACHEENTRY(mEntry->)
     397             : private:
     398             :   virtual ~CacheEntryHandle();
     399             :   RefPtr<CacheEntry> mEntry;
     400             : };
     401             : 
     402             : 
     403             : class CacheOutputCloseListener final : public Runnable
     404             : {
     405             : public:
     406             :   void OnOutputClosed();
     407             : 
     408             : private:
     409             :   friend class CacheEntry;
     410             : 
     411             :   virtual ~CacheOutputCloseListener();
     412             : 
     413             :   NS_DECL_NSIRUNNABLE
     414             :   explicit CacheOutputCloseListener(CacheEntry* aEntry);
     415             : 
     416             : private:
     417             :   RefPtr<CacheEntry> mEntry;
     418             : };
     419             : 
     420             : } // namespace net
     421             : } // namespace mozilla
     422             : 
     423             : #endif

Generated by: LCOV version 1.13