/src/mozilla-central/dom/quota/QuotaManager.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
5 | | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef mozilla_dom_quota_quotamanager_h__ |
8 | | #define mozilla_dom_quota_quotamanager_h__ |
9 | | |
10 | | #include "QuotaCommon.h" |
11 | | |
12 | | #include "mozilla/dom/Nullable.h" |
13 | | #include "mozilla/dom/ipc/IdType.h" |
14 | | #include "mozilla/Mutex.h" |
15 | | |
16 | | #include "nsClassHashtable.h" |
17 | | #include "nsRefPtrHashtable.h" |
18 | | |
19 | | #include "Client.h" |
20 | | #include "PersistenceType.h" |
21 | | |
22 | | #include "prenv.h" |
23 | | |
24 | | #define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1" |
25 | | |
26 | | class mozIStorageConnection; |
27 | | class nsIEventTarget; |
28 | | class nsIPrincipal; |
29 | | class nsIThread; |
30 | | class nsITimer; |
31 | | class nsIURI; |
32 | | class nsPIDOMWindowOuter; |
33 | | class nsIRunnable; |
34 | | |
35 | | BEGIN_QUOTA_NAMESPACE |
36 | | |
37 | | class DirectoryLockImpl; |
38 | | class GroupInfo; |
39 | | class GroupInfoPair; |
40 | | class OriginInfo; |
41 | | class OriginScope; |
42 | | class QuotaObject; |
43 | | |
44 | | class NS_NO_VTABLE RefCountedObject |
45 | | { |
46 | | public: |
47 | | NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING |
48 | | }; |
49 | | |
50 | | class DirectoryLock |
51 | | : public RefCountedObject |
52 | | { |
53 | | friend class DirectoryLockImpl; |
54 | | |
55 | | private: |
56 | | DirectoryLock() |
57 | 0 | { } |
58 | | |
59 | | ~DirectoryLock() |
60 | 0 | { } |
61 | | }; |
62 | | |
63 | | class NS_NO_VTABLE OpenDirectoryListener |
64 | | : public RefCountedObject |
65 | | { |
66 | | public: |
67 | | virtual void |
68 | | DirectoryLockAcquired(DirectoryLock* aLock) = 0; |
69 | | |
70 | | virtual void |
71 | | DirectoryLockFailed() = 0; |
72 | | |
73 | | protected: |
74 | | virtual ~OpenDirectoryListener() |
75 | | { } |
76 | | }; |
77 | | |
78 | | struct OriginParams |
79 | | { |
80 | | OriginParams(PersistenceType aPersistenceType, |
81 | | const nsACString& aOrigin) |
82 | | : mOrigin(aOrigin) |
83 | | , mPersistenceType(aPersistenceType) |
84 | 0 | { } |
85 | | |
86 | | nsCString mOrigin; |
87 | | PersistenceType mPersistenceType; |
88 | | }; |
89 | | |
90 | | class QuotaManager final |
91 | | : public BackgroundThreadObject |
92 | | { |
93 | | friend class DirectoryLockImpl; |
94 | | friend class GroupInfo; |
95 | | friend class OriginInfo; |
96 | | friend class QuotaObject; |
97 | | |
98 | | typedef nsClassHashtable<nsCStringHashKey, |
99 | | nsTArray<DirectoryLockImpl*>> DirectoryLockTable; |
100 | | |
101 | | public: |
102 | | class CreateRunnable; |
103 | | |
104 | | private: |
105 | | class ShutdownRunnable; |
106 | | class ShutdownObserver; |
107 | | |
108 | | public: |
109 | | NS_INLINE_DECL_REFCOUNTING(QuotaManager) |
110 | | |
111 | | static bool IsRunningXPCShellTests() |
112 | 0 | { |
113 | 0 | static bool kRunningXPCShellTests = !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR"); |
114 | 0 | return kRunningXPCShellTests; |
115 | 0 | } |
116 | | |
117 | | static const char kReplaceChars[]; |
118 | | |
119 | | static void |
120 | | GetOrCreate(nsIRunnable* aCallback); |
121 | | |
122 | | // Returns a non-owning reference. |
123 | | static QuotaManager* |
124 | | Get(); |
125 | | |
126 | | // Returns true if we've begun the shutdown process. |
127 | | static bool IsShuttingDown(); |
128 | | |
129 | | bool |
130 | | IsOriginInitialized(const nsACString& aOrigin) const |
131 | 0 | { |
132 | 0 | AssertIsOnIOThread(); |
133 | 0 |
|
134 | 0 | return mInitializedOrigins.Contains(aOrigin); |
135 | 0 | } |
136 | | |
137 | | bool |
138 | | IsTemporaryStorageInitialized() const |
139 | 0 | { |
140 | 0 | AssertIsOnIOThread(); |
141 | 0 |
|
142 | 0 | return mTemporaryStorageInitialized; |
143 | 0 | } |
144 | | |
145 | | void |
146 | | InitQuotaForOrigin(PersistenceType aPersistenceType, |
147 | | const nsACString& aGroup, |
148 | | const nsACString& aOrigin, |
149 | | uint64_t aUsageBytes, |
150 | | int64_t aAccessTime, |
151 | | bool aPersisted); |
152 | | |
153 | | void |
154 | | DecreaseUsageForOrigin(PersistenceType aPersistenceType, |
155 | | const nsACString& aGroup, |
156 | | const nsACString& aOrigin, |
157 | | int64_t aSize); |
158 | | |
159 | | void |
160 | | UpdateOriginAccessTime(PersistenceType aPersistenceType, |
161 | | const nsACString& aGroup, |
162 | | const nsACString& aOrigin); |
163 | | |
164 | | void |
165 | | RemoveQuota(); |
166 | | |
167 | | void |
168 | | RemoveQuotaForOrigin(PersistenceType aPersistenceType, |
169 | | const nsACString& aGroup, |
170 | | const nsACString& aOrigin) |
171 | 0 | { |
172 | 0 | MutexAutoLock lock(mQuotaMutex); |
173 | 0 | LockedRemoveQuotaForOrigin(aPersistenceType, aGroup, aOrigin); |
174 | 0 | } |
175 | | |
176 | | already_AddRefed<QuotaObject> |
177 | | GetQuotaObject(PersistenceType aPersistenceType, |
178 | | const nsACString& aGroup, |
179 | | const nsACString& aOrigin, |
180 | | nsIFile* aFile, |
181 | | int64_t* aFileSizeOut = nullptr); |
182 | | |
183 | | already_AddRefed<QuotaObject> |
184 | | GetQuotaObject(PersistenceType aPersistenceType, |
185 | | const nsACString& aGroup, |
186 | | const nsACString& aOrigin, |
187 | | const nsAString& aPath, |
188 | | int64_t* aFileSizeOut = nullptr); |
189 | | |
190 | | Nullable<bool> |
191 | | OriginPersisted(const nsACString& aGroup, |
192 | | const nsACString& aOrigin); |
193 | | |
194 | | void |
195 | | PersistOrigin(const nsACString& aGroup, |
196 | | const nsACString& aOrigin); |
197 | | |
198 | | // Called when a process is being shot down. Aborts any running operations |
199 | | // for the given process. |
200 | | void |
201 | | AbortOperationsForProcess(ContentParentId aContentParentId); |
202 | | |
203 | | nsresult |
204 | | GetDirectoryForOrigin(PersistenceType aPersistenceType, |
205 | | const nsACString& aASCIIOrigin, |
206 | | nsIFile** aDirectory) const; |
207 | | |
208 | | nsresult |
209 | | RestoreDirectoryMetadata2(nsIFile* aDirectory, bool aPersistent); |
210 | | |
211 | | nsresult |
212 | | GetDirectoryMetadata2(nsIFile* aDirectory, |
213 | | int64_t* aTimestamp, |
214 | | bool* aPersisted, |
215 | | nsACString& aSuffix, |
216 | | nsACString& aGroup, |
217 | | nsACString& aOrigin); |
218 | | |
219 | | nsresult |
220 | | GetDirectoryMetadata2WithRestore(nsIFile* aDirectory, |
221 | | bool aPersistent, |
222 | | int64_t* aTimestamp, |
223 | | bool* aPersisted, |
224 | | nsACString& aSuffix, |
225 | | nsACString& aGroup, |
226 | | nsACString& aOrigin); |
227 | | |
228 | | nsresult |
229 | | GetDirectoryMetadata2(nsIFile* aDirectory, |
230 | | int64_t* aTimestamp, |
231 | | bool* aPersisted); |
232 | | |
233 | | nsresult |
234 | | GetDirectoryMetadata2WithRestore(nsIFile* aDirectory, |
235 | | bool aPersistent, |
236 | | int64_t* aTimestamp, |
237 | | bool* aPersisted); |
238 | | |
239 | | // This is the main entry point into the QuotaManager API. |
240 | | // Any storage API implementation (quota client) that participates in |
241 | | // centralized quota and storage handling should call this method to get |
242 | | // a directory lock which will protect client's files from being deleted |
243 | | // while they are still in use. |
244 | | // After a lock is acquired, client is notified via the open listener's |
245 | | // method DirectoryLockAcquired. If the lock couldn't be acquired, client |
246 | | // gets DirectoryLockFailed notification. |
247 | | // A lock is a reference counted object and at the time DirectoryLockAcquired |
248 | | // is called, quota manager holds just one strong reference to it which is |
249 | | // then immediatelly cleared by quota manager. So it's up to client to add |
250 | | // a new reference in order to keep the lock alive. |
251 | | // Unlocking is simply done by dropping all references to the lock object. |
252 | | // In other words, protection which the lock represents dies with the lock |
253 | | // object itself. |
254 | | void |
255 | | OpenDirectory(PersistenceType aPersistenceType, |
256 | | const nsACString& aGroup, |
257 | | const nsACString& aOrigin, |
258 | | Client::Type aClientType, |
259 | | bool aExclusive, |
260 | | OpenDirectoryListener* aOpenListener); |
261 | | |
262 | | // XXX RemoveMe once bug 1170279 gets fixed. |
263 | | void |
264 | | OpenDirectoryInternal(const Nullable<PersistenceType>& aPersistenceType, |
265 | | const OriginScope& aOriginScope, |
266 | | const Nullable<Client::Type>& aClientType, |
267 | | bool aExclusive, |
268 | | OpenDirectoryListener* aOpenListener); |
269 | | |
270 | | // Collect inactive and the least recently used origins. |
271 | | uint64_t |
272 | | CollectOriginsForEviction(uint64_t aMinSizeToBeFreed, |
273 | | nsTArray<RefPtr<DirectoryLockImpl>>& aLocks); |
274 | | |
275 | | void |
276 | | AssertStorageIsInitialized() const |
277 | | #ifdef DEBUG |
278 | | ; |
279 | | #else |
280 | 0 | { } |
281 | | #endif |
282 | | |
283 | | nsresult |
284 | | EnsureStorageIsInitialized(); |
285 | | |
286 | | nsresult |
287 | | EnsureOriginIsInitialized(PersistenceType aPersistenceType, |
288 | | const nsACString& aSuffix, |
289 | | const nsACString& aGroup, |
290 | | const nsACString& aOrigin, |
291 | | nsIFile** aDirectory); |
292 | | |
293 | | nsresult |
294 | | EnsureOriginIsInitializedInternal(PersistenceType aPersistenceType, |
295 | | const nsACString& aSuffix, |
296 | | const nsACString& aGroup, |
297 | | const nsACString& aOrigin, |
298 | | nsIFile** aDirectory, |
299 | | bool* aCreated); |
300 | | |
301 | | nsresult |
302 | | EnsureTemporaryStorageIsInitialized(); |
303 | | |
304 | | nsresult |
305 | | EnsureOriginDirectory(nsIFile* aDirectory, |
306 | | bool* aCreated); |
307 | | |
308 | | void |
309 | | OriginClearCompleted(PersistenceType aPersistenceType, |
310 | | const nsACString& aOrigin); |
311 | | |
312 | | void |
313 | | ResetOrClearCompleted(); |
314 | | |
315 | | void |
316 | | StartIdleMaintenance() |
317 | 0 | { |
318 | 0 | AssertIsOnOwningThread(); |
319 | 0 |
|
320 | 0 | for (auto& client : mClients) { |
321 | 0 | client->StartIdleMaintenance(); |
322 | 0 | } |
323 | 0 | } |
324 | | |
325 | | void |
326 | | StopIdleMaintenance() |
327 | 0 | { |
328 | 0 | AssertIsOnOwningThread(); |
329 | 0 |
|
330 | 0 | for (auto& client : mClients) { |
331 | 0 | client->StopIdleMaintenance(); |
332 | 0 | } |
333 | 0 | } |
334 | | |
335 | | void |
336 | | AssertCurrentThreadOwnsQuotaMutex() |
337 | | { |
338 | | mQuotaMutex.AssertCurrentThreadOwns(); |
339 | | } |
340 | | |
341 | | nsIThread* |
342 | | IOThread() |
343 | | { |
344 | | NS_ASSERTION(mIOThread, "This should never be null!"); |
345 | | return mIOThread; |
346 | | } |
347 | | |
348 | | Client* |
349 | | GetClient(Client::Type aClientType); |
350 | | |
351 | | const nsString& |
352 | | GetBasePath() const |
353 | 0 | { |
354 | 0 | return mBasePath; |
355 | 0 | } |
356 | | |
357 | | const nsString& |
358 | | GetStoragePath() const |
359 | 0 | { |
360 | 0 | return mStoragePath; |
361 | 0 | } |
362 | | |
363 | | const nsString& |
364 | | GetStoragePath(PersistenceType aPersistenceType) const |
365 | 0 | { |
366 | 0 | if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) { |
367 | 0 | return mPermanentStoragePath; |
368 | 0 | } |
369 | 0 | |
370 | 0 | if (aPersistenceType == PERSISTENCE_TYPE_TEMPORARY) { |
371 | 0 | return mTemporaryStoragePath; |
372 | 0 | } |
373 | 0 | |
374 | 0 | MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_DEFAULT); |
375 | 0 |
|
376 | 0 | return mDefaultStoragePath; |
377 | 0 | } |
378 | | |
379 | | uint64_t |
380 | | GetGroupLimit() const; |
381 | | |
382 | | void |
383 | | GetGroupUsageAndLimit(const nsACString& aGroup, |
384 | | UsageInfo* aUsageInfo); |
385 | | |
386 | | void |
387 | | NotifyStoragePressure(uint64_t aUsage); |
388 | | |
389 | | static void |
390 | | GetStorageId(PersistenceType aPersistenceType, |
391 | | const nsACString& aOrigin, |
392 | | Client::Type aClientType, |
393 | | nsACString& aDatabaseId); |
394 | | |
395 | | static nsresult |
396 | | GetInfoFromPrincipal(nsIPrincipal* aPrincipal, |
397 | | nsACString* aSuffix, |
398 | | nsACString* aGroup, |
399 | | nsACString* aOrigin); |
400 | | |
401 | | static nsresult |
402 | | GetInfoFromWindow(nsPIDOMWindowOuter* aWindow, |
403 | | nsACString* aSuffix, |
404 | | nsACString* aGroup, |
405 | | nsACString* aOrigin); |
406 | | |
407 | | static void |
408 | | GetInfoForChrome(nsACString* aSuffix, |
409 | | nsACString* aGroup, |
410 | | nsACString* aOrigin); |
411 | | |
412 | | static bool |
413 | | IsOriginInternal(const nsACString& aOrigin); |
414 | | |
415 | | static void |
416 | | ChromeOrigin(nsACString& aOrigin); |
417 | | |
418 | | static bool |
419 | | AreOriginsEqualOnDisk(nsACString& aOrigin1, |
420 | | nsACString& aOrigin2); |
421 | | |
422 | | private: |
423 | | QuotaManager(); |
424 | | |
425 | | virtual ~QuotaManager(); |
426 | | |
427 | | nsresult |
428 | | Init(const nsAString& aBaseDirPath); |
429 | | |
430 | | void |
431 | | Shutdown(); |
432 | | |
433 | | already_AddRefed<DirectoryLockImpl> |
434 | | CreateDirectoryLock(const Nullable<PersistenceType>& aPersistenceType, |
435 | | const nsACString& aGroup, |
436 | | const OriginScope& aOriginScope, |
437 | | const Nullable<Client::Type>& aClientType, |
438 | | bool aExclusive, |
439 | | bool aInternal, |
440 | | OpenDirectoryListener* aOpenListener); |
441 | | |
442 | | already_AddRefed<DirectoryLockImpl> |
443 | | CreateDirectoryLockForEviction(PersistenceType aPersistenceType, |
444 | | const nsACString& aGroup, |
445 | | const nsACString& aOrigin); |
446 | | |
447 | | void |
448 | | RegisterDirectoryLock(DirectoryLockImpl* aLock); |
449 | | |
450 | | void |
451 | | UnregisterDirectoryLock(DirectoryLockImpl* aLock); |
452 | | |
453 | | void |
454 | | RemovePendingDirectoryLock(DirectoryLockImpl* aLock); |
455 | | |
456 | | uint64_t |
457 | | LockedCollectOriginsForEviction( |
458 | | uint64_t aMinSizeToBeFreed, |
459 | | nsTArray<RefPtr<DirectoryLockImpl>>& aLocks); |
460 | | |
461 | | void |
462 | | LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType, |
463 | | const nsACString& aGroup, |
464 | | const nsACString& aOrigin); |
465 | | |
466 | | already_AddRefed<OriginInfo> |
467 | | LockedGetOriginInfo(PersistenceType aPersistenceType, |
468 | | const nsACString& aGroup, |
469 | | const nsACString& aOrigin); |
470 | | |
471 | | nsresult |
472 | | MaybeUpgradeIndexedDBDirectory(); |
473 | | |
474 | | nsresult |
475 | | MaybeUpgradePersistentStorageDirectory(); |
476 | | |
477 | | nsresult |
478 | | MaybeRemoveOldDirectories(); |
479 | | |
480 | | nsresult |
481 | | UpgradeStorageFrom0_0To1_0(mozIStorageConnection* aConnection); |
482 | | |
483 | | nsresult |
484 | | UpgradeStorageFrom1_0To2_0(mozIStorageConnection* aConnection); |
485 | | |
486 | | nsresult |
487 | | UpgradeStorageFrom2_0To2_1(mozIStorageConnection* aConnection); |
488 | | |
489 | | nsresult |
490 | | MaybeRemoveLocalStorageData(); |
491 | | |
492 | | nsresult |
493 | | MaybeRemoveLocalStorageDirectories(); |
494 | | |
495 | | nsresult |
496 | | InitializeRepository(PersistenceType aPersistenceType); |
497 | | |
498 | | nsresult |
499 | | InitializeOrigin(PersistenceType aPersistenceType, |
500 | | const nsACString& aGroup, |
501 | | const nsACString& aOrigin, |
502 | | int64_t aAccessTime, |
503 | | bool aPersisted, |
504 | | nsIFile* aDirectory); |
505 | | |
506 | | void |
507 | | CheckTemporaryStorageLimits(); |
508 | | |
509 | | void |
510 | | DeleteFilesForOrigin(PersistenceType aPersistenceType, |
511 | | const nsACString& aOrigin); |
512 | | |
513 | | void |
514 | | FinalizeOriginEviction(nsTArray<RefPtr<DirectoryLockImpl>>& aLocks); |
515 | | |
516 | | void |
517 | | ReleaseIOThreadObjects() |
518 | 0 | { |
519 | 0 | AssertIsOnIOThread(); |
520 | 0 |
|
521 | 0 | for (uint32_t index = 0; index < Client::TYPE_MAX; index++) { |
522 | 0 | mClients[index]->ReleaseIOThreadObjects(); |
523 | 0 | } |
524 | 0 | } |
525 | | |
526 | | DirectoryLockTable& |
527 | | GetDirectoryLockTable(PersistenceType aPersistenceType); |
528 | | |
529 | | bool |
530 | | IsSanitizedOriginValid(const nsACString& aSanitizedOrigin); |
531 | | |
532 | | static void |
533 | | ShutdownTimerCallback(nsITimer* aTimer, void* aClosure); |
534 | | |
535 | | mozilla::Mutex mQuotaMutex; |
536 | | |
537 | | nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs; |
538 | | |
539 | | // Maintains a list of directory locks that are queued. |
540 | | nsTArray<RefPtr<DirectoryLockImpl>> mPendingDirectoryLocks; |
541 | | |
542 | | // Maintains a list of directory locks that are acquired or queued. |
543 | | nsTArray<DirectoryLockImpl*> mDirectoryLocks; |
544 | | |
545 | | // Directory lock tables that are used to update origin access time. |
546 | | DirectoryLockTable mTemporaryDirectoryLockTable; |
547 | | DirectoryLockTable mDefaultDirectoryLockTable; |
548 | | |
549 | | // Thread on which IO is performed. |
550 | | nsCOMPtr<nsIThread> mIOThread; |
551 | | |
552 | | // A timer that gets activated at shutdown to ensure we close all storages. |
553 | | nsCOMPtr<nsITimer> mShutdownTimer; |
554 | | |
555 | | // A list of all successfully initialized persistent origins. This list isn't |
556 | | // protected by any mutex but it is only ever touched on the IO thread. |
557 | | nsTArray<nsCString> mInitializedOrigins; |
558 | | |
559 | | // A hash table that is used to cache origin parser results for given |
560 | | // sanitized origin strings. This hash table isn't protected by any mutex but |
561 | | // it is only ever touched on the IO thread. |
562 | | nsDataHashtable<nsCStringHashKey, bool> mValidOrigins; |
563 | | |
564 | | // This array is populated at initialization time and then never modified, so |
565 | | // it can be iterated on any thread. |
566 | | AutoTArray<RefPtr<Client>, Client::TYPE_MAX> mClients; |
567 | | |
568 | | nsString mBasePath; |
569 | | nsString mIndexedDBPath; |
570 | | nsString mStoragePath; |
571 | | nsString mPermanentStoragePath; |
572 | | nsString mTemporaryStoragePath; |
573 | | nsString mDefaultStoragePath; |
574 | | |
575 | | uint64_t mTemporaryStorageLimit; |
576 | | uint64_t mTemporaryStorageUsage; |
577 | | bool mTemporaryStorageInitialized; |
578 | | |
579 | | bool mStorageInitialized; |
580 | | }; |
581 | | |
582 | | END_QUOTA_NAMESPACE |
583 | | |
584 | | #endif /* mozilla_dom_quota_quotamanager_h__ */ |