Coverage Report

Created: 2018-09-25 14:53

/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_