OnOriginClearCompleted currently takes two separate arguments which can be expressed as just one argument. Differential Revision: https://phabricator.services.mozilla.com/D198494
938 lines
33 KiB
C++
938 lines
33 KiB
C++
/* -*- 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 <cstdint>
|
|
#include <utility>
|
|
#include "Client.h"
|
|
#include "ErrorList.h"
|
|
#include "mozilla/AlreadyAddRefed.h"
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/InitializedOnce.h"
|
|
#include "mozilla/MozPromise.h"
|
|
#include "mozilla/Mutex.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "mozilla/Result.h"
|
|
#include "mozilla/ThreadBound.h"
|
|
#include "mozilla/dom/Nullable.h"
|
|
#include "mozilla/dom/ipc/IdType.h"
|
|
#include "mozilla/dom/quota/Assertions.h"
|
|
#include "mozilla/dom/quota/BackgroundThreadObject.h"
|
|
#include "mozilla/dom/quota/CommonMetadata.h"
|
|
#include "mozilla/dom/quota/DirectoryLockCategory.h"
|
|
#include "mozilla/dom/quota/ForwardDecls.h"
|
|
#include "mozilla/dom/quota/HashKeys.h"
|
|
#include "mozilla/dom/quota/InitializationTypes.h"
|
|
#include "mozilla/dom/quota/NotifyUtils.h"
|
|
#include "mozilla/dom/quota/OriginOperationCallbacks.h"
|
|
#include "mozilla/dom/quota/PersistenceType.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsClassHashtable.h"
|
|
#include "nsTHashMap.h"
|
|
#include "nsDebug.h"
|
|
#include "nsHashKeys.h"
|
|
#include "nsISupports.h"
|
|
#include "nsStringFwd.h"
|
|
#include "nsTArray.h"
|
|
#include "nsTStringRepr.h"
|
|
#include "nscore.h"
|
|
#include "prenv.h"
|
|
|
|
#define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1"
|
|
|
|
class mozIStorageConnection;
|
|
class nsIEventTarget;
|
|
class nsIFile;
|
|
class nsIRunnable;
|
|
class nsIThread;
|
|
class nsITimer;
|
|
|
|
namespace mozilla {
|
|
|
|
class OriginAttributes;
|
|
class OriginAttributesPattern;
|
|
|
|
namespace ipc {
|
|
|
|
class PrincipalInfo;
|
|
|
|
} // namespace ipc
|
|
|
|
} // namespace mozilla
|
|
|
|
namespace mozilla::dom::quota {
|
|
|
|
class CanonicalQuotaObject;
|
|
class ClientUsageArray;
|
|
class ClientDirectoryLock;
|
|
class DirectoryLockImpl;
|
|
class GroupInfo;
|
|
class GroupInfoPair;
|
|
class NormalOriginOperationBase;
|
|
class OriginDirectoryLock;
|
|
class OriginInfo;
|
|
class OriginScope;
|
|
class QuotaObject;
|
|
class UniversalDirectoryLock;
|
|
|
|
class QuotaManager final : public BackgroundThreadObject {
|
|
friend class CanonicalQuotaObject;
|
|
friend class ClearStorageOp;
|
|
friend class DirectoryLockImpl;
|
|
friend class FinalizeOriginEvictionOp;
|
|
friend class GroupInfo;
|
|
friend class InitOp;
|
|
friend class InitializePersistentOriginOp;
|
|
friend class InitializePersistentStorageOp;
|
|
friend class InitializeTemporaryGroupOp;
|
|
friend class InitializeTemporaryOriginOp;
|
|
friend class InitTemporaryStorageOp;
|
|
friend class OriginInfo;
|
|
friend class ShutdownStorageOp;
|
|
|
|
friend Result<PrincipalMetadata, nsresult> GetInfoFromValidatedPrincipalInfo(
|
|
QuotaManager& aQuotaManager,
|
|
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
|
|
|
|
using PrincipalInfo = mozilla::ipc::PrincipalInfo;
|
|
using DirectoryLockTable =
|
|
nsClassHashtable<nsCStringHashKey, nsTArray<NotNull<DirectoryLockImpl*>>>;
|
|
|
|
class Observer;
|
|
|
|
public:
|
|
QuotaManager(const nsAString& aBasePath, const nsAString& aStorageName);
|
|
|
|
NS_INLINE_DECL_REFCOUNTING(QuotaManager)
|
|
|
|
static nsresult Initialize();
|
|
|
|
static bool IsRunningXPCShellTests() {
|
|
static bool kRunningXPCShellTests =
|
|
!!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR");
|
|
return kRunningXPCShellTests;
|
|
}
|
|
|
|
static bool IsRunningGTests() {
|
|
static bool kRunningGTests = !!PR_GetEnv("MOZ_RUN_GTEST");
|
|
return kRunningGTests;
|
|
}
|
|
|
|
static const char kReplaceChars[];
|
|
static const char16_t kReplaceChars16[];
|
|
|
|
static Result<MovingNotNull<RefPtr<QuotaManager>>, nsresult> GetOrCreate();
|
|
|
|
static Result<Ok, nsresult> EnsureCreated();
|
|
|
|
// Returns a non-owning reference.
|
|
static QuotaManager* Get();
|
|
|
|
// Use only in gtests!
|
|
static nsIObserver* GetObserver();
|
|
|
|
// Returns true if we've begun the shutdown process.
|
|
static bool IsShuttingDown();
|
|
|
|
static void ShutdownInstance();
|
|
|
|
// Use only in gtests!
|
|
static void Reset();
|
|
|
|
static bool IsOSMetadata(const nsAString& aFileName);
|
|
|
|
static bool IsDotFile(const nsAString& aFileName);
|
|
|
|
void RegisterNormalOriginOp(NormalOriginOperationBase& aNormalOriginOp);
|
|
|
|
void UnregisterNormalOriginOp(NormalOriginOperationBase& aNormalOriginOp);
|
|
|
|
bool IsPersistentOriginInitializedInternal(const nsACString& aOrigin) const {
|
|
AssertIsOnIOThread();
|
|
|
|
return mInitializedOriginsInternal.Contains(aOrigin);
|
|
}
|
|
|
|
bool IsTemporaryStorageInitializedInternal() const {
|
|
AssertIsOnIOThread();
|
|
|
|
return mTemporaryStorageInitializedInternal;
|
|
}
|
|
|
|
/**
|
|
* For initialization of an origin where the directory either exists or it
|
|
* does not. The directory exists case is used by InitializeOrigin once it
|
|
* has tallied origin usage by calling each of the QuotaClient InitOrigin
|
|
* methods. It's also used by LoadQuota when quota information is available
|
|
* from the cache. EnsureTemporaryStorageIsInitializedInternal calls this
|
|
* either if the directory exists or it does not depending on requirements
|
|
* of a particular quota client. The special case when origin directory is
|
|
* not created during origin initialization is currently utilized only by
|
|
* LSNG.
|
|
*/
|
|
void InitQuotaForOrigin(const FullOriginMetadata& aFullOriginMetadata,
|
|
const ClientUsageArray& aClientUsages,
|
|
uint64_t aUsageBytes, bool aDirectoryExists = true);
|
|
|
|
// XXX clients can use QuotaObject instead of calling this method directly.
|
|
void DecreaseUsageForClient(const ClientMetadata& aClientMetadata,
|
|
int64_t aSize);
|
|
|
|
void ResetUsageForClient(const ClientMetadata& aClientMetadata);
|
|
|
|
UsageInfo GetUsageForClient(PersistenceType aPersistenceType,
|
|
const OriginMetadata& aOriginMetadata,
|
|
Client::Type aClientType);
|
|
|
|
void UpdateOriginAccessTime(PersistenceType aPersistenceType,
|
|
const OriginMetadata& aOriginMetadata);
|
|
|
|
void RemoveQuota();
|
|
|
|
void RemoveQuotaForRepository(PersistenceType aPersistenceType) {
|
|
MutexAutoLock lock(mQuotaMutex);
|
|
LockedRemoveQuotaForRepository(aPersistenceType);
|
|
}
|
|
|
|
void RemoveQuotaForOrigin(PersistenceType aPersistenceType,
|
|
const OriginMetadata& aOriginMetadata) {
|
|
MutexAutoLock lock(mQuotaMutex);
|
|
LockedRemoveQuotaForOrigin(aOriginMetadata);
|
|
}
|
|
|
|
nsresult LoadQuota();
|
|
|
|
void UnloadQuota();
|
|
|
|
void RemoveOriginFromCache(const OriginMetadata& aOriginMetadata);
|
|
|
|
already_AddRefed<QuotaObject> GetQuotaObject(
|
|
PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
|
|
Client::Type aClientType, nsIFile* aFile, int64_t aFileSize = -1,
|
|
int64_t* aFileSizeOut = nullptr);
|
|
|
|
already_AddRefed<QuotaObject> GetQuotaObject(
|
|
PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
|
|
Client::Type aClientType, const nsAString& aPath, int64_t aFileSize = -1,
|
|
int64_t* aFileSizeOut = nullptr);
|
|
|
|
already_AddRefed<QuotaObject> GetQuotaObject(const int64_t aDirectoryLockId,
|
|
const nsAString& aPath);
|
|
|
|
Nullable<bool> OriginPersisted(const OriginMetadata& aOriginMetadata);
|
|
|
|
void PersistOrigin(const OriginMetadata& aOriginMetadata);
|
|
|
|
template <typename F>
|
|
auto WithOriginInfo(const OriginMetadata& aOriginMetadata, F aFunction)
|
|
-> std::invoke_result_t<F, const RefPtr<OriginInfo>&>;
|
|
|
|
using DirectoryLockIdTableArray =
|
|
AutoTArray<Client::DirectoryLockIdTable, Client::TYPE_MAX>;
|
|
void AbortOperationsForLocks(const DirectoryLockIdTableArray& aLockIds);
|
|
|
|
// Called when a process is being shot down. Aborts any running operations
|
|
// for the given process.
|
|
void AbortOperationsForProcess(ContentParentId aContentParentId);
|
|
|
|
Result<nsCOMPtr<nsIFile>, nsresult> GetOriginDirectory(
|
|
const OriginMetadata& aOriginMetadata) const;
|
|
|
|
Result<bool, nsresult> DoesOriginDirectoryExist(
|
|
const OriginMetadata& aOriginMetadata) const;
|
|
|
|
Result<nsCOMPtr<nsIFile>, nsresult> GetOrCreateTemporaryOriginDirectory(
|
|
const OriginMetadata& aOriginMetadata);
|
|
|
|
Result<Ok, nsresult> EnsureTemporaryOriginDirectoryCreated(
|
|
const OriginMetadata& aOriginMetadata);
|
|
|
|
static nsresult CreateDirectoryMetadata(
|
|
nsIFile& aDirectory, int64_t aTimestamp,
|
|
const OriginMetadata& aOriginMetadata);
|
|
|
|
static nsresult CreateDirectoryMetadata2(
|
|
nsIFile& aDirectory, int64_t aTimestamp, bool aPersisted,
|
|
const OriginMetadata& aOriginMetadata);
|
|
|
|
nsresult RestoreDirectoryMetadata2(nsIFile* aDirectory);
|
|
|
|
// XXX Remove aPersistenceType argument once the persistence type is stored
|
|
// in the metadata file.
|
|
Result<FullOriginMetadata, nsresult> LoadFullOriginMetadata(
|
|
nsIFile* aDirectory, PersistenceType aPersistenceType);
|
|
|
|
Result<FullOriginMetadata, nsresult> LoadFullOriginMetadataWithRestore(
|
|
nsIFile* aDirectory);
|
|
|
|
Result<OriginMetadata, nsresult> GetOriginMetadata(nsIFile* aDirectory);
|
|
|
|
Result<Ok, nsresult> RemoveOriginDirectory(nsIFile& aDirectory);
|
|
|
|
Result<bool, nsresult> DoesClientDirectoryExist(
|
|
const ClientMetadata& aClientMetadata) const;
|
|
|
|
RefPtr<UniversalDirectoryLockPromise> OpenStorageDirectory(
|
|
const PersistenceScope& aPersistenceScope,
|
|
const OriginScope& aOriginScope,
|
|
const Nullable<Client::Type>& aClientType, bool aExclusive,
|
|
bool aInitializeOrigins = false,
|
|
DirectoryLockCategory aCategory = DirectoryLockCategory::None,
|
|
Maybe<RefPtr<UniversalDirectoryLock>&> aPendingDirectoryLockOut =
|
|
Nothing());
|
|
|
|
// 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 by resolving the returned
|
|
// promise. If the lock couldn't be acquired, client is notified by rejecting
|
|
// the returned promise. The returned lock could have been invalidated by a
|
|
// clear operation so consumers are supposed to check that and eventually
|
|
// release the lock as soon as possible (this is usually not needed for short
|
|
// lived operations).
|
|
// A lock is a reference counted object and at the time the returned promise
|
|
// is resolved, there are no longer other strong references except the one
|
|
// held by the resolve value itself. So it's up to client to add a new
|
|
// reference in order to keep the lock alive.
|
|
// Unlocking is simply done by calling lock object's Drop method. Unlocking
|
|
// must be always done explicitly before the lock object is destroyed (when
|
|
// the last strong reference is removed).
|
|
RefPtr<ClientDirectoryLockPromise> OpenClientDirectory(
|
|
const ClientMetadata& aClientMetadata, bool aCreateIfNonExistent = true,
|
|
Maybe<RefPtr<ClientDirectoryLock>&> aPendingDirectoryLockOut = Nothing());
|
|
|
|
RefPtr<ClientDirectoryLock> CreateDirectoryLock(
|
|
const ClientMetadata& aClientMetadata, bool aExclusive);
|
|
|
|
// XXX RemoveMe once bug 1170279 gets fixed.
|
|
RefPtr<UniversalDirectoryLock> CreateDirectoryLockInternal(
|
|
const PersistenceScope& aPersistenceScope,
|
|
const OriginScope& aOriginScope,
|
|
const Nullable<Client::Type>& aClientType, bool aExclusive,
|
|
DirectoryLockCategory aCategory = DirectoryLockCategory::None);
|
|
|
|
// Collect inactive and the least recently used origins.
|
|
uint64_t CollectOriginsForEviction(
|
|
uint64_t aMinSizeToBeFreed,
|
|
nsTArray<RefPtr<OriginDirectoryLock>>& aLocks);
|
|
|
|
/**
|
|
* Helper method to invoke the provided predicate on all "pending" OriginInfo
|
|
* instances. These are origins for which the origin directory has not yet
|
|
* been created but for which quota is already being tracked. This happens,
|
|
* for example, for the LocalStorage client where an origin that previously
|
|
* was not using LocalStorage can start issuing writes which it buffers until
|
|
* eventually flushing them. We defer creating the origin directory for as
|
|
* long as possible in that case, so the directory won't exist. Logic that
|
|
* would otherwise only consult the filesystem also needs to use this method.
|
|
*/
|
|
template <typename P>
|
|
void CollectPendingOriginsForListing(P aPredicate);
|
|
|
|
bool IsPendingOrigin(const OriginMetadata& aOriginMetadata) const;
|
|
|
|
RefPtr<BoolPromise> InitializeStorage();
|
|
|
|
RefPtr<BoolPromise> InitializeStorage(
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock);
|
|
|
|
RefPtr<BoolPromise> StorageInitialized();
|
|
|
|
bool IsStorageInitialized() const {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mStorageInitialized;
|
|
}
|
|
|
|
bool IsStorageInitializedInternal() const {
|
|
AssertIsOnIOThread();
|
|
return static_cast<bool>(mStorageConnection);
|
|
}
|
|
|
|
void AssertStorageIsInitializedInternal() const
|
|
#ifdef DEBUG
|
|
;
|
|
#else
|
|
{
|
|
}
|
|
#endif
|
|
|
|
RefPtr<BoolPromise> TemporaryStorageInitialized();
|
|
|
|
private:
|
|
nsresult EnsureStorageIsInitializedInternal();
|
|
|
|
public:
|
|
RefPtr<BoolPromise> InitializePersistentStorage();
|
|
|
|
RefPtr<BoolPromise> InitializePersistentStorage(
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock);
|
|
|
|
RefPtr<BoolPromise> PersistentStorageInitialized();
|
|
|
|
bool IsPersistentStorageInitialized() const {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mPersistentStorageInitialized;
|
|
}
|
|
|
|
bool IsPersistentStorageInitializedInternal() const {
|
|
AssertIsOnIOThread();
|
|
|
|
return mPersistentStorageInitializedInternal;
|
|
}
|
|
|
|
private:
|
|
nsresult EnsurePersistentStorageIsInitializedInternal();
|
|
|
|
public:
|
|
RefPtr<BoolPromise> InitializeTemporaryGroup(
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
RefPtr<BoolPromise> InitializeTemporaryGroup(
|
|
const PrincipalInfo& aPrincipalInfo,
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock);
|
|
|
|
RefPtr<BoolPromise> TemporaryGroupInitialized(
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
bool IsTemporaryGroupInitialized(const PrincipalInfo& aPrincipalInfo);
|
|
|
|
bool IsTemporaryGroupInitializedInternal(
|
|
const PrincipalMetadata& aPrincipalMetadata) const;
|
|
|
|
private:
|
|
Result<Ok, nsresult> EnsureTemporaryGroupIsInitializedInternal(
|
|
const PrincipalMetadata& aPrincipalMetadata);
|
|
|
|
public:
|
|
RefPtr<BoolPromise> InitializePersistentOrigin(
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
RefPtr<BoolPromise> InitializePersistentOrigin(
|
|
const PrincipalInfo& aPrincipalInfo,
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock);
|
|
|
|
RefPtr<BoolPromise> PersistentOriginInitialized(
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
bool IsPersistentOriginInitialized(const PrincipalInfo& aPrincipalInfo);
|
|
|
|
bool IsPersistentOriginInitializedInternal(
|
|
const OriginMetadata& aOriginMetadata) const;
|
|
|
|
private:
|
|
// Returns a pair of an nsIFile object referring to the directory, and a bool
|
|
// indicating whether the directory was newly created.
|
|
Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
|
|
EnsurePersistentOriginIsInitializedInternal(
|
|
const OriginMetadata& aOriginMetadata);
|
|
|
|
public:
|
|
RefPtr<BoolPromise> InitializeTemporaryOrigin(
|
|
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
|
|
bool aCreateIfNonExistent);
|
|
|
|
RefPtr<BoolPromise> InitializeTemporaryOrigin(
|
|
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
|
|
bool aCreateIfNonExistent, RefPtr<UniversalDirectoryLock> aDirectoryLock);
|
|
|
|
RefPtr<BoolPromise> TemporaryOriginInitialized(
|
|
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo);
|
|
|
|
bool IsTemporaryOriginInitialized(PersistenceType aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
bool IsTemporaryOriginInitializedInternal(
|
|
const OriginMetadata& aOriginMetadata) const;
|
|
|
|
private:
|
|
// Returns a pair of an nsIFile object referring to the directory, and a bool
|
|
// indicating whether the directory was newly created.
|
|
Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
|
|
EnsureTemporaryOriginIsInitializedInternal(
|
|
const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent);
|
|
|
|
public:
|
|
RefPtr<BoolPromise> InitializePersistentClient(
|
|
const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
|
|
|
|
// Returns a pair of an nsIFile object referring to the directory, and a bool
|
|
// indicating whether the directory was newly created.
|
|
Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
|
|
EnsurePersistentClientIsInitialized(const ClientMetadata& aClientMetadata);
|
|
|
|
RefPtr<BoolPromise> InitializeTemporaryClient(
|
|
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
|
|
Client::Type aClientType);
|
|
|
|
// Returns a pair of an nsIFile object referring to the directory, and a bool
|
|
// indicating whether the directory was newly created.
|
|
Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
|
|
EnsureTemporaryClientIsInitialized(const ClientMetadata& aClientMetadata);
|
|
|
|
RefPtr<BoolPromise> InitializeTemporaryStorage();
|
|
|
|
RefPtr<BoolPromise> InitializeTemporaryStorage(
|
|
RefPtr<UniversalDirectoryLock> aDirectoryLock);
|
|
|
|
bool IsTemporaryStorageInitialized() const {
|
|
AssertIsOnOwningThread();
|
|
|
|
return mTemporaryStorageInitialized;
|
|
}
|
|
|
|
private:
|
|
nsresult EnsureTemporaryStorageIsInitializedInternal();
|
|
|
|
public:
|
|
RefPtr<OriginUsageMetadataArrayPromise> GetUsage(
|
|
bool aGetAll, RefPtr<BoolPromise> aOnCancelPromise = nullptr);
|
|
|
|
RefPtr<UsageInfoPromise> GetOriginUsage(
|
|
const PrincipalInfo& aPrincipalInfo,
|
|
RefPtr<BoolPromise> aOnCancelPromise = nullptr);
|
|
|
|
RefPtr<UInt64Promise> GetCachedOriginUsage(
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
RefPtr<BoolPromise> ClearStoragesForOrigin(
|
|
const Maybe<PersistenceType>& aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
RefPtr<BoolPromise> ClearStoragesForClient(
|
|
Maybe<PersistenceType> aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
|
|
|
|
RefPtr<BoolPromise> ClearStoragesForOriginPrefix(
|
|
const Maybe<PersistenceType>& aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
RefPtr<BoolPromise> ClearStoragesForOriginAttributesPattern(
|
|
const OriginAttributesPattern& aPattern);
|
|
|
|
RefPtr<BoolPromise> ClearPrivateRepository();
|
|
|
|
RefPtr<BoolPromise> ClearStorage();
|
|
|
|
RefPtr<BoolPromise> ShutdownStoragesForOrigin(
|
|
Maybe<PersistenceType> aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo);
|
|
|
|
RefPtr<BoolPromise> ShutdownStoragesForClient(
|
|
Maybe<PersistenceType> aPersistenceType,
|
|
const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);
|
|
|
|
RefPtr<BoolPromise> ShutdownStorage(
|
|
Maybe<OriginOperationCallbackOptions> aCallbackOptions = Nothing(),
|
|
Maybe<OriginOperationCallbacks&> aCallbacks = Nothing());
|
|
|
|
void ShutdownStorageInternal();
|
|
|
|
// Returns a bool indicating whether the directory was newly created.
|
|
Result<bool, nsresult> EnsureOriginDirectory(nsIFile& aDirectory);
|
|
|
|
nsresult AboutToClearOrigins(const PersistenceScope& aPersistenceScope,
|
|
const OriginScope& aOriginScope,
|
|
const Nullable<Client::Type>& aClientType);
|
|
|
|
void OriginClearCompleted(const OriginMetadata& aOriginMetadata,
|
|
const Nullable<Client::Type>& aClientType);
|
|
|
|
void RepositoryClearCompleted(PersistenceType aPersistenceType);
|
|
|
|
void StartIdleMaintenance() {
|
|
AssertIsOnOwningThread();
|
|
|
|
for (const auto& client : *mClients) {
|
|
client->StartIdleMaintenance();
|
|
}
|
|
|
|
NotifyMaintenanceStarted(*this);
|
|
}
|
|
|
|
void StopIdleMaintenance() {
|
|
AssertIsOnOwningThread();
|
|
|
|
for (const auto& client : *mClients) {
|
|
client->StopIdleMaintenance();
|
|
}
|
|
}
|
|
|
|
void AssertCurrentThreadOwnsQuotaMutex() {
|
|
mQuotaMutex.AssertCurrentThreadOwns();
|
|
}
|
|
|
|
void AssertNotCurrentThreadOwnsQuotaMutex() {
|
|
mQuotaMutex.AssertNotCurrentThreadOwns();
|
|
}
|
|
|
|
nsIThread* IOThread() { return mIOThread->get(); }
|
|
|
|
Client* GetClient(Client::Type aClientType);
|
|
|
|
const AutoTArray<Client::Type, Client::TYPE_MAX>& AllClientTypes();
|
|
|
|
const nsString& GetBasePath() const { return mBasePath; }
|
|
|
|
const nsString& GetStorageName() const { return mStorageName; }
|
|
|
|
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;
|
|
}
|
|
|
|
if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
|
|
return *mDefaultStoragePath;
|
|
}
|
|
|
|
MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_PRIVATE);
|
|
|
|
return *mPrivateStoragePath;
|
|
}
|
|
|
|
uint64_t GetGroupLimit() const;
|
|
|
|
std::pair<uint64_t, uint64_t> GetUsageAndLimitForEstimate(
|
|
const OriginMetadata& aOriginMetadata);
|
|
|
|
uint64_t GetOriginUsage(const PrincipalMetadata& aPrincipalMetadata);
|
|
|
|
Maybe<FullOriginMetadata> GetFullOriginMetadata(
|
|
const OriginMetadata& aOriginMetadata);
|
|
|
|
// Record a quota client shutdown step, if shutting down.
|
|
// Assumes that the QuotaManager singleton is alive.
|
|
static void MaybeRecordQuotaClientShutdownStep(
|
|
const Client::Type aClientType, const nsACString& aStepDescription);
|
|
|
|
// Record a quota client shutdown step, if shutting down.
|
|
// Checks if the QuotaManager singleton is alive.
|
|
static void SafeMaybeRecordQuotaClientShutdownStep(
|
|
Client::Type aClientType, const nsACString& aStepDescription);
|
|
|
|
// Record a quota manager shutdown step, use only if shutdown is active.
|
|
void RecordQuotaManagerShutdownStep(const nsACString& aStepDescription);
|
|
|
|
// Record a quota manager shutdown step, if shutting down.
|
|
void MaybeRecordQuotaManagerShutdownStep(const nsACString& aStepDescription);
|
|
|
|
template <typename F>
|
|
void MaybeRecordQuotaManagerShutdownStepWith(F&& aFunc);
|
|
|
|
static void GetStorageId(PersistenceType aPersistenceType,
|
|
const nsACString& aOrigin, Client::Type aClientType,
|
|
nsACString& aDatabaseId);
|
|
|
|
static bool IsOriginInternal(const nsACString& aOrigin);
|
|
|
|
static bool AreOriginsEqualOnDisk(const nsACString& aOrigin1,
|
|
const nsACString& aOrigin2);
|
|
|
|
// XXX This method currently expects the original origin string (not yet
|
|
// sanitized).
|
|
static Result<PrincipalInfo, nsresult> ParseOrigin(const nsACString& aOrigin);
|
|
|
|
static void InvalidateQuotaCache();
|
|
|
|
private:
|
|
virtual ~QuotaManager();
|
|
|
|
nsresult Init();
|
|
|
|
void Shutdown();
|
|
|
|
void RegisterDirectoryLock(DirectoryLockImpl& aLock);
|
|
|
|
void UnregisterDirectoryLock(DirectoryLockImpl& aLock);
|
|
|
|
void AddPendingDirectoryLock(DirectoryLockImpl& aLock);
|
|
|
|
void RemovePendingDirectoryLock(DirectoryLockImpl& aLock);
|
|
|
|
uint64_t LockedCollectOriginsForEviction(
|
|
uint64_t aMinSizeToBeFreed,
|
|
nsTArray<RefPtr<OriginDirectoryLock>>& aLocks);
|
|
|
|
void LockedRemoveQuotaForRepository(PersistenceType aPersistenceType);
|
|
|
|
void LockedRemoveQuotaForOrigin(const OriginMetadata& aOriginMetadata);
|
|
|
|
bool LockedHasGroupInfoPair(const nsACString& aGroup) const;
|
|
|
|
already_AddRefed<GroupInfo> LockedGetOrCreateGroupInfo(
|
|
PersistenceType aPersistenceType, const nsACString& aSuffix,
|
|
const nsACString& aGroup);
|
|
|
|
already_AddRefed<OriginInfo> LockedGetOriginInfo(
|
|
PersistenceType aPersistenceType,
|
|
const OriginMetadata& aOriginMetadata) const;
|
|
|
|
nsresult UpgradeFromIndexedDBDirectoryToPersistentStorageDirectory(
|
|
nsIFile* aIndexedDBDir);
|
|
|
|
nsresult UpgradeFromPersistentStorageDirectoryToDefaultStorageDirectory(
|
|
nsIFile* aPersistentStorageDir);
|
|
|
|
nsresult MaybeUpgradeToDefaultStorageDirectory(nsIFile& aStorageFile);
|
|
|
|
template <typename Helper>
|
|
nsresult UpgradeStorage(const int32_t aOldVersion, const int32_t aNewVersion,
|
|
mozIStorageConnection* aConnection);
|
|
|
|
nsresult UpgradeStorageFrom0_0To1_0(mozIStorageConnection* aConnection);
|
|
|
|
nsresult UpgradeStorageFrom1_0To2_0(mozIStorageConnection* aConnection);
|
|
|
|
nsresult UpgradeStorageFrom2_0To2_1(mozIStorageConnection* aConnection);
|
|
|
|
nsresult UpgradeStorageFrom2_1To2_2(mozIStorageConnection* aConnection);
|
|
|
|
nsresult UpgradeStorageFrom2_2To2_3(mozIStorageConnection* aConnection);
|
|
|
|
nsresult MaybeCreateOrUpgradeStorage(mozIStorageConnection& aConnection);
|
|
|
|
OkOrErr MaybeRemoveLocalStorageArchiveTmpFile();
|
|
|
|
nsresult MaybeRemoveLocalStorageDataAndArchive(nsIFile& aLsArchiveFile);
|
|
|
|
nsresult MaybeRemoveLocalStorageDirectories();
|
|
|
|
Result<Ok, nsresult> CopyLocalStorageArchiveFromWebAppsStore(
|
|
nsIFile& aLsArchiveFile) const;
|
|
|
|
Result<nsCOMPtr<mozIStorageConnection>, nsresult>
|
|
CreateLocalStorageArchiveConnection(nsIFile& aLsArchiveFile) const;
|
|
|
|
Result<nsCOMPtr<mozIStorageConnection>, nsresult>
|
|
RecopyLocalStorageArchiveFromWebAppsStore(nsIFile& aLsArchiveFile);
|
|
|
|
Result<nsCOMPtr<mozIStorageConnection>, nsresult>
|
|
DowngradeLocalStorageArchive(nsIFile& aLsArchiveFile);
|
|
|
|
Result<nsCOMPtr<mozIStorageConnection>, nsresult>
|
|
UpgradeLocalStorageArchiveFromLessThan4To4(nsIFile& aLsArchiveFile);
|
|
|
|
/*
|
|
nsresult UpgradeLocalStorageArchiveFrom4To5();
|
|
*/
|
|
|
|
Result<Ok, nsresult> MaybeCreateOrUpgradeLocalStorageArchive(
|
|
nsIFile& aLsArchiveFile);
|
|
|
|
Result<Ok, nsresult> CreateEmptyLocalStorageArchive(
|
|
nsIFile& aLsArchiveFile) const;
|
|
|
|
template <typename OriginFunc>
|
|
nsresult InitializeRepository(PersistenceType aPersistenceType,
|
|
OriginFunc&& aOriginFunc);
|
|
|
|
nsresult InitializeOrigin(PersistenceType aPersistenceType,
|
|
const OriginMetadata& aOriginMetadata,
|
|
int64_t aAccessTime, bool aPersisted,
|
|
nsIFile* aDirectory);
|
|
|
|
using OriginInfosFlatTraversable =
|
|
nsTArray<NotNull<RefPtr<const OriginInfo>>>;
|
|
|
|
using OriginInfosNestedTraversable =
|
|
nsTArray<nsTArray<NotNull<RefPtr<const OriginInfo>>>>;
|
|
|
|
OriginInfosNestedTraversable GetOriginInfosExceedingGroupLimit() const;
|
|
|
|
OriginInfosNestedTraversable GetOriginInfosExceedingGlobalLimit() const;
|
|
|
|
void ClearOrigins(const OriginInfosNestedTraversable& aDoomedOriginInfos);
|
|
|
|
void CleanupTemporaryStorage();
|
|
|
|
void DeleteOriginDirectory(const OriginMetadata& aOriginMetadata);
|
|
|
|
void FinalizeOriginEviction(nsTArray<RefPtr<OriginDirectoryLock>>&& aLocks);
|
|
|
|
Result<Ok, nsresult> ArchiveOrigins(
|
|
const nsTArray<FullOriginMetadata>& aFullOriginMetadatas);
|
|
|
|
void ReleaseIOThreadObjects() {
|
|
AssertIsOnIOThread();
|
|
|
|
for (Client::Type type : AllClientTypes()) {
|
|
(*mClients)[type]->ReleaseIOThreadObjects();
|
|
}
|
|
}
|
|
|
|
DirectoryLockTable& GetDirectoryLockTable(PersistenceType aPersistenceType);
|
|
|
|
void ClearDirectoryLockTables();
|
|
|
|
void NoteInitializedOrigin(PersistenceType aPersistenceType,
|
|
const nsACString& aOrigin);
|
|
|
|
void NoteUninitializedOrigins(
|
|
const OriginMetadataArray& aOriginMetadataArray);
|
|
|
|
void NoteUninitializedRepository(PersistenceType aPersistenceType);
|
|
|
|
bool IsOriginInitialized(PersistenceType aPersistenceType,
|
|
const nsACString& aOrigin) const;
|
|
|
|
bool IsSanitizedOriginValid(const nsACString& aSanitizedOrigin);
|
|
|
|
Result<nsCString, nsresult> EnsureStorageOriginFromOrigin(
|
|
const nsACString& aOrigin);
|
|
|
|
Result<nsCString, nsresult> GetOriginFromStorageOrigin(
|
|
const nsACString& aStorageOrigin);
|
|
|
|
int64_t GenerateDirectoryLockId();
|
|
|
|
bool ShutdownStarted() const;
|
|
|
|
void RecordShutdownStep(Maybe<Client::Type> aClientType,
|
|
const nsACString& aStepDescription);
|
|
|
|
template <typename Func>
|
|
auto ExecuteInitialization(Initialization aInitialization, Func&& aFunc)
|
|
-> std::invoke_result_t<Func, const FirstInitializationAttempt<
|
|
Initialization, StringGenerator>&>;
|
|
|
|
template <typename Func>
|
|
auto ExecuteInitialization(Initialization aInitialization,
|
|
const nsACString& aContext, Func&& aFunc)
|
|
-> std::invoke_result_t<Func, const FirstInitializationAttempt<
|
|
Initialization, StringGenerator>&>;
|
|
|
|
template <typename Func>
|
|
auto ExecuteGroupInitialization(const nsACString& aGroup,
|
|
const GroupInitialization aInitialization,
|
|
const nsACString& aContext, Func&& aFunc)
|
|
-> std::invoke_result_t<Func, const FirstInitializationAttempt<
|
|
Initialization, StringGenerator>&>;
|
|
|
|
template <typename Func>
|
|
auto ExecuteOriginInitialization(const nsACString& aOrigin,
|
|
const OriginInitialization aInitialization,
|
|
const nsACString& aContext, Func&& aFunc)
|
|
-> std::invoke_result_t<Func, const FirstInitializationAttempt<
|
|
Initialization, StringGenerator>&>;
|
|
|
|
template <typename Iterator>
|
|
static void MaybeInsertNonPersistedOriginInfos(
|
|
Iterator aDest, const RefPtr<GroupInfo>& aTemporaryGroupInfo,
|
|
const RefPtr<GroupInfo>& aDefaultGroupInfo,
|
|
const RefPtr<GroupInfo>& aPrivateGroupInfo);
|
|
|
|
template <typename Collect, typename Pred>
|
|
static OriginInfosFlatTraversable CollectLRUOriginInfosUntil(
|
|
Collect&& aCollect, Pred&& aPred);
|
|
|
|
// Thread on which IO is performed.
|
|
LazyInitializedOnceNotNull<const nsCOMPtr<nsIThread>> mIOThread;
|
|
|
|
nsCOMPtr<mozIStorageConnection> mStorageConnection;
|
|
|
|
EnumeratedArray<Client::Type, nsCString, size_t(Client::TYPE_MAX)>
|
|
mShutdownSteps;
|
|
LazyInitializedOnce<const TimeStamp> mShutdownStartedAt;
|
|
|
|
// Accesses to mQuotaManagerShutdownSteps must be protected by mQuotaMutex.
|
|
nsCString mQuotaManagerShutdownSteps;
|
|
|
|
mutable mozilla::Mutex mQuotaMutex MOZ_UNANNOTATED;
|
|
|
|
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. It can be
|
|
// accessed on the owning (PBackground) thread only.
|
|
nsTArray<NotNull<DirectoryLockImpl*>> mDirectoryLocks;
|
|
|
|
// Only modifed on the owning thread, but read on multiple threads. Therefore
|
|
// all modifications (including those on the owning thread) and all reads off
|
|
// the owning thread must be protected by mQuotaMutex. In other words, only
|
|
// reads on the owning thread don't have to be protected by mQuotaMutex.
|
|
nsTHashMap<nsUint64HashKey, NotNull<DirectoryLockImpl*>>
|
|
mDirectoryLockIdTable;
|
|
|
|
// Directory lock tables that are used to update origin access time.
|
|
DirectoryLockTable mTemporaryDirectoryLockTable;
|
|
DirectoryLockTable mDefaultDirectoryLockTable;
|
|
DirectoryLockTable mPrivateDirectoryLockTable;
|
|
|
|
// Things touched on the owning (PBackground) thread only.
|
|
struct BackgroundThreadAccessible {
|
|
nsTHashSet<nsCString> mInitializedGroups;
|
|
};
|
|
ThreadBound<BackgroundThreadAccessible> mBackgroundThreadAccessible;
|
|
|
|
using BoolArray = AutoTArray<bool, PERSISTENCE_TYPE_INVALID>;
|
|
nsTHashMap<nsCStringHashKeyWithDisabledMemmove, BoolArray>
|
|
mInitializedOrigins;
|
|
|
|
// A list of all successfully initialized persistent origins. This list isn't
|
|
// protected by any mutex but it is only ever touched on the IO thread.
|
|
nsTArray<nsCString> mInitializedOriginsInternal;
|
|
|
|
// A hash table that is used to cache origin parser results for given
|
|
// sanitized origin strings. This hash table isn't protected by any mutex but
|
|
// it is only ever touched on the IO thread.
|
|
nsTHashMap<nsCStringHashKey, bool> mValidOrigins;
|
|
|
|
// These maps are protected by mQuotaMutex.
|
|
nsTHashMap<nsCStringHashKey, nsCString> mOriginToStorageOriginMap;
|
|
nsTHashMap<nsCStringHashKey, nsCString> mStorageOriginToOriginMap;
|
|
|
|
// This array is populated at initialization time and then never modified, so
|
|
// it can be iterated on any thread.
|
|
LazyInitializedOnce<const AutoTArray<RefPtr<Client>, Client::TYPE_MAX>>
|
|
mClients;
|
|
|
|
using ClientTypesArray = AutoTArray<Client::Type, Client::TYPE_MAX>;
|
|
LazyInitializedOnce<const ClientTypesArray> mAllClientTypes;
|
|
LazyInitializedOnce<const ClientTypesArray> mAllClientTypesExceptLS;
|
|
|
|
// This object isn't protected by any mutex but it is only ever touched on
|
|
// the IO thread.
|
|
InitializationInfo mInitializationInfo;
|
|
|
|
const nsString mBasePath;
|
|
const nsString mStorageName;
|
|
LazyInitializedOnce<const nsString> mIndexedDBPath;
|
|
LazyInitializedOnce<const nsString> mStoragePath;
|
|
LazyInitializedOnce<const nsString> mStorageArchivesPath;
|
|
LazyInitializedOnce<const nsString> mPermanentStoragePath;
|
|
LazyInitializedOnce<const nsString> mTemporaryStoragePath;
|
|
LazyInitializedOnce<const nsString> mDefaultStoragePath;
|
|
LazyInitializedOnce<const nsString> mPrivateStoragePath;
|
|
LazyInitializedOnce<const nsString> mToBeRemovedStoragePath;
|
|
|
|
uint64_t mTemporaryStorageLimit;
|
|
uint64_t mTemporaryStorageUsage;
|
|
int64_t mNextDirectoryLockId;
|
|
bool mStorageInitialized;
|
|
bool mPersistentStorageInitialized;
|
|
bool mPersistentStorageInitializedInternal;
|
|
bool mTemporaryStorageInitialized;
|
|
bool mTemporaryStorageInitializedInternal;
|
|
bool mCacheUsable;
|
|
};
|
|
|
|
} // namespace mozilla::dom::quota
|
|
|
|
#endif /* mozilla_dom_quota_quotamanager_h__ */
|