/* -*- 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/. */
inline uint32_t GetDataSetIndex(const LocalStorage* aStorage) { // A session only mode doesn't exist anymore, so having a separate data set // for it here is basically useless. This code is only kept until we remove // the old / legacy LocalStorage implementation. return GetDataSetIndex(aStorage->IsPrivateBrowsing(),
aStorage->IsPrivateBrowsingOrLess());
}
} // namespace
// LocalStorageCacheBridge
NS_IMPL_ADDREF(LocalStorageCacheBridge)
// Since there is no consumer of return value of Release, we can turn this // method to void to make implementation of asynchronous // LocalStorageCache::Release much simpler.
NS_IMETHODIMP_(void) LocalStorageCacheBridge::Release(void) {
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
nsrefcnt count = --mRefCnt;
NS_LOG_RELEASE(this, count, "LocalStorageCacheBridge"); if (0 == count) {
mRefCnt = 1; /* stabilize */ /* enable this to find non-threadsafe destructors: */ /* NS_ASSERT_OWNINGTHREAD(_class); */ delete (this);
}
}
LocalStorageCache::~LocalStorageCache() { if (mActor) {
mActor->SendDeleteMeInternal();
MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
}
NS_IMETHODIMP_(void)
LocalStorageCache::Release(void) { // We must actually release on the main thread since the cache removes it // self from the manager's hash table. And we don't want to lock access to // that hash table. if (NS_IsMainThread()) {
LocalStorageCacheBridge::Release(); return;
}
nsresult rv = NS_DispatchToMainThread(event); if (NS_FAILED(rv)) {
NS_WARNING("LocalStorageCache::Release() on a non-main thread");
LocalStorageCacheBridge::Release();
}
}
if (mPersistent) {
mManager = aManager;
Preload();
}
// Check the quota string has (or has not) the identical origin suffix as // this storage cache is bound to.
MOZ_ASSERT(StringBeginsWith(mQuotaOriginScope, mOriginSuffix));
MOZ_ASSERT(mOriginSuffix.IsEmpty() !=
StringBeginsWith(mQuotaOriginScope, "^"_ns));
void LocalStorageCache::WaitForPreload() { if (!mPersistent) { return;
}
bool loaded = mLoaded;
// Telemetry of rates of pending preloads if (!mPreloadTelemetryRecorded) {
mPreloadTelemetryRecorded = true;
Telemetry::Accumulate(
Telemetry::LOCALDOMSTORAGE_PRELOAD_PENDING_ON_FIRST_ACCESS, !loaded);
}
if (loaded) { return;
}
// If preload already started (i.e. we got some first data, but not all) // SyncPreload will just wait for it to finish rather then synchronously // read from the database. It seems to me more optimal.
// TODO place for A/B testing (force main thread load vs. let preload finish)
// No need to check sDatabase for being non-null since preload is either // done before we've shut the DB down or when the DB could not start, // preload has not even be started.
StorageDBChild::Get(mPrivateBrowsingId)->SyncPreload(this);
}
nsresult LocalStorageCache::GetLength(const LocalStorage* aStorage,
uint32_t* aRetval) { if (Persist(aStorage)) {
WaitForPreload(); if (NS_FAILED(mLoadResult)) { return mLoadResult;
}
}
nsresult LocalStorageCache::GetKey(const LocalStorage* aStorage,
uint32_t aIndex, nsAString& aRetval) { // XXX: This does a linear search for the key at index, which would // suck if there's a large numer of indexes. Do we care? If so, // maybe we need to have a lazily populated key array here or // something? if (Persist(aStorage)) {
WaitForPreload(); if (NS_FAILED(mLoadResult)) { return mLoadResult;
}
}
aRetval.SetIsVoid(true); for (auto iter = DataSet(aStorage).mKeys.Iter(); !iter.Done(); iter.Next()) { if (aIndex == 0) {
aRetval = iter.Key(); break;
}
aIndex--;
}
// not using AutoString since we don't want to copy buffer to result
nsString value; if (!DataSet(aStorage).mKeys.Get(aKey, &value)) {
SetDOMStringToNull(value);
}
aRetval = value;
return NS_OK;
}
nsresult LocalStorageCache::SetItem(const LocalStorage* aStorage, const nsAString& aKey, const nsAString& aValue, nsString& aOld, const MutationSource aSource) { // Size of the cache that will change after this action.
int64_t delta = 0;
if (Persist(aStorage)) {
WaitForPreload(); if (NS_FAILED(mLoadResult)) { return mLoadResult;
}
}
Data& data = DataSet(aStorage); if (!data.mKeys.Get(aKey, &aOld)) {
SetDOMStringToNull(aOld);
// We only consider key size if the key doesn't exist before.
delta += static_cast<int64_t>(aKey.Length());
}
if (Persist(aStorage)) {
StorageDBChild* storageChild = StorageDBChild::Get(mPrivateBrowsingId); if (!storageChild) {
NS_ERROR( "Writing to localStorage after the database has been shut down" ", data lose!"); return NS_ERROR_NOT_INITIALIZED;
}
if (DOMStringIsNull(aOld)) { return storageChild->AsyncAddItem(this, aKey, aValue);
}
if (Persist(aStorage)) {
StorageDBChild* storageChild = StorageDBChild::Get(mPrivateBrowsingId); if (!storageChild) {
NS_ERROR( "Writing to localStorage after the database has been shut down" ", data lose!"); return NS_ERROR_NOT_INITIALIZED;
}
nsresult LocalStorageCache::Clear(const LocalStorage* aStorage, const MutationSource aSource) { bool refresh = false; if (Persist(aStorage)) { // We need to preload all data (know the size) before we can proceeed // to correctly decrease cached usage number. // XXX as in case of unload, this is not technically needed now, but // after super-scope quota introduction we have to do this. Get telemetry // right now.
WaitForPreload(); if (NS_FAILED(mLoadResult)) { // When we failed to load data from the database, force delete of the // scope data and make use of the storage possible again.
refresh = true;
mLoadResult = NS_OK;
}
}
Data& data = DataSet(aStorage); bool hadData = !!data.mKeys.Count();
if (hadData) {
Unused << ProcessUsageDelta(aStorage, -data.mOriginQuotaUsage, aSource);
data.mKeys.Clear();
}
if (Persist(aStorage) && (refresh || hadData)) {
StorageDBChild* storageChild = StorageDBChild::Get(mPrivateBrowsingId); if (!storageChild) {
NS_ERROR( "Writing to localStorage after the database has been shut down" ", data lose!"); return NS_ERROR_NOT_INITIALIZED;
}
void LocalStorageCache::UnloadItems(uint32_t aUnloadFlags) { if (aUnloadFlags & kUnloadDefault) { // Must wait for preload to pass correct usage to ProcessUsageDelta // XXX this is not technically needed right now since there is just // per-origin isolated quota handling, but when we introduce super- // -scope quotas, we have to do this. Better to start getting // telemetry right now.
WaitForPreload();
void StorageUsage::LoadUsage(const int64_t aUsage) { // Using kDefaultSet index since it is the index for the persitent data // stored in the database we have just loaded usage for. if (!NS_IsMainThread()) { // In single process scenario we get this call from the DB thread
RefPtr<LoadUsageRunnable> r = new LoadUsageRunnable(mUsage + kDefaultSet, aUsage);
NS_DispatchToMainThread(r);
} else { // On a child process we get this on the main thread already
mUsage[kDefaultSet] += aUsage;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.