startupcache/StartupCache.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef StartupCache_h_
     7 #define StartupCache_h_
     9 #include "nsClassHashtable.h"
    10 #include "nsComponentManagerUtils.h"
    11 #include "nsZipArchive.h"
    12 #include "nsIStartupCache.h"
    13 #include "nsITimer.h"
    14 #include "nsIMemoryReporter.h"
    15 #include "nsIObserverService.h"
    16 #include "nsIObserver.h"
    17 #include "nsIOutputStream.h"
    18 #include "nsIFile.h"
    19 #include "mozilla/Attributes.h"
    20 #include "mozilla/MemoryReporting.h"
    21 #include "mozilla/StaticPtr.h"
    23 /**
    24  * The StartupCache is a persistent cache of simple key-value pairs,
    25  * where the keys are null-terminated c-strings and the values are 
    26  * arbitrary data, passed as a (char*, size) tuple. 
    27  *
    28  * Clients should use the GetSingleton() static method to access the cache. It 
    29  * will be available from the end of XPCOM init (NS_InitXPCOM3 in nsXPComInit.cpp), 
    30  * until XPCOM shutdown begins. The GetSingleton() method will return null if the cache
    31  * is unavailable. The cache is only provided for libxul builds --
    32  * it will fail to link in non-libxul builds. The XPCOM interface is provided
    33  * only to allow compiled-code tests; clients should avoid using it.
    34  *
    35  * The API provided is very simple: GetBuffer() returns a buffer that was previously
    36  * stored in the cache (if any), and PutBuffer() inserts a buffer into the cache.
    37  * GetBuffer returns a new buffer, and the caller must take ownership of it.
    38  * PutBuffer will assert if the client attempts to insert a buffer with the same name as
    39  * an existing entry. The cache makes a copy of the passed-in buffer, so client
    40  * retains ownership.
    41  *
    42  * InvalidateCache() may be called if a client suspects data corruption 
    43  * or wishes to invalidate for any other reason. This will remove all existing cache data.
    44  * Additionally, the static method IgnoreDiskCache() can be called if it is
    45  * believed that the on-disk cache file is itself corrupt. This call implicitly
    46  * calls InvalidateCache (if the singleton has been initialized) to ensure any
    47  * data already read from disk is discarded. The cache will not load data from
    48  * the disk file until a successful write occurs.
    49  *
    50  * Finally, getDebugObjectOutputStream() allows debug code to wrap an objectstream
    51  * with a debug objectstream, to check for multiply-referenced objects. These will
    52  * generally fail to deserialize correctly, unless they are stateless singletons or the 
    53  * client maintains their own object data map for deserialization.
    54  *
    55  * Writes before the final-ui-startup notification are placed in an intermediate
    56  * cache in memory, then written out to disk at a later time, to get writes off the
    57  * startup path. In any case, clients should not rely on being able to GetBuffer()
    58  * data that is written to the cache, since it may not have been written to disk or
    59  * another client may have invalidated the cache. In other words, it should be used as
    60  * a cache only, and not a reliable persistent store.
    61  *
    62  * Some utility functions are provided in StartupCacheUtils. These functions wrap the
    63  * buffers into object streams, which may be useful for serializing objects. Note
    64  * the above caution about multiply-referenced objects, though -- the streams are just
    65  * as 'dumb' as the underlying buffers about multiply-referenced objects. They just
    66  * provide some convenience in writing out data.
    67  */
    69 namespace mozilla {
    71 namespace scache {
    73 struct CacheEntry
    74 {
    75   nsAutoArrayPtr<char> data;
    76   uint32_t size;
    78   CacheEntry() : data(nullptr), size(0) { }
    80   // Takes possession of buf
    81   CacheEntry(char* buf, uint32_t len) : data(buf), size(len) { }
    83   ~CacheEntry()
    84   {
    85   }
    87   size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
    88     return mallocSizeOf(data);
    89   }
    90 };
    92 // We don't want to refcount StartupCache, and ObserverService wants to
    93 // refcount its listeners, so we'll let it refcount this instead.
    94 class StartupCacheListener MOZ_FINAL : public nsIObserver
    95 {
    96   NS_DECL_THREADSAFE_ISUPPORTS
    97   NS_DECL_NSIOBSERVER
    98 };
   100 class StartupCache : public nsIMemoryReporter
   101 {
   103 friend class StartupCacheListener;
   104 friend class StartupCacheWrapper;
   106 public:
   107   NS_DECL_THREADSAFE_ISUPPORTS
   108   NS_DECL_NSIMEMORYREPORTER
   110   // StartupCache methods. See above comments for a more detailed description.
   112   // Returns a buffer that was previously stored, caller takes ownership.
   113   nsresult GetBuffer(const char* id, char** outbuf, uint32_t* length);
   115   // Stores a buffer. Caller keeps ownership, we make a copy.
   116   nsresult PutBuffer(const char* id, const char* inbuf, uint32_t length);
   118   // Removes the cache file.
   119   void InvalidateCache();
   121   // Signal that data should not be loaded from the cache file
   122   static void IgnoreDiskCache();
   124   // In DEBUG builds, returns a stream that will attempt to check for
   125   // and disallow multiple writes of the same object.
   126   nsresult GetDebugObjectOutputStream(nsIObjectOutputStream* aStream,
   127                                       nsIObjectOutputStream** outStream);
   129   nsresult RecordAgesAlways();
   131   static StartupCache* GetSingleton();
   132   static void DeleteSingleton();
   134   // This measures all the heap memory used by the StartupCache, i.e. it
   135   // excludes the mapping.
   136   size_t HeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
   138   size_t SizeOfMapping();
   140 private:
   141   StartupCache();
   142   virtual ~StartupCache();
   144   enum TelemetrifyAge {
   145     IGNORE_AGE = 0,
   146     RECORD_AGE = 1
   147   };
   148   static enum TelemetrifyAge gPostFlushAgeAction;
   150   nsresult LoadArchive(enum TelemetrifyAge flag);
   151   nsresult Init();
   152   void WriteToDisk();
   153   nsresult ResetStartupWriteTimer();
   154   void WaitOnWriteThread();
   156   static nsresult InitSingleton();
   157   static void WriteTimeout(nsITimer *aTimer, void *aClosure);
   158   static void ThreadedWrite(void *aClosure);
   160   static size_t SizeOfEntryExcludingThis(const nsACString& key,
   161                                          const nsAutoPtr<CacheEntry>& data,
   162                                          mozilla::MallocSizeOf mallocSizeOf,
   163                                          void *);
   165   nsClassHashtable<nsCStringHashKey, CacheEntry> mTable;
   166   nsRefPtr<nsZipArchive> mArchive;
   167   nsCOMPtr<nsIFile> mFile;
   169   nsCOMPtr<nsIObserverService> mObserverService;
   170   nsRefPtr<StartupCacheListener> mListener;
   171   nsCOMPtr<nsITimer> mTimer;
   173   bool mStartupWriteInitiated;
   175   static StaticRefPtr<StartupCache> gStartupCache;
   176   static bool gShutdownInitiated;
   177   static bool gIgnoreDiskCache;
   178   PRThread *mWriteThread;
   179 #ifdef DEBUG
   180   nsTHashtable<nsISupportsHashKey> mWriteObjectMap;
   181 #endif
   182 };
   184 // This debug outputstream attempts to detect if clients are writing multiple
   185 // references to the same object. We only support that if that object
   186 // is a singleton.
   187 #ifdef DEBUG
   188 class StartupCacheDebugOutputStream MOZ_FINAL
   189   : public nsIObjectOutputStream
   190 {  
   191   NS_DECL_ISUPPORTS
   192   NS_DECL_NSIOBJECTOUTPUTSTREAM
   194   StartupCacheDebugOutputStream (nsIObjectOutputStream* binaryStream,
   195                                    nsTHashtable<nsISupportsHashKey>* objectMap)
   196   : mBinaryStream(binaryStream), mObjectMap(objectMap) { }
   198   NS_FORWARD_SAFE_NSIBINARYOUTPUTSTREAM(mBinaryStream)
   199   NS_FORWARD_SAFE_NSIOUTPUTSTREAM(mBinaryStream)
   201   bool CheckReferences(nsISupports* aObject);
   203   nsCOMPtr<nsIObjectOutputStream> mBinaryStream;
   204   nsTHashtable<nsISupportsHashKey> *mObjectMap;
   205 };
   206 #endif // DEBUG
   208 // XPCOM wrapper interface provided for tests only.
   209 #define NS_STARTUPCACHE_CID \
   210       {0xae4505a9, 0x87ab, 0x477c, \
   211       {0xb5, 0x77, 0xf9, 0x23, 0x57, 0xed, 0xa8, 0x84}}
   212 // contract id: "@mozilla.org/startupcache/cache;1"
   214 class StartupCacheWrapper MOZ_FINAL
   215   : public nsIStartupCache
   216 {
   217   NS_DECL_THREADSAFE_ISUPPORTS
   218   NS_DECL_NSISTARTUPCACHE
   220   static StartupCacheWrapper* GetSingleton();
   221   static StartupCacheWrapper *gStartupCacheWrapper;
   222 };
   224 } // namespace scache
   225 } // namespace mozilla
   226 #endif //StartupCache_h_

mercurial