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