blob: a01d3c6f7fb3c1c19b8ef6a2b4a24ee31b46a1c2 [file] [log] [blame]
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +01001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/renderer/dom_storage/dom_storage_cached_area.h"
6
7#include "base/basictypes.h"
8#include "base/metrics/histogram.h"
9#include "base/time/time.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010010#include "content/common/dom_storage/dom_storage_map.h"
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010011#include "content/renderer/dom_storage/dom_storage_proxy.h"
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010012
13namespace content {
14
Ben Murdochbb1529c2013-08-08 10:24:53 +010015DOMStorageCachedArea::DOMStorageCachedArea(int64 namespace_id,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010016 const GURL& origin,
Ben Murdochbb1529c2013-08-08 10:24:53 +010017 DOMStorageProxy* proxy)
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010018 : ignore_all_mutations_(false),
19 namespace_id_(namespace_id),
20 origin_(origin),
21 proxy_(proxy),
22 weak_factory_(this) {}
23
Ben Murdochbb1529c2013-08-08 10:24:53 +010024DOMStorageCachedArea::~DOMStorageCachedArea() {}
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010025
Ben Murdochbb1529c2013-08-08 10:24:53 +010026unsigned DOMStorageCachedArea::GetLength(int connection_id) {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010027 PrimeIfNeeded(connection_id);
28 return map_->Length();
29}
30
Ben Murdochbb1529c2013-08-08 10:24:53 +010031base::NullableString16 DOMStorageCachedArea::GetKey(int connection_id,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010032 unsigned index) {
33 PrimeIfNeeded(connection_id);
34 return map_->Key(index);
35}
36
Ben Murdochbb1529c2013-08-08 10:24:53 +010037base::NullableString16 DOMStorageCachedArea::GetItem(
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010038 int connection_id,
39 const base::string16& key) {
40 PrimeIfNeeded(connection_id);
41 return map_->GetItem(key);
42}
43
Ben Murdochbb1529c2013-08-08 10:24:53 +010044bool DOMStorageCachedArea::SetItem(int connection_id,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010045 const base::string16& key,
46 const base::string16& value,
47 const GURL& page_url) {
48 // A quick check to reject obviously overbudget items to avoid
49 // the priming the cache.
Ben Murdochbb1529c2013-08-08 10:24:53 +010050 if (key.length() + value.length() > kPerStorageAreaQuota)
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010051 return false;
52
53 PrimeIfNeeded(connection_id);
54 base::NullableString16 unused;
55 if (!map_->SetItem(key, value, &unused))
56 return false;
57
58 // Ignore mutations to 'key' until OnSetItemComplete.
59 ignore_key_mutations_[key]++;
60 proxy_->SetItem(
61 connection_id, key, value, page_url,
Ben Murdochbb1529c2013-08-08 10:24:53 +010062 base::Bind(&DOMStorageCachedArea::OnSetItemComplete,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010063 weak_factory_.GetWeakPtr(), key));
64 return true;
65}
66
Ben Murdochbb1529c2013-08-08 10:24:53 +010067void DOMStorageCachedArea::RemoveItem(int connection_id,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010068 const base::string16& key,
69 const GURL& page_url) {
70 PrimeIfNeeded(connection_id);
71 base::string16 unused;
72 if (!map_->RemoveItem(key, &unused))
73 return;
74
75 // Ignore mutations to 'key' until OnRemoveItemComplete.
76 ignore_key_mutations_[key]++;
77 proxy_->RemoveItem(
78 connection_id, key, page_url,
Ben Murdochbb1529c2013-08-08 10:24:53 +010079 base::Bind(&DOMStorageCachedArea::OnRemoveItemComplete,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010080 weak_factory_.GetWeakPtr(), key));
81}
82
Ben Murdochbb1529c2013-08-08 10:24:53 +010083void DOMStorageCachedArea::Clear(int connection_id, const GURL& page_url) {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010084 // No need to prime the cache in this case.
85 Reset();
Ben Murdochbb1529c2013-08-08 10:24:53 +010086 map_ = new DOMStorageMap(kPerStorageAreaQuota);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010087
88 // Ignore all mutations until OnClearComplete time.
89 ignore_all_mutations_ = true;
90 proxy_->ClearArea(connection_id,
91 page_url,
Ben Murdochbb1529c2013-08-08 10:24:53 +010092 base::Bind(&DOMStorageCachedArea::OnClearComplete,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010093 weak_factory_.GetWeakPtr()));
94}
95
Ben Murdochbb1529c2013-08-08 10:24:53 +010096void DOMStorageCachedArea::ApplyMutation(
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010097 const base::NullableString16& key,
98 const base::NullableString16& new_value) {
99 if (!map_.get() || ignore_all_mutations_)
100 return;
101
102 if (key.is_null()) {
103 // It's a clear event.
Ben Murdochbb1529c2013-08-08 10:24:53 +0100104 scoped_refptr<DOMStorageMap> old = map_;
105 map_ = new DOMStorageMap(kPerStorageAreaQuota);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100106
107 // We have to retain local additions which happened after this
108 // clear operation from another process.
109 std::map<base::string16, int>::iterator iter =
110 ignore_key_mutations_.begin();
111 while (iter != ignore_key_mutations_.end()) {
112 base::NullableString16 value = old->GetItem(iter->first);
113 if (!value.is_null()) {
114 base::NullableString16 unused;
115 map_->SetItem(iter->first, value.string(), &unused);
116 }
117 ++iter;
118 }
119 return;
120 }
121
122 // We have to retain local changes.
123 if (should_ignore_key_mutation(key.string()))
124 return;
125
126 if (new_value.is_null()) {
127 // It's a remove item event.
128 base::string16 unused;
129 map_->RemoveItem(key.string(), &unused);
130 return;
131 }
132
133 // It's a set item event.
134 // We turn off quota checking here to accomodate the over budget
135 // allowance that's provided in the browser process.
136 base::NullableString16 unused;
137 map_->set_quota(kint32max);
138 map_->SetItem(key.string(), new_value.string(), &unused);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100139 map_->set_quota(kPerStorageAreaQuota);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100140}
141
Ben Murdochbb1529c2013-08-08 10:24:53 +0100142size_t DOMStorageCachedArea::MemoryBytesUsedByCache() const {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100143 return map_.get() ? map_->bytes_used() : 0;
144}
145
Ben Murdochbb1529c2013-08-08 10:24:53 +0100146void DOMStorageCachedArea::Prime(int connection_id) {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100147 DCHECK(!map_.get());
148
149 // The LoadArea method is actually synchronous, but we have to
150 // wait for an asyncly delivered message to know when incoming
151 // mutation events should be applied. Our valuemap is plucked
152 // from ipc stream out of order, mutations in front if it need
153 // to be ignored.
154
155 // Ignore all mutations until OnLoadComplete time.
156 ignore_all_mutations_ = true;
Ben Murdochbb1529c2013-08-08 10:24:53 +0100157 DOMStorageValuesMap values;
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100158 base::TimeTicks before = base::TimeTicks::Now();
159 proxy_->LoadArea(connection_id,
160 &values,
Ben Murdochbb1529c2013-08-08 10:24:53 +0100161 base::Bind(&DOMStorageCachedArea::OnLoadComplete,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100162 weak_factory_.GetWeakPtr()));
163 base::TimeDelta time_to_prime = base::TimeTicks::Now() - before;
164 // Keeping this histogram named the same (without the ForRenderer suffix)
165 // to maintain histogram continuity.
166 UMA_HISTOGRAM_TIMES("LocalStorage.TimeToPrimeLocalStorage",
167 time_to_prime);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100168 map_ = new DOMStorageMap(kPerStorageAreaQuota);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100169 map_->SwapValues(&values);
170
171 size_t local_storage_size_kb = map_->bytes_used() / 1024;
172 // Track localStorage size, from 0-6MB. Note that the maximum size should be
173 // 5MB, but we add some slop since we want to make sure the max size is always
174 // above what we see in practice, since histograms can't change.
175 UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.RendererLocalStorageSizeInKB",
176 local_storage_size_kb,
177 0, 6 * 1024, 50);
178 if (local_storage_size_kb < 100) {
179 UMA_HISTOGRAM_TIMES(
180 "LocalStorage.RendererTimeToPrimeLocalStorageUnder100KB",
181 time_to_prime);
182 } else if (local_storage_size_kb < 1000) {
183 UMA_HISTOGRAM_TIMES(
184 "LocalStorage.RendererTimeToPrimeLocalStorage100KBTo1MB",
185 time_to_prime);
186 } else {
187 UMA_HISTOGRAM_TIMES(
188 "LocalStorage.RendererTimeToPrimeLocalStorage1MBTo5MB",
189 time_to_prime);
190 }
191}
192
Ben Murdochbb1529c2013-08-08 10:24:53 +0100193void DOMStorageCachedArea::Reset() {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100194 map_ = NULL;
195 weak_factory_.InvalidateWeakPtrs();
196 ignore_key_mutations_.clear();
197 ignore_all_mutations_ = false;
198}
199
Ben Murdochbb1529c2013-08-08 10:24:53 +0100200void DOMStorageCachedArea::OnLoadComplete(bool success) {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100201 DCHECK(success);
202 DCHECK(ignore_all_mutations_);
203 ignore_all_mutations_ = false;
204}
205
Ben Murdochbb1529c2013-08-08 10:24:53 +0100206void DOMStorageCachedArea::OnSetItemComplete(const base::string16& key,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100207 bool success) {
208 if (!success) {
209 Reset();
210 return;
211 }
212 std::map<base::string16, int>::iterator found =
213 ignore_key_mutations_.find(key);
214 DCHECK(found != ignore_key_mutations_.end());
215 if (--found->second == 0)
216 ignore_key_mutations_.erase(found);
217}
218
Ben Murdochbb1529c2013-08-08 10:24:53 +0100219void DOMStorageCachedArea::OnRemoveItemComplete(const base::string16& key,
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100220 bool success) {
221 DCHECK(success);
222 std::map<base::string16, int>::iterator found =
223 ignore_key_mutations_.find(key);
224 DCHECK(found != ignore_key_mutations_.end());
225 if (--found->second == 0)
226 ignore_key_mutations_.erase(found);
227}
228
Ben Murdochbb1529c2013-08-08 10:24:53 +0100229void DOMStorageCachedArea::OnClearComplete(bool success) {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100230 DCHECK(success);
231 DCHECK(ignore_all_mutations_);
232 ignore_all_mutations_ = false;
233}
234
235} // namespace content