summaryrefslogtreecommitdiffstats
path: root/dom/quota/QuotaManager.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/QuotaManager.h')
-rw-r--r--dom/quota/QuotaManager.h546
1 files changed, 546 insertions, 0 deletions
diff --git a/dom/quota/QuotaManager.h b/dom/quota/QuotaManager.h
new file mode 100644
index 000000000..206c3c665
--- /dev/null
+++ b/dom/quota/QuotaManager.h
@@ -0,0 +1,546 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_quota_quotamanager_h__
+#define mozilla_dom_quota_quotamanager_h__
+
+#include "QuotaCommon.h"
+
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/Mutex.h"
+
+#include "nsClassHashtable.h"
+#include "nsRefPtrHashtable.h"
+
+#include "Client.h"
+#include "PersistenceType.h"
+
+#include "prenv.h"
+
+#define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1"
+
+class mozIStorageConnection;
+class nsIEventTarget;
+class nsIPrincipal;
+class nsIThread;
+class nsITimer;
+class nsIURI;
+class nsPIDOMWindowOuter;
+class nsIRunnable;
+
+BEGIN_QUOTA_NAMESPACE
+
+class DirectoryLockImpl;
+class GroupInfo;
+class GroupInfoPair;
+class OriginInfo;
+class OriginScope;
+class QuotaObject;
+
+class NS_NO_VTABLE RefCountedObject
+{
+public:
+ NS_IMETHOD_(MozExternalRefCountType)
+ AddRef() = 0;
+
+ NS_IMETHOD_(MozExternalRefCountType)
+ Release() = 0;
+};
+
+class DirectoryLock
+ : public RefCountedObject
+{
+ friend class DirectoryLockImpl;
+
+private:
+ DirectoryLock()
+ { }
+
+ ~DirectoryLock()
+ { }
+};
+
+class NS_NO_VTABLE OpenDirectoryListener
+ : public RefCountedObject
+{
+public:
+ virtual void
+ DirectoryLockAcquired(DirectoryLock* aLock) = 0;
+
+ virtual void
+ DirectoryLockFailed() = 0;
+
+protected:
+ virtual ~OpenDirectoryListener()
+ { }
+};
+
+struct OriginParams
+{
+ OriginParams(PersistenceType aPersistenceType,
+ const nsACString& aOrigin,
+ bool aIsApp)
+ : mOrigin(aOrigin)
+ , mPersistenceType(aPersistenceType)
+ , mIsApp(aIsApp)
+ { }
+
+ nsCString mOrigin;
+ PersistenceType mPersistenceType;
+ bool mIsApp;
+};
+
+class QuotaManager final
+ : public BackgroundThreadObject
+{
+ friend class DirectoryLockImpl;
+ friend class GroupInfo;
+ friend class OriginInfo;
+ friend class QuotaObject;
+
+ typedef nsClassHashtable<nsCStringHashKey,
+ nsTArray<DirectoryLockImpl*>> DirectoryLockTable;
+
+public:
+ class CreateRunnable;
+
+private:
+ class ShutdownRunnable;
+ class ShutdownObserver;
+
+public:
+ NS_INLINE_DECL_REFCOUNTING(QuotaManager)
+
+ static bool IsRunningXPCShellTests()
+ {
+ static bool kRunningXPCShellTests = !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR");
+ return kRunningXPCShellTests;
+ }
+
+ static const char kReplaceChars[];
+
+ static void
+ GetOrCreate(nsIRunnable* aCallback);
+
+ // Returns a non-owning reference.
+ static QuotaManager*
+ Get();
+
+ // Returns true if we've begun the shutdown process.
+ static bool IsShuttingDown();
+
+ bool
+ IsOriginInitialized(const nsACString& aOrigin) const
+ {
+ AssertIsOnIOThread();
+
+ return mInitializedOrigins.Contains(aOrigin);
+ }
+
+ bool
+ IsTemporaryStorageInitialized() const
+ {
+ AssertIsOnIOThread();
+
+ return mTemporaryStorageInitialized;
+ }
+
+ void
+ InitQuotaForOrigin(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ bool aIsApp,
+ uint64_t aUsageBytes,
+ int64_t aAccessTime);
+
+ void
+ DecreaseUsageForOrigin(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ int64_t aSize);
+
+ void
+ UpdateOriginAccessTime(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin);
+
+ void
+ RemoveQuota();
+
+ void
+ RemoveQuotaForOrigin(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin)
+ {
+ MutexAutoLock lock(mQuotaMutex);
+ LockedRemoveQuotaForOrigin(aPersistenceType, aGroup, aOrigin);
+ }
+
+ already_AddRefed<QuotaObject>
+ GetQuotaObject(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ nsIFile* aFile);
+
+ already_AddRefed<QuotaObject>
+ GetQuotaObject(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ const nsAString& aPath);
+
+ // Called when a process is being shot down. Aborts any running operations
+ // for the given process.
+ void
+ AbortOperationsForProcess(ContentParentId aContentParentId);
+
+ nsresult
+ GetDirectoryForOrigin(PersistenceType aPersistenceType,
+ const nsACString& aASCIIOrigin,
+ nsIFile** aDirectory) const;
+
+ nsresult
+ RestoreDirectoryMetadata2(nsIFile* aDirectory, bool aPersistent);
+
+ nsresult
+ GetDirectoryMetadata2(nsIFile* aDirectory,
+ int64_t* aTimestamp,
+ nsACString& aSuffix,
+ nsACString& aGroup,
+ nsACString& aOrigin,
+ bool* aIsApp);
+
+ nsresult
+ GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
+ bool aPersistent,
+ int64_t* aTimestamp,
+ nsACString& aSuffix,
+ nsACString& aGroup,
+ nsACString& aOrigin,
+ bool* aIsApp);
+
+ nsresult
+ GetDirectoryMetadata2(nsIFile* aDirectory, int64_t* aTimestamp);
+
+ nsresult
+ GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
+ bool aPersistent,
+ int64_t* aTimestamp);
+
+ // This is the main entry point into the QuotaManager API.
+ // Any storage API implementation (quota client) that participates in
+ // centralized quota and storage handling should call this method to get
+ // a directory lock which will protect client's files from being deleted
+ // while they are still in use.
+ // After a lock is acquired, client is notified via the open listener's
+ // method DirectoryLockAcquired. If the lock couldn't be acquired, client
+ // gets DirectoryLockFailed notification.
+ // A lock is a reference counted object and at the time DirectoryLockAcquired
+ // is called, quota manager holds just one strong reference to it which is
+ // then immediatelly cleared by quota manager. So it's up to client to add
+ // a new reference in order to keep the lock alive.
+ // Unlocking is simply done by dropping all references to the lock object.
+ // In other words, protection which the lock represents dies with the lock
+ // object itself.
+ void
+ OpenDirectory(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ bool aIsApp,
+ Client::Type aClientType,
+ bool aExclusive,
+ OpenDirectoryListener* aOpenListener);
+
+ // XXX RemoveMe once bug 1170279 gets fixed.
+ void
+ OpenDirectoryInternal(Nullable<PersistenceType> aPersistenceType,
+ const OriginScope& aOriginScope,
+ Nullable<Client::Type> aClientType,
+ bool aExclusive,
+ OpenDirectoryListener* aOpenListener);
+
+ // Collect inactive and the least recently used origins.
+ uint64_t
+ CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
+ nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
+
+ nsresult
+ EnsureStorageIsInitialized();
+
+ nsresult
+ EnsureOriginIsInitialized(PersistenceType aPersistenceType,
+ const nsACString& aSuffix,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ bool aIsApp,
+ nsIFile** aDirectory);
+
+ void
+ OriginClearCompleted(PersistenceType aPersistenceType,
+ const nsACString& aOrigin,
+ bool aIsApp);
+
+ void
+ ResetOrClearCompleted();
+
+ void
+ StartIdleMaintenance()
+ {
+ AssertIsOnOwningThread();
+
+ for (auto& client : mClients) {
+ client->StartIdleMaintenance();
+ }
+ }
+
+ void
+ StopIdleMaintenance()
+ {
+ AssertIsOnOwningThread();
+
+ for (auto& client : mClients) {
+ client->StopIdleMaintenance();
+ }
+ }
+
+ void
+ AssertCurrentThreadOwnsQuotaMutex()
+ {
+ mQuotaMutex.AssertCurrentThreadOwns();
+ }
+
+ nsIThread*
+ IOThread()
+ {
+ NS_ASSERTION(mIOThread, "This should never be null!");
+ return mIOThread;
+ }
+
+ Client*
+ GetClient(Client::Type aClientType);
+
+ const nsString&
+ GetBasePath() const
+ {
+ return mBasePath;
+ }
+
+ const nsString&
+ GetStoragePath() const
+ {
+ return mStoragePath;
+ }
+
+ const nsString&
+ GetStoragePath(PersistenceType aPersistenceType) const
+ {
+ if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
+ return mPermanentStoragePath;
+ }
+
+ if (aPersistenceType == PERSISTENCE_TYPE_TEMPORARY) {
+ return mTemporaryStoragePath;
+ }
+
+ MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_DEFAULT);
+
+ return mDefaultStoragePath;
+ }
+
+ uint64_t
+ GetGroupLimit() const;
+
+ void
+ GetGroupUsageAndLimit(const nsACString& aGroup,
+ UsageInfo* aUsageInfo);
+
+ static void
+ GetStorageId(PersistenceType aPersistenceType,
+ const nsACString& aOrigin,
+ Client::Type aClientType,
+ nsACString& aDatabaseId);
+
+ static nsresult
+ GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
+ nsACString* aSuffix,
+ nsACString* aGroup,
+ nsACString* aOrigin,
+ bool* aIsApp);
+
+ static nsresult
+ GetInfoFromWindow(nsPIDOMWindowOuter* aWindow,
+ nsACString* aSuffix,
+ nsACString* aGroup,
+ nsACString* aOrigin,
+ bool* aIsApp);
+
+ static void
+ GetInfoForChrome(nsACString* aSuffix,
+ nsACString* aGroup,
+ nsACString* aOrigin,
+ bool* aIsApp);
+
+ static bool
+ IsOriginInternal(const nsACString& aOrigin);
+
+ static bool
+ IsFirstPromptRequired(PersistenceType aPersistenceType,
+ const nsACString& aOrigin,
+ bool aIsApp);
+
+ static bool
+ IsQuotaEnforced(PersistenceType aPersistenceType,
+ const nsACString& aOrigin,
+ bool aIsApp);
+
+ static void
+ ChromeOrigin(nsACString& aOrigin);
+
+private:
+ QuotaManager();
+
+ virtual ~QuotaManager();
+
+ nsresult
+ Init(const nsAString& aBaseDirPath);
+
+ void
+ Shutdown();
+
+ already_AddRefed<DirectoryLockImpl>
+ CreateDirectoryLock(Nullable<PersistenceType> aPersistenceType,
+ const nsACString& aGroup,
+ const OriginScope& aOriginScope,
+ Nullable<bool> aIsApp,
+ Nullable<Client::Type> aClientType,
+ bool aExclusive,
+ bool aInternal,
+ OpenDirectoryListener* aOpenListener);
+
+ already_AddRefed<DirectoryLockImpl>
+ CreateDirectoryLockForEviction(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ bool aIsApp);
+
+ void
+ RegisterDirectoryLock(DirectoryLockImpl* aLock);
+
+ void
+ UnregisterDirectoryLock(DirectoryLockImpl* aLock);
+
+ void
+ RemovePendingDirectoryLock(DirectoryLockImpl* aLock);
+
+ uint64_t
+ LockedCollectOriginsForEviction(
+ uint64_t aMinSizeToBeFreed,
+ nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
+
+ void
+ LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin);
+
+ nsresult
+ MaybeUpgradeIndexedDBDirectory();
+
+ nsresult
+ MaybeUpgradePersistentStorageDirectory();
+
+ nsresult
+ MaybeRemoveOldDirectories();
+
+ nsresult
+ UpgradeStorageFrom0ToCurrent(mozIStorageConnection* aConnection);
+
+#if 0
+ nsresult
+ UpgradeStorageFrom1To2(mozIStorageConnection* aConnection);
+#endif
+
+ nsresult
+ InitializeRepository(PersistenceType aPersistenceType);
+
+ nsresult
+ InitializeOrigin(PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ bool aIsApp,
+ int64_t aAccessTime,
+ nsIFile* aDirectory);
+
+ void
+ CheckTemporaryStorageLimits();
+
+ void
+ DeleteFilesForOrigin(PersistenceType aPersistenceType,
+ const nsACString& aOrigin);
+
+ void
+ FinalizeOriginEviction(nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
+
+ void
+ ReleaseIOThreadObjects()
+ {
+ AssertIsOnIOThread();
+
+ for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
+ mClients[index]->ReleaseIOThreadObjects();
+ }
+ }
+
+ DirectoryLockTable&
+ GetDirectoryLockTable(PersistenceType aPersistenceType);
+
+ static void
+ ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
+
+ mozilla::Mutex mQuotaMutex;
+
+ nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;
+
+ // Maintains a list of directory locks that are queued.
+ nsTArray<RefPtr<DirectoryLockImpl>> mPendingDirectoryLocks;
+
+ // Maintains a list of directory locks that are acquired or queued.
+ nsTArray<DirectoryLockImpl*> mDirectoryLocks;
+
+ // Directory lock tables that are used to update origin access time.
+ DirectoryLockTable mTemporaryDirectoryLockTable;
+ DirectoryLockTable mDefaultDirectoryLockTable;
+
+ // Thread on which IO is performed.
+ nsCOMPtr<nsIThread> mIOThread;
+
+ // A timer that gets activated at shutdown to ensure we close all storages.
+ nsCOMPtr<nsITimer> mShutdownTimer;
+
+ // A list of all successfully initialized origins. This list isn't protected
+ // by any mutex but it is only ever touched on the IO thread.
+ nsTArray<nsCString> mInitializedOrigins;
+
+ // This array is populated at initialization time and then never modified, so
+ // it can be iterated on any thread.
+ AutoTArray<RefPtr<Client>, Client::TYPE_MAX> mClients;
+
+ nsString mBasePath;
+ nsString mIndexedDBPath;
+ nsString mStoragePath;
+ nsString mPermanentStoragePath;
+ nsString mTemporaryStoragePath;
+ nsString mDefaultStoragePath;
+
+ uint64_t mTemporaryStorageLimit;
+ uint64_t mTemporaryStorageUsage;
+ bool mTemporaryStorageInitialized;
+
+ bool mStorageInitialized;
+};
+
+END_QUOTA_NAMESPACE
+
+#endif /* mozilla_dom_quota_quotamanager_h__ */