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

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: 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/strings/string_split.h"
9 #include "content/common/dom_storage/dom_storage_map.h"
7 #include "content/common/storage_partition_service.mojom.h" 10 #include "content/common/storage_partition_service.mojom.h"
11 #include "content/renderer/dom_storage/local_storage_area.h"
8 #include "content/renderer/dom_storage/local_storage_cached_areas.h" 12 #include "content/renderer/dom_storage/local_storage_cached_areas.h"
13 #include "mojo/common/common_type_converters.h"
14 #include "third_party/WebKit/public/platform/WebURL.h"
15 #include "third_party/WebKit/public/web/WebStorageEventDispatcher.h"
16 #include "url/gurl.h"
9 17
10 namespace content { 18 namespace content {
11 19
20 // These methods are used to pack and unpack the page_url/storage_area_id into
21 // source strings to/from the browser.
22 std::string PackSource(const GURL& page_url,
23 const std::string& storage_area_id) {
24 return page_url.spec() + "\n" + storage_area_id;
dcheng 2016/03/18 06:35:29 Can GURL::spec() contain raw newlines?
jam 2016/03/18 16:48:33 no (that's why i used it. it's one of the characte
25 }
26
27 void UnpackSource(const mojo::String& source,
28 GURL* page_url,
29 std::string* storage_area_id) {
30 std::vector<std::string> result = base::SplitString(
31 source.To<std::string>(), "\n", base::KEEP_WHITESPACE,
32 base::SPLIT_WANT_ALL);
33 DCHECK_EQ(result.size(), 2u);
34 *page_url = GURL(result[0]);
35 *storage_area_id = result[1];
36 }
37
12 LocalStorageCachedArea::LocalStorageCachedArea( 38 LocalStorageCachedArea::LocalStorageCachedArea(
13 const url::Origin& origin, 39 const url::Origin& origin,
14 StoragePartitionService* storage_partition_service, 40 StoragePartitionService* storage_partition_service,
15 LocalStorageCachedAreas* cached_areas) 41 LocalStorageCachedAreas* cached_areas)
16 : loaded_(false), origin_(origin), binding_(this), 42 : loaded_(false), origin_(origin), binding_(this),
17 cached_areas_(cached_areas) { 43 cached_areas_(cached_areas) {
18 storage_partition_service->OpenLocalStorage( 44 storage_partition_service->OpenLocalStorage(
19 origin_, mojo::GetProxy(&leveldb_)); 45 origin_, mojo::GetProxy(&leveldb_));
20 } 46 }
21 47
22 LocalStorageCachedArea::~LocalStorageCachedArea() { 48 LocalStorageCachedArea::~LocalStorageCachedArea() {
23 cached_areas_->LocalStorageCacheAreaClosed(this); 49 cached_areas_->LocalStorageCacheAreaClosed(this);
24 } 50 }
25 51
26 unsigned LocalStorageCachedArea::GetLength() { 52 unsigned LocalStorageCachedArea::GetLength() {
27 EnsureLoaded(); 53 EnsureLoaded();
28 return 0u; 54 return map_->Length();
29 } 55 }
30 56
31 base::NullableString16 LocalStorageCachedArea::GetKey(unsigned index) { 57 base::NullableString16 LocalStorageCachedArea::GetKey(unsigned index) {
32 EnsureLoaded(); 58 EnsureLoaded();
33 return base::NullableString16(); 59 return map_->Key(index);
34 } 60 }
35 61
36 base::NullableString16 LocalStorageCachedArea::GetItem( 62 base::NullableString16 LocalStorageCachedArea::GetItem(
37 const base::string16& key) { 63 const base::string16& key) {
38 EnsureLoaded(); 64 EnsureLoaded();
39 return base::NullableString16(); 65 return map_->GetItem(key);
40 } 66 }
michaeln 2016/03/18 01:05:16 do we care about retaining this behavior? // Su
jam 2016/03/18 16:48:33 good question. i should have called it out that i
michaeln 2016/03/18 22:01:14 per our hallway discussion... nevermind :) mojo h
41 67
42 bool LocalStorageCachedArea::SetItem(const base::string16& key, 68 bool LocalStorageCachedArea::SetItem(const base::string16& key,
43 const base::string16& value, 69 const base::string16& value,
44 const GURL& page_url) { 70 const GURL& page_url,
71 const std::string& storage_area_id) {
72 // A quick check to reject obviously overbudget items to avoid priming the
73 // cache.
74 if (key.length() + value.length() > kPerStorageAreaQuota)
75 return false;
76
45 EnsureLoaded(); 77 EnsureLoaded();
46 return false; 78 base::NullableString16 unused;
79 if (!map_->SetItem(key, value, &unused))
80 return false;
81
82 // Ignore mutations to 'key' until OnSetItemComplete.
83 ignore_key_mutations_[key]++;
84 leveldb_->Put(mojo::Array<uint8_t>::From(key),
85 mojo::Array<uint8_t>::From(value),
86 PackSource(page_url, storage_area_id),
87 base::Bind(&LocalStorageCachedArea::OnSetItemComplete,
88 base::Unretained(this), key));
89 return true;
47 } 90 }
48 91
49 void LocalStorageCachedArea::RemoveItem(const base::string16& key, 92 void LocalStorageCachedArea::RemoveItem(const base::string16& key,
50 const GURL& page_url) { 93 const GURL& page_url,
94 const std::string& storage_area_id) {
51 EnsureLoaded(); 95 EnsureLoaded();
96 base::string16 unused;
97 if (!map_->RemoveItem(key, &unused))
98 return;
99
100 // Ignore mutations to 'key' until OnRemoveItemComplete.
101 ignore_key_mutations_[key]++;
102 leveldb_->Delete(mojo::Array<uint8_t>::From(key),
103 PackSource(page_url, storage_area_id),
104 base::Bind(&LocalStorageCachedArea::OnRemoveItemComplete,
105 base::Unretained(this), key));
52 } 106 }
53 107
54 void LocalStorageCachedArea::Clear(const GURL& page_url) { 108 void LocalStorageCachedArea::Clear(const GURL& page_url,
109 const std::string& storage_area_id) {
55 // No need to prime the cache in this case. 110 // No need to prime the cache in this case.
56 111
112 Reset();
113 map_ = new DOMStorageMap(kPerStorageAreaQuota);
57 binding_.Close(); 114 binding_.Close();
58 // TODO: 115
59 // binding_.CreateInterfacePtrAndBind() 116 leveldb_->DeleteAll(binding_.CreateInterfacePtrAndBind(),
117 PackSource(page_url, storage_area_id),
118 base::Bind(&LocalStorageCachedArea::OnClearComplete,
119 base::Unretained(this)));
120 }
121
122 void LocalStorageCachedArea::LocalStorageAreaCreated(LocalStorageArea* area) {
123 areas_[area->id()] = area;
124 }
125
126 void LocalStorageCachedArea::LocalStorageAreaDestroyed(LocalStorageArea* area) {
127 areas_.erase(area->id());
michaeln 2016/03/18 01:05:17 Where is the LocalStorageCachedArea deleted? I th
jam 2016/03/18 16:48:33 ah I forgot to add that (hard to remember this stu
60 } 128 }
61 129
62 void LocalStorageCachedArea::KeyChanged(mojo::Array<uint8_t> key, 130 void LocalStorageCachedArea::KeyChanged(mojo::Array<uint8_t> key,
63 mojo::Array<uint8_t> new_value, 131 mojo::Array<uint8_t> new_value,
64 mojo::Array<uint8_t> old_value, 132 mojo::Array<uint8_t> old_value,
65 const mojo::String& source) { 133 const mojo::String& source) {
134 GURL page_url;
135 std::string storage_area_id;
136 UnpackSource(source, &page_url, &storage_area_id);
137
138 base::string16 key_string = key.To<base::string16>();
139 base::string16 new_value_string = new_value.To<base::string16>();
140
141 blink::WebStorageArea* originating_area = nullptr;
142 if (areas_.find(storage_area_id) != areas_.end()) {
143 // The source storage area is in this process.
144 originating_area = areas_[storage_area_id];
145 } else {
146 // This was from another process, so apply it to our cache if we haven't
147 // already changed it and are waiting for the confirmation callback.
michaeln 2016/03/18 01:05:17 i'm not sure this holds true if the originating wa
jam 2016/03/18 16:48:33 this is covered by the fact that observers are cal
michaeln 2016/03/18 22:01:14 ah, yes, i see! ok, please update the comment to
jam 2016/03/18 22:15:01 Done.
148 if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) {
149 // We turn off quota checking here to accomodate the over budget allowance
150 // that's provided in the browser process.
151 base::NullableString16 unused;
152 map_->set_quota(std::numeric_limits<int32_t>::max());
153 map_->SetItem(key_string, new_value_string, &unused);
154 map_->set_quota(kPerStorageAreaQuota);
155 }
156 }
157
158 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent(
159 key_string, old_value.To<base::string16>(), new_value_string,
160 GURL(origin_.Serialize()), page_url, originating_area);
66 } 161 }
67 162
68 void LocalStorageCachedArea::KeyDeleted(mojo::Array<uint8_t> key, 163 void LocalStorageCachedArea::KeyDeleted(mojo::Array<uint8_t> key,
164 mojo::Array<uint8_t> old_value,
69 const mojo::String& source) { 165 const mojo::String& source) {
166 GURL page_url;
167 std::string storage_area_id;
168 UnpackSource(source, &page_url, &storage_area_id);
169
170 base::string16 key_string = key.To<base::string16>();
171
172 blink::WebStorageArea* originating_area = nullptr;
173 if (areas_.find(storage_area_id) != areas_.end()) {
174 // The source storage area is in this process.
175 originating_area = areas_[storage_area_id];
176 } else {
177 // This was from another process, so remove it from our cache if we haven't
178 // already changed it and are waiting for the confirmation callback.
179 if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) {
180 base::string16 unused;
181 map_->RemoveItem(key_string, &unused);
182 }
183 }
184
185 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent(
186 key_string, old_value.To<base::string16>(), base::NullableString16(),
187 GURL(origin_.Serialize()), page_url, originating_area);
70 } 188 }
71 189
72 void LocalStorageCachedArea::AllDeleted(const mojo::String& source) { 190 void LocalStorageCachedArea::AllDeleted(const mojo::String& source) {
191 GURL page_url;
192 std::string storage_area_id;
193 UnpackSource(source, &page_url, &storage_area_id);
194
195 blink::WebStorageArea* originating_area = nullptr;
196 if (areas_.find(storage_area_id) != areas_.end()) {
197 // The source storage area is in this process.
198 originating_area = areas_[storage_area_id];
199 } else {
200 scoped_refptr<DOMStorageMap> old = map_;
201 map_ = new DOMStorageMap(kPerStorageAreaQuota);
202
203 // We have to retain local additions which happened after this clear
204 // operation from another process.
205 std::map<base::string16, int>::iterator iter =
206 ignore_key_mutations_.begin();
207 while (iter != ignore_key_mutations_.end()) {
208 base::NullableString16 value = old->GetItem(iter->first);
209 if (!value.is_null()) {
210 base::NullableString16 unused;
211 map_->SetItem(iter->first, value.string(), &unused);
212 }
213 ++iter;
214 }
215 }
216
217 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent(
218 base::NullableString16(), base::NullableString16(),
219 base::NullableString16(), GURL(origin_.Serialize()), page_url,
220 originating_area);
73 } 221 }
74 222
75 void LocalStorageCachedArea::EnsureLoaded() { 223 void LocalStorageCachedArea::EnsureLoaded() {
76 if (loaded_) 224 if (loaded_)
77 return; 225 return;
78 226
79 loaded_ = true; 227 loaded_ = true;
80 leveldb::DatabaseError status = leveldb::DatabaseError::OK; 228 leveldb::DatabaseError status = leveldb::DatabaseError::OK;
81 mojo::Array<content::KeyValuePtr> data; 229 mojo::Array<content::KeyValuePtr> data;
82 leveldb_->GetAll(binding_.CreateInterfacePtrAndBind(), &status, &data); 230 leveldb_->GetAll(binding_.CreateInterfacePtrAndBind(), &status, &data);
231
232 DOMStorageValuesMap values;
233 for (size_t i = 0; i < data.size(); ++i) {
234 values[data[i]->key.To<base::string16>()] =
235 base::NullableString16(data[i]->value.To<base::string16>(), false);
236 }
237
238 map_ = new DOMStorageMap(kPerStorageAreaQuota);
239 map_->SwapValues(&values);
michaeln 2016/03/18 01:05:17 wdyt about creating parallel TimeToPrime uma stats
jam 2016/03/18 16:48:33 good idea, done
240 }
241
242 void LocalStorageCachedArea::OnSetItemComplete(const base::string16& key,
243 leveldb::DatabaseError result) {
244 if (result != leveldb::DatabaseError::OK) {
245 Reset();
246 return;
247 }
248 std::map<base::string16, int>::iterator found =
michaeln 2016/03/18 01:05:17 maybe use auto here for readability?
jam 2016/03/18 16:48:33 Done.
249 ignore_key_mutations_.find(key);
250 DCHECK(found != ignore_key_mutations_.end());
251 if (--found->second == 0)
252 ignore_key_mutations_.erase(found);
253 }
254
255 void LocalStorageCachedArea::OnRemoveItemComplete(
michaeln 2016/03/18 01:05:17 looks like we could share code for OnSet and OnRem
jam 2016/03/18 16:48:33 it's 3 lines ignoring the dcheck; i didn't think i
256 const base::string16& key, leveldb::DatabaseError result) {
257 DCHECK_EQ(result, leveldb::DatabaseError::OK);
258 std::map<base::string16, int>::iterator found =
259 ignore_key_mutations_.find(key);
260 DCHECK(found != ignore_key_mutations_.end());
261 if (--found->second == 0)
262 ignore_key_mutations_.erase(found);
263 }
264
265 void LocalStorageCachedArea::OnClearComplete(leveldb::DatabaseError result) {
michaeln 2016/03/18 01:05:17 maybe we don't need this callback, i think recreat
jam 2016/03/18 16:48:33 i kept it just so we can have a DCHECK during test
266 DCHECK_EQ(result, leveldb::DatabaseError::OK);
267 }
268
269 void LocalStorageCachedArea::Reset() {
270 map_ = NULL;
271 ignore_key_mutations_.clear();
83 } 272 }
84 273
85 } // namespace content 274 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698