Line data Source code
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 0 : 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 0 : DirectoryLock()
57 0 : { }
58 :
59 0 : ~DirectoryLock()
60 0 : { }
61 : };
62 :
63 0 : 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 0 : virtual ~OpenDirectoryListener()
75 0 : { }
76 : };
77 :
78 0 : struct OriginParams
79 : {
80 0 : OriginParams(PersistenceType aPersistenceType,
81 : const nsACString& aOrigin)
82 0 : : mOrigin(aOrigin)
83 0 : , 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 0 : NS_INLINE_DECL_REFCOUNTING(QuotaManager)
110 :
111 0 : static bool IsRunningXPCShellTests()
112 : {
113 0 : static bool kRunningXPCShellTests = !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR");
114 0 : return kRunningXPCShellTests;
115 : }
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 0 : IsOriginInitialized(const nsACString& aOrigin) const
131 : {
132 0 : AssertIsOnIOThread();
133 :
134 0 : return mInitializedOrigins.Contains(aOrigin);
135 : }
136 :
137 : bool
138 0 : IsTemporaryStorageInitialized() const
139 : {
140 0 : AssertIsOnIOThread();
141 :
142 0 : return mTemporaryStorageInitialized;
143 : }
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 0 : RemoveQuotaForOrigin(PersistenceType aPersistenceType,
169 : const nsACString& aGroup,
170 : const nsACString& aOrigin)
171 : {
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 :
182 : already_AddRefed<QuotaObject>
183 : GetQuotaObject(PersistenceType aPersistenceType,
184 : const nsACString& aGroup,
185 : const nsACString& aOrigin,
186 : const nsAString& aPath);
187 :
188 : Nullable<bool>
189 : OriginPersisted(const nsACString& aGroup,
190 : const nsACString& aOrigin);
191 :
192 : void
193 : PersistOrigin(const nsACString& aGroup,
194 : const nsACString& aOrigin);
195 :
196 : // Called when a process is being shot down. Aborts any running operations
197 : // for the given process.
198 : void
199 : AbortOperationsForProcess(ContentParentId aContentParentId);
200 :
201 : nsresult
202 : GetDirectoryForOrigin(PersistenceType aPersistenceType,
203 : const nsACString& aASCIIOrigin,
204 : nsIFile** aDirectory) const;
205 :
206 : nsresult
207 : RestoreDirectoryMetadata2(nsIFile* aDirectory, bool aPersistent);
208 :
209 : nsresult
210 : GetDirectoryMetadata2(nsIFile* aDirectory,
211 : int64_t* aTimestamp,
212 : bool* aPersisted,
213 : nsACString& aSuffix,
214 : nsACString& aGroup,
215 : nsACString& aOrigin);
216 :
217 : nsresult
218 : GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
219 : bool aPersistent,
220 : int64_t* aTimestamp,
221 : bool* aPersisted,
222 : nsACString& aSuffix,
223 : nsACString& aGroup,
224 : nsACString& aOrigin);
225 :
226 : nsresult
227 : GetDirectoryMetadata2(nsIFile* aDirectory,
228 : int64_t* aTimestamp,
229 : bool* aPersisted);
230 :
231 : nsresult
232 : GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
233 : bool aPersistent,
234 : int64_t* aTimestamp,
235 : bool* aPersisted);
236 :
237 : // This is the main entry point into the QuotaManager API.
238 : // Any storage API implementation (quota client) that participates in
239 : // centralized quota and storage handling should call this method to get
240 : // a directory lock which will protect client's files from being deleted
241 : // while they are still in use.
242 : // After a lock is acquired, client is notified via the open listener's
243 : // method DirectoryLockAcquired. If the lock couldn't be acquired, client
244 : // gets DirectoryLockFailed notification.
245 : // A lock is a reference counted object and at the time DirectoryLockAcquired
246 : // is called, quota manager holds just one strong reference to it which is
247 : // then immediatelly cleared by quota manager. So it's up to client to add
248 : // a new reference in order to keep the lock alive.
249 : // Unlocking is simply done by dropping all references to the lock object.
250 : // In other words, protection which the lock represents dies with the lock
251 : // object itself.
252 : void
253 : OpenDirectory(PersistenceType aPersistenceType,
254 : const nsACString& aGroup,
255 : const nsACString& aOrigin,
256 : Client::Type aClientType,
257 : bool aExclusive,
258 : OpenDirectoryListener* aOpenListener);
259 :
260 : // XXX RemoveMe once bug 1170279 gets fixed.
261 : void
262 : OpenDirectoryInternal(const Nullable<PersistenceType>& aPersistenceType,
263 : const OriginScope& aOriginScope,
264 : const Nullable<Client::Type>& aClientType,
265 : bool aExclusive,
266 : OpenDirectoryListener* aOpenListener);
267 :
268 : // Collect inactive and the least recently used origins.
269 : uint64_t
270 : CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
271 : nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
272 :
273 : void
274 : AssertStorageIsInitialized() const
275 : #ifdef DEBUG
276 : ;
277 : #else
278 : { }
279 : #endif
280 :
281 : nsresult
282 : EnsureStorageIsInitialized();
283 :
284 : nsresult
285 : EnsureOriginIsInitialized(PersistenceType aPersistenceType,
286 : const nsACString& aSuffix,
287 : const nsACString& aGroup,
288 : const nsACString& aOrigin,
289 : nsIFile** aDirectory);
290 :
291 : nsresult
292 : EnsureOriginIsInitializedInternal(PersistenceType aPersistenceType,
293 : const nsACString& aSuffix,
294 : const nsACString& aGroup,
295 : const nsACString& aOrigin,
296 : nsIFile** aDirectory,
297 : bool* aCreated);
298 :
299 : void
300 : OriginClearCompleted(PersistenceType aPersistenceType,
301 : const nsACString& aOrigin);
302 :
303 : void
304 : ResetOrClearCompleted();
305 :
306 : void
307 0 : StartIdleMaintenance()
308 : {
309 0 : AssertIsOnOwningThread();
310 :
311 0 : for (auto& client : mClients) {
312 0 : client->StartIdleMaintenance();
313 : }
314 0 : }
315 :
316 : void
317 0 : StopIdleMaintenance()
318 : {
319 0 : AssertIsOnOwningThread();
320 :
321 0 : for (auto& client : mClients) {
322 0 : client->StopIdleMaintenance();
323 : }
324 0 : }
325 :
326 : void
327 0 : AssertCurrentThreadOwnsQuotaMutex()
328 : {
329 0 : mQuotaMutex.AssertCurrentThreadOwns();
330 0 : }
331 :
332 : nsIThread*
333 0 : IOThread()
334 : {
335 0 : NS_ASSERTION(mIOThread, "This should never be null!");
336 0 : return mIOThread;
337 : }
338 :
339 : Client*
340 : GetClient(Client::Type aClientType);
341 :
342 : const nsString&
343 0 : GetBasePath() const
344 : {
345 0 : return mBasePath;
346 : }
347 :
348 : const nsString&
349 0 : GetStoragePath() const
350 : {
351 0 : return mStoragePath;
352 : }
353 :
354 : const nsString&
355 0 : GetStoragePath(PersistenceType aPersistenceType) const
356 : {
357 0 : if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
358 0 : return mPermanentStoragePath;
359 : }
360 :
361 0 : if (aPersistenceType == PERSISTENCE_TYPE_TEMPORARY) {
362 0 : return mTemporaryStoragePath;
363 : }
364 :
365 0 : MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_DEFAULT);
366 :
367 0 : return mDefaultStoragePath;
368 : }
369 :
370 : uint64_t
371 : GetGroupLimit() const;
372 :
373 : void
374 : GetGroupUsageAndLimit(const nsACString& aGroup,
375 : UsageInfo* aUsageInfo);
376 :
377 : static void
378 : GetStorageId(PersistenceType aPersistenceType,
379 : const nsACString& aOrigin,
380 : Client::Type aClientType,
381 : nsACString& aDatabaseId);
382 :
383 : static nsresult
384 : GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
385 : nsACString* aSuffix,
386 : nsACString* aGroup,
387 : nsACString* aOrigin);
388 :
389 : static nsresult
390 : GetInfoFromWindow(nsPIDOMWindowOuter* aWindow,
391 : nsACString* aSuffix,
392 : nsACString* aGroup,
393 : nsACString* aOrigin);
394 :
395 : static void
396 : GetInfoForChrome(nsACString* aSuffix,
397 : nsACString* aGroup,
398 : nsACString* aOrigin);
399 :
400 : static bool
401 : IsOriginInternal(const nsACString& aOrigin);
402 :
403 : static void
404 : ChromeOrigin(nsACString& aOrigin);
405 :
406 : static bool
407 : AreOriginsEqualOnDisk(nsACString& aOrigin1,
408 : nsACString& aOrigin2);
409 :
410 : private:
411 : QuotaManager();
412 :
413 : virtual ~QuotaManager();
414 :
415 : nsresult
416 : Init(const nsAString& aBaseDirPath);
417 :
418 : void
419 : Shutdown();
420 :
421 : already_AddRefed<DirectoryLockImpl>
422 : CreateDirectoryLock(const Nullable<PersistenceType>& aPersistenceType,
423 : const nsACString& aGroup,
424 : const OriginScope& aOriginScope,
425 : const Nullable<Client::Type>& aClientType,
426 : bool aExclusive,
427 : bool aInternal,
428 : OpenDirectoryListener* aOpenListener);
429 :
430 : already_AddRefed<DirectoryLockImpl>
431 : CreateDirectoryLockForEviction(PersistenceType aPersistenceType,
432 : const nsACString& aGroup,
433 : const nsACString& aOrigin);
434 :
435 : void
436 : RegisterDirectoryLock(DirectoryLockImpl* aLock);
437 :
438 : void
439 : UnregisterDirectoryLock(DirectoryLockImpl* aLock);
440 :
441 : void
442 : RemovePendingDirectoryLock(DirectoryLockImpl* aLock);
443 :
444 : uint64_t
445 : LockedCollectOriginsForEviction(
446 : uint64_t aMinSizeToBeFreed,
447 : nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
448 :
449 : void
450 : LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
451 : const nsACString& aGroup,
452 : const nsACString& aOrigin);
453 :
454 : already_AddRefed<OriginInfo>
455 : LockedGetOriginInfo(PersistenceType aPersistenceType,
456 : const nsACString& aGroup,
457 : const nsACString& aOrigin);
458 :
459 : nsresult
460 : MaybeUpgradeIndexedDBDirectory();
461 :
462 : nsresult
463 : MaybeUpgradePersistentStorageDirectory();
464 :
465 : nsresult
466 : MaybeRemoveOldDirectories();
467 :
468 : nsresult
469 : UpgradeStorageFrom0_0To1_0(mozIStorageConnection* aConnection);
470 :
471 : nsresult
472 : UpgradeStorageFrom1_0To2_0(mozIStorageConnection* aConnection);
473 :
474 : nsresult
475 : InitializeRepository(PersistenceType aPersistenceType);
476 :
477 : nsresult
478 : InitializeOrigin(PersistenceType aPersistenceType,
479 : const nsACString& aGroup,
480 : const nsACString& aOrigin,
481 : int64_t aAccessTime,
482 : bool aPersisted,
483 : nsIFile* aDirectory);
484 :
485 : void
486 : CheckTemporaryStorageLimits();
487 :
488 : void
489 : DeleteFilesForOrigin(PersistenceType aPersistenceType,
490 : const nsACString& aOrigin);
491 :
492 : void
493 : FinalizeOriginEviction(nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
494 :
495 : void
496 0 : ReleaseIOThreadObjects()
497 : {
498 0 : AssertIsOnIOThread();
499 :
500 0 : for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
501 0 : mClients[index]->ReleaseIOThreadObjects();
502 : }
503 0 : }
504 :
505 : DirectoryLockTable&
506 : GetDirectoryLockTable(PersistenceType aPersistenceType);
507 :
508 : static void
509 : ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
510 :
511 : mozilla::Mutex mQuotaMutex;
512 :
513 : nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;
514 :
515 : // Maintains a list of directory locks that are queued.
516 : nsTArray<RefPtr<DirectoryLockImpl>> mPendingDirectoryLocks;
517 :
518 : // Maintains a list of directory locks that are acquired or queued.
519 : nsTArray<DirectoryLockImpl*> mDirectoryLocks;
520 :
521 : // Directory lock tables that are used to update origin access time.
522 : DirectoryLockTable mTemporaryDirectoryLockTable;
523 : DirectoryLockTable mDefaultDirectoryLockTable;
524 :
525 : // Thread on which IO is performed.
526 : nsCOMPtr<nsIThread> mIOThread;
527 :
528 : // A timer that gets activated at shutdown to ensure we close all storages.
529 : nsCOMPtr<nsITimer> mShutdownTimer;
530 :
531 : // A list of all successfully initialized origins. This list isn't protected
532 : // by any mutex but it is only ever touched on the IO thread.
533 : nsTArray<nsCString> mInitializedOrigins;
534 :
535 : // This array is populated at initialization time and then never modified, so
536 : // it can be iterated on any thread.
537 : AutoTArray<RefPtr<Client>, Client::TYPE_MAX> mClients;
538 :
539 : nsString mBasePath;
540 : nsString mIndexedDBPath;
541 : nsString mStoragePath;
542 : nsString mPermanentStoragePath;
543 : nsString mTemporaryStoragePath;
544 : nsString mDefaultStoragePath;
545 :
546 : uint64_t mTemporaryStorageLimit;
547 : uint64_t mTemporaryStorageUsage;
548 : bool mTemporaryStorageInitialized;
549 :
550 : bool mStorageInitialized;
551 : };
552 :
553 : END_QUOTA_NAMESPACE
554 :
555 : #endif /* mozilla_dom_quota_quotamanager_h__ */
|