dom/src/storage/DOMStorageCache.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:861b574405b5
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 nsDOMStorageCache_h___
7 #define nsDOMStorageCache_h___
8
9 #include "nsIURI.h"
10 #include "nsIPrincipal.h"
11 #include "nsITimer.h"
12
13 #include "nsString.h"
14 #include "nsDataHashtable.h"
15 #include "nsHashKeys.h"
16 #include "mozilla/Monitor.h"
17 #include "mozilla/Telemetry.h"
18 #include "nsAutoPtr.h"
19
20 namespace mozilla {
21 namespace dom {
22
23 class DOMStorage;
24 class DOMStorageUsage;
25 class DOMStorageManager;
26 class DOMStorageDBBridge;
27
28 // Interface class on which only the database or IPC may call.
29 // Used to populate the cache with DB data.
30 class DOMStorageCacheBridge
31 {
32 public:
33 NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
34 NS_IMETHOD_(void) Release(void);
35
36 virtual ~DOMStorageCacheBridge() {}
37
38 // The scope (origin) in the database usage format (reversed)
39 virtual const nsCString& Scope() const = 0;
40
41 // Whether the cache is already fully loaded
42 virtual bool Loaded() = 0;
43
44 // How many items has so far been loaded into the cache, used
45 // for optimization purposes
46 virtual uint32_t LoadedCount() = 0;
47
48 // Called by the database to load a key and its value to the cache
49 virtual bool LoadItem(const nsAString& aKey, const nsString& aValue) = 0;
50
51 // Called by the database after all keys and values has been loaded
52 // to this cache
53 virtual void LoadDone(nsresult aRv) = 0;
54
55 // Use to synchronously wait until the cache gets fully loaded with data,
56 // this method exits after LoadDone has been called
57 virtual void LoadWait() = 0;
58
59 protected:
60 ThreadSafeAutoRefCnt mRefCnt;
61 NS_DECL_OWNINGTHREAD
62 };
63
64 // Implementation of scope cache that is responsible for preloading data
65 // for persistent storage (localStorage) and hold data for non-private,
66 // private and session-only cookie modes. It is also responsible for
67 // persisting data changes using the database, works as a write-back cache.
68 class DOMStorageCache : public DOMStorageCacheBridge
69 {
70 public:
71 NS_IMETHOD_(void) Release(void);
72
73 DOMStorageCache(const nsACString* aScope);
74 virtual ~DOMStorageCache();
75
76 void Init(DOMStorageManager* aManager, bool aPersistent,
77 nsIURI* aFirstPartyIsolationURI, nsIPrincipal* aPrincipal,
78 const nsACString& aQuotaScope);
79
80 // Copies all data from the other storage.
81 void CloneFrom(const DOMStorageCache* aThat);
82
83 // Starts async preload of this cache if it persistent and not loaded.
84 void Preload();
85
86 // Keeps the cache alive (i.e. present in the manager's hash table) for a time.
87 void KeepAlive();
88
89 // The set of methods that are invoked by DOM storage web API.
90 // We are passing the DOMStorage object just to let the cache
91 // read properties like mPrivate and mSessionOnly.
92 // Get* methods return error when load from the database has failed.
93 nsresult GetLength(const DOMStorage* aStorage, uint32_t* aRetval);
94 nsresult GetKey(const DOMStorage* aStorage, uint32_t index, nsAString& aRetval);
95 nsresult GetItem(const DOMStorage* aStorage, const nsAString& aKey, nsAString& aRetval);
96 nsresult SetItem(const DOMStorage* aStorage, const nsAString& aKey, const nsString& aValue, nsString& aOld);
97 nsresult RemoveItem(const DOMStorage* aStorage, const nsAString& aKey, nsString& aOld);
98 nsresult Clear(const DOMStorage* aStorage);
99
100 nsTArray<nsString>* GetKeys(const DOMStorage* aStorage);
101
102 nsIURI* FirstPartyIsolationURI() const { return mFirstPartyIsolationURI; }
103
104 // Whether the principal equals principal the cache was created for
105 bool CheckPrincipal(nsIPrincipal* aPrincipal) const;
106 nsIPrincipal* Principal() const { return mPrincipal; }
107
108 // Starts the database engine thread or the IPC bridge
109 static DOMStorageDBBridge* StartDatabase();
110 static DOMStorageDBBridge* GetDatabase();
111
112 // Stops the thread and flushes all uncommited data
113 static nsresult StopDatabase();
114
115 // DOMStorageCacheBridge
116
117 virtual const nsCString& Scope() const { return mScope; }
118 virtual bool Loaded() { return mLoaded; }
119 virtual uint32_t LoadedCount();
120 virtual bool LoadItem(const nsAString& aKey, const nsString& aValue);
121 virtual void LoadDone(nsresult aRv);
122 virtual void LoadWait();
123
124 // Cache keeps 3 sets of data: regular, private and session-only.
125 // This class keeps keys and values for a set and also caches
126 // size of the data for quick per-origin quota checking.
127 class Data
128 {
129 public:
130 Data() : mOriginQuotaUsage(0) {}
131 int64_t mOriginQuotaUsage;
132 nsDataHashtable<nsStringHashKey, nsString> mKeys;
133 };
134
135 public:
136 // Number of data sets we keep: default, private, session
137 static const uint32_t kDataSetCount = 3;
138
139 private:
140 // API to clear the cache data, this is invoked by chrome operations
141 // like cookie deletion.
142 friend class DOMStorageManager;
143
144 static const uint32_t kUnloadDefault = 1 << 0;
145 static const uint32_t kUnloadPrivate = 1 << 1;
146 static const uint32_t kUnloadSession = 1 << 2;
147 static const uint32_t kUnloadComplete =
148 kUnloadDefault | kUnloadPrivate | kUnloadSession;
149
150 #ifdef DOM_STORAGE_TESTS
151 static const uint32_t kTestReload = 1 << 15;
152 #endif
153
154 void UnloadItems(uint32_t aUnloadFlags);
155
156 private:
157 // Synchronously blocks until the cache is fully loaded from the database
158 void WaitForPreload(mozilla::Telemetry::ID aTelemetryID);
159
160 // Helper to get one of the 3 data sets (regular, private, session)
161 Data& DataSet(const DOMStorage* aStorage);
162
163 // Whether the storage change is about to persist
164 bool Persist(const DOMStorage* aStorage) const;
165
166 // Changes the quota usage on the given data set if it fits the quota.
167 // If not, then false is returned and no change to the set must be done.
168 bool ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta);
169 bool ProcessUsageDelta(const DOMStorage* aStorage, const int64_t aDelta);
170
171 private:
172 // When a cache is reponsible for its life time (in case of localStorage data
173 // cache) we need to refer our manager since removal of the cache from the hash
174 // table is handled in the destructor by call to the manager.
175 // Cache could potentially overlive the manager, hence the hard ref.
176 nsRefPtr<DOMStorageManager> mManager;
177
178 // Reference to the usage counter object we check on for eTLD+1 quota limit.
179 // Obtained from the manager during initialization (Init method).
180 nsRefPtr<DOMStorageUsage> mUsage;
181
182 // Timer that holds this cache alive for a while after it has been preloaded.
183 nsCOMPtr<nsITimer> mKeepAliveTimer;
184
185 // The first party URI associated with this cache.
186 nsCOMPtr<nsIURI> mFirstPartyIsolationURI;
187
188 // Principal the cache has been initially created for, this is used only
189 // for sessionStorage access checks since sessionStorage objects are strictly
190 // scoped by a principal. localStorage objects on the other hand are scoped by
191 // origin only.
192 nsCOMPtr<nsIPrincipal> mPrincipal;
193
194 // The scope this cache belongs to in the "DB format", i.e. reversed
195 nsCString mScope;
196
197 // The eTLD+1 scope used to count quota usage.
198 nsCString mQuotaScope;
199
200 // Non-private Browsing, Private Browsing and Session Only sets.
201 Data mData[kDataSetCount];
202
203 // This monitor is used to wait for full load of data.
204 mozilla::Monitor mMonitor;
205
206 // Flag that is initially false. When the cache is about to work with
207 // the database (i.e. it is persistent) this flags is set to true after
208 // all keys and coresponding values are loaded from the database.
209 // This flag never goes from true back to false.
210 bool mLoaded;
211
212 // Result of load from the database. Valid after mLoaded flag has been set.
213 nsresult mLoadResult;
214
215 // Init() method has been called
216 bool mInitialized : 1;
217
218 // This cache is about to be bound with the database (i.e. it has
219 // to load from the DB first and has to persist when modifying the
220 // default data set.)
221 bool mPersistent : 1;
222
223 // - False when the session-only data set was never used.
224 // - True after access to session-only data has been made for the first time.
225 // We also fill session-only data set with the default one at that moment.
226 // Drops back to false when session-only data are cleared from chrome.
227 bool mSessionOnlyDataSetActive : 1;
228
229 // Whether we have already captured state of the cache preload on our first access.
230 bool mPreloadTelemetryRecorded : 1;
231
232 // DOMStorageDBThread on the parent or single process,
233 // DOMStorageDBChild on the child process.
234 static DOMStorageDBBridge* sDatabase;
235
236 // False until we shut the database down.
237 static bool sDatabaseDown;
238 };
239
240 // DOMStorageUsage
241 // Infrastructure to manage and check eTLD+1 quota
242 class DOMStorageUsageBridge
243 {
244 public:
245 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DOMStorageUsageBridge)
246
247 virtual const nsCString& Scope() = 0;
248 virtual void LoadUsage(const int64_t aUsage) = 0;
249
250 protected:
251 // Protected destructor, to discourage deletion outside of Release():
252 virtual ~DOMStorageUsageBridge() {}
253 };
254
255 class DOMStorageUsage : public DOMStorageUsageBridge
256 {
257 public:
258 DOMStorageUsage(const nsACString& aScope);
259
260 bool CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex, int64_t aUsageDelta);
261
262 private:
263 virtual const nsCString& Scope() { return mScope; }
264 virtual void LoadUsage(const int64_t aUsage);
265
266 nsCString mScope;
267 int64_t mUsage[DOMStorageCache::kDataSetCount];
268 };
269
270 } // ::dom
271 } // ::mozilla
272
273 #endif

mercurial