StartupCache.h 7.8 KB

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