OLD | NEW |
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" | 7 #include "base/bind.h" |
8 #include "base/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
| 9 #include "base/rand_util.h" |
9 #include "base/strings/string_split.h" | 10 #include "base/strings/string_split.h" |
10 #include "base/time/time.h" | 11 #include "base/time/time.h" |
11 #include "content/common/dom_storage/dom_storage_map.h" | 12 #include "content/common/dom_storage/dom_storage_map.h" |
12 #include "content/common/storage_partition_service.mojom.h" | 13 #include "content/common/storage_partition_service.mojom.h" |
13 #include "content/renderer/dom_storage/local_storage_area.h" | 14 #include "content/renderer/dom_storage/local_storage_area.h" |
14 #include "content/renderer/dom_storage/local_storage_cached_areas.h" | 15 #include "content/renderer/dom_storage/local_storage_cached_areas.h" |
15 #include "mojo/common/common_type_converters.h" | 16 #include "mojo/common/common_type_converters.h" |
16 #include "third_party/WebKit/public/platform/WebURL.h" | 17 #include "third_party/WebKit/public/platform/WebURL.h" |
17 #include "third_party/WebKit/public/web/WebStorageEventDispatcher.h" | 18 #include "third_party/WebKit/public/web/WebStorageEventDispatcher.h" |
18 #include "url/gurl.h" | 19 #include "url/gurl.h" |
(...skipping 15 matching lines...) Expand all Loading... |
34 base::SPLIT_WANT_ALL); | 35 base::SPLIT_WANT_ALL); |
35 DCHECK_EQ(result.size(), 2u); | 36 DCHECK_EQ(result.size(), 2u); |
36 *page_url = GURL(result[0]); | 37 *page_url = GURL(result[0]); |
37 *storage_area_id = result[1]; | 38 *storage_area_id = result[1]; |
38 } | 39 } |
39 | 40 |
40 LocalStorageCachedArea::LocalStorageCachedArea( | 41 LocalStorageCachedArea::LocalStorageCachedArea( |
41 const url::Origin& origin, | 42 const url::Origin& origin, |
42 StoragePartitionService* storage_partition_service, | 43 StoragePartitionService* storage_partition_service, |
43 LocalStorageCachedAreas* cached_areas) | 44 LocalStorageCachedAreas* cached_areas) |
44 : loaded_(false), origin_(origin), binding_(this), | 45 : origin_(origin), binding_(this), |
45 cached_areas_(cached_areas) { | 46 cached_areas_(cached_areas), weak_factory_(this) { |
46 storage_partition_service->OpenLocalStorage( | 47 storage_partition_service->OpenLocalStorage( |
47 origin_, mojo::GetProxy(&leveldb_)); | 48 origin_, mojo::GetProxy(&leveldb_)); |
| 49 leveldb_->AddObserver(binding_.CreateInterfacePtrAndBind()); |
48 } | 50 } |
49 | 51 |
50 LocalStorageCachedArea::~LocalStorageCachedArea() { | 52 LocalStorageCachedArea::~LocalStorageCachedArea() { |
51 cached_areas_->CacheAreaClosed(this); | 53 cached_areas_->CacheAreaClosed(this); |
52 } | 54 } |
53 | 55 |
54 unsigned LocalStorageCachedArea::GetLength() { | 56 unsigned LocalStorageCachedArea::GetLength() { |
55 EnsureLoaded(); | 57 EnsureLoaded(); |
56 return map_->Length(); | 58 return map_->Length(); |
57 } | 59 } |
(...skipping 22 matching lines...) Expand all Loading... |
80 base::NullableString16 unused; | 82 base::NullableString16 unused; |
81 if (!map_->SetItem(key, value, &unused)) | 83 if (!map_->SetItem(key, value, &unused)) |
82 return false; | 84 return false; |
83 | 85 |
84 // Ignore mutations to |key| until OnSetItemComplete. | 86 // Ignore mutations to |key| until OnSetItemComplete. |
85 ignore_key_mutations_[key]++; | 87 ignore_key_mutations_[key]++; |
86 leveldb_->Put(mojo::Array<uint8_t>::From(key), | 88 leveldb_->Put(mojo::Array<uint8_t>::From(key), |
87 mojo::Array<uint8_t>::From(value), | 89 mojo::Array<uint8_t>::From(value), |
88 PackSource(page_url, storage_area_id), | 90 PackSource(page_url, storage_area_id), |
89 base::Bind(&LocalStorageCachedArea::OnSetItemComplete, | 91 base::Bind(&LocalStorageCachedArea::OnSetItemComplete, |
90 base::Unretained(this), key)); | 92 weak_factory_.GetWeakPtr(), key)); |
91 return true; | 93 return true; |
92 } | 94 } |
93 | 95 |
94 void LocalStorageCachedArea::RemoveItem(const base::string16& key, | 96 void LocalStorageCachedArea::RemoveItem(const base::string16& key, |
95 const GURL& page_url, | 97 const GURL& page_url, |
96 const std::string& storage_area_id) { | 98 const std::string& storage_area_id) { |
97 EnsureLoaded(); | 99 EnsureLoaded(); |
98 base::string16 unused; | 100 base::string16 unused; |
99 if (!map_->RemoveItem(key, &unused)) | 101 if (!map_->RemoveItem(key, &unused)) |
100 return; | 102 return; |
101 | 103 |
102 // Ignore mutations to |key| until OnRemoveItemComplete. | 104 // Ignore mutations to |key| until OnRemoveItemComplete. |
103 ignore_key_mutations_[key]++; | 105 ignore_key_mutations_[key]++; |
104 leveldb_->Delete(mojo::Array<uint8_t>::From(key), | 106 leveldb_->Delete(mojo::Array<uint8_t>::From(key), |
105 PackSource(page_url, storage_area_id), | 107 PackSource(page_url, storage_area_id), |
106 base::Bind(&LocalStorageCachedArea::OnRemoveItemComplete, | 108 base::Bind(&LocalStorageCachedArea::OnRemoveItemComplete, |
107 base::Unretained(this), key)); | 109 weak_factory_.GetWeakPtr(), key)); |
108 } | 110 } |
109 | 111 |
110 void LocalStorageCachedArea::Clear(const GURL& page_url, | 112 void LocalStorageCachedArea::Clear(const GURL& page_url, |
111 const std::string& storage_area_id) { | 113 const std::string& storage_area_id) { |
112 // No need to prime the cache in this case. | 114 // No need to prime the cache in this case. |
113 | 115 |
114 Reset(); | 116 Reset(); |
115 map_ = new DOMStorageMap(kPerStorageAreaQuota); | 117 map_ = new DOMStorageMap(kPerStorageAreaQuota); |
116 binding_.Close(); | 118 ignore_all_mutations_ = true; |
117 | 119 leveldb_->DeleteAll(PackSource(page_url, storage_area_id), |
118 leveldb_->DeleteAll(binding_.CreateInterfacePtrAndBind(), | |
119 PackSource(page_url, storage_area_id), | |
120 base::Bind(&LocalStorageCachedArea::OnClearComplete, | 120 base::Bind(&LocalStorageCachedArea::OnClearComplete, |
121 base::Unretained(this))); | 121 weak_factory_.GetWeakPtr())); |
122 } | 122 } |
123 | 123 |
124 void LocalStorageCachedArea::AreaCreated(LocalStorageArea* area) { | 124 void LocalStorageCachedArea::AreaCreated(LocalStorageArea* area) { |
125 areas_[area->id()] = area; | 125 areas_[area->id()] = area; |
126 } | 126 } |
127 | 127 |
128 void LocalStorageCachedArea::AreaDestroyed(LocalStorageArea* area) { | 128 void LocalStorageCachedArea::AreaDestroyed(LocalStorageArea* area) { |
129 areas_.erase(area->id()); | 129 areas_.erase(area->id()); |
130 } | 130 } |
131 | 131 |
| 132 void LocalStorageCachedArea::KeyAdded(mojo::Array<uint8_t> key, |
| 133 mojo::Array<uint8_t> value, |
| 134 const mojo::String& source) { |
| 135 base::NullableString16 null_value; |
| 136 KeyAddedOrChanged(std::move(key), std::move(value), |
| 137 null_value, source); |
| 138 } |
| 139 |
132 void LocalStorageCachedArea::KeyChanged(mojo::Array<uint8_t> key, | 140 void LocalStorageCachedArea::KeyChanged(mojo::Array<uint8_t> key, |
133 mojo::Array<uint8_t> new_value, | 141 mojo::Array<uint8_t> new_value, |
134 mojo::Array<uint8_t> old_value, | 142 mojo::Array<uint8_t> old_value, |
135 const mojo::String& source) { | 143 const mojo::String& source) { |
136 GURL page_url; | 144 base::NullableString16 old_value_str(old_value.To<base::string16>(), false); |
137 std::string storage_area_id; | 145 KeyAddedOrChanged(std::move(key), std::move(new_value), |
138 UnpackSource(source, &page_url, &storage_area_id); | 146 old_value_str, source); |
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); | |
165 } | 147 } |
166 | 148 |
167 void LocalStorageCachedArea::KeyDeleted(mojo::Array<uint8_t> key, | 149 void LocalStorageCachedArea::KeyDeleted(mojo::Array<uint8_t> key, |
168 mojo::Array<uint8_t> old_value, | 150 mojo::Array<uint8_t> old_value, |
169 const mojo::String& source) { | 151 const mojo::String& source) { |
170 GURL page_url; | 152 GURL page_url; |
171 std::string storage_area_id; | 153 std::string storage_area_id; |
172 UnpackSource(source, &page_url, &storage_area_id); | 154 UnpackSource(source, &page_url, &storage_area_id); |
173 | 155 |
174 base::string16 key_string = key.To<base::string16>(); | 156 base::string16 key_string = key.To<base::string16>(); |
175 | 157 |
176 blink::WebStorageArea* originating_area = nullptr; | 158 blink::WebStorageArea* originating_area = nullptr; |
177 if (areas_.find(storage_area_id) != areas_.end()) { | 159 if (areas_.find(storage_area_id) != areas_.end()) { |
178 // The source storage area is in this process. | 160 // The source storage area is in this process. |
179 originating_area = areas_[storage_area_id]; | 161 originating_area = areas_[storage_area_id]; |
180 } else { | 162 } else if (map_.get() && !ignore_all_mutations_) { |
181 // This was from another process or the storage area is gone. If the former, | 163 // 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 | 164 // 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 | 165 // 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. | 166 // because ignore_key_mutations_ won't be updated until the callback runs. |
185 if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) { | 167 if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) { |
186 base::string16 unused; | 168 base::string16 unused; |
187 map_->RemoveItem(key_string, &unused); | 169 map_->RemoveItem(key_string, &unused); |
188 } | 170 } |
189 } | 171 } |
190 | 172 |
191 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( | 173 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( |
192 key_string, old_value.To<base::string16>(), base::NullableString16(), | 174 key_string, old_value.To<base::string16>(), base::NullableString16(), |
193 GURL(origin_.Serialize()), page_url, originating_area); | 175 GURL(origin_.Serialize()), page_url, originating_area); |
194 } | 176 } |
195 | 177 |
196 void LocalStorageCachedArea::AllDeleted(const mojo::String& source) { | 178 void LocalStorageCachedArea::AllDeleted(const mojo::String& source) { |
197 GURL page_url; | 179 GURL page_url; |
198 std::string storage_area_id; | 180 std::string storage_area_id; |
199 UnpackSource(source, &page_url, &storage_area_id); | 181 UnpackSource(source, &page_url, &storage_area_id); |
200 | 182 |
201 blink::WebStorageArea* originating_area = nullptr; | 183 blink::WebStorageArea* originating_area = nullptr; |
202 if (areas_.find(storage_area_id) != areas_.end()) { | 184 if (areas_.find(storage_area_id) != areas_.end()) { |
203 // The source storage area is in this process. | 185 // The source storage area is in this process. |
204 originating_area = areas_[storage_area_id]; | 186 originating_area = areas_[storage_area_id]; |
205 } else { | 187 } else if (map_.get() && !ignore_all_mutations_) { |
206 scoped_refptr<DOMStorageMap> old = map_; | 188 scoped_refptr<DOMStorageMap> old = map_; |
207 map_ = new DOMStorageMap(kPerStorageAreaQuota); | 189 map_ = new DOMStorageMap(kPerStorageAreaQuota); |
208 | 190 |
209 // We have to retain local additions which happened after this clear | 191 // We have to retain local additions which happened after this clear |
210 // operation from another process. | 192 // operation from another process. |
211 auto iter = ignore_key_mutations_.begin(); | 193 auto iter = ignore_key_mutations_.begin(); |
212 while (iter != ignore_key_mutations_.end()) { | 194 while (iter != ignore_key_mutations_.end()) { |
213 base::NullableString16 value = old->GetItem(iter->first); | 195 base::NullableString16 value = old->GetItem(iter->first); |
214 if (!value.is_null()) { | 196 if (!value.is_null()) { |
215 base::NullableString16 unused; | 197 base::NullableString16 unused; |
216 map_->SetItem(iter->first, value.string(), &unused); | 198 map_->SetItem(iter->first, value.string(), &unused); |
217 } | 199 } |
218 ++iter; | 200 ++iter; |
219 } | 201 } |
220 } | 202 } |
221 | 203 |
222 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( | 204 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( |
223 base::NullableString16(), base::NullableString16(), | 205 base::NullableString16(), base::NullableString16(), |
224 base::NullableString16(), GURL(origin_.Serialize()), page_url, | 206 base::NullableString16(), GURL(origin_.Serialize()), page_url, |
225 originating_area); | 207 originating_area); |
226 } | 208 } |
227 | 209 |
| 210 void LocalStorageCachedArea::GetAllComplete(uint64_t request_id) { |
| 211 if (request_id == get_all_request_id_) { |
| 212 DCHECK(ignore_all_mutations_); |
| 213 ignore_all_mutations_ = false; |
| 214 get_all_request_id_ = 0; |
| 215 } |
| 216 } |
| 217 |
| 218 void LocalStorageCachedArea::KeyAddedOrChanged( |
| 219 mojo::Array<uint8_t> key, |
| 220 mojo::Array<uint8_t> new_value, |
| 221 base::NullableString16& old_value, |
| 222 const mojo::String& source) { |
| 223 GURL page_url; |
| 224 std::string storage_area_id; |
| 225 UnpackSource(source, &page_url, &storage_area_id); |
| 226 |
| 227 base::string16 key_string = key.To<base::string16>(); |
| 228 base::string16 new_value_string = new_value.To<base::string16>(); |
| 229 |
| 230 blink::WebStorageArea* originating_area = nullptr; |
| 231 if (areas_.find(storage_area_id) != areas_.end()) { |
| 232 // The source storage area is in this process. |
| 233 originating_area = areas_[storage_area_id]; |
| 234 } else if (map_.get() && !ignore_all_mutations_) { |
| 235 // This was from another process or the storage area is gone. If the former, |
| 236 // apply it to our cache if we haven't already changed it and are waiting |
| 237 // for the confirmation callback. In the latter case, we won't do anything |
| 238 // because ignore_key_mutations_ won't be updated until the callback runs. |
| 239 if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) { |
| 240 // We turn off quota checking here to accomodate the over budget allowance |
| 241 // that's provided in the browser process. |
| 242 base::NullableString16 unused; |
| 243 map_->set_quota(std::numeric_limits<int32_t>::max()); |
| 244 map_->SetItem(key_string, new_value_string, &unused); |
| 245 map_->set_quota(kPerStorageAreaQuota); |
| 246 } |
| 247 } |
| 248 |
| 249 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( |
| 250 key_string, old_value, new_value_string, |
| 251 GURL(origin_.Serialize()), page_url, originating_area); |
| 252 |
| 253 } |
| 254 |
228 void LocalStorageCachedArea::EnsureLoaded() { | 255 void LocalStorageCachedArea::EnsureLoaded() { |
229 if (loaded_) | 256 if (map_.get()) |
230 return; | 257 return; |
231 | 258 |
232 loaded_ = true; | |
233 base::TimeTicks before = base::TimeTicks::Now(); | 259 base::TimeTicks before = base::TimeTicks::Now(); |
| 260 ignore_all_mutations_ = true; |
| 261 do { |
| 262 get_all_request_id_ = base::RandUint64(); |
| 263 } while(!get_all_request_id_); |
234 leveldb::DatabaseError status = leveldb::DatabaseError::OK; | 264 leveldb::DatabaseError status = leveldb::DatabaseError::OK; |
235 mojo::Array<content::KeyValuePtr> data; | 265 mojo::Array<content::KeyValuePtr> data; |
236 leveldb_->GetAll(binding_.CreateInterfacePtrAndBind(), &status, &data); | 266 leveldb_->GetAll(get_all_request_id_, &status, &data); |
237 | 267 |
238 DOMStorageValuesMap values; | 268 DOMStorageValuesMap values; |
239 for (size_t i = 0; i < data.size(); ++i) { | 269 for (size_t i = 0; i < data.size(); ++i) { |
240 values[data[i]->key.To<base::string16>()] = | 270 values[data[i]->key.To<base::string16>()] = |
241 base::NullableString16(data[i]->value.To<base::string16>(), false); | 271 base::NullableString16(data[i]->value.To<base::string16>(), false); |
242 } | 272 } |
243 | 273 |
244 map_ = new DOMStorageMap(kPerStorageAreaQuota); | 274 map_ = new DOMStorageMap(kPerStorageAreaQuota); |
245 map_->SwapValues(&values); | 275 map_->SwapValues(&values); |
246 | 276 |
(...skipping 13 matching lines...) Expand all Loading... |
260 } else if (local_storage_size_kb < 1000) { | 290 } else if (local_storage_size_kb < 1000) { |
261 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrimeFor100KBTo1MB", | 291 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrimeFor100KBTo1MB", |
262 time_to_prime); | 292 time_to_prime); |
263 } else { | 293 } else { |
264 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrimeFor1MBTo5MB", | 294 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrimeFor1MBTo5MB", |
265 time_to_prime); | 295 time_to_prime); |
266 } | 296 } |
267 } | 297 } |
268 | 298 |
269 void LocalStorageCachedArea::OnSetItemComplete(const base::string16& key, | 299 void LocalStorageCachedArea::OnSetItemComplete(const base::string16& key, |
270 leveldb::DatabaseError result) { | 300 bool success) { |
271 if (result != leveldb::DatabaseError::OK) { | 301 if (!success) { |
272 Reset(); | 302 Reset(); |
273 return; | 303 return; |
274 } | 304 } |
275 | 305 |
276 auto found = ignore_key_mutations_.find(key); | 306 auto found = ignore_key_mutations_.find(key); |
277 DCHECK(found != ignore_key_mutations_.end()); | 307 DCHECK(found != ignore_key_mutations_.end()); |
278 if (--found->second == 0) | 308 if (--found->second == 0) |
279 ignore_key_mutations_.erase(found); | 309 ignore_key_mutations_.erase(found); |
280 } | 310 } |
281 | 311 |
282 void LocalStorageCachedArea::OnRemoveItemComplete( | 312 void LocalStorageCachedArea::OnRemoveItemComplete( |
283 const base::string16& key, leveldb::DatabaseError result) { | 313 const base::string16& key, bool success) { |
284 DCHECK_EQ(result, leveldb::DatabaseError::OK); | 314 DCHECK(success); |
285 auto found = ignore_key_mutations_.find(key); | 315 auto found = ignore_key_mutations_.find(key); |
286 DCHECK(found != ignore_key_mutations_.end()); | 316 DCHECK(found != ignore_key_mutations_.end()); |
287 if (--found->second == 0) | 317 if (--found->second == 0) |
288 ignore_key_mutations_.erase(found); | 318 ignore_key_mutations_.erase(found); |
289 } | 319 } |
290 | 320 |
291 void LocalStorageCachedArea::OnClearComplete(leveldb::DatabaseError result) { | 321 void LocalStorageCachedArea::OnClearComplete(bool success) { |
292 DCHECK_EQ(result, leveldb::DatabaseError::OK); | 322 DCHECK(success); |
| 323 DCHECK(ignore_all_mutations_); |
| 324 ignore_all_mutations_ = false; |
293 } | 325 } |
294 | 326 |
295 void LocalStorageCachedArea::Reset() { | 327 void LocalStorageCachedArea::Reset() { |
296 map_ = NULL; | 328 map_ = NULL; |
297 ignore_key_mutations_.clear(); | 329 ignore_key_mutations_.clear(); |
| 330 ignore_all_mutations_ = false; |
| 331 weak_factory_.InvalidateWeakPtrs(); |
298 } | 332 } |
299 | 333 |
300 } // namespace content | 334 } // namespace content |
OLD | NEW |