зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
e7d9a87493
|
@ -389,8 +389,7 @@ Context::QuotaInitRunnable::Run() {
|
|||
MOZ_DIAGNOSTIC_ASSERT(qm);
|
||||
nsresult rv = qm->EnsureOriginIsInitialized(
|
||||
PERSISTENCE_TYPE_DEFAULT, mQuotaInfo.mSuffix, mQuotaInfo.mGroup,
|
||||
mQuotaInfo.mOrigin,
|
||||
/* aCreateIfNotExists */ true, getter_AddRefs(mQuotaInfo.mDir));
|
||||
mQuotaInfo.mOrigin, getter_AddRefs(mQuotaInfo.mDir));
|
||||
if (NS_FAILED(rv)) {
|
||||
resolver->Resolve(rv);
|
||||
break;
|
||||
|
|
|
@ -17159,8 +17159,7 @@ nsresult Maintenance::DirectoryWork() {
|
|||
// Ensure origin is initialized first. It will initialize all origins
|
||||
// for temporary storage including IDB origins.
|
||||
rv = quotaManager->EnsureOriginIsInitialized(
|
||||
persistenceType, suffix, group, origin,
|
||||
/* aCreateIfNotExists */ true, getter_AddRefs(directory));
|
||||
persistenceType, suffix, group, origin, getter_AddRefs(directory));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
|
@ -19869,8 +19868,7 @@ nsresult OpenDatabaseOp::DoDatabaseWork() {
|
|||
nsCOMPtr<nsIFile> dbDirectory;
|
||||
|
||||
nsresult rv = quotaManager->EnsureOriginIsInitialized(
|
||||
persistenceType, mSuffix, mGroup, mOrigin,
|
||||
/* aCreateIfNotExists */ true, getter_AddRefs(dbDirectory));
|
||||
persistenceType, mSuffix, mGroup, mOrigin, getter_AddRefs(dbDirectory));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -70,9 +70,9 @@ mozilla::ipc::IPCResult LSDatabaseChild::RecvRequestAllowToClose() {
|
|||
}
|
||||
|
||||
PBackgroundLSSnapshotChild* LSDatabaseChild::AllocPBackgroundLSSnapshotChild(
|
||||
const nsString& aDocumentURI, const bool& aIncreasePeakUsage,
|
||||
const int64_t& aRequestedSize, const int64_t& aMinSize,
|
||||
LSSnapshotInitInfo* aInitInfo) {
|
||||
const nsString& aDocumentURI, const nsString& aKey,
|
||||
const bool& aIncreasePeakUsage, const int64_t& aRequestedSize,
|
||||
const int64_t& aMinSize, LSSnapshotInitInfo* aInitInfo) {
|
||||
MOZ_CRASH("PBackgroundLSSnapshotChild actor should be manually constructed!");
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ void LSObserverChild::ActorDestroy(ActorDestroyReason aWhy) {
|
|||
mozilla::ipc::IPCResult LSObserverChild::RecvObserve(
|
||||
const PrincipalInfo& aPrincipalInfo, const uint32_t& aPrivateBrowsingId,
|
||||
const nsString& aDocumentURI, const nsString& aKey,
|
||||
const nsString& aOldValue, const nsString& aNewValue) {
|
||||
const LSValue& aOldValue, const LSValue& aNewValue) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (!mObserver) {
|
||||
|
@ -140,8 +140,8 @@ mozilla::ipc::IPCResult LSObserverChild::RecvObserve(
|
|||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
Storage::NotifyChange(/* aStorage */ nullptr, principal, aKey, aOldValue,
|
||||
aNewValue,
|
||||
Storage::NotifyChange(/* aStorage */ nullptr, principal, aKey,
|
||||
aOldValue.AsString(), aNewValue.AsString(),
|
||||
/* aStorageType */ kLocalStorageType, aDocumentURI,
|
||||
/* aIsPrivate */ !!aPrivateBrowsingId,
|
||||
/* aImmediateDispatch */ true);
|
||||
|
|
|
@ -78,9 +78,9 @@ class LSDatabaseChild final : public PBackgroundLSDatabaseChild {
|
|||
mozilla::ipc::IPCResult RecvRequestAllowToClose() override;
|
||||
|
||||
PBackgroundLSSnapshotChild* AllocPBackgroundLSSnapshotChild(
|
||||
const nsString& aDocumentURI, const bool& aIncreasePeakUsage,
|
||||
const int64_t& aRequestedSize, const int64_t& aMinSize,
|
||||
LSSnapshotInitInfo* aInitInfo) override;
|
||||
const nsString& aDocumentURI, const nsString& aKey,
|
||||
const bool& aIncreasePeakUsage, const int64_t& aRequestedSize,
|
||||
const int64_t& aMinSize, LSSnapshotInitInfo* aInitInfo) override;
|
||||
|
||||
bool DeallocPBackgroundLSSnapshotChild(
|
||||
PBackgroundLSSnapshotChild* aActor) override;
|
||||
|
@ -124,8 +124,8 @@ class LSObserverChild final : public PBackgroundLSObserverChild {
|
|||
const uint32_t& aPrivateBrowsingId,
|
||||
const nsString& aDocumentURI,
|
||||
const nsString& aKey,
|
||||
const nsString& aOldValue,
|
||||
const nsString& aNewValue) override;
|
||||
const LSValue& aOldValue,
|
||||
const LSValue& aNewValue) override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -120,7 +120,7 @@ nsresult LSDatabase::GetLength(LSObject* aObject, uint32_t* aResult) {
|
|||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mAllowedToClose);
|
||||
|
||||
nsresult rv = EnsureSnapshot(aObject);
|
||||
nsresult rv = EnsureSnapshot(aObject, VoidString());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ nsresult LSDatabase::GetKey(LSObject* aObject, uint32_t aIndex,
|
|||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mAllowedToClose);
|
||||
|
||||
nsresult rv = EnsureSnapshot(aObject);
|
||||
nsresult rv = EnsureSnapshot(aObject, VoidString());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ nsresult LSDatabase::GetItem(LSObject* aObject, const nsAString& aKey,
|
|||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mAllowedToClose);
|
||||
|
||||
nsresult rv = EnsureSnapshot(aObject);
|
||||
nsresult rv = EnsureSnapshot(aObject, aKey);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ nsresult LSDatabase::GetKeys(LSObject* aObject, nsTArray<nsString>& aKeys) {
|
|||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mAllowedToClose);
|
||||
|
||||
nsresult rv = EnsureSnapshot(aObject);
|
||||
nsresult rv = EnsureSnapshot(aObject, VoidString());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ nsresult LSDatabase::SetItem(LSObject* aObject, const nsAString& aKey,
|
|||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mAllowedToClose);
|
||||
|
||||
nsresult rv = EnsureSnapshot(aObject);
|
||||
nsresult rv = EnsureSnapshot(aObject, aKey);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ nsresult LSDatabase::RemoveItem(LSObject* aObject, const nsAString& aKey,
|
|||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mAllowedToClose);
|
||||
|
||||
nsresult rv = EnsureSnapshot(aObject);
|
||||
nsresult rv = EnsureSnapshot(aObject, aKey);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ nsresult LSDatabase::Clear(LSObject* aObject, LSNotifyInfo& aNotifyInfo) {
|
|||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mAllowedToClose);
|
||||
|
||||
nsresult rv = EnsureSnapshot(aObject);
|
||||
nsresult rv = EnsureSnapshot(aObject, VoidString());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -262,7 +262,7 @@ nsresult LSDatabase::BeginExplicitSnapshot(LSObject* aObject) {
|
|||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureSnapshot(aObject, /* aExplicit */ true);
|
||||
nsresult rv = EnsureSnapshot(aObject, VoidString(), /* aExplicit */ true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -290,7 +290,8 @@ nsresult LSDatabase::EndExplicitSnapshot(LSObject* aObject) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult LSDatabase::EnsureSnapshot(LSObject* aObject, bool aExplicit) {
|
||||
nsresult LSDatabase::EnsureSnapshot(LSObject* aObject, const nsAString& aKey,
|
||||
bool aExplicit) {
|
||||
MOZ_ASSERT(aObject);
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT_IF(mSnapshot, !aExplicit);
|
||||
|
@ -306,7 +307,7 @@ nsresult LSDatabase::EnsureSnapshot(LSObject* aObject, bool aExplicit) {
|
|||
|
||||
LSSnapshotInitInfo initInfo;
|
||||
bool ok = mActor->SendPBackgroundLSSnapshotConstructor(
|
||||
actor, aObject->DocumentURI(),
|
||||
actor, aObject->DocumentURI(), nsString(aKey),
|
||||
/* increasePeakUsage */ true,
|
||||
/* requestedSize */ 131072,
|
||||
/* minSize */ 4096, &initInfo);
|
||||
|
@ -317,7 +318,7 @@ nsresult LSDatabase::EnsureSnapshot(LSObject* aObject, bool aExplicit) {
|
|||
snapshot->SetActor(actor);
|
||||
|
||||
// This add refs snapshot.
|
||||
nsresult rv = snapshot->Init(initInfo, aExplicit);
|
||||
nsresult rv = snapshot->Init(aKey, initInfo, aExplicit);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,8 @@ class LSDatabase final {
|
|||
private:
|
||||
~LSDatabase();
|
||||
|
||||
nsresult EnsureSnapshot(LSObject* aObject, bool aExplicit = false);
|
||||
nsresult EnsureSnapshot(LSObject* aObject, const nsAString& aKey,
|
||||
bool aExplicit = false);
|
||||
|
||||
void AllowToClose();
|
||||
};
|
||||
|
|
|
@ -59,7 +59,8 @@ void LSSnapshot::SetActor(LSSnapshotChild* aActor) {
|
|||
mActor = aActor;
|
||||
}
|
||||
|
||||
nsresult LSSnapshot::Init(const LSSnapshotInitInfo& aInitInfo, bool aExplicit) {
|
||||
nsresult LSSnapshot::Init(const nsAString& aKey,
|
||||
const LSSnapshotInitInfo& aInitInfo, bool aExplicit) {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mSelfRef);
|
||||
MOZ_ASSERT(mActor);
|
||||
|
@ -75,16 +76,19 @@ nsresult LSSnapshot::Init(const LSSnapshotInitInfo& aInitInfo, bool aExplicit) {
|
|||
for (uint32_t i = 0; i < itemInfos.Length(); i++) {
|
||||
const LSItemInfo& itemInfo = itemInfos[i];
|
||||
|
||||
const nsString& value = itemInfo.value();
|
||||
const LSValue& value = itemInfo.value();
|
||||
|
||||
if (loadState != LoadState::AllOrderedItems && !value.IsVoid()) {
|
||||
mLoadedItems.PutEntry(itemInfo.key());
|
||||
}
|
||||
|
||||
mValues.Put(itemInfo.key(), value);
|
||||
mValues.Put(itemInfo.key(), value.AsString());
|
||||
}
|
||||
|
||||
if (loadState == LoadState::Partial) {
|
||||
if (aInitInfo.addKeyToUnknownItems()) {
|
||||
mUnknownItems.PutEntry(aKey);
|
||||
}
|
||||
mInitLength = aInitInfo.totalLength();
|
||||
mLength = mInitLength;
|
||||
} else if (loadState == LoadState::AllOrderedKeys) {
|
||||
|
@ -239,8 +243,8 @@ nsresult LSSnapshot::SetItem(const nsAString& aKey, const nsAString& aValue,
|
|||
|
||||
LSSetItemInfo setItemInfo;
|
||||
setItemInfo.key() = aKey;
|
||||
setItemInfo.oldValue() = oldValue;
|
||||
setItemInfo.value() = aValue;
|
||||
setItemInfo.oldValue() = LSValue(oldValue);
|
||||
setItemInfo.value() = LSValue(aValue);
|
||||
|
||||
mWriteInfos.AppendElement(std::move(setItemInfo));
|
||||
}
|
||||
|
@ -285,7 +289,7 @@ nsresult LSSnapshot::RemoveItem(const nsAString& aKey,
|
|||
|
||||
LSRemoveItemInfo removeItemInfo;
|
||||
removeItemInfo.key() = aKey;
|
||||
removeItemInfo.oldValue() = oldValue;
|
||||
removeItemInfo.oldValue() = LSValue(oldValue);
|
||||
|
||||
mWriteInfos.AppendElement(std::move(removeItemInfo));
|
||||
}
|
||||
|
@ -432,12 +436,15 @@ nsresult LSSnapshot::GetItemInternal(const nsAString& aKey,
|
|||
} else if (mLoadedItems.GetEntry(aKey) || mUnknownItems.GetEntry(aKey)) {
|
||||
result.SetIsVoid(true);
|
||||
} else {
|
||||
LSValue value;
|
||||
nsTArray<LSItemInfo> itemInfos;
|
||||
if (NS_WARN_IF(!mActor->SendLoadValueAndMoreItems(
|
||||
nsString(aKey), &result, &itemInfos))) {
|
||||
nsString(aKey), &value, &itemInfos))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = value.AsString();
|
||||
|
||||
if (result.IsVoid()) {
|
||||
mUnknownItems.PutEntry(aKey);
|
||||
} else {
|
||||
|
@ -451,7 +458,7 @@ nsresult LSSnapshot::GetItemInternal(const nsAString& aKey,
|
|||
const LSItemInfo& itemInfo = itemInfos[i];
|
||||
|
||||
mLoadedItems.PutEntry(itemInfo.key());
|
||||
mValues.Put(itemInfo.key(), itemInfo.value());
|
||||
mValues.Put(itemInfo.key(), itemInfo.value().AsString());
|
||||
}
|
||||
|
||||
if (mLoadedItems.Count() == mInitLength) {
|
||||
|
@ -477,12 +484,15 @@ nsresult LSSnapshot::GetItemInternal(const nsAString& aKey,
|
|||
case LoadState::AllOrderedKeys: {
|
||||
if (mValues.Get(aKey, &result)) {
|
||||
if (result.IsVoid()) {
|
||||
LSValue value;
|
||||
nsTArray<LSItemInfo> itemInfos;
|
||||
if (NS_WARN_IF(!mActor->SendLoadValueAndMoreItems(
|
||||
nsString(aKey), &result, &itemInfos))) {
|
||||
nsString(aKey), &value, &itemInfos))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = value.AsString();
|
||||
|
||||
MOZ_ASSERT(!result.IsVoid());
|
||||
|
||||
mLoadedItems.PutEntry(aKey);
|
||||
|
@ -494,7 +504,7 @@ nsresult LSSnapshot::GetItemInternal(const nsAString& aKey,
|
|||
const LSItemInfo& itemInfo = itemInfos[i];
|
||||
|
||||
mLoadedItems.PutEntry(itemInfo.key());
|
||||
mValues.Put(itemInfo.key(), itemInfo.value());
|
||||
mValues.Put(itemInfo.key(), itemInfo.value().AsString());
|
||||
}
|
||||
|
||||
if (mLoadedItems.Count() == mInitLength) {
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef mozilla_dom_localstorage_LSSnapshot_h
|
||||
#define mozilla_dom_localstorage_LSSnapshot_h
|
||||
|
||||
#include "LSValue.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -112,7 +114,8 @@ class LSSnapshot final : public nsIRunnable {
|
|||
|
||||
bool Explicit() const { return mExplicit; }
|
||||
|
||||
nsresult Init(const LSSnapshotInitInfo& aInitInfo, bool aExplicit);
|
||||
nsresult Init(const nsAString& aKey, const LSSnapshotInitInfo& aInitInfo,
|
||||
bool aExplicit);
|
||||
|
||||
nsresult GetLength(uint32_t* aResult);
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=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/. */
|
||||
|
||||
#include "LSValue.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
const LSValue& VoidLSValue() {
|
||||
static const LSValue sVoidLSValue(VoidCString(), 0, false);
|
||||
|
||||
return sVoidLSValue;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,123 @@
|
|||
/* -*- 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_localstorage_LSValue_h
|
||||
#define mozilla_dom_localstorage_LSValue_h
|
||||
|
||||
#include "SnappyUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* Represents a LocalStorage value. From content's perspective, values (if
|
||||
* present) are always DOMStrings. This is also true from a quota-tracking
|
||||
* perspective. However, for memory and disk efficiency it's preferable to store
|
||||
* the value in alternate compressed or utf-8 encoding representations. The
|
||||
* LSValue type exists to support these alternate representations, dynamically
|
||||
* decompressing/re-encoding to utf-16 while still tracking value size on a
|
||||
* utf-16 basis for quota purposes.
|
||||
*/
|
||||
class LSValue final {
|
||||
friend struct IPC::ParamTraits<LSValue>;
|
||||
|
||||
nsCString mBuffer;
|
||||
uint32_t mUTF16Length;
|
||||
bool mCompressed;
|
||||
|
||||
public:
|
||||
LSValue() : mUTF16Length(0), mCompressed(false) {}
|
||||
|
||||
explicit LSValue(const nsACString& aBuffer, uint32_t aUTF16Length,
|
||||
bool aCompressed)
|
||||
: mBuffer(aBuffer),
|
||||
mUTF16Length(aUTF16Length),
|
||||
mCompressed(aCompressed) {}
|
||||
|
||||
explicit LSValue(const nsAString& aBuffer) : mUTF16Length(aBuffer.Length()) {
|
||||
if (aBuffer.IsVoid()) {
|
||||
mBuffer.SetIsVoid(true);
|
||||
mCompressed = false;
|
||||
} else {
|
||||
CopyUTF16toUTF8(aBuffer, mBuffer);
|
||||
nsCString buffer;
|
||||
if ((mCompressed = SnappyCompress(mBuffer, buffer))) {
|
||||
mBuffer = buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsVoid() const { return mBuffer.IsVoid(); }
|
||||
|
||||
void SetIsVoid(bool aVal) { mBuffer.SetIsVoid(aVal); }
|
||||
|
||||
/**
|
||||
* This represents the "physical" length that the parent process uses for
|
||||
* the size of value/item computation. This can also be used to see how much
|
||||
* memory the value is using at rest or what the cost is for sending the value
|
||||
* over IPC.
|
||||
*/
|
||||
uint32_t Length() const { return mBuffer.Length(); }
|
||||
|
||||
/*
|
||||
* This represents the "logical" length that content sees and that is also
|
||||
* used for quota management purposes.
|
||||
*/
|
||||
uint32_t UTF16Length() const { return mUTF16Length; }
|
||||
|
||||
bool IsCompressed() const { return mCompressed; }
|
||||
|
||||
bool Equals(const LSValue& aOther) const {
|
||||
return mBuffer == aOther.mBuffer &&
|
||||
mBuffer.IsVoid() == aOther.mBuffer.IsVoid() &&
|
||||
mUTF16Length == aOther.mUTF16Length &&
|
||||
mCompressed == aOther.mCompressed;
|
||||
}
|
||||
|
||||
bool operator==(const LSValue& aOther) const { return Equals(aOther); }
|
||||
|
||||
bool operator!=(const LSValue& aOther) const { return !Equals(aOther); }
|
||||
|
||||
operator const nsCString&() const { return mBuffer; }
|
||||
|
||||
operator Span<const char>() const { return mBuffer; }
|
||||
|
||||
class Converter {
|
||||
nsString mBuffer;
|
||||
|
||||
public:
|
||||
explicit Converter(const LSValue& aValue) {
|
||||
if (aValue.mBuffer.IsVoid()) {
|
||||
mBuffer.SetIsVoid(true);
|
||||
} else if (aValue.mCompressed) {
|
||||
nsCString buffer;
|
||||
MOZ_ALWAYS_TRUE(SnappyUncompress(aValue.mBuffer, buffer));
|
||||
CopyUTF8toUTF16(buffer, mBuffer);
|
||||
} else {
|
||||
CopyUTF8toUTF16(aValue.mBuffer, mBuffer);
|
||||
}
|
||||
}
|
||||
Converter(Converter&& aOther) : mBuffer(aOther.mBuffer) {}
|
||||
~Converter() {}
|
||||
|
||||
operator const nsString&() const { return mBuffer; }
|
||||
|
||||
private:
|
||||
Converter() = delete;
|
||||
Converter(const Converter&) = delete;
|
||||
Converter& operator=(const Converter&) = delete;
|
||||
Converter& operator=(const Converter&&) = delete;
|
||||
};
|
||||
|
||||
Converter AsString() const { return Converter(const_cast<LSValue&>(*this)); }
|
||||
};
|
||||
|
||||
const LSValue& VoidLSValue();
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_localstorage_LSValue_h
|
|
@ -22,6 +22,14 @@ namespace dom {
|
|||
*/
|
||||
struct LSSnapshotInitInfo
|
||||
{
|
||||
/**
|
||||
* Boolean indicating whether the `key` provided as an argument to the
|
||||
* PBackgroundLSSnapshot constructor did not exist in the Datastore and should
|
||||
* be treated as an unknown and therefore undefined value. Note that `key` may
|
||||
* have been provided as a void string, in which case this value is forced to
|
||||
* be false.
|
||||
*/
|
||||
bool addKeyToUnknownItems;
|
||||
/**
|
||||
* As many key/value or key/void pairs as the snapshot prefill byte budget
|
||||
* allowed.
|
||||
|
@ -99,11 +107,20 @@ parent:
|
|||
* consult any other threads or perform any I/O. Additionally, the response
|
||||
* is explicitly bounded in size by the tunable snapshot prefill byte limit.
|
||||
*
|
||||
* @param key
|
||||
* If key is non-void, then the snapshot is being triggered by a direct
|
||||
* access to a localStorage key (get, set, or removal, with set/removal
|
||||
* requiring the old value in order to properly populate the "storage"
|
||||
* event), the key being requested. It's possible the key is not present in
|
||||
* localStorage, in which case LSSnapshotInitInfo::addKeyToUnknownItems will
|
||||
* be true indicating that there is no such key/value pair, otherwise it
|
||||
* will be false.
|
||||
* @param increasePeakUsage
|
||||
* Whether the parent should attempt to pre-allocate some amount of quota
|
||||
* usage to the Snapshot.
|
||||
*/
|
||||
sync PBackgroundLSSnapshot(nsString documentURI,
|
||||
nsString key,
|
||||
bool increasePeakUsage,
|
||||
int64_t requestedSize,
|
||||
int64_t minSize)
|
||||
|
|
|
@ -6,6 +6,11 @@ include protocol PBackground;
|
|||
|
||||
include PBackgroundSharedTypes;
|
||||
|
||||
include "mozilla/dom/localstorage/SerializationHelpers.h";
|
||||
|
||||
using mozilla::dom::LSValue
|
||||
from "mozilla/dom/LSValue.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -49,8 +54,8 @@ child:
|
|||
uint32_t privateBrowsingId,
|
||||
nsString documentURI,
|
||||
nsString key,
|
||||
nsString oldValue,
|
||||
nsString newValue);
|
||||
LSValue oldValue,
|
||||
LSValue newValue);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
include PBackgroundSharedTypes;
|
||||
include ProtocolTypes;
|
||||
|
||||
include "mozilla/dom/localstorage/SerializationHelpers.h";
|
||||
|
||||
using mozilla::dom::LSValue
|
||||
from "mozilla/dom/LSValue.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -57,7 +62,7 @@ union LSSimpleRequestParams
|
|||
struct LSItemInfo
|
||||
{
|
||||
nsString key;
|
||||
nsString value;
|
||||
LSValue value;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -7,20 +7,25 @@ include protocol PBackgroundLSDatabase;
|
|||
|
||||
include PBackgroundLSSharedTypes;
|
||||
|
||||
include "mozilla/dom/localstorage/SerializationHelpers.h";
|
||||
|
||||
using mozilla::dom::LSValue
|
||||
from "mozilla/dom/LSValue.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct LSSetItemInfo
|
||||
{
|
||||
nsString key;
|
||||
nsString oldValue;
|
||||
nsString value;
|
||||
LSValue oldValue;
|
||||
LSValue value;
|
||||
};
|
||||
|
||||
struct LSRemoveItemInfo
|
||||
{
|
||||
nsString key;
|
||||
nsString oldValue;
|
||||
LSValue oldValue;
|
||||
};
|
||||
|
||||
struct LSClearInfo
|
||||
|
@ -61,7 +66,7 @@ parent:
|
|||
* consult any other threads or perform any I/O.
|
||||
*/
|
||||
sync LoadValueAndMoreItems(nsString key)
|
||||
returns (nsString value, LSItemInfo[] itemInfos);
|
||||
returns (LSValue value, LSItemInfo[] itemInfos);
|
||||
|
||||
/**
|
||||
* Invoked on demand to load all keys in in their canonical order if they
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
#include "mozilla/dom/LSSnapshot.h"
|
||||
#include "mozilla/dom/LSValue.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
@ -20,6 +21,30 @@ struct ParamTraits<mozilla::dom::LSSnapshot::LoadState>
|
|||
mozilla::dom::LSSnapshot::LoadState::Initial,
|
||||
mozilla::dom::LSSnapshot::LoadState::EndGuard> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::LSValue> {
|
||||
typedef mozilla::dom::LSValue paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam) {
|
||||
WriteParam(aMsg, aParam.mBuffer);
|
||||
WriteParam(aMsg, aParam.mUTF16Length);
|
||||
WriteParam(aMsg, aParam.mCompressed);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter,
|
||||
paramType* aResult) {
|
||||
return ReadParam(aMsg, aIter, &aResult->mBuffer) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mUTF16Length) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mCompressed);
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog) {
|
||||
LogParam(aParam.mBuffer, aLog);
|
||||
LogParam(aParam.mUTF16Length, aLog);
|
||||
LogParam(aParam.mCompressed, aLog);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // mozilla_dom_localstorage_SerializationHelpers_h
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=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/. */
|
||||
|
||||
#include "SnappyUtils.h"
|
||||
|
||||
#include "snappy/snappy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
bool SnappyCompress(const nsACString& aSource, nsACString& aDest) {
|
||||
MOZ_ASSERT(!aSource.IsVoid());
|
||||
|
||||
size_t uncompressedLength = aSource.Length();
|
||||
|
||||
if (uncompressedLength <= 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
|
||||
|
||||
aDest.SetLength(compressedLength);
|
||||
|
||||
snappy::RawCompress(aSource.BeginReading(), uncompressedLength,
|
||||
aDest.BeginWriting(), &compressedLength);
|
||||
|
||||
if (compressedLength >= uncompressedLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aDest.SetLength(compressedLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SnappyUncompress(const nsACString& aSource, nsACString& aDest) {
|
||||
MOZ_ASSERT(!aSource.IsVoid());
|
||||
|
||||
const char* compressed = aSource.BeginReading();
|
||||
|
||||
size_t compressedLength = aSource.Length();
|
||||
|
||||
size_t uncompressedLength;
|
||||
if (!snappy::GetUncompressedLength(compressed, compressedLength,
|
||||
&uncompressedLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aDest.SetLength(uncompressedLength);
|
||||
|
||||
if (!snappy::RawUncompress(compressed, compressedLength,
|
||||
aDest.BeginWriting())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,20 @@
|
|||
/* -*- 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_localstorage_SnappyUtils_h
|
||||
#define mozilla_dom_localstorage_SnappyUtils_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
bool SnappyCompress(const nsACString& aSource, nsACString& aDest);
|
||||
|
||||
bool SnappyUncompress(const nsACString& aSource, nsACString& aDest);
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_localstorage_SnappyUtils_h
|
|
@ -34,6 +34,8 @@ EXPORTS.mozilla.dom += [
|
|||
'LSObject.h',
|
||||
'LSObserver.h',
|
||||
'LSSnapshot.h',
|
||||
'LSValue.h',
|
||||
'SnappyUtils.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
@ -45,7 +47,9 @@ UNIFIED_SOURCES += [
|
|||
'LSObject.cpp',
|
||||
'LSObserver.cpp',
|
||||
'LSSnapshot.cpp',
|
||||
'LSValue.cpp',
|
||||
'ReportInternalError.cpp',
|
||||
'SnappyUtils.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
|
|
|
@ -218,7 +218,7 @@ const char kResourceOriginPrefix[] = "resource://";
|
|||
#define LS_ARCHIVE_FILE_NAME "ls-archive.sqlite"
|
||||
#define LS_ARCHIVE_TMP_FILE_NAME "ls-archive-tmp.sqlite"
|
||||
|
||||
const uint32_t kLocalStorageArchiveVersion = 1;
|
||||
const uint32_t kLocalStorageArchiveVersion = 3;
|
||||
|
||||
const char kProfileDoChangeTopic[] = "profile-do-change";
|
||||
|
||||
|
@ -446,7 +446,6 @@ nsresult LoadLocalStorageArchiveVersion(mozIStorageConnection* aConnection,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
nsresult SaveLocalStorageArchiveVersion(mozIStorageConnection* aConnection,
|
||||
uint32_t aVersion) {
|
||||
AssertIsOnIOThread();
|
||||
|
@ -472,7 +471,6 @@ nsresult SaveLocalStorageArchiveVersion(mozIStorageConnection* aConnection,
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* Quota manager class declarations
|
||||
|
@ -615,10 +613,20 @@ class OriginInfo final {
|
|||
|
||||
public:
|
||||
OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin, uint64_t aUsage,
|
||||
int64_t aAccessTime, bool aPersisted);
|
||||
int64_t aAccessTime, bool aPersisted, bool aDirectoryExists);
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
|
||||
|
||||
GroupInfo* GetGroupInfo() const { return mGroupInfo; }
|
||||
|
||||
const nsCString& Origin() const { return mOrigin; }
|
||||
|
||||
int64_t LockedUsage() const {
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
return mUsage;
|
||||
}
|
||||
|
||||
int64_t LockedAccessTime() const {
|
||||
AssertCurrentThreadOwnsQuotaMutex();
|
||||
|
||||
|
@ -656,6 +664,19 @@ class OriginInfo final {
|
|||
uint64_t mUsage;
|
||||
int64_t mAccessTime;
|
||||
bool mPersisted;
|
||||
/**
|
||||
* In some special cases like the LocalStorage client where it's possible to
|
||||
* create a Quota-using representation but not actually write any data, we
|
||||
* want to be able to track quota for an origin without creating its origin
|
||||
* directory or the per-client files until they are actually needed to store
|
||||
* data. In those cases, the OriginInfo will be created by
|
||||
* EnsureQuotaForOrigin and the resulting mDirectoryExists will be false until
|
||||
* the origin actually needs to be created. It is possible for mUsage to be
|
||||
* greater than zero while mDirectoryExists is false, representing a state
|
||||
* where a client like LocalStorage has reserved quota for disk writes, but
|
||||
* has not yet flushed the data to disk.
|
||||
*/
|
||||
bool mDirectoryExists;
|
||||
};
|
||||
|
||||
class OriginInfoLRUComparator {
|
||||
|
@ -691,6 +712,8 @@ class GroupInfo final {
|
|||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GroupInfo)
|
||||
|
||||
PersistenceType GetPersistenceType() const { return mPersistenceType; }
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
~GroupInfo() { MOZ_COUNT_DTOR(GroupInfo); }
|
||||
|
@ -1126,6 +1149,12 @@ class GetUsageOp final : public QuotaUsageRequestBase,
|
|||
private:
|
||||
~GetUsageOp() {}
|
||||
|
||||
void ProcessOriginInternal(QuotaManager* aQuotaManager,
|
||||
const PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const int64_t aTimestamp, const bool aPersisted,
|
||||
const uint64_t aUsage);
|
||||
|
||||
nsresult DoDirectoryWork(QuotaManager* aQuotaManager) override;
|
||||
|
||||
bool IsCanceled() override;
|
||||
|
@ -2226,26 +2255,21 @@ nsresult CreateDirectoryMetadataFiles(nsIFile* aDirectory, bool aPersisted,
|
|||
const nsACString& aSuffix,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
int64_t* aTimestamp) {
|
||||
int64_t aTimestamp) {
|
||||
AssertIsOnIOThread();
|
||||
|
||||
int64_t timestamp = PR_Now();
|
||||
|
||||
nsresult rv =
|
||||
CreateDirectoryMetadata(aDirectory, timestamp, aSuffix, aGroup, aOrigin);
|
||||
CreateDirectoryMetadata(aDirectory, aTimestamp, aSuffix, aGroup, aOrigin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = CreateDirectoryMetadata2(aDirectory, timestamp, aPersisted, aSuffix,
|
||||
rv = CreateDirectoryMetadata2(aDirectory, aTimestamp, aPersisted, aSuffix,
|
||||
aGroup, aOrigin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aTimestamp) {
|
||||
*aTimestamp = timestamp;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3387,6 +3411,28 @@ uint64_t QuotaManager::CollectOriginsForEviction(
|
|||
return 0;
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
void QuotaManager::CollectPendingOriginsForListing(P aPredicate) {
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
|
||||
GroupInfoPair* pair = iter.UserData();
|
||||
|
||||
MOZ_ASSERT(!iter.Key().IsEmpty());
|
||||
MOZ_ASSERT(pair);
|
||||
|
||||
RefPtr<GroupInfo> groupInfo =
|
||||
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
|
||||
if (groupInfo) {
|
||||
for (RefPtr<OriginInfo>& originInfo : groupInfo->mOriginInfos) {
|
||||
if (!originInfo->mDirectoryExists) {
|
||||
aPredicate(originInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult QuotaManager::Init(const nsAString& aBasePath) {
|
||||
mBasePath = aBasePath;
|
||||
|
||||
|
@ -3523,24 +3569,66 @@ void QuotaManager::InitQuotaForOrigin(PersistenceType aPersistenceType,
|
|||
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
GroupInfoPair* pair;
|
||||
if (!mGroupInfoPairs.Get(aGroup, &pair)) {
|
||||
pair = new GroupInfoPair();
|
||||
mGroupInfoPairs.Put(aGroup, pair);
|
||||
// The hashtable is now responsible to delete the GroupInfoPair.
|
||||
}
|
||||
|
||||
RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
|
||||
if (!groupInfo) {
|
||||
groupInfo = new GroupInfo(pair, aPersistenceType, aGroup);
|
||||
pair->LockedSetGroupInfo(aPersistenceType, groupInfo);
|
||||
}
|
||||
RefPtr<GroupInfo> groupInfo =
|
||||
LockedGetOrCreateGroupInfo(aPersistenceType, aGroup);
|
||||
|
||||
RefPtr<OriginInfo> originInfo =
|
||||
new OriginInfo(groupInfo, aOrigin, aUsageBytes, aAccessTime, aPersisted);
|
||||
new OriginInfo(groupInfo, aOrigin, aUsageBytes, aAccessTime, aPersisted,
|
||||
/* aDirectoryExists */ true);
|
||||
groupInfo->LockedAddOriginInfo(originInfo);
|
||||
}
|
||||
|
||||
void QuotaManager::EnsureQuotaForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
|
||||
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
RefPtr<GroupInfo> groupInfo =
|
||||
LockedGetOrCreateGroupInfo(aPersistenceType, aGroup);
|
||||
|
||||
RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
|
||||
if (!originInfo) {
|
||||
originInfo = new OriginInfo(
|
||||
groupInfo, aOrigin, /* aUsageBytes */ 0, /* aAccessTime */ PR_Now(),
|
||||
/* aPersisted */ false, /* aDirectoryExists */ false);
|
||||
groupInfo->LockedAddOriginInfo(originInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void QuotaManager::NoteOriginDirectoryCreated(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
bool aPersisted,
|
||||
int64_t& aTimestamp) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
|
||||
|
||||
int64_t timestamp;
|
||||
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
RefPtr<GroupInfo> groupInfo =
|
||||
LockedGetOrCreateGroupInfo(aPersistenceType, aGroup);
|
||||
|
||||
RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
|
||||
if (originInfo) {
|
||||
originInfo->mPersisted = aPersisted;
|
||||
originInfo->mDirectoryExists = true;
|
||||
timestamp = originInfo->LockedAccessTime();
|
||||
} else {
|
||||
timestamp = PR_Now();
|
||||
RefPtr<OriginInfo> originInfo = new OriginInfo(
|
||||
groupInfo, aOrigin, /* aUsageBytes */ 0, /* aAccessTime */ timestamp,
|
||||
aPersisted, /* aDirectoryExists */ true);
|
||||
groupInfo->LockedAddOriginInfo(originInfo);
|
||||
}
|
||||
|
||||
aTimestamp = timestamp;
|
||||
}
|
||||
|
||||
void QuotaManager::DecreaseUsageForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
|
@ -5261,7 +5349,6 @@ nsresult QuotaManager::UpgradeLocalStorageArchiveFrom0To1(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
nsresult QuotaManager::UpgradeLocalStorageArchiveFrom1To2(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection) {
|
||||
nsresult rv = SaveLocalStorageArchiveVersion(aConnection, 2);
|
||||
|
@ -5271,7 +5358,16 @@ nsresult QuotaManager::UpgradeLocalStorageArchiveFrom1To2(
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
nsresult QuotaManager::UpgradeLocalStorageArchiveFrom2To3(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection) {
|
||||
nsresult rv = SaveLocalStorageArchiveVersion(aConnection, 3);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
|
@ -5495,17 +5591,18 @@ nsresult QuotaManager::EnsureStorageIsInitialized() {
|
|||
return rv;
|
||||
}
|
||||
} else {
|
||||
static_assert(kLocalStorageArchiveVersion == 1,
|
||||
static_assert(kLocalStorageArchiveVersion == 3,
|
||||
"Upgrade function needed due to LocalStorage archive "
|
||||
"version increase.");
|
||||
|
||||
while (version != kLocalStorageArchiveVersion) {
|
||||
if (version == 0) {
|
||||
rv = UpgradeLocalStorageArchiveFrom0To1(connection);
|
||||
} /* else if (version == 1) {
|
||||
} else if (version == 1) {
|
||||
rv = UpgradeLocalStorageArchiveFrom1To2(connection);
|
||||
} */
|
||||
else {
|
||||
} else if (version == 2) {
|
||||
rv = UpgradeLocalStorageArchiveFrom2To3(connection);
|
||||
} else {
|
||||
QM_WARNING(
|
||||
"Unable to initialize LocalStorage archive, no upgrade path is "
|
||||
"available!");
|
||||
|
@ -5622,19 +5719,15 @@ void QuotaManager::OpenDirectoryInternal(
|
|||
|
||||
nsresult QuotaManager::EnsureOriginIsInitialized(
|
||||
PersistenceType aPersistenceType, const nsACString& aSuffix,
|
||||
const nsACString& aGroup, const nsACString& aOrigin,
|
||||
bool aCreateIfNotExists, nsIFile** aDirectory) {
|
||||
const nsACString& aGroup, const nsACString& aOrigin, nsIFile** aDirectory) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aDirectory);
|
||||
|
||||
nsCOMPtr<nsIFile> directory;
|
||||
bool created;
|
||||
nsresult rv = EnsureOriginIsInitializedInternal(
|
||||
aPersistenceType, aSuffix, aGroup, aOrigin, aCreateIfNotExists,
|
||||
getter_AddRefs(directory), &created);
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
return rv;
|
||||
}
|
||||
aPersistenceType, aSuffix, aGroup, aOrigin, getter_AddRefs(directory),
|
||||
&created);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -5645,8 +5738,8 @@ nsresult QuotaManager::EnsureOriginIsInitialized(
|
|||
|
||||
nsresult QuotaManager::EnsureOriginIsInitializedInternal(
|
||||
PersistenceType aPersistenceType, const nsACString& aSuffix,
|
||||
const nsACString& aGroup, const nsACString& aOrigin,
|
||||
bool aCreateIfNotExists, nsIFile** aDirectory, bool* aCreated) {
|
||||
const nsACString& aGroup, const nsACString& aOrigin, nsIFile** aDirectory,
|
||||
bool* aCreated) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aDirectory);
|
||||
MOZ_ASSERT(aCreated);
|
||||
|
@ -5674,10 +5767,7 @@ nsresult QuotaManager::EnsureOriginIsInitializedInternal(
|
|||
}
|
||||
|
||||
bool created;
|
||||
rv = EnsureOriginDirectory(directory, aCreateIfNotExists, &created);
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
return rv;
|
||||
}
|
||||
rv = EnsureOriginDirectory(directory, &created);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -5685,9 +5775,11 @@ nsresult QuotaManager::EnsureOriginIsInitializedInternal(
|
|||
int64_t timestamp;
|
||||
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
|
||||
if (created) {
|
||||
timestamp = PR_Now();
|
||||
|
||||
rv = CreateDirectoryMetadataFiles(directory,
|
||||
/* aPersisted */ true, aSuffix, aGroup,
|
||||
aOrigin, ×tamp);
|
||||
aOrigin, timestamp);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -5708,17 +5800,15 @@ nsresult QuotaManager::EnsureOriginIsInitializedInternal(
|
|||
|
||||
mInitializedOrigins.AppendElement(aOrigin);
|
||||
} else if (created) {
|
||||
NoteOriginDirectoryCreated(aPersistenceType, aGroup, aOrigin,
|
||||
/* aPersisted */ false, timestamp);
|
||||
|
||||
rv = CreateDirectoryMetadataFiles(directory,
|
||||
/* aPersisted */ false, aSuffix, aGroup,
|
||||
aOrigin, ×tamp);
|
||||
aOrigin, timestamp);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Don't need to traverse the directory, since it's empty.
|
||||
InitQuotaForOrigin(aPersistenceType, aGroup, aOrigin,
|
||||
/* aUsageBytes */ 0, timestamp,
|
||||
/* aPersisted */ false);
|
||||
}
|
||||
|
||||
directory.forget(aDirectory);
|
||||
|
@ -5796,7 +5886,6 @@ nsresult QuotaManager::EnsureTemporaryStorageIsInitialized() {
|
|||
}
|
||||
|
||||
nsresult QuotaManager::EnsureOriginDirectory(nsIFile* aDirectory,
|
||||
bool aCreateIfNotExists,
|
||||
bool* aCreated) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aDirectory);
|
||||
|
@ -5809,10 +5898,6 @@ nsresult QuotaManager::EnsureOriginDirectory(nsIFile* aDirectory,
|
|||
}
|
||||
|
||||
if (!exists) {
|
||||
if (!aCreateIfNotExists) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsString leafName;
|
||||
rv = aDirectory->GetLeafName(leafName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -6261,6 +6346,27 @@ void QuotaManager::LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
|
|||
}
|
||||
}
|
||||
|
||||
already_AddRefed<GroupInfo> QuotaManager::LockedGetOrCreateGroupInfo(
|
||||
PersistenceType aPersistenceType, const nsACString& aGroup) {
|
||||
mQuotaMutex.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
|
||||
|
||||
GroupInfoPair* pair;
|
||||
if (!mGroupInfoPairs.Get(aGroup, &pair)) {
|
||||
pair = new GroupInfoPair();
|
||||
mGroupInfoPairs.Put(aGroup, pair);
|
||||
// The hashtable is now responsible to delete the GroupInfoPair.
|
||||
}
|
||||
|
||||
RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
|
||||
if (!groupInfo) {
|
||||
groupInfo = new GroupInfo(pair, aPersistenceType, aGroup);
|
||||
pair->LockedSetGroupInfo(aPersistenceType, groupInfo);
|
||||
}
|
||||
|
||||
return groupInfo.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<OriginInfo> QuotaManager::LockedGetOriginInfo(
|
||||
PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin) {
|
||||
|
@ -6516,12 +6622,14 @@ bool QuotaManager::IsSanitizedOriginValid(const nsACString& aSanitizedOrigin) {
|
|||
******************************************************************************/
|
||||
|
||||
OriginInfo::OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin,
|
||||
uint64_t aUsage, int64_t aAccessTime, bool aPersisted)
|
||||
uint64_t aUsage, int64_t aAccessTime, bool aPersisted,
|
||||
bool aDirectoryExists)
|
||||
: mGroupInfo(aGroupInfo),
|
||||
mOrigin(aOrigin),
|
||||
mUsage(aUsage),
|
||||
mAccessTime(aAccessTime),
|
||||
mPersisted(aPersisted) {
|
||||
mPersisted(aPersisted),
|
||||
mDirectoryExists(aDirectoryExists) {
|
||||
MOZ_ASSERT(aGroupInfo);
|
||||
MOZ_ASSERT_IF(aPersisted,
|
||||
aGroupInfo->mPersistenceType == PERSISTENCE_TYPE_DEFAULT);
|
||||
|
@ -7624,6 +7732,47 @@ GetUsageOp::GetUsageOp(const UsageRequestParams& aParams)
|
|||
MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams);
|
||||
}
|
||||
|
||||
void GetUsageOp::ProcessOriginInternal(QuotaManager* aQuotaManager,
|
||||
const PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
const int64_t aTimestamp,
|
||||
const bool aPersisted,
|
||||
const uint64_t aUsage) {
|
||||
if (!mGetAll && aQuotaManager->IsOriginInternal(aOrigin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
OriginUsage* originUsage;
|
||||
|
||||
// We can't store pointers to OriginUsage objects in the hashtable
|
||||
// since AppendElement() reallocates its internal array buffer as number
|
||||
// of elements grows.
|
||||
uint32_t index;
|
||||
if (mOriginUsagesIndex.Get(aOrigin, &index)) {
|
||||
originUsage = &mOriginUsages[index];
|
||||
} else {
|
||||
index = mOriginUsages.Length();
|
||||
|
||||
originUsage = mOriginUsages.AppendElement();
|
||||
|
||||
originUsage->origin() = aOrigin;
|
||||
originUsage->persisted() = false;
|
||||
originUsage->usage() = 0;
|
||||
originUsage->lastAccessed() = 0;
|
||||
|
||||
mOriginUsagesIndex.Put(aOrigin, index);
|
||||
}
|
||||
|
||||
if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
|
||||
originUsage->persisted() = aPersisted;
|
||||
}
|
||||
|
||||
originUsage->usage() = originUsage->usage() + aUsage;
|
||||
|
||||
originUsage->lastAccessed() =
|
||||
std::max<int64_t>(originUsage->lastAccessed(), aTimestamp);
|
||||
}
|
||||
|
||||
bool GetUsageOp::IsCanceled() {
|
||||
AssertIsOnIOThread();
|
||||
|
||||
|
@ -7648,36 +7797,6 @@ nsresult GetUsageOp::ProcessOrigin(QuotaManager* aQuotaManager,
|
|||
return rv;
|
||||
}
|
||||
|
||||
if (!mGetAll && aQuotaManager->IsOriginInternal(origin)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OriginUsage* originUsage;
|
||||
|
||||
// We can't store pointers to OriginUsage objects in the hashtable
|
||||
// since AppendElement() reallocates its internal array buffer as number
|
||||
// of elements grows.
|
||||
uint32_t index;
|
||||
if (mOriginUsagesIndex.Get(origin, &index)) {
|
||||
originUsage = &mOriginUsages[index];
|
||||
} else {
|
||||
index = mOriginUsages.Length();
|
||||
|
||||
originUsage = mOriginUsages.AppendElement();
|
||||
|
||||
originUsage->origin() = origin;
|
||||
originUsage->persisted() = false;
|
||||
originUsage->usage() = 0;
|
||||
|
||||
mOriginUsagesIndex.Put(origin, index);
|
||||
}
|
||||
|
||||
if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
|
||||
originUsage->persisted() = persisted;
|
||||
}
|
||||
|
||||
originUsage->lastAccessed() = timestamp;
|
||||
|
||||
UsageInfo usageInfo;
|
||||
rv = GetUsageForOrigin(aQuotaManager, aPersistenceType, group, origin,
|
||||
&usageInfo);
|
||||
|
@ -7685,7 +7804,8 @@ nsresult GetUsageOp::ProcessOrigin(QuotaManager* aQuotaManager,
|
|||
return rv;
|
||||
}
|
||||
|
||||
originUsage->usage() = originUsage->usage() + usageInfo.TotalUsage();
|
||||
ProcessOriginInternal(aQuotaManager, aPersistenceType, origin, timestamp,
|
||||
persisted, usageInfo.TotalUsage());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -7704,6 +7824,18 @@ nsresult GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) {
|
|||
}
|
||||
}
|
||||
|
||||
// TraverseRepository above only consulted the filesystem. We also need to
|
||||
// consider origins which may have pending quota usage, such as buffered
|
||||
// LocalStorage writes for an origin which didn't previously have any
|
||||
// LocalStorage data.
|
||||
|
||||
aQuotaManager->CollectPendingOriginsForListing([&](OriginInfo* aOriginInfo) {
|
||||
ProcessOriginInternal(
|
||||
aQuotaManager, aOriginInfo->GetGroupInfo()->GetPersistenceType(),
|
||||
aOriginInfo->Origin(), aOriginInfo->LockedAccessTime(),
|
||||
aOriginInfo->LockedPersisted(), aOriginInfo->LockedUsage());
|
||||
});
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -7919,7 +8051,7 @@ nsresult InitOriginOp::DoDirectoryWork(QuotaManager* aQuotaManager) {
|
|||
bool created;
|
||||
nsresult rv = aQuotaManager->EnsureOriginIsInitializedInternal(
|
||||
mPersistenceType.Value(), mSuffix, mGroup, mOriginScope.GetOrigin(),
|
||||
/* aCreateIfNotExists */ true, getter_AddRefs(directory), &created);
|
||||
getter_AddRefs(directory), &created);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -8432,29 +8564,29 @@ nsresult PersistOp::DoDirectoryWork(QuotaManager* aQuotaManager) {
|
|||
}
|
||||
|
||||
bool created;
|
||||
rv = aQuotaManager->EnsureOriginDirectory(directory,
|
||||
/* aCreateIfNotExists */ true,
|
||||
&created);
|
||||
rv = aQuotaManager->EnsureOriginDirectory(directory, &created);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (created) {
|
||||
int64_t timestamp;
|
||||
rv = CreateDirectoryMetadataFiles(directory,
|
||||
/* aPersisted */ true, mSuffix, mGroup,
|
||||
mOriginScope.GetOrigin(), ×tamp);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Directory metadata has been successfully created.
|
||||
// Origin directory has been successfully created.
|
||||
// Create OriginInfo too if temporary storage was already initialized.
|
||||
if (aQuotaManager->IsTemporaryStorageInitialized()) {
|
||||
aQuotaManager->InitQuotaForOrigin(mPersistenceType.Value(), mGroup,
|
||||
mOriginScope.GetOrigin(),
|
||||
/* aUsageBytes */ 0, timestamp,
|
||||
/* aPersisted */ true);
|
||||
aQuotaManager->NoteOriginDirectoryCreated(
|
||||
mPersistenceType.Value(), mGroup, mOriginScope.GetOrigin(),
|
||||
/* aPersisted */ true, timestamp);
|
||||
} else {
|
||||
timestamp = PR_Now();
|
||||
}
|
||||
|
||||
rv = CreateDirectoryMetadataFiles(directory,
|
||||
/* aPersisted */ true, mSuffix, mGroup,
|
||||
mOriginScope.GetOrigin(), timestamp);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
// Get the persisted flag (restore the metadata file if necessary).
|
||||
|
@ -8549,6 +8681,14 @@ nsresult ListInitializedOriginsOp::DoDirectoryWork(
|
|||
}
|
||||
}
|
||||
|
||||
// TraverseRepository above only consulted the file-system to get a list of
|
||||
// known origins, but we also need to include origins that have pending quota
|
||||
// usage.
|
||||
|
||||
aQuotaManager->CollectPendingOriginsForListing([&](OriginInfo* aOriginInfo) {
|
||||
mOrigins.AppendElement(aOriginInfo->Origin());
|
||||
});
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,11 +145,41 @@ class QuotaManager final : public BackgroundThreadObject {
|
|||
return mTemporaryStorageInitialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* For initialization of an origin where the directory already exists. This is
|
||||
* used by EnsureTemporaryStorageIsInitialized/InitializeRepository once it
|
||||
* has tallied origin usage by calling each of the QuotaClient InitOrigin
|
||||
* methods.
|
||||
*/
|
||||
void InitQuotaForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup, const nsACString& aOrigin,
|
||||
uint64_t aUsageBytes, int64_t aAccessTime,
|
||||
bool aPersisted);
|
||||
|
||||
/**
|
||||
* For use in special-cases like LSNG where we need to be able to know that
|
||||
* there is no data stored for an origin. LSNG knows that there is 0 usage for
|
||||
* its storage of an origin and wants to make sure there is a QuotaObject
|
||||
* tracking this. This method will create a non-persisted, 0-usage,
|
||||
* mDirectoryExists=false OriginInfo if there isn't already an OriginInfo. If
|
||||
* an OriginInfo already exists, it will be left as-is, because that implies a
|
||||
* different client has usages for the origin (and there's no need to add
|
||||
* LSNG's 0 usage to the QuotaObject).
|
||||
*/
|
||||
void EnsureQuotaForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin);
|
||||
|
||||
/**
|
||||
* For use when creating an origin directory. It's possible that origin usage
|
||||
* is already being tracked due to a call to EnsureQuotaForOrigin, and in that
|
||||
* case we need to update the existing OriginInfo rather than create a new one.
|
||||
*/
|
||||
void NoteOriginDirectoryCreated(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin, bool aPersisted,
|
||||
int64_t& aTimestamp);
|
||||
|
||||
void DecreaseUsageForOrigin(PersistenceType aPersistenceType,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin, int64_t aSize);
|
||||
|
@ -248,6 +278,19 @@ class QuotaManager final : public BackgroundThreadObject {
|
|||
uint64_t CollectOriginsForEviction(
|
||||
uint64_t aMinSizeToBeFreed, nsTArray<RefPtr<DirectoryLockImpl>>& 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);
|
||||
|
||||
void AssertStorageIsInitialized() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
|
@ -262,18 +305,18 @@ class QuotaManager final : public BackgroundThreadObject {
|
|||
const nsACString& aSuffix,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
bool aCreateIfNotExists,
|
||||
nsIFile** aDirectory);
|
||||
|
||||
nsresult EnsureOriginIsInitializedInternal(
|
||||
PersistenceType aPersistenceType, const nsACString& aSuffix,
|
||||
const nsACString& aGroup, const nsACString& aOrigin,
|
||||
bool aCreateIfNotExists, nsIFile** aDirectory, bool* aCreated);
|
||||
nsresult EnsureOriginIsInitializedInternal(PersistenceType aPersistenceType,
|
||||
const nsACString& aSuffix,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin,
|
||||
nsIFile** aDirectory,
|
||||
bool* aCreated);
|
||||
|
||||
nsresult EnsureTemporaryStorageIsInitialized();
|
||||
|
||||
nsresult EnsureOriginDirectory(nsIFile* aDirectory, bool aCreateIfNotExists,
|
||||
bool* aCreated);
|
||||
nsresult EnsureOriginDirectory(nsIFile* aDirectory, bool* aCreated);
|
||||
|
||||
nsresult AboutToClearOrigins(
|
||||
const Nullable<PersistenceType>& aPersistenceType,
|
||||
|
@ -399,6 +442,9 @@ class QuotaManager final : public BackgroundThreadObject {
|
|||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin);
|
||||
|
||||
already_AddRefed<GroupInfo> LockedGetOrCreateGroupInfo(
|
||||
PersistenceType aPersistenceType, const nsACString& aGroup);
|
||||
|
||||
already_AddRefed<OriginInfo> LockedGetOriginInfo(
|
||||
PersistenceType aPersistenceType, const nsACString& aGroup,
|
||||
const nsACString& aOrigin);
|
||||
|
@ -440,10 +486,11 @@ class QuotaManager final : public BackgroundThreadObject {
|
|||
nsresult UpgradeLocalStorageArchiveFrom0To1(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection);
|
||||
|
||||
/*
|
||||
nsresult UpgradeLocalStorageArchiveFrom1To2(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection);
|
||||
*/
|
||||
nsresult UpgradeLocalStorageArchiveFrom1To2(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection);
|
||||
|
||||
nsresult UpgradeLocalStorageArchiveFrom2To3(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection);
|
||||
|
||||
nsresult InitializeRepository(PersistenceType aPersistenceType);
|
||||
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This test is mainly to verify that local storage directories are not removed
|
||||
* during local storage archive upgrade from version 1 to version 2.
|
||||
* See bug 1546310.
|
||||
*/
|
||||
|
||||
async function testSteps() {
|
||||
const lsDirs = [
|
||||
"storage/default/http+++example.com/ls",
|
||||
"storage/default/http+++localhost/ls",
|
||||
"storage/default/http+++www.mozilla.org/ls",
|
||||
];
|
||||
|
||||
info("Clearing");
|
||||
|
||||
let request = clear();
|
||||
await requestFinished(request);
|
||||
|
||||
info("Installing package");
|
||||
|
||||
// The profile contains three initialized origin directories with local
|
||||
// storage data, local storage archive, a script for origin initialization,
|
||||
// the storage database and the web apps store database:
|
||||
// - storage/default/https+++example.com
|
||||
// - storage/default/https+++localhost
|
||||
// - storage/default/https+++www.mozilla.org
|
||||
// - storage/ls-archive.sqlite
|
||||
// - create_db.js
|
||||
// - storage.sqlite
|
||||
// - webappsstore.sqlite
|
||||
// The file create_db.js in the package was run locally (with a build with
|
||||
// local storage archive version 1), specifically it was temporarily added to
|
||||
// xpcshell.ini and then executed:
|
||||
// mach xpcshell-test --interactive dom/localstorage/test/unit/create_db.js
|
||||
// Note: to make it become the profile in the test, additional manual steps
|
||||
// are needed.
|
||||
// 1. Remove the folder "storage/temporary".
|
||||
installPackage("localStorageArchive2upgrade_profile");
|
||||
|
||||
info("Checking ls dirs");
|
||||
|
||||
for (let lsDir of lsDirs) {
|
||||
let dir = getRelativeFile(lsDir);
|
||||
|
||||
exists = dir.exists();
|
||||
ok(exists, "ls directory does exist");
|
||||
}
|
||||
|
||||
request = init();
|
||||
request = await requestFinished(request);
|
||||
|
||||
info("Checking ls dirs");
|
||||
|
||||
for (let lsDir of lsDirs) {
|
||||
let dir = getRelativeFile(lsDir);
|
||||
|
||||
exists = dir.exists();
|
||||
ok(exists, "ls directory does exist");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This test is mainly to verify that local storage directories are not removed
|
||||
* during local storage archive upgrade from version 2 to version 3.
|
||||
* See bug 1513937.
|
||||
*/
|
||||
|
||||
async function testSteps() {
|
||||
const lsDirs = [
|
||||
"storage/default/http+++example.com/ls",
|
||||
"storage/default/http+++localhost/ls",
|
||||
"storage/default/http+++www.mozilla.org/ls",
|
||||
];
|
||||
|
||||
info("Clearing");
|
||||
|
||||
let request = clear();
|
||||
await requestFinished(request);
|
||||
|
||||
info("Installing package");
|
||||
|
||||
// The profile contains three initialized origin directories with local
|
||||
// storage data, local storage archive, a script for origin initialization,
|
||||
// the storage database and the web apps store database:
|
||||
// - storage/default/https+++example.com
|
||||
// - storage/default/https+++localhost
|
||||
// - storage/default/https+++www.mozilla.org
|
||||
// - storage/ls-archive.sqlite
|
||||
// - create_db.js
|
||||
// - storage.sqlite
|
||||
// - webappsstore.sqlite
|
||||
// The file create_db.js in the package was run locally (with a build with
|
||||
// local storage archive version 2), specifically it was temporarily added to
|
||||
// xpcshell.ini and then executed:
|
||||
// mach xpcshell-test --interactive dom/localstorage/test/unit/create_db.js
|
||||
// Note: to make it become the profile in the test, additional manual steps
|
||||
// are needed.
|
||||
// 1. Remove the folder "storage/temporary".
|
||||
installPackage("localStorageArchive3upgrade_profile");
|
||||
|
||||
info("Checking ls dirs");
|
||||
|
||||
for (let lsDir of lsDirs) {
|
||||
let dir = getRelativeFile(lsDir);
|
||||
|
||||
exists = dir.exists();
|
||||
ok(exists, "ls directory does exist");
|
||||
}
|
||||
|
||||
request = init();
|
||||
request = await requestFinished(request);
|
||||
|
||||
info("Checking ls dirs");
|
||||
|
||||
for (let lsDir of lsDirs) {
|
||||
let dir = getRelativeFile(lsDir);
|
||||
|
||||
exists = dir.exists();
|
||||
ok(exists, "ls directory does exist");
|
||||
}
|
||||
}
|
|
@ -14,6 +14,8 @@ support-files =
|
|||
idbSubdirUpgrade1_profile.zip
|
||||
idbSubdirUpgrade2_profile.zip
|
||||
localStorageArchive1upgrade_profile.zip
|
||||
localStorageArchive2upgrade_profile.zip
|
||||
localStorageArchive3upgrade_profile.zip
|
||||
localStorageArchiveDowngrade_profile.zip
|
||||
morgueCleanup_profile.zip
|
||||
obsoleteOriginAttributes_profile.zip
|
||||
|
@ -36,6 +38,8 @@ support-files =
|
|||
[test_initTemporaryStorage.js]
|
||||
[test_listInitializedOrigins.js]
|
||||
[test_localStorageArchive1upgrade.js]
|
||||
[test_localStorageArchive2upgrade.js]
|
||||
[test_localStorageArchive3upgrade.js]
|
||||
[test_localStorageArchiveDowngrade.js]
|
||||
[test_morgueCleanup.js]
|
||||
[test_obsoleteOriginAttributesUpgrade.js]
|
||||
|
|
|
@ -1152,7 +1152,7 @@ nsresult OpenOp::DatabaseWork() {
|
|||
nsCOMPtr<nsIFile> dbDirectory;
|
||||
nsresult rv = quotaManager->EnsureOriginIsInitialized(
|
||||
PERSISTENCE_TYPE_DEFAULT, mSuffix, mGroup, mOrigin,
|
||||
/* aCreateIfNotExists */ true, getter_AddRefs(dbDirectory));
|
||||
getter_AddRefs(dbDirectory));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -264,7 +264,7 @@ parent:
|
|||
returns (bool isContentOnlyTDR);
|
||||
|
||||
async BeginRecording(TimeStamp aRecordingStart);
|
||||
async EndRecording();
|
||||
sync EndRecording();
|
||||
|
||||
child:
|
||||
// Send back Compositor Frame Metrics from APZCs so tiled layers can
|
||||
|
|
|
@ -987,6 +987,8 @@ description =
|
|||
[PCompositorWidget::EnterPresentLock]
|
||||
description =
|
||||
platform = win
|
||||
[PCompositorBridge::EndRecording]
|
||||
description = This call is only used for performance analysis scenarios
|
||||
[PCompositorWidget::LeavePresentLock]
|
||||
description =
|
||||
platform = win
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import errno
|
||||
import glob
|
||||
import random
|
||||
import os
|
||||
import shutil
|
||||
|
@ -41,6 +42,7 @@ class CppEclipseBackend(CommonBackend):
|
|||
self._args_for_dirs = {}
|
||||
self._project_name = 'Gecko'
|
||||
self._workspace_dir = self._get_workspace_path()
|
||||
self._workspace_lang_dir = os.path.join(self._workspace_dir, '.metadata/.plugins/org.eclipse.cdt.core')
|
||||
self._project_dir = os.path.join(self._workspace_dir, self._project_name)
|
||||
self._overwriting_workspace = os.path.isdir(self._workspace_dir)
|
||||
|
||||
|
@ -104,9 +106,8 @@ class CppEclipseBackend(CommonBackend):
|
|||
settings_dir = os.path.join(self._project_dir, '.settings')
|
||||
launch_dir = os.path.join(self._project_dir, 'RunConfigurations')
|
||||
workspace_settings_dir = os.path.join(self._workspace_dir, '.metadata/.plugins/org.eclipse.core.runtime/.settings')
|
||||
workspace_language_dir = os.path.join(self._workspace_dir, '.metadata/.plugins/org.eclipse.cdt.core')
|
||||
|
||||
for dir_name in [self._project_dir, settings_dir, launch_dir, workspace_settings_dir, workspace_language_dir]:
|
||||
for dir_name in [self._project_dir, settings_dir, launch_dir, workspace_settings_dir, self._workspace_lang_dir]:
|
||||
try:
|
||||
os.makedirs(dir_name)
|
||||
except OSError as e:
|
||||
|
@ -125,7 +126,7 @@ class CppEclipseBackend(CommonBackend):
|
|||
with open(language_path, 'wb') as fh:
|
||||
self._write_language_settings(fh)
|
||||
|
||||
workspace_language_path = os.path.join(workspace_language_dir, 'language.settings.xml')
|
||||
workspace_language_path = os.path.join(self._workspace_lang_dir, 'language.settings.xml')
|
||||
with open(workspace_language_path, 'wb') as fh:
|
||||
workspace_lang_settings = WORKSPACE_LANGUAGE_SETTINGS_TEMPLATE
|
||||
workspace_lang_settings = workspace_lang_settings.replace("@COMPILER_FLAGS@", self._cxx + " " + self._cppflags);
|
||||
|
@ -210,6 +211,13 @@ class CppEclipseBackend(CommonBackend):
|
|||
fh.write(NOINDEX_TEMPLATE);
|
||||
|
||||
def _remove_noindex(self):
|
||||
# Below we remove the config file that temporarily disabled the indexer
|
||||
# while we were importing the project. Unfornutanely, CDT doesn't
|
||||
# notice indexer settings changes in config files when it restarts. To
|
||||
# work around that we remove the index database here to force it to:
|
||||
for f in glob.glob(os.path.join(self._workspace_lang_dir, "*.pdom")):
|
||||
os.remove(f)
|
||||
|
||||
noindex_path = os.path.join(self._project_dir, '.settings/org.eclipse.cdt.core.prefs')
|
||||
# This may fail if the entire tree has been removed; that's fine.
|
||||
try:
|
||||
|
|
Загрузка…
Ссылка в новой задаче