OLD | NEW |
| (Empty) |
1 // 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 "webkit/dom_storage/dom_storage_cached_area.h" | |
6 | |
7 #include "base/basictypes.h" | |
8 #include "base/time.h" | |
9 #include "base/metrics/histogram.h" | |
10 #include "webkit/dom_storage/dom_storage_map.h" | |
11 #include "webkit/dom_storage/dom_storage_proxy.h" | |
12 | |
13 namespace dom_storage { | |
14 | |
15 DomStorageCachedArea::DomStorageCachedArea( | |
16 int64 namespace_id, const GURL& origin, DomStorageProxy* proxy) | |
17 : ignore_all_mutations_(false), | |
18 namespace_id_(namespace_id), origin_(origin), | |
19 proxy_(proxy), weak_factory_(this) { | |
20 } | |
21 | |
22 DomStorageCachedArea::~DomStorageCachedArea() { | |
23 } | |
24 | |
25 unsigned DomStorageCachedArea::GetLength(int connection_id) { | |
26 PrimeIfNeeded(connection_id); | |
27 return map_->Length(); | |
28 } | |
29 | |
30 NullableString16 DomStorageCachedArea::GetKey( | |
31 int connection_id, unsigned index) { | |
32 PrimeIfNeeded(connection_id); | |
33 return map_->Key(index); | |
34 } | |
35 | |
36 NullableString16 DomStorageCachedArea::GetItem( | |
37 int connection_id, const base::string16& key) { | |
38 PrimeIfNeeded(connection_id); | |
39 return map_->GetItem(key); | |
40 } | |
41 | |
42 bool DomStorageCachedArea::SetItem( | |
43 int connection_id, const base::string16& key, | |
44 const base::string16& value, const GURL& page_url) { | |
45 // A quick check to reject obviously overbudget items to avoid | |
46 // the priming the cache. | |
47 if (key.length() + value.length() > dom_storage::kPerAreaQuota) | |
48 return false; | |
49 | |
50 PrimeIfNeeded(connection_id); | |
51 NullableString16 unused; | |
52 if (!map_->SetItem(key, value, &unused)) | |
53 return false; | |
54 | |
55 // Ignore mutations to 'key' until OnSetItemComplete. | |
56 ignore_key_mutations_[key]++; | |
57 proxy_->SetItem( | |
58 connection_id, key, value, page_url, | |
59 base::Bind(&DomStorageCachedArea::OnSetItemComplete, | |
60 weak_factory_.GetWeakPtr(), key)); | |
61 return true; | |
62 } | |
63 | |
64 void DomStorageCachedArea::RemoveItem( | |
65 int connection_id, const base::string16& key, const GURL& page_url) { | |
66 PrimeIfNeeded(connection_id); | |
67 base::string16 unused; | |
68 if (!map_->RemoveItem(key, &unused)) | |
69 return; | |
70 | |
71 // Ignore mutations to 'key' until OnRemoveItemComplete. | |
72 ignore_key_mutations_[key]++; | |
73 proxy_->RemoveItem( | |
74 connection_id, key, page_url, | |
75 base::Bind(&DomStorageCachedArea::OnRemoveItemComplete, | |
76 weak_factory_.GetWeakPtr(), key)); | |
77 } | |
78 | |
79 void DomStorageCachedArea::Clear(int connection_id, const GURL& page_url) { | |
80 // No need to prime the cache in this case. | |
81 Reset(); | |
82 map_ = new DomStorageMap(dom_storage::kPerAreaQuota); | |
83 | |
84 // Ignore all mutations until OnClearComplete time. | |
85 ignore_all_mutations_ = true; | |
86 proxy_->ClearArea( | |
87 connection_id, page_url, | |
88 base::Bind(&DomStorageCachedArea::OnClearComplete, | |
89 weak_factory_.GetWeakPtr())); | |
90 } | |
91 | |
92 void DomStorageCachedArea::ApplyMutation( | |
93 const NullableString16& key, const NullableString16& new_value) { | |
94 if (!map_.get() || ignore_all_mutations_) | |
95 return; | |
96 | |
97 if (key.is_null()) { | |
98 // It's a clear event. | |
99 scoped_refptr<DomStorageMap> old = map_; | |
100 map_ = new DomStorageMap(dom_storage::kPerAreaQuota); | |
101 | |
102 // We have to retain local additions which happened after this | |
103 // clear operation from another process. | |
104 std::map<base::string16, int>::iterator iter = | |
105 ignore_key_mutations_.begin(); | |
106 while (iter != ignore_key_mutations_.end()) { | |
107 NullableString16 value = old->GetItem(iter->first); | |
108 if (!value.is_null()) { | |
109 NullableString16 unused; | |
110 map_->SetItem(iter->first, value.string(), &unused); | |
111 } | |
112 ++iter; | |
113 } | |
114 return; | |
115 } | |
116 | |
117 // We have to retain local changes. | |
118 if (should_ignore_key_mutation(key.string())) | |
119 return; | |
120 | |
121 if (new_value.is_null()) { | |
122 // It's a remove item event. | |
123 base::string16 unused; | |
124 map_->RemoveItem(key.string(), &unused); | |
125 return; | |
126 } | |
127 | |
128 // It's a set item event. | |
129 // We turn off quota checking here to accomodate the over budget | |
130 // allowance that's provided in the browser process. | |
131 NullableString16 unused; | |
132 map_->set_quota(kint32max); | |
133 map_->SetItem(key.string(), new_value.string(), &unused); | |
134 map_->set_quota(dom_storage::kPerAreaQuota); | |
135 } | |
136 | |
137 size_t DomStorageCachedArea::MemoryBytesUsedByCache() const { | |
138 return map_.get() ? map_->bytes_used() : 0; | |
139 } | |
140 | |
141 void DomStorageCachedArea::Prime(int connection_id) { | |
142 DCHECK(!map_.get()); | |
143 | |
144 // The LoadArea method is actually synchronous, but we have to | |
145 // wait for an asyncly delivered message to know when incoming | |
146 // mutation events should be applied. Our valuemap is plucked | |
147 // from ipc stream out of order, mutations in front if it need | |
148 // to be ignored. | |
149 | |
150 // Ignore all mutations until OnLoadComplete time. | |
151 ignore_all_mutations_ = true; | |
152 ValuesMap values; | |
153 base::TimeTicks before = base::TimeTicks::Now(); | |
154 proxy_->LoadArea( | |
155 connection_id, &values, | |
156 base::Bind(&DomStorageCachedArea::OnLoadComplete, | |
157 weak_factory_.GetWeakPtr())); | |
158 base::TimeDelta time_to_prime = base::TimeTicks::Now() - before; | |
159 // Keeping this histogram named the same (without the ForRenderer suffix) | |
160 // to maintain histogram continuity. | |
161 UMA_HISTOGRAM_TIMES("LocalStorage.TimeToPrimeLocalStorage", | |
162 time_to_prime); | |
163 map_ = new DomStorageMap(dom_storage::kPerAreaQuota); | |
164 map_->SwapValues(&values); | |
165 | |
166 size_t local_storage_size_kb = map_->bytes_used() / 1024; | |
167 // Track localStorage size, from 0-6MB. Note that the maximum size should be | |
168 // 5MB, but we add some slop since we want to make sure the max size is always | |
169 // above what we see in practice, since histograms can't change. | |
170 UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.RendererLocalStorageSizeInKB", | |
171 local_storage_size_kb, | |
172 0, 6 * 1024, 50); | |
173 if (local_storage_size_kb < 100) { | |
174 UMA_HISTOGRAM_TIMES( | |
175 "LocalStorage.RendererTimeToPrimeLocalStorageUnder100KB", | |
176 time_to_prime); | |
177 } else if (local_storage_size_kb < 1000) { | |
178 UMA_HISTOGRAM_TIMES( | |
179 "LocalStorage.RendererTimeToPrimeLocalStorage100KBTo1MB", | |
180 time_to_prime); | |
181 } else { | |
182 UMA_HISTOGRAM_TIMES( | |
183 "LocalStorage.RendererTimeToPrimeLocalStorage1MBTo5MB", | |
184 time_to_prime); | |
185 } | |
186 } | |
187 | |
188 void DomStorageCachedArea::Reset() { | |
189 map_ = NULL; | |
190 weak_factory_.InvalidateWeakPtrs(); | |
191 ignore_key_mutations_.clear(); | |
192 ignore_all_mutations_ = false; | |
193 } | |
194 | |
195 void DomStorageCachedArea::OnLoadComplete(bool success) { | |
196 DCHECK(success); | |
197 DCHECK(ignore_all_mutations_); | |
198 ignore_all_mutations_ = false; | |
199 } | |
200 | |
201 void DomStorageCachedArea::OnSetItemComplete( | |
202 const base::string16& key, bool success) { | |
203 if (!success) { | |
204 Reset(); | |
205 return; | |
206 } | |
207 std::map<base::string16, int>::iterator found = | |
208 ignore_key_mutations_.find(key); | |
209 DCHECK(found != ignore_key_mutations_.end()); | |
210 if (--found->second == 0) | |
211 ignore_key_mutations_.erase(found); | |
212 } | |
213 | |
214 void DomStorageCachedArea::OnRemoveItemComplete( | |
215 const base::string16& key, bool success) { | |
216 DCHECK(success); | |
217 std::map<base::string16, int>::iterator found = | |
218 ignore_key_mutations_.find(key); | |
219 DCHECK(found != ignore_key_mutations_.end()); | |
220 if (--found->second == 0) | |
221 ignore_key_mutations_.erase(found); | |
222 } | |
223 | |
224 void DomStorageCachedArea::OnClearComplete(bool success) { | |
225 DCHECK(success); | |
226 DCHECK(ignore_all_mutations_); | |
227 ignore_all_mutations_ = false; | |
228 } | |
229 | |
230 } // namespace dom_storage | |
OLD | NEW |