tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CacheStorageService.h (15803B)


      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 CacheStorageService__h__
      6 #define CacheStorageService__h__
      7 
      8 #include "mozilla/LinkedList.h"
      9 #include "nsICacheStorageService.h"
     10 #include "nsIMemoryReporter.h"
     11 #include "nsINamed.h"
     12 #include "nsITimer.h"
     13 #include "nsICacheTesting.h"
     14 
     15 #include "nsClassHashtable.h"
     16 #include "nsTHashMap.h"
     17 #include "nsString.h"
     18 #include "nsThreadUtils.h"
     19 #include "nsProxyRelease.h"
     20 #include "mozilla/Monitor.h"
     21 #include "mozilla/Mutex.h"
     22 #include "mozilla/StaticMutex.h"
     23 #include "mozilla/AtomicBitfields.h"
     24 #include "mozilla/Atomics.h"
     25 #include "mozilla/TimeStamp.h"
     26 #include "nsTArray.h"
     27 
     28 class nsIURI;
     29 class nsICacheEntryDoomCallback;
     30 class nsICacheStorageVisitor;
     31 class nsIRunnable;
     32 class nsIThread;
     33 class nsIEventTarget;
     34 
     35 namespace mozilla {
     36 
     37 class OriginAttributes;
     38 
     39 namespace net {
     40 
     41 class CacheStorageService;
     42 class CacheStorage;
     43 class CacheEntry;
     44 class CacheEntryHandle;
     45 class CacheEntryTable;
     46 
     47 class CacheMemoryConsumer {
     48 private:
     49  friend class CacheStorageService;
     50  // clang-format off
     51  MOZ_ATOMIC_BITFIELDS(mAtomicBitfields, 32, (
     52    (uint32_t, ReportedMemoryConsumption, 30),
     53    (uint32_t, Flags, 2)
     54  ))
     55  // clang-format on
     56 
     57 private:
     58  CacheMemoryConsumer() = delete;
     59 
     60 protected:
     61  enum {
     62    // No special treatment, reports always to the disk-entries pool.
     63    NORMAL = 0,
     64    // This consumer is belonging to a memory-only cache entry, used to decide
     65    // which of the two disk and memory pools count this consumption at.
     66    MEMORY_ONLY = 1 << 0,
     67    // Prevent reports of this consumer at all, used for disk data chunks since
     68    // we throw them away as soon as the entry is not used by any consumer and
     69    // don't want to make them wipe the whole pool out during their short life.
     70    DONT_REPORT = 1 << 1
     71  };
     72 
     73  explicit CacheMemoryConsumer(uint32_t aFlags);
     74  ~CacheMemoryConsumer() { DoMemoryReport(0); }
     75  void DoMemoryReport(uint32_t aCurrentSize);
     76 };
     77 
     78 using GlobalEntryTables = nsClassHashtable<nsCStringHashKey, CacheEntryTable>;
     79 class WalkMemoryCacheRunnable;
     80 
     81 namespace CacheStorageServiceInternal {
     82 class WalkMemoryCacheRunnable;
     83 class WalkDiskCacheRunnable;
     84 }  // namespace CacheStorageServiceInternal
     85 
     86 class CacheStorageService final : public nsICacheStorageService,
     87                                  public nsIMemoryReporter,
     88                                  public nsITimerCallback,
     89                                  public nsICacheTesting,
     90                                  public nsINamed {
     91  friend class CacheStorageServiceInternal::WalkMemoryCacheRunnable;
     92  friend class CacheStorageServiceInternal::WalkDiskCacheRunnable;
     93 
     94 public:
     95  NS_DECL_THREADSAFE_ISUPPORTS
     96  NS_DECL_NSICACHESTORAGESERVICE
     97  NS_DECL_NSIMEMORYREPORTER
     98  NS_DECL_NSITIMERCALLBACK
     99  NS_DECL_NSICACHETESTING
    100  NS_DECL_NSINAMED
    101 
    102  CacheStorageService();
    103 
    104  void Shutdown();
    105  void DropPrivateBrowsingEntries();
    106 
    107  static CacheStorageService* Self() { return sSelf; }
    108  static nsISupports* SelfISupports() {
    109    return static_cast<nsICacheStorageService*>(Self());
    110  }
    111  nsresult Dispatch(nsIRunnable* aEvent);
    112  static bool IsRunning() { return sSelf && !sSelf->mShutdown; }
    113  static bool IsOnManagementThread();
    114  already_AddRefed<nsIEventTarget> Thread() const;
    115  StaticMutex& Lock() { return sLock; }
    116 
    117  // Tracks entries that may be forced valid in a pruned hashtable.
    118  struct ForcedValidData {
    119    // The timestamp is computed when the entry gets inserted into the map.
    120    // It should never be null for an entry in the map.
    121    TimeStamp validUntil;
    122    // viewed gets set to true by a call to MarkForcedValidEntryUse()
    123    bool viewed = false;
    124  };
    125  nsTHashMap<nsCStringHashKey, ForcedValidData> mForcedValidEntries;
    126  void ForcedValidEntriesPrune(TimeStamp& now);
    127 
    128  // Helper thread-safe interface to pass entry info, only difference from
    129  // nsICacheStorageVisitor is that instead of nsIURI only the uri spec is
    130  // passed.
    131  class EntryInfoCallback {
    132   public:
    133    virtual void OnEntryInfo(const nsACString& aURISpec,
    134                             const nsACString& aIdEnhance, int64_t aDataSize,
    135                             int64_t aAltDataSize, uint32_t aFetchCount,
    136                             uint32_t aLastModifiedTime,
    137                             uint32_t aExpirationTime, bool aPinned,
    138                             nsILoadContextInfo* aInfo) = 0;
    139  };
    140 
    141  // Invokes OnEntryInfo for the given aEntry, synchronously.
    142  static void GetCacheEntryInfo(CacheEntry* aEntry,
    143                                EntryInfoCallback* aCallback);
    144 
    145  nsresult GetCacheIndexEntryAttrs(CacheStorage const* aStorage,
    146                                   const nsACString& aURI,
    147                                   const nsACString& aIdExtension,
    148                                   bool* aHasAltData, uint32_t* aFileSizeKb);
    149 
    150  static uint32_t CacheQueueSize(bool highPriority);
    151 
    152  // Memory reporting
    153  size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    154  size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    155  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
    156 
    157 private:
    158  virtual ~CacheStorageService();
    159  void ShutdownBackground();
    160 
    161  /**
    162   * Keeps tables of entries.  There is one entries table for each distinct load
    163   * context type.  The distinction is based on following load context info
    164   * states: <isPrivate|isAnon|inIsolatedMozBrowser> which builds a mapping
    165   * key.
    166   *
    167   * Thread-safe to access, protected by the service mutex.
    168   */
    169  static GlobalEntryTables* sGlobalEntryTables MOZ_GUARDED_BY(sLock);
    170 
    171 private:
    172  // The following methods may only be called on the management
    173  // thread.
    174  friend class CacheEntry;
    175 
    176  /**
    177   * Registers the entry into the associated MemoryPool.
    178   * Holds a strong reference until it is unregistered.
    179   */
    180  void RegisterEntry(CacheEntry* aEntry);
    181 
    182  /**
    183   * Deregisters the entry from the associated MemoryPool.
    184   */
    185  void UnregisterEntry(CacheEntry* aEntry);
    186 
    187  /**
    188   * Removes the entry from the related entry hash table, if still present.
    189   */
    190  bool RemoveEntry(CacheEntry* aEntry, bool aOnlyUnreferenced = false);
    191 
    192  /**
    193   * Tells the storage service whether this entry is only to be stored in
    194   * memory.
    195   */
    196  void RecordMemoryOnlyEntry(CacheEntry* aEntry, bool aOnlyInMemory,
    197                             bool aOverwrite);
    198 
    199  /**
    200   * Sets a cache entry valid (overrides the default loading behavior by loading
    201   * directly from cache) for the given number of seconds
    202   * See nsICacheEntry.idl for more details
    203   */
    204  void ForceEntryValidFor(nsACString const& aContextKey,
    205                          nsACString const& aEntryKey,
    206                          uint32_t aSecondsToTheFuture);
    207 
    208  /**
    209   * Remove the validity info
    210   */
    211  void RemoveEntryForceValid(nsACString const& aContextKey,
    212                             nsACString const& aEntryKey);
    213 
    214  /**
    215   * Retrieves the status of the cache entry to see if it has been forced valid
    216   * (so it will loaded directly from cache without further validation)
    217   */
    218  bool IsForcedValidEntry(nsACString const& aContextKey,
    219                          nsACString const& aEntryKey);
    220 
    221  // Marks the entry as used, so we may properly report when it gets evicted
    222  // if the prefetched resource was used or not.
    223  void MarkForcedValidEntryUse(nsACString const& aContextKey,
    224                               nsACString const& aEntryKey);
    225 
    226 private:
    227  friend class CacheIndex;
    228 
    229  /**
    230   * CacheIndex uses this to prevent a cache entry from being prememptively
    231   * thrown away when forced valid
    232   * See nsICacheEntry.idl for more details
    233   */
    234  bool IsForcedValidEntry(nsACString const& aContextEntryKey);
    235 
    236 private:
    237  // These are helpers for telemetry monitoring of the memory pools.
    238  void TelemetryPrune(TimeStamp& now);
    239  void TelemetryRecordEntryCreation(CacheEntry const* entry);
    240  void TelemetryRecordEntryRemoval(CacheEntry* entry);
    241 
    242 private:
    243  // Following methods are thread safe to call.
    244  friend class CacheStorage;
    245 
    246  /**
    247   * Get, or create when not existing and demanded, an entry for the storage
    248   * and uri+id extension.
    249   */
    250  nsresult AddStorageEntry(CacheStorage const* aStorage, const nsACString& aURI,
    251                           const nsACString& aIdExtension, uint32_t aFlags,
    252                           CacheEntryHandle** aResult);
    253 
    254  /**
    255   * Check existance of an entry.  This may throw NS_ERROR_NOT_AVAILABLE
    256   * when the information cannot be obtained synchronously w/o blocking.
    257   */
    258  nsresult CheckStorageEntry(CacheStorage const* aStorage,
    259                             const nsACString& aURI,
    260                             const nsACString& aIdExtension, bool* aResult);
    261 
    262  /**
    263   * Removes the entry from the related entry hash table, if still present
    264   * and returns it.
    265   */
    266  nsresult DoomStorageEntry(CacheStorage const* aStorage,
    267                            const nsACString& aURI,
    268                            const nsACString& aIdExtension,
    269                            nsICacheEntryDoomCallback* aCallback);
    270 
    271  /**
    272   * Removes and returns entry table for the storage.
    273   */
    274  nsresult DoomStorageEntries(CacheStorage const* aStorage,
    275                              nsICacheEntryDoomCallback* aCallback);
    276 
    277  /**
    278   * Walk all entiries beloging to the storage.
    279   */
    280  nsresult WalkStorageEntries(CacheStorage const* aStorage, bool aVisitEntries,
    281                              nsICacheStorageVisitor* aVisitor);
    282 
    283 private:
    284  friend class CacheFileIOManager;
    285 
    286  /**
    287   * CacheFileIOManager uses this method to notify CacheStorageService that
    288   * an active entry was removed. This method is called even if the entry
    289   * removal was originated by CacheStorageService.  This also removes the entry
    290   * from the DictionaryCache.
    291   */
    292  void CacheFileDoomed(const nsACString& aKey,
    293                       nsILoadContextInfo* aLoadContextInfo,
    294                       const nsACString& aIdExtension,
    295                       const nsACString& aURISpec);
    296 
    297  /**
    298   * Tries to find an existing entry in the hashtables and synchronously call
    299   * OnCacheEntryInfo of the aVisitor callback when found.
    300   * @retuns
    301   *   true, when the entry has been found that also implies the callbacks has
    302   *        beem invoked
    303   *   false, when an entry has not been found
    304   */
    305  bool GetCacheEntryInfo(nsILoadContextInfo* aLoadContextInfo,
    306                         const nsACString& aIdExtension,
    307                         const nsACString& aURISpec,
    308                         EntryInfoCallback* aCallback);
    309 
    310 private:
    311  friend class CacheMemoryConsumer;
    312 
    313  /**
    314   * When memory consumption of this entry radically changes, this method
    315   * is called to reflect the size of allocated memory.  This call may purge
    316   * unspecified number of entries from memory (but not from disk).
    317   */
    318  void OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer,
    319                                 uint32_t aCurrentMemoryConsumption);
    320 
    321  /**
    322   * If not already pending, it schedules mPurgeTimer that fires after 1 second
    323   * and dispatches PurgeOverMemoryLimit().
    324   */
    325  void SchedulePurgeOverMemoryLimit();
    326 
    327  /**
    328   * Called on the management thread, removes all expired and then least used
    329   * entries from the memory, first from the disk pool and then from the memory
    330   * pool.
    331   */
    332  void PurgeExpiredOrOverMemoryLimit();
    333 
    334 private:
    335  nsresult DoomStorageEntries(const nsACString& aContextKey,
    336                              nsILoadContextInfo* aContext, bool aDiskStorage,
    337                              bool aPin, nsICacheEntryDoomCallback* aCallback);
    338  nsresult AddStorageEntry(const nsACString& aContextKey,
    339                           const nsACString& aURI,
    340                           const nsACString& aIdExtension, bool aWriteToDisk,
    341                           bool aSkipSizeCheck, bool aPin, uint32_t aFlags,
    342                           CacheEntryHandle** aResult);
    343 
    344  nsresult ClearOriginInternal(
    345      const nsAString& aOrigin,
    346      const mozilla::OriginAttributes& aOriginAttributes, bool aAnonymous);
    347 
    348  static CacheStorageService* sSelf;
    349 
    350  static StaticMutex sLock;
    351  mozilla::Mutex mForcedValidEntriesLock{
    352      "CacheStorageService.mForcedValidEntriesLock"};
    353 
    354  Atomic<bool, Relaxed> mShutdown{false};
    355 
    356  // Accessible only on the service thread
    357  class MemoryPool {
    358   public:
    359    enum EType {
    360      DISK,
    361      MEMORY,
    362    } mType;
    363 
    364    explicit MemoryPool(EType aType);
    365    ~MemoryPool();
    366 
    367    // We want to have constant O(1) for removal from this list.
    368    LinkedList<RefPtr<CacheEntry>> mManagedEntries;
    369    Atomic<uint32_t, Relaxed> mMemorySize{0};
    370 
    371    bool OnMemoryConsumptionChange(uint32_t aSavedMemorySize,
    372                                   uint32_t aCurrentMemoryConsumption);
    373    /**
    374     * Purges entries from memory based on the frecency ordered array.
    375     */
    376    void PurgeExpiredOrOverMemoryLimit();
    377    size_t PurgeExpired(size_t minprogress);
    378    Result<size_t, nsresult> PurgeByFrecency(size_t minprogress);
    379    size_t PurgeAll(uint32_t aWhat, size_t minprogress);
    380 
    381   private:
    382    uint32_t Limit() const;
    383    MemoryPool() = delete;
    384  };
    385 
    386  MemoryPool mDiskPool{MemoryPool::DISK};
    387  MemoryPool mMemoryPool{MemoryPool::MEMORY};
    388  TimeStamp mLastPurgeTime;
    389  MemoryPool& Pool(bool aUsingDisk) {
    390    return aUsingDisk ? mDiskPool : mMemoryPool;
    391  }
    392  MemoryPool const& Pool(bool aUsingDisk) const {
    393    return aUsingDisk ? mDiskPool : mMemoryPool;
    394  }
    395 
    396  nsCOMPtr<nsITimer> mPurgeTimer;
    397 #ifdef MOZ_TSAN
    398  // In OnMemoryConsumptionChange() we check whether the timer exists, but we
    399  // cannot grab the lock there (see comment 6 in bug 1614637) and TSan reports
    400  // a data race. This data race is harmless, so we use this atomic flag only in
    401  // TSan build to suppress it.
    402  Atomic<bool, Relaxed> mPurgeTimerActive{false};
    403 #endif
    404 
    405  class PurgeFromMemoryRunnable : public Runnable {
    406   public:
    407    PurgeFromMemoryRunnable(CacheStorageService* aService, uint32_t aWhat)
    408        : Runnable("net::CacheStorageService::PurgeFromMemoryRunnable"),
    409          mService(aService),
    410          mWhat(aWhat) {}
    411 
    412   private:
    413    virtual ~PurgeFromMemoryRunnable() = default;
    414 
    415    NS_IMETHOD Run() override;
    416 
    417    RefPtr<CacheStorageService> mService;
    418    uint32_t mWhat;
    419  };
    420 
    421  // Used just for telemetry purposes, accessed only on the management thread.
    422  // Note: not included in the memory reporter, this is not expected to be huge
    423  // and also would be complicated to report since reporting happens on the main
    424  // thread but this table is manipulated on the management thread.
    425  nsTHashMap<nsCStringHashKey, mozilla::TimeStamp> mPurgeTimeStamps;
    426 
    427  // nsICacheTesting
    428  class IOThreadSuspender : public Runnable {
    429   public:
    430    IOThreadSuspender()
    431        : Runnable("net::CacheStorageService::IOThreadSuspender"),
    432          mMon("IOThreadSuspender") {}
    433    void Notify();
    434 
    435   private:
    436    virtual ~IOThreadSuspender() = default;
    437    NS_IMETHOD Run() override;
    438 
    439    Monitor mMon MOZ_UNANNOTATED;
    440    bool mSignaled{false};
    441  };
    442 
    443  RefPtr<IOThreadSuspender> mActiveIOSuspender;
    444 };
    445 
    446 template <class T>
    447 void ProxyRelease(const char* aName, nsCOMPtr<T>& object,
    448                  nsIEventTarget* target) {
    449  NS_ProxyRelease(aName, target, object.forget());
    450 }
    451 
    452 template <class T>
    453 void ProxyReleaseMainThread(const char* aName, nsCOMPtr<T>& object) {
    454  ProxyRelease(aName, object, GetMainThreadSerialEventTarget());
    455 }
    456 
    457 }  // namespace net
    458 }  // namespace mozilla
    459 
    460 #define NS_CACHE_STORAGE_SERVICE_CID \
    461  {0xea70b098, 0x5014, 0x4e21, {0xae, 0xe1, 0x75, 0xe6, 0xb2, 0xc4, 0xb8, 0xe0}}
    462 
    463 #define NS_CACHE_STORAGE_SERVICE_CONTRACTID \
    464  "@mozilla.org/netwerk/cache-storage-service;1"
    465 
    466 #define NS_CACHE_STORAGE_SERVICE_CONTRACTID2 \
    467  "@mozilla.org/network/cache-storage-service;1"
    468 
    469 #endif