1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Startup Cache.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * The Mozilla Foundation <http://www.mozilla.org/>.
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Benedict Hsieh <bhsieh@mozilla.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef StartupCache_h_
40 : #define StartupCache_h_
41 :
42 : #include "prio.h"
43 : #include "prtypes.h"
44 :
45 : #include "nsClassHashtable.h"
46 : #include "nsIZipWriter.h"
47 : #include "nsIZipReader.h"
48 : #include "nsComponentManagerUtils.h"
49 : #include "nsZipArchive.h"
50 : #include "nsIStartupCache.h"
51 : #include "nsIStorageStream.h"
52 : #include "nsITimer.h"
53 : #include "nsIObserverService.h"
54 : #include "nsIObserver.h"
55 : #include "nsIOutputStream.h"
56 : #include "nsIFile.h"
57 :
58 : /**
59 : * The StartupCache is a persistent cache of simple key-value pairs,
60 : * where the keys are null-terminated c-strings and the values are
61 : * arbitrary data, passed as a (char*, size) tuple.
62 : *
63 : * Clients should use the GetSingleton() static method to access the cache. It
64 : * will be available from the end of XPCOM init (NS_InitXPCOM3 in nsXPComInit.cpp),
65 : * until XPCOM shutdown begins. The GetSingleton() method will return null if the cache
66 : * is unavailable. The cache is only provided for libxul builds --
67 : * it will fail to link in non-libxul builds. The XPCOM interface is provided
68 : * only to allow compiled-code tests; clients should avoid using it.
69 : *
70 : * The API provided is very simple: GetBuffer() returns a buffer that was previously
71 : * stored in the cache (if any), and PutBuffer() inserts a buffer into the cache.
72 : * GetBuffer returns a new buffer, and the caller must take ownership of it.
73 : * PutBuffer will assert if the client attempts to insert a buffer with the same name as
74 : * an existing entry. The cache makes a copy of the passed-in buffer, so client
75 : * retains ownership.
76 : *
77 : * InvalidateCache() may be called if a client suspects data corruption
78 : * or wishes to invalidate for any other reason. This will remove all existing cache data.
79 : * Finally, getDebugObjectOutputStream() allows debug code to wrap an objectstream
80 : * with a debug objectstream, to check for multiply-referenced objects. These will
81 : * generally fail to deserialize correctly, unless they are stateless singletons or the
82 : * client maintains their own object data map for deserialization.
83 : *
84 : * Writes before the final-ui-startup notification are placed in an intermediate
85 : * cache in memory, then written out to disk at a later time, to get writes off the
86 : * startup path. In any case, clients should not rely on being able to GetBuffer()
87 : * data that is written to the cache, since it may not have been written to disk or
88 : * another client may have invalidated the cache. In other words, it should be used as
89 : * a cache only, and not a reliable persistent store.
90 : *
91 : * Some utility functions are provided in StartupCacheUtils. These functions wrap the
92 : * buffers into object streams, which may be useful for serializing objects. Note
93 : * the above caution about multiply-referenced objects, though -- the streams are just
94 : * as 'dumb' as the underlying buffers about multiply-referenced objects. They just
95 : * provide some convenience in writing out data.
96 : */
97 :
98 : class nsIMemoryReporter;
99 :
100 : namespace mozilla {
101 : namespace scache {
102 :
103 : struct CacheEntry
104 : {
105 : nsAutoArrayPtr<char> data;
106 : PRUint32 size;
107 :
108 : CacheEntry() : data(nsnull), size(0) { }
109 :
110 : // Takes possession of buf
111 7379 : CacheEntry(char* buf, PRUint32 len) : data(buf), size(len) { }
112 :
113 7379 : ~CacheEntry()
114 7379 : {
115 7379 : }
116 :
117 0 : size_t SizeOfExcludingThis(nsMallocSizeOfFun mallocSizeOf) {
118 0 : return mallocSizeOf(data);
119 : }
120 : };
121 :
122 : // We don't want to refcount StartupCache, and ObserverService wants to
123 : // refcount its listeners, so we'll let it refcount this instead.
124 : class StartupCacheListener : public nsIObserver
125 687 : {
126 : NS_DECL_ISUPPORTS
127 : NS_DECL_NSIOBSERVER
128 : };
129 :
130 : class StartupCache
131 : {
132 :
133 : friend class StartupCacheListener;
134 : friend class StartupCacheWrapper;
135 :
136 : public:
137 :
138 : // StartupCache methods. See above comments for a more detailed description.
139 :
140 : // Returns a buffer that was previously stored, caller takes ownership.
141 : nsresult GetBuffer(const char* id, char** outbuf, PRUint32* length);
142 :
143 : // Stores a buffer. Caller keeps ownership, we make a copy.
144 : nsresult PutBuffer(const char* id, const char* inbuf, PRUint32 length);
145 :
146 : // Removes the cache file.
147 : void InvalidateCache();
148 :
149 : // In DEBUG builds, returns a stream that will attempt to check for
150 : // and disallow multiple writes of the same object.
151 : nsresult GetDebugObjectOutputStream(nsIObjectOutputStream* aStream,
152 : nsIObjectOutputStream** outStream);
153 :
154 : nsresult RecordAgesAlways();
155 :
156 : static StartupCache* GetSingleton();
157 : static void DeleteSingleton();
158 :
159 : // This measures all the heap memory used by the StartupCache, i.e. it
160 : // excludes the mapping.
161 : size_t HeapSizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
162 :
163 : size_t SizeOfMapping();
164 :
165 : private:
166 : StartupCache();
167 : ~StartupCache();
168 :
169 : enum TelemetrifyAge {
170 : IGNORE_AGE = 0,
171 : RECORD_AGE = 1
172 : };
173 : static enum TelemetrifyAge gPostFlushAgeAction;
174 :
175 : nsresult LoadArchive(enum TelemetrifyAge flag);
176 : nsresult Init();
177 : void WriteToDisk();
178 : nsresult ResetStartupWriteTimer();
179 : void WaitOnWriteThread();
180 :
181 : static nsresult InitSingleton();
182 : static void WriteTimeout(nsITimer *aTimer, void *aClosure);
183 : static void ThreadedWrite(void *aClosure);
184 :
185 : static size_t SizeOfEntryExcludingThis(const nsACString& key,
186 : const nsAutoPtr<CacheEntry>& data,
187 : nsMallocSizeOfFun mallocSizeOf,
188 : void *);
189 :
190 : nsClassHashtable<nsCStringHashKey, CacheEntry> mTable;
191 : nsRefPtr<nsZipArchive> mArchive;
192 : nsCOMPtr<nsILocalFile> mFile;
193 :
194 : nsCOMPtr<nsIObserverService> mObserverService;
195 : nsRefPtr<StartupCacheListener> mListener;
196 : nsCOMPtr<nsITimer> mTimer;
197 :
198 : bool mStartupWriteInitiated;
199 :
200 : static StartupCache *gStartupCache;
201 : static bool gShutdownInitiated;
202 : PRThread *mWriteThread;
203 : #ifdef DEBUG
204 : nsTHashtable<nsISupportsHashKey> mWriteObjectMap;
205 : #endif
206 :
207 : nsIMemoryReporter* mMappingMemoryReporter;
208 : nsIMemoryReporter* mDataMemoryReporter;
209 : };
210 :
211 : // This debug outputstream attempts to detect if clients are writing multiple
212 : // references to the same object. We only support that if that object
213 : // is a singleton.
214 : #ifdef DEBUG
215 : class StartupCacheDebugOutputStream
216 : : public nsIObjectOutputStream
217 7375 : {
218 : NS_DECL_ISUPPORTS
219 : NS_DECL_NSIOBJECTOUTPUTSTREAM
220 :
221 7375 : StartupCacheDebugOutputStream (nsIObjectOutputStream* binaryStream,
222 : nsTHashtable<nsISupportsHashKey>* objectMap)
223 7375 : : mBinaryStream(binaryStream), mObjectMap(objectMap) { }
224 :
225 29500 : NS_FORWARD_SAFE_NSIBINARYOUTPUTSTREAM(mBinaryStream)
226 7375 : NS_FORWARD_SAFE_NSIOUTPUTSTREAM(mBinaryStream)
227 :
228 : bool CheckReferences(nsISupports* aObject);
229 :
230 : nsCOMPtr<nsIObjectOutputStream> mBinaryStream;
231 : nsTHashtable<nsISupportsHashKey> *mObjectMap;
232 : };
233 : #endif // DEBUG
234 :
235 : // XPCOM wrapper interface provided for tests only.
236 : #define NS_STARTUPCACHE_CID \
237 : {0xae4505a9, 0x87ab, 0x477c, \
238 : {0xb5, 0x77, 0xf9, 0x23, 0x57, 0xed, 0xa8, 0x84}}
239 : // contract id: "@mozilla.org/startupcache/cache;1"
240 :
241 : class StartupCacheWrapper
242 : : public nsIStartupCache
243 1 : {
244 : NS_DECL_ISUPPORTS
245 : NS_DECL_NSISTARTUPCACHE
246 :
247 : static StartupCacheWrapper* GetSingleton();
248 : static StartupCacheWrapper *gStartupCacheWrapper;
249 : };
250 :
251 : } // namespace scache
252 : } // namespace mozilla
253 : #endif //StartupCache_h_
|