Bug 1708193 - Remove mozapps/extensions/internal/Content.js r=rpl
[gecko.git] / dom / storage / SessionStorageCache.cpp
blobc1e8ae95f06e75a3e37ae827cb00792d36ecd20a
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "SessionStorageCache.h"
9 #include "LocalStorageManager.h"
10 #include "StorageIPC.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/dom/LSWriteOptimizer.h"
13 #include "mozilla/dom/PBackgroundSessionStorageCache.h"
14 #include "nsDOMString.h"
16 namespace mozilla {
17 namespace dom {
19 void SSWriteOptimizer::Enumerate(nsTArray<SSWriteInfo>& aWriteInfos) {
20 AssertIsOnOwningThread();
22 // The mWriteInfos hash table contains all write infos, but it keeps them in
23 // an arbitrary order, which means write infos need to be sorted before being
24 // processed.
26 nsTArray<NotNull<WriteInfo*>> writeInfos;
27 GetSortedWriteInfos(writeInfos);
29 for (const auto& writeInfo : writeInfos) {
30 switch (writeInfo->GetType()) {
31 case WriteInfo::InsertItem: {
32 const auto& insertItemInfo =
33 static_cast<const InsertItemInfo&>(*writeInfo);
35 aWriteInfos.AppendElement(
36 SSSetItemInfo{nsString{insertItemInfo.GetKey()},
37 nsString{insertItemInfo.GetValue()}});
39 break;
42 case WriteInfo::UpdateItem: {
43 const auto& updateItemInfo =
44 static_cast<const UpdateItemInfo&>(*writeInfo);
46 if (updateItemInfo.UpdateWithMove()) {
47 // See the comment in LSWriteOptimizer::InsertItem for more details
48 // about the UpdateWithMove flag.
50 aWriteInfos.AppendElement(
51 SSRemoveItemInfo{nsString{updateItemInfo.GetKey()}});
54 aWriteInfos.AppendElement(
55 SSSetItemInfo{nsString{updateItemInfo.GetKey()},
56 nsString{updateItemInfo.GetValue()}});
58 break;
61 case WriteInfo::DeleteItem: {
62 const auto& deleteItemInfo =
63 static_cast<const DeleteItemInfo&>(*writeInfo);
65 aWriteInfos.AppendElement(
66 SSRemoveItemInfo{nsString{deleteItemInfo.GetKey()}});
68 break;
71 case WriteInfo::Truncate: {
72 aWriteInfos.AppendElement(SSClearInfo{});
74 break;
77 default:
78 MOZ_CRASH("Bad type!");
83 SessionStorageCache::SessionStorageCache()
84 : mActor(nullptr), mLoadedOrCloned(false) {}
86 SessionStorageCache::~SessionStorageCache() {
87 if (mActor) {
88 mActor->SendDeleteMeInternal();
89 MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
93 int64_t SessionStorageCache::GetOriginQuotaUsage() {
94 return mDataSet.mOriginQuotaUsage;
97 uint32_t SessionStorageCache::Length() { return mDataSet.mKeys.Count(); }
99 void SessionStorageCache::Key(uint32_t aIndex, nsAString& aResult) {
100 aResult.SetIsVoid(true);
101 for (auto iter = mDataSet.mKeys.ConstIter(); !iter.Done(); iter.Next()) {
102 if (aIndex == 0) {
103 aResult = iter.Key();
104 return;
106 aIndex--;
110 void SessionStorageCache::GetItem(const nsAString& aKey, nsAString& aResult) {
111 // not using AutoString since we don't want to copy buffer to result
112 nsString value;
113 if (!mDataSet.mKeys.Get(aKey, &value)) {
114 SetDOMStringToNull(value);
116 aResult = value;
119 void SessionStorageCache::GetKeys(nsTArray<nsString>& aKeys) {
120 AppendToArray(aKeys, mDataSet.mKeys.Keys());
123 nsresult SessionStorageCache::SetItem(const nsAString& aKey,
124 const nsAString& aValue,
125 nsString& aOldValue,
126 bool aRecordWriteInfo) {
127 int64_t delta = 0;
129 if (!mDataSet.mKeys.Get(aKey, &aOldValue)) {
130 SetDOMStringToNull(aOldValue);
132 // We only consider key size if the key doesn't exist before.
133 delta = static_cast<int64_t>(aKey.Length());
136 delta += static_cast<int64_t>(aValue.Length()) -
137 static_cast<int64_t>(aOldValue.Length());
139 if (aValue == aOldValue &&
140 DOMStringIsNull(aValue) == DOMStringIsNull(aOldValue)) {
141 return NS_SUCCESS_DOM_NO_OPERATION;
144 if (!mDataSet.ProcessUsageDelta(delta)) {
145 return NS_ERROR_DOM_QUOTA_EXCEEDED_ERR;
148 if (aRecordWriteInfo && XRE_IsContentProcess()) {
149 if (DOMStringIsNull(aOldValue)) {
150 mDataSet.mWriteOptimizer.InsertItem(aKey, aValue);
151 } else {
152 mDataSet.mWriteOptimizer.UpdateItem(aKey, aValue);
156 mDataSet.mKeys.InsertOrUpdate(aKey, nsString(aValue));
157 return NS_OK;
160 nsresult SessionStorageCache::RemoveItem(const nsAString& aKey,
161 nsString& aOldValue,
162 bool aRecordWriteInfo) {
163 if (!mDataSet.mKeys.Get(aKey, &aOldValue)) {
164 return NS_SUCCESS_DOM_NO_OPERATION;
167 // Recalculate the cached data size
168 mDataSet.ProcessUsageDelta(-(static_cast<int64_t>(aOldValue.Length()) +
169 static_cast<int64_t>(aKey.Length())));
171 if (aRecordWriteInfo && XRE_IsContentProcess()) {
172 mDataSet.mWriteOptimizer.DeleteItem(aKey);
175 mDataSet.mKeys.Remove(aKey);
176 return NS_OK;
179 void SessionStorageCache::Clear(bool aByUserInteraction,
180 bool aRecordWriteInfo) {
181 mDataSet.ProcessUsageDelta(-mDataSet.mOriginQuotaUsage);
183 if (aRecordWriteInfo && XRE_IsContentProcess()) {
184 mDataSet.mWriteOptimizer.Truncate();
187 mDataSet.mKeys.Clear();
190 void SessionStorageCache::ResetWriteInfos() {
191 mDataSet.mWriteOptimizer.Reset();
194 already_AddRefed<SessionStorageCache> SessionStorageCache::Clone() const {
195 RefPtr<SessionStorageCache> cache = new SessionStorageCache();
197 cache->mDataSet.mOriginQuotaUsage = mDataSet.mOriginQuotaUsage;
198 for (const auto& keyEntry : mDataSet.mKeys) {
199 cache->mDataSet.mKeys.InsertOrUpdate(keyEntry.GetKey(), keyEntry.GetData());
200 cache->mDataSet.mWriteOptimizer.InsertItem(keyEntry.GetKey(),
201 keyEntry.GetData());
204 return cache.forget();
207 nsTArray<SSSetItemInfo> SessionStorageCache::SerializeData() {
208 nsTArray<SSSetItemInfo> data;
209 for (const auto& keyEntry : mDataSet.mKeys) {
210 data.EmplaceBack(nsString{keyEntry.GetKey()}, keyEntry.GetData());
212 return data;
215 nsTArray<SSWriteInfo> SessionStorageCache::SerializeWriteInfos() {
216 nsTArray<SSWriteInfo> writeInfos;
217 mDataSet.mWriteOptimizer.Enumerate(writeInfos);
218 return writeInfos;
221 void SessionStorageCache::DeserializeData(
222 const nsTArray<SSSetItemInfo>& aData) {
223 Clear(false, /* aRecordWriteInfo */ false);
224 for (const auto& keyValuePair : aData) {
225 nsString oldValue;
226 SetItem(keyValuePair.key(), keyValuePair.value(), oldValue, false);
230 void SessionStorageCache::DeserializeWriteInfos(
231 const nsTArray<SSWriteInfo>& aInfos) {
232 for (const auto& writeInfo : aInfos) {
233 switch (writeInfo.type()) {
234 case SSWriteInfo::TSSSetItemInfo: {
235 const SSSetItemInfo& info = writeInfo.get_SSSetItemInfo();
237 nsString oldValue;
238 SetItem(info.key(), info.value(), oldValue,
239 /* aRecordWriteInfo */ false);
241 break;
244 case SSWriteInfo::TSSRemoveItemInfo: {
245 const SSRemoveItemInfo& info = writeInfo.get_SSRemoveItemInfo();
247 nsString oldValue;
248 RemoveItem(info.key(), oldValue,
249 /* aRecordWriteInfo */ false);
251 break;
254 case SSWriteInfo::TSSClearInfo: {
255 Clear(false, /* aRecordWriteInfo */ false);
257 break;
260 default:
261 MOZ_CRASH("Should never get here!");
266 void SessionStorageCache::SetActor(SessionStorageCacheChild* aActor) {
267 AssertIsOnMainThread();
268 MOZ_ASSERT(aActor);
269 MOZ_ASSERT(!mActor);
271 mActor = aActor;
274 void SessionStorageCache::ClearActor() {
275 AssertIsOnMainThread();
276 MOZ_ASSERT(mActor);
278 mActor = nullptr;
281 bool SessionStorageCache::DataSet::ProcessUsageDelta(int64_t aDelta) {
282 // Check limit per this origin
283 uint64_t newOriginUsage = mOriginQuotaUsage + aDelta;
284 if (aDelta > 0 && newOriginUsage > LocalStorageManager::GetOriginQuota()) {
285 return false;
288 // Update size in our data set
289 mOriginQuotaUsage = newOriginUsage;
290 return true;
293 } // namespace dom
294 } // namespace mozilla