Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: content/renderer/dom_storage/local_storage_cached_area.cc

Issue 1814003002: Implement the renderer side of the mojo based local storage implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: review comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/dom_storage/local_storage_cached_area.h" 5 #include "content/renderer/dom_storage/local_storage_cached_area.h"
6 6
7 #include "base/bind.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/strings/string_split.h"
10 #include "base/time/time.h"
11 #include "content/common/dom_storage/dom_storage_map.h"
7 #include "content/common/storage_partition_service.mojom.h" 12 #include "content/common/storage_partition_service.mojom.h"
13 #include "content/renderer/dom_storage/local_storage_area.h"
8 #include "content/renderer/dom_storage/local_storage_cached_areas.h" 14 #include "content/renderer/dom_storage/local_storage_cached_areas.h"
15 #include "mojo/common/common_type_converters.h"
16 #include "third_party/WebKit/public/platform/WebURL.h"
17 #include "third_party/WebKit/public/web/WebStorageEventDispatcher.h"
18 #include "url/gurl.h"
9 19
10 namespace content { 20 namespace content {
11 21
22 // These methods are used to pack and unpack the page_url/storage_area_id into
23 // source strings to/from the browser.
24 std::string PackSource(const GURL& page_url,
25 const std::string& storage_area_id) {
26 return page_url.spec() + "\n" + storage_area_id;
27 }
28
29 void UnpackSource(const mojo::String& source,
30 GURL* page_url,
31 std::string* storage_area_id) {
32 std::vector<std::string> result = base::SplitString(
33 source.To<std::string>(), "\n", base::KEEP_WHITESPACE,
34 base::SPLIT_WANT_ALL);
35 DCHECK_EQ(result.size(), 2u);
36 *page_url = GURL(result[0]);
37 *storage_area_id = result[1];
38 }
39
12 LocalStorageCachedArea::LocalStorageCachedArea( 40 LocalStorageCachedArea::LocalStorageCachedArea(
13 const url::Origin& origin, 41 const url::Origin& origin,
14 StoragePartitionService* storage_partition_service, 42 StoragePartitionService* storage_partition_service,
15 LocalStorageCachedAreas* cached_areas) 43 LocalStorageCachedAreas* cached_areas)
16 : loaded_(false), origin_(origin), binding_(this), 44 : loaded_(false), origin_(origin), binding_(this),
17 cached_areas_(cached_areas) { 45 cached_areas_(cached_areas) {
18 storage_partition_service->OpenLocalStorage( 46 storage_partition_service->OpenLocalStorage(
19 origin_, mojo::GetProxy(&leveldb_)); 47 origin_, mojo::GetProxy(&leveldb_));
20 } 48 }
21 49
22 LocalStorageCachedArea::~LocalStorageCachedArea() { 50 LocalStorageCachedArea::~LocalStorageCachedArea() {
23 cached_areas_->LocalStorageCacheAreaClosed(this); 51 cached_areas_->CacheAreaClosed(this);
24 } 52 }
25 53
26 unsigned LocalStorageCachedArea::GetLength() { 54 unsigned LocalStorageCachedArea::GetLength() {
27 EnsureLoaded(); 55 EnsureLoaded();
28 return 0u; 56 return map_->Length();
29 } 57 }
30 58
31 base::NullableString16 LocalStorageCachedArea::GetKey(unsigned index) { 59 base::NullableString16 LocalStorageCachedArea::GetKey(unsigned index) {
32 EnsureLoaded(); 60 EnsureLoaded();
33 return base::NullableString16(); 61 return map_->Key(index);
34 } 62 }
35 63
36 base::NullableString16 LocalStorageCachedArea::GetItem( 64 base::NullableString16 LocalStorageCachedArea::GetItem(
37 const base::string16& key) { 65 const base::string16& key) {
38 EnsureLoaded(); 66 EnsureLoaded();
39 return base::NullableString16(); 67 return map_->GetItem(key);
40 } 68 }
41 69
42 bool LocalStorageCachedArea::SetItem(const base::string16& key, 70 bool LocalStorageCachedArea::SetItem(const base::string16& key,
43 const base::string16& value, 71 const base::string16& value,
44 const GURL& page_url) { 72 const GURL& page_url,
73 const std::string& storage_area_id) {
74 // A quick check to reject obviously overbudget items to avoid priming the
75 // cache.
76 if (key.length() + value.length() > kPerStorageAreaQuota)
77 return false;
78
45 EnsureLoaded(); 79 EnsureLoaded();
46 return false; 80 base::NullableString16 unused;
81 if (!map_->SetItem(key, value, &unused))
82 return false;
83
84 // Ignore mutations to |key| until OnSetItemComplete.
85 ignore_key_mutations_[key]++;
86 leveldb_->Put(mojo::Array<uint8_t>::From(key),
87 mojo::Array<uint8_t>::From(value),
88 PackSource(page_url, storage_area_id),
89 base::Bind(&LocalStorageCachedArea::OnSetItemComplete,
90 base::Unretained(this), key));
91 return true;
47 } 92 }
48 93
49 void LocalStorageCachedArea::RemoveItem(const base::string16& key, 94 void LocalStorageCachedArea::RemoveItem(const base::string16& key,
50 const GURL& page_url) { 95 const GURL& page_url,
96 const std::string& storage_area_id) {
51 EnsureLoaded(); 97 EnsureLoaded();
98 base::string16 unused;
99 if (!map_->RemoveItem(key, &unused))
100 return;
101
102 // Ignore mutations to |key| until OnRemoveItemComplete.
103 ignore_key_mutations_[key]++;
104 leveldb_->Delete(mojo::Array<uint8_t>::From(key),
105 PackSource(page_url, storage_area_id),
106 base::Bind(&LocalStorageCachedArea::OnRemoveItemComplete,
107 base::Unretained(this), key));
52 } 108 }
53 109
54 void LocalStorageCachedArea::Clear(const GURL& page_url) { 110 void LocalStorageCachedArea::Clear(const GURL& page_url,
111 const std::string& storage_area_id) {
55 // No need to prime the cache in this case. 112 // No need to prime the cache in this case.
56 113
114 Reset();
115 map_ = new DOMStorageMap(kPerStorageAreaQuota);
57 binding_.Close(); 116 binding_.Close();
58 // TODO: 117
59 // binding_.CreateInterfacePtrAndBind() 118 leveldb_->DeleteAll(binding_.CreateInterfacePtrAndBind(),
119 PackSource(page_url, storage_area_id),
120 base::Bind(&LocalStorageCachedArea::OnClearComplete,
121 base::Unretained(this)));
122 }
123
124 void LocalStorageCachedArea::AreaCreated(LocalStorageArea* area) {
125 areas_[area->id()] = area;
126 }
127
128 void LocalStorageCachedArea::AreaDestroyed(LocalStorageArea* area) {
129 areas_.erase(area->id());
60 } 130 }
61 131
62 void LocalStorageCachedArea::KeyChanged(mojo::Array<uint8_t> key, 132 void LocalStorageCachedArea::KeyChanged(mojo::Array<uint8_t> key,
63 mojo::Array<uint8_t> new_value, 133 mojo::Array<uint8_t> new_value,
64 mojo::Array<uint8_t> old_value, 134 mojo::Array<uint8_t> old_value,
65 const mojo::String& source) { 135 const mojo::String& source) {
136 GURL page_url;
137 std::string storage_area_id;
138 UnpackSource(source, &page_url, &storage_area_id);
139
140 base::string16 key_string = key.To<base::string16>();
141 base::string16 new_value_string = new_value.To<base::string16>();
142
143 blink::WebStorageArea* originating_area = nullptr;
144 if (areas_.find(storage_area_id) != areas_.end()) {
145 // The source storage area is in this process.
146 originating_area = areas_[storage_area_id];
147 } else {
148 // This was from another process or the storage area is gone. If the former,
149 // apply it to our cache if we haven't already changed it and are waiting
150 // for the confirmation callback. In the latter case, we won't do anything
151 // because ignore_key_mutations_ won't be updated until the callback runs.
152 if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) {
153 // We turn off quota checking here to accomodate the over budget allowance
154 // that's provided in the browser process.
155 base::NullableString16 unused;
156 map_->set_quota(std::numeric_limits<int32_t>::max());
157 map_->SetItem(key_string, new_value_string, &unused);
158 map_->set_quota(kPerStorageAreaQuota);
159 }
160 }
161
162 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent(
163 key_string, old_value.To<base::string16>(), new_value_string,
164 GURL(origin_.Serialize()), page_url, originating_area);
66 } 165 }
67 166
68 void LocalStorageCachedArea::KeyDeleted(mojo::Array<uint8_t> key, 167 void LocalStorageCachedArea::KeyDeleted(mojo::Array<uint8_t> key,
168 mojo::Array<uint8_t> old_value,
69 const mojo::String& source) { 169 const mojo::String& source) {
170 GURL page_url;
171 std::string storage_area_id;
172 UnpackSource(source, &page_url, &storage_area_id);
173
174 base::string16 key_string = key.To<base::string16>();
175
176 blink::WebStorageArea* originating_area = nullptr;
177 if (areas_.find(storage_area_id) != areas_.end()) {
178 // The source storage area is in this process.
179 originating_area = areas_[storage_area_id];
180 } else {
181 // This was from another process or the storage area is gone. If the former,
182 // remove it from our cache if we haven't already changed it and are waiting
183 // for the confirmation callback. In the latter case, we won't do anything
184 // because ignore_key_mutations_ won't be updated until the callback runs.
185 if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) {
186 base::string16 unused;
187 map_->RemoveItem(key_string, &unused);
188 }
189 }
190
191 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent(
192 key_string, old_value.To<base::string16>(), base::NullableString16(),
193 GURL(origin_.Serialize()), page_url, originating_area);
70 } 194 }
71 195
72 void LocalStorageCachedArea::AllDeleted(const mojo::String& source) { 196 void LocalStorageCachedArea::AllDeleted(const mojo::String& source) {
197 GURL page_url;
198 std::string storage_area_id;
199 UnpackSource(source, &page_url, &storage_area_id);
200
201 blink::WebStorageArea* originating_area = nullptr;
202 if (areas_.find(storage_area_id) != areas_.end()) {
203 // The source storage area is in this process.
204 originating_area = areas_[storage_area_id];
205 } else {
206 scoped_refptr<DOMStorageMap> old = map_;
207 map_ = new DOMStorageMap(kPerStorageAreaQuota);
208
209 // We have to retain local additions which happened after this clear
210 // operation from another process.
211 auto iter = ignore_key_mutations_.begin();
212 while (iter != ignore_key_mutations_.end()) {
213 base::NullableString16 value = old->GetItem(iter->first);
214 if (!value.is_null()) {
215 base::NullableString16 unused;
216 map_->SetItem(iter->first, value.string(), &unused);
217 }
218 ++iter;
219 }
220 }
221
222 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent(
223 base::NullableString16(), base::NullableString16(),
224 base::NullableString16(), GURL(origin_.Serialize()), page_url,
225 originating_area);
73 } 226 }
74 227
75 void LocalStorageCachedArea::EnsureLoaded() { 228 void LocalStorageCachedArea::EnsureLoaded() {
76 if (loaded_) 229 if (loaded_)
77 return; 230 return;
78 231
79 loaded_ = true; 232 loaded_ = true;
233 base::TimeTicks before = base::TimeTicks::Now();
80 leveldb::DatabaseError status = leveldb::DatabaseError::OK; 234 leveldb::DatabaseError status = leveldb::DatabaseError::OK;
81 mojo::Array<content::KeyValuePtr> data; 235 mojo::Array<content::KeyValuePtr> data;
82 leveldb_->GetAll(binding_.CreateInterfacePtrAndBind(), &status, &data); 236 leveldb_->GetAll(binding_.CreateInterfacePtrAndBind(), &status, &data);
237
238 DOMStorageValuesMap values;
239 for (size_t i = 0; i < data.size(); ++i) {
240 values[data[i]->key.To<base::string16>()] =
241 base::NullableString16(data[i]->value.To<base::string16>(), false);
242 }
243
244 map_ = new DOMStorageMap(kPerStorageAreaQuota);
245 map_->SwapValues(&values);
246
247 base::TimeDelta time_to_prime = base::TimeTicks::Now() - before;
248 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrime", time_to_prime);
249
250 size_t local_storage_size_kb = map_->bytes_used() / 1024;
251 // Track localStorage size, from 0-6MB. Note that the maximum size should be
252 // 5MB, but we add some slop since we want to make sure the max size is always
253 // above what we see in practice, since histograms can't change.
254 UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.MojoSizeInKB",
255 local_storage_size_kb,
256 0, 6 * 1024, 50);
257 if (local_storage_size_kb < 100) {
258 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrimeForUnder100KB",
259 time_to_prime);
260 } else if (local_storage_size_kb < 1000) {
261 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrimeFor100KBTo1MB",
262 time_to_prime);
263 } else {
264 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrimeFor1MBTo5MB",
265 time_to_prime);
266 }
267 }
268
269 void LocalStorageCachedArea::OnSetItemComplete(const base::string16& key,
270 leveldb::DatabaseError result) {
271 if (result != leveldb::DatabaseError::OK) {
272 Reset();
273 return;
274 }
275
276 auto found = ignore_key_mutations_.find(key);
277 DCHECK(found != ignore_key_mutations_.end());
278 if (--found->second == 0)
279 ignore_key_mutations_.erase(found);
280 }
281
282 void LocalStorageCachedArea::OnRemoveItemComplete(
283 const base::string16& key, leveldb::DatabaseError result) {
284 DCHECK_EQ(result, leveldb::DatabaseError::OK);
285 auto found = ignore_key_mutations_.find(key);
286 DCHECK(found != ignore_key_mutations_.end());
287 if (--found->second == 0)
288 ignore_key_mutations_.erase(found);
289 }
290
291 void LocalStorageCachedArea::OnClearComplete(leveldb::DatabaseError result) {
292 DCHECK_EQ(result, leveldb::DatabaseError::OK);
293 }
294
295 void LocalStorageCachedArea::Reset() {
296 map_ = NULL;
297 ignore_key_mutations_.clear();
83 } 298 }
84 299
85 } // namespace content 300 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/dom_storage/local_storage_cached_area.h ('k') | content/renderer/dom_storage/local_storage_cached_areas.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698