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/. */
7 #ifndef mozilla_dom_quota_quotamanager_h__
8 #define mozilla_dom_quota_quotamanager_h__
10 #include "QuotaCommon.h"
12 #include "mozilla/dom/Nullable.h"
13 #include "mozilla/dom/ipc/IdType.h"
14 #include "mozilla/Mutex.h"
16 #include "nsClassHashtable.h"
17 #include "nsRefPtrHashtable.h"
20 #include "PersistenceType.h"
24 #define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1"
26 class mozIStorageConnection
;
32 class nsPIDOMWindowOuter
;
37 class OriginAttributes
;
39 } // namespace mozilla
43 class DirectoryLockImpl
;
50 class NS_NO_VTABLE RefCountedObject
{
52 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
55 class DirectoryLock
: public RefCountedObject
{
56 friend class DirectoryLockImpl
;
64 class NS_NO_VTABLE OpenDirectoryListener
: public RefCountedObject
{
66 virtual void DirectoryLockAcquired(DirectoryLock
* aLock
) = 0;
68 virtual void DirectoryLockFailed() = 0;
71 virtual ~OpenDirectoryListener() {}
75 OriginParams(PersistenceType aPersistenceType
, const nsACString
& aOrigin
)
76 : mOrigin(aOrigin
), mPersistenceType(aPersistenceType
) {}
79 PersistenceType mPersistenceType
;
82 class QuotaManager final
: public BackgroundThreadObject
{
83 friend class DirectoryLockImpl
;
84 friend class GroupInfo
;
85 friend class OriginInfo
;
86 friend class QuotaObject
;
88 typedef nsClassHashtable
<nsCStringHashKey
, nsTArray
<DirectoryLockImpl
*>>
95 class ShutdownRunnable
;
96 class ShutdownObserver
;
99 NS_INLINE_DECL_REFCOUNTING(QuotaManager
)
101 static bool IsRunningXPCShellTests() {
102 static bool kRunningXPCShellTests
=
103 !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR");
104 return kRunningXPCShellTests
;
107 static bool IsRunningGTests() {
108 static bool kRunningGTests
= !!PR_GetEnv("MOZ_RUN_GTEST");
109 return kRunningGTests
;
112 static const char kReplaceChars
[];
114 static void GetOrCreate(nsIRunnable
* aCallback
,
115 nsIEventTarget
* aMainEventTarget
= nullptr);
117 // Returns a non-owning reference.
118 static QuotaManager
* Get();
120 // Returns true if we've begun the shutdown process.
121 static bool IsShuttingDown();
123 static bool IsOSMetadata(const nsAString
& aFileName
);
125 static bool IsDotFile(const nsAString
& aFileName
);
127 bool IsOriginInitialized(const nsACString
& aOrigin
) const {
128 AssertIsOnIOThread();
130 return mInitializedOrigins
.Contains(aOrigin
);
133 bool IsTemporaryStorageInitialized() const {
134 AssertIsOnIOThread();
136 return mTemporaryStorageInitialized
;
139 void InitQuotaForOrigin(PersistenceType aPersistenceType
,
140 const nsACString
& aGroup
, const nsACString
& aOrigin
,
141 uint64_t aUsageBytes
, int64_t aAccessTime
,
144 void DecreaseUsageForOrigin(PersistenceType aPersistenceType
,
145 const nsACString
& aGroup
,
146 const nsACString
& aOrigin
, int64_t aSize
);
148 void UpdateOriginAccessTime(PersistenceType aPersistenceType
,
149 const nsACString
& aGroup
,
150 const nsACString
& aOrigin
);
154 void RemoveQuotaForOrigin(PersistenceType aPersistenceType
,
155 const nsACString
& aGroup
,
156 const nsACString
& aOrigin
) {
157 MutexAutoLock
lock(mQuotaMutex
);
158 LockedRemoveQuotaForOrigin(aPersistenceType
, aGroup
, aOrigin
);
161 already_AddRefed
<QuotaObject
> GetQuotaObject(PersistenceType aPersistenceType
,
162 const nsACString
& aGroup
,
163 const nsACString
& aOrigin
,
165 int64_t aFileSize
= -1,
166 int64_t* aFileSizeOut
= nullptr);
168 already_AddRefed
<QuotaObject
> GetQuotaObject(PersistenceType aPersistenceType
,
169 const nsACString
& aGroup
,
170 const nsACString
& aOrigin
,
171 const nsAString
& aPath
,
172 int64_t aFileSize
= -1,
173 int64_t* aFileSizeOut
= nullptr);
175 Nullable
<bool> OriginPersisted(const nsACString
& aGroup
,
176 const nsACString
& aOrigin
);
178 void PersistOrigin(const nsACString
& aGroup
, const nsACString
& aOrigin
);
180 // Called when a process is being shot down. Aborts any running operations
181 // for the given process.
182 void AbortOperationsForProcess(ContentParentId aContentParentId
);
184 nsresult
GetDirectoryForOrigin(PersistenceType aPersistenceType
,
185 const nsACString
& aASCIIOrigin
,
186 nsIFile
** aDirectory
) const;
188 nsresult
RestoreDirectoryMetadata2(nsIFile
* aDirectory
, bool aPersistent
);
190 nsresult
GetDirectoryMetadata2(nsIFile
* aDirectory
, int64_t* aTimestamp
,
191 bool* aPersisted
, nsACString
& aSuffix
,
192 nsACString
& aGroup
, nsACString
& aOrigin
);
194 nsresult
GetDirectoryMetadata2WithRestore(
195 nsIFile
* aDirectory
, bool aPersistent
, int64_t* aTimestamp
,
196 bool* aPersisted
, nsACString
& aSuffix
, nsACString
& aGroup
,
197 nsACString
& aOrigin
, const bool aTelemetry
= false);
199 nsresult
GetDirectoryMetadata2(nsIFile
* aDirectory
, int64_t* aTimestamp
,
202 nsresult
GetDirectoryMetadata2WithRestore(nsIFile
* aDirectory
,
207 // This is the main entry point into the QuotaManager API.
208 // Any storage API implementation (quota client) that participates in
209 // centralized quota and storage handling should call this method to get
210 // a directory lock which will protect client's files from being deleted
211 // while they are still in use.
212 // After a lock is acquired, client is notified via the open listener's
213 // method DirectoryLockAcquired. If the lock couldn't be acquired, client
214 // gets DirectoryLockFailed notification.
215 // A lock is a reference counted object and at the time DirectoryLockAcquired
216 // is called, quota manager holds just one strong reference to it which is
217 // then immediatelly cleared by quota manager. So it's up to client to add
218 // a new reference in order to keep the lock alive.
219 // Unlocking is simply done by dropping all references to the lock object.
220 // In other words, protection which the lock represents dies with the lock
222 void OpenDirectory(PersistenceType aPersistenceType
, const nsACString
& aGroup
,
223 const nsACString
& aOrigin
, Client::Type aClientType
,
224 bool aExclusive
, OpenDirectoryListener
* aOpenListener
);
226 // XXX RemoveMe once bug 1170279 gets fixed.
227 void OpenDirectoryInternal(const Nullable
<PersistenceType
>& aPersistenceType
,
228 const OriginScope
& aOriginScope
,
229 const Nullable
<Client::Type
>& aClientType
,
231 OpenDirectoryListener
* aOpenListener
);
233 // Collect inactive and the least recently used origins.
234 uint64_t CollectOriginsForEviction(
235 uint64_t aMinSizeToBeFreed
, nsTArray
<RefPtr
<DirectoryLockImpl
>>& aLocks
);
237 void AssertStorageIsInitialized() const
245 nsresult
EnsureStorageIsInitialized();
247 nsresult
EnsureOriginIsInitialized(PersistenceType aPersistenceType
,
248 const nsACString
& aSuffix
,
249 const nsACString
& aGroup
,
250 const nsACString
& aOrigin
,
251 bool aCreateIfNotExists
,
252 nsIFile
** aDirectory
);
254 nsresult
EnsureOriginIsInitializedInternal(
255 PersistenceType aPersistenceType
, const nsACString
& aSuffix
,
256 const nsACString
& aGroup
, const nsACString
& aOrigin
,
257 bool aCreateIfNotExists
, nsIFile
** aDirectory
, bool* aCreated
);
259 nsresult
EnsureTemporaryStorageIsInitialized();
261 nsresult
EnsureOriginDirectory(nsIFile
* aDirectory
, bool aCreateIfNotExists
,
264 nsresult
AboutToClearOrigins(
265 const Nullable
<PersistenceType
>& aPersistenceType
,
266 const OriginScope
& aOriginScope
,
267 const Nullable
<Client::Type
>& aClientType
);
269 void OriginClearCompleted(PersistenceType aPersistenceType
,
270 const nsACString
& aOrigin
,
271 const Nullable
<Client::Type
>& aClientType
);
273 void ResetOrClearCompleted();
275 void StartIdleMaintenance() {
276 AssertIsOnOwningThread();
278 for (auto& client
: mClients
) {
279 client
->StartIdleMaintenance();
283 void StopIdleMaintenance() {
284 AssertIsOnOwningThread();
286 for (auto& client
: mClients
) {
287 client
->StopIdleMaintenance();
291 void AssertCurrentThreadOwnsQuotaMutex() {
292 mQuotaMutex
.AssertCurrentThreadOwns();
295 nsIThread
* IOThread() {
296 NS_ASSERTION(mIOThread
, "This should never be null!");
300 Client
* GetClient(Client::Type aClientType
);
302 const nsString
& GetBasePath() const { return mBasePath
; }
304 const nsString
& GetStoragePath() const { return mStoragePath
; }
306 const nsString
& GetStoragePath(PersistenceType aPersistenceType
) const {
307 if (aPersistenceType
== PERSISTENCE_TYPE_PERSISTENT
) {
308 return mPermanentStoragePath
;
311 if (aPersistenceType
== PERSISTENCE_TYPE_TEMPORARY
) {
312 return mTemporaryStoragePath
;
315 MOZ_ASSERT(aPersistenceType
== PERSISTENCE_TYPE_DEFAULT
);
317 return mDefaultStoragePath
;
320 uint64_t GetGroupLimit() const;
322 void GetGroupUsageAndLimit(const nsACString
& aGroup
, UsageInfo
* aUsageInfo
);
324 void NotifyStoragePressure(uint64_t aUsage
);
326 static void GetStorageId(PersistenceType aPersistenceType
,
327 const nsACString
& aOrigin
, Client::Type aClientType
,
328 nsACString
& aDatabaseId
);
330 static nsresult
GetInfoFromPrincipal(nsIPrincipal
* aPrincipal
,
331 nsACString
* aSuffix
, nsACString
* aGroup
,
332 nsACString
* aOrigin
);
334 static nsresult
GetInfoFromWindow(nsPIDOMWindowOuter
* aWindow
,
335 nsACString
* aSuffix
, nsACString
* aGroup
,
336 nsACString
* aOrigin
);
338 static void GetInfoForChrome(nsACString
* aSuffix
, nsACString
* aGroup
,
339 nsACString
* aOrigin
);
341 static bool IsOriginInternal(const nsACString
& aOrigin
);
343 static void ChromeOrigin(nsACString
& aOrigin
);
345 static bool AreOriginsEqualOnDisk(nsACString
& aOrigin1
, nsACString
& aOrigin2
);
347 static bool ParseOrigin(const nsACString
& aOrigin
, nsCString
& aSpec
,
348 OriginAttributes
* aAttrs
);
353 virtual ~QuotaManager();
355 nsresult
Init(const nsAString
& aBaseDirPath
);
359 already_AddRefed
<DirectoryLockImpl
> CreateDirectoryLock(
360 const Nullable
<PersistenceType
>& aPersistenceType
,
361 const nsACString
& aGroup
, const OriginScope
& aOriginScope
,
362 const Nullable
<Client::Type
>& aClientType
, bool aExclusive
,
363 bool aInternal
, OpenDirectoryListener
* aOpenListener
);
365 already_AddRefed
<DirectoryLockImpl
> CreateDirectoryLockForEviction(
366 PersistenceType aPersistenceType
, const nsACString
& aGroup
,
367 const nsACString
& aOrigin
);
369 void RegisterDirectoryLock(DirectoryLockImpl
* aLock
);
371 void UnregisterDirectoryLock(DirectoryLockImpl
* aLock
);
373 void RemovePendingDirectoryLock(DirectoryLockImpl
* aLock
);
375 uint64_t LockedCollectOriginsForEviction(
376 uint64_t aMinSizeToBeFreed
, nsTArray
<RefPtr
<DirectoryLockImpl
>>& aLocks
);
378 void LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType
,
379 const nsACString
& aGroup
,
380 const nsACString
& aOrigin
);
382 already_AddRefed
<OriginInfo
> LockedGetOriginInfo(
383 PersistenceType aPersistenceType
, const nsACString
& aGroup
,
384 const nsACString
& aOrigin
);
386 nsresult
MaybeUpgradeIndexedDBDirectory();
388 nsresult
MaybeUpgradePersistentStorageDirectory();
390 nsresult
MaybeRemoveOldDirectories();
392 template <typename Helper
>
393 nsresult
UpgradeStorage(const int32_t aOldVersion
, const int32_t aNewVersion
,
394 mozIStorageConnection
* aConnection
);
396 nsresult
UpgradeStorageFrom0_0To1_0(mozIStorageConnection
* aConnection
);
398 nsresult
UpgradeStorageFrom1_0To2_0(mozIStorageConnection
* aConnection
);
400 nsresult
UpgradeStorageFrom2_0To2_1(mozIStorageConnection
* aConnection
);
402 nsresult
MaybeRemoveLocalStorageData();
404 nsresult
MaybeRemoveLocalStorageDirectories();
406 nsresult
MaybeCreateLocalStorageArchive();
408 nsresult
InitializeRepository(PersistenceType aPersistenceType
);
410 nsresult
InitializeOrigin(PersistenceType aPersistenceType
,
411 const nsACString
& aGroup
, const nsACString
& aOrigin
,
412 int64_t aAccessTime
, bool aPersisted
,
413 nsIFile
* aDirectory
);
415 void CheckTemporaryStorageLimits();
417 void DeleteFilesForOrigin(PersistenceType aPersistenceType
,
418 const nsACString
& aOrigin
);
420 void FinalizeOriginEviction(nsTArray
<RefPtr
<DirectoryLockImpl
>>& aLocks
);
422 void ReleaseIOThreadObjects() {
423 AssertIsOnIOThread();
425 for (uint32_t index
= 0; index
< uint32_t(Client::TypeMax()); index
++) {
426 mClients
[index
]->ReleaseIOThreadObjects();
430 DirectoryLockTable
& GetDirectoryLockTable(PersistenceType aPersistenceType
);
432 bool IsSanitizedOriginValid(const nsACString
& aSanitizedOrigin
);
434 static void ShutdownTimerCallback(nsITimer
* aTimer
, void* aClosure
);
436 mozilla::Mutex mQuotaMutex
;
438 nsClassHashtable
<nsCStringHashKey
, GroupInfoPair
> mGroupInfoPairs
;
440 // Maintains a list of directory locks that are queued.
441 nsTArray
<RefPtr
<DirectoryLockImpl
>> mPendingDirectoryLocks
;
443 // Maintains a list of directory locks that are acquired or queued.
444 nsTArray
<DirectoryLockImpl
*> mDirectoryLocks
;
446 // Directory lock tables that are used to update origin access time.
447 DirectoryLockTable mTemporaryDirectoryLockTable
;
448 DirectoryLockTable mDefaultDirectoryLockTable
;
450 // Thread on which IO is performed.
451 nsCOMPtr
<nsIThread
> mIOThread
;
453 // A timer that gets activated at shutdown to ensure we close all storages.
454 nsCOMPtr
<nsITimer
> mShutdownTimer
;
456 // A list of all successfully initialized persistent origins. This list isn't
457 // protected by any mutex but it is only ever touched on the IO thread.
458 nsTArray
<nsCString
> mInitializedOrigins
;
460 // A hash table that is used to cache origin parser results for given
461 // sanitized origin strings. This hash table isn't protected by any mutex but
462 // it is only ever touched on the IO thread.
463 nsDataHashtable
<nsCStringHashKey
, bool> mValidOrigins
;
465 // This array is populated at initialization time and then never modified, so
466 // it can be iterated on any thread.
467 AutoTArray
<RefPtr
<Client
>, Client::TYPE_MAX
> mClients
;
470 nsString mIndexedDBPath
;
471 nsString mStoragePath
;
472 nsString mPermanentStoragePath
;
473 nsString mTemporaryStoragePath
;
474 nsString mDefaultStoragePath
;
476 uint64_t mTemporaryStorageLimit
;
477 uint64_t mTemporaryStorageUsage
;
478 bool mTemporaryStorageInitialized
;
480 bool mStorageInitialized
;
485 #endif /* mozilla_dom_quota_quotamanager_h__ */