mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-29 21:25:35 +00:00
3b07e666f0
--HG-- extra : rebase_source : 609795f25eeab0d96f962799629e4e81492fb087
541 lines
14 KiB
C++
541 lines
14 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 "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"
|
|
|
|
#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 const bool 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
|
|
IsOriginWhitelistedForPersistentStorage(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__ */
|