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

Side by Side Diff: chrome/browser/extensions/api/storage/settings_storage_quota_enforcer.cc

Issue 24021002: Propagate more information about ValueStore errors to callers, notably an (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add Pass*() Created 7 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 "chrome/browser/extensions/api/storage/settings_storage_quota_enforcer. h" 5 #include "chrome/browser/extensions/api/storage/settings_storage_quota_enforcer. h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/json/json_writer.h" 8 #include "base/json/json_writer.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop.h"
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "base/strings/stringprintf.h"
13 #include "chrome/browser/value_store/value_store_util.h"
12 #include "chrome/common/extensions/api/extension_api.h" 14 #include "chrome/common/extensions/api/extension_api.h"
13 #include "extensions/common/error_utils.h" 15
16 namespace util = value_store_util;
14 17
15 namespace extensions { 18 namespace extensions {
16 19
17 namespace { 20 namespace {
18 21
19 const char* kQuotaExceededError = "* quota exceeded.";
20
21 // Resources there are a quota for. 22 // Resources there are a quota for.
22 enum Resource { 23 enum Resource {
23 QUOTA_BYTES, 24 QUOTA_BYTES,
24 QUOTA_BYTES_PER_ITEM, 25 QUOTA_BYTES_PER_ITEM,
25 MAX_ITEMS 26 MAX_ITEMS
26 }; 27 };
27 28
28 // Allocates a setting in a record of total and per-setting usage. 29 // Allocates a setting in a record of total and per-setting usage.
29 void Allocate( 30 void Allocate(
30 const std::string& key, 31 const std::string& key,
(...skipping 15 matching lines...) Expand all
46 47
47 // Frees the allocation of a setting in a record of total and per-setting usage. 48 // Frees the allocation of a setting in a record of total and per-setting usage.
48 void Free( 49 void Free(
49 size_t* used_total, 50 size_t* used_total,
50 std::map<std::string, size_t>* used_per_setting, 51 std::map<std::string, size_t>* used_per_setting,
51 const std::string& key) { 52 const std::string& key) {
52 *used_total -= (*used_per_setting)[key]; 53 *used_total -= (*used_per_setting)[key];
53 used_per_setting->erase(key); 54 used_per_setting->erase(key);
54 } 55 }
55 56
56 // Returns an error result and logs the quota exceeded to UMA. 57 scoped_ptr<ValueStore::Error> QuotaExceededError(Resource resource,
57 ValueStore::WriteResult QuotaExceededFor(Resource resource) { 58 scoped_ptr<std::string> key) {
58 std::string name; 59 const char* name = NULL;
60 // TODO(kalman): These hisograms are both silly and untracked. Fix.
59 switch (resource) { 61 switch (resource) {
60 case QUOTA_BYTES: 62 case QUOTA_BYTES:
61 name = "QUOTA_BYTES"; 63 name = "QUOTA_BYTES";
62 UMA_HISTOGRAM_COUNTS_100( 64 UMA_HISTOGRAM_COUNTS_100(
63 "Extensions.SettingsQuotaExceeded.TotalBytes", 1); 65 "Extensions.SettingsQuotaExceeded.TotalBytes", 1);
64 break; 66 break;
65 case QUOTA_BYTES_PER_ITEM: 67 case QUOTA_BYTES_PER_ITEM:
66 name = "QUOTA_BYTES_PER_ITEM"; 68 name = "QUOTA_BYTES_PER_ITEM";
67 UMA_HISTOGRAM_COUNTS_100( 69 UMA_HISTOGRAM_COUNTS_100(
68 "Extensions.SettingsQuotaExceeded.BytesPerSetting", 1); 70 "Extensions.SettingsQuotaExceeded.BytesPerSetting", 1);
69 break; 71 break;
70 case MAX_ITEMS: 72 case MAX_ITEMS:
71 name = "MAX_ITEMS"; 73 name = "MAX_ITEMS";
72 UMA_HISTOGRAM_COUNTS_100( 74 UMA_HISTOGRAM_COUNTS_100(
73 "Extensions.SettingsQuotaExceeded.KeyCount", 1); 75 "Extensions.SettingsQuotaExceeded.KeyCount", 1);
74 break; 76 break;
75 default:
76 NOTREACHED();
77 } 77 }
78 return ValueStore::MakeWriteResult( 78 CHECK(name);
79 ErrorUtils::FormatErrorMessage(kQuotaExceededError, name)); 79 return make_scoped_ptr(new ValueStore::Error(
80 ValueStore::QUOTA_EXCEEDED,
81 base::StringPrintf("%s quota exceeded", name),
82 key.Pass()));
80 } 83 }
81 84
82 } // namespace 85 } // namespace
83 86
84 SettingsStorageQuotaEnforcer::SettingsStorageQuotaEnforcer( 87 SettingsStorageQuotaEnforcer::SettingsStorageQuotaEnforcer(
85 const Limits& limits, ValueStore* delegate) 88 const Limits& limits, ValueStore* delegate)
86 : limits_(limits), delegate_(delegate), used_total_(0) { 89 : limits_(limits), delegate_(delegate), used_total_(0) {
87 ReadResult maybe_settings = delegate_->Get(); 90 ReadResult maybe_settings = delegate_->Get();
88 if (maybe_settings->HasError()) { 91 if (maybe_settings->HasError()) {
89 LOG(WARNING) << "Failed to get initial settings for quota: " << 92 LOG(WARNING) << "Failed to get initial settings for quota: " <<
90 maybe_settings->error(); 93 maybe_settings->error().message;
91 return; 94 return;
92 } 95 }
93 96
94 for (base::DictionaryValue::Iterator it(*maybe_settings->settings().get()); 97 for (base::DictionaryValue::Iterator it(maybe_settings->settings());
95 !it.IsAtEnd(); it.Advance()) { 98 !it.IsAtEnd(); it.Advance()) {
96 Allocate(it.key(), it.value(), &used_total_, &used_per_setting_); 99 Allocate(it.key(), it.value(), &used_total_, &used_per_setting_);
97 } 100 }
98 } 101 }
99 102
100 SettingsStorageQuotaEnforcer::~SettingsStorageQuotaEnforcer() {} 103 SettingsStorageQuotaEnforcer::~SettingsStorageQuotaEnforcer() {}
101 104
102 size_t SettingsStorageQuotaEnforcer::GetBytesInUse(const std::string& key) { 105 size_t SettingsStorageQuotaEnforcer::GetBytesInUse(const std::string& key) {
103 std::map<std::string, size_t>::iterator maybe_used = 106 std::map<std::string, size_t>::iterator maybe_used =
104 used_per_setting_.find(key); 107 used_per_setting_.find(key);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 } 139 }
137 140
138 ValueStore::WriteResult SettingsStorageQuotaEnforcer::Set( 141 ValueStore::WriteResult SettingsStorageQuotaEnforcer::Set(
139 WriteOptions options, const std::string& key, const Value& value) { 142 WriteOptions options, const std::string& key, const Value& value) {
140 size_t new_used_total = used_total_; 143 size_t new_used_total = used_total_;
141 std::map<std::string, size_t> new_used_per_setting = used_per_setting_; 144 std::map<std::string, size_t> new_used_per_setting = used_per_setting_;
142 Allocate(key, value, &new_used_total, &new_used_per_setting); 145 Allocate(key, value, &new_used_total, &new_used_per_setting);
143 146
144 if (!(options & IGNORE_QUOTA)) { 147 if (!(options & IGNORE_QUOTA)) {
145 if (new_used_total > limits_.quota_bytes) { 148 if (new_used_total > limits_.quota_bytes) {
146 return QuotaExceededFor(QUOTA_BYTES); 149 return MakeWriteResult(
150 QuotaExceededError(QUOTA_BYTES, util::NewKey(key)));
147 } 151 }
148 if (new_used_per_setting[key] > limits_.quota_bytes_per_item) { 152 if (new_used_per_setting[key] > limits_.quota_bytes_per_item) {
149 return QuotaExceededFor(QUOTA_BYTES_PER_ITEM); 153 return MakeWriteResult(
154 QuotaExceededError(QUOTA_BYTES_PER_ITEM, util::NewKey(key)));
150 } 155 }
151 if (new_used_per_setting.size() > limits_.max_items) { 156 if (new_used_per_setting.size() > limits_.max_items)
152 return QuotaExceededFor(MAX_ITEMS); 157 return MakeWriteResult(QuotaExceededError(MAX_ITEMS, util::NewKey(key)));
153 }
154 } 158 }
155 159
156 WriteResult result = delegate_->Set(options, key, value); 160 WriteResult result = delegate_->Set(options, key, value);
157 if (result->HasError()) { 161 if (result->HasError()) {
158 return result.Pass(); 162 return result.Pass();
159 } 163 }
160 164
161 used_total_ = new_used_total; 165 used_total_ = new_used_total;
162 used_per_setting_.swap(new_used_per_setting); 166 used_per_setting_.swap(new_used_per_setting);
163 return result.Pass(); 167 return result.Pass();
164 } 168 }
165 169
166 ValueStore::WriteResult SettingsStorageQuotaEnforcer::Set( 170 ValueStore::WriteResult SettingsStorageQuotaEnforcer::Set(
167 WriteOptions options, const base::DictionaryValue& values) { 171 WriteOptions options, const base::DictionaryValue& values) {
168 size_t new_used_total = used_total_; 172 size_t new_used_total = used_total_;
169 std::map<std::string, size_t> new_used_per_setting = used_per_setting_; 173 std::map<std::string, size_t> new_used_per_setting = used_per_setting_;
170 for (base::DictionaryValue::Iterator it(values); !it.IsAtEnd(); 174 for (base::DictionaryValue::Iterator it(values); !it.IsAtEnd();
171 it.Advance()) { 175 it.Advance()) {
172 Allocate(it.key(), it.value(), &new_used_total, &new_used_per_setting); 176 Allocate(it.key(), it.value(), &new_used_total, &new_used_per_setting);
173 177
174 if (!(options & IGNORE_QUOTA) && 178 if (!(options & IGNORE_QUOTA) &&
175 new_used_per_setting[it.key()] > limits_.quota_bytes_per_item) { 179 new_used_per_setting[it.key()] > limits_.quota_bytes_per_item) {
176 return QuotaExceededFor(QUOTA_BYTES_PER_ITEM); 180 return MakeWriteResult(
181 QuotaExceededError(QUOTA_BYTES_PER_ITEM, util::NewKey(it.key())));
177 } 182 }
178 } 183 }
179 184
180 if (!(options & IGNORE_QUOTA)) { 185 if (!(options & IGNORE_QUOTA)) {
181 if (new_used_total > limits_.quota_bytes) { 186 if (new_used_total > limits_.quota_bytes)
182 return QuotaExceededFor(QUOTA_BYTES); 187 return MakeWriteResult(QuotaExceededError(QUOTA_BYTES, util::NoKey()));
183 } 188 if (new_used_per_setting.size() > limits_.max_items)
184 if (new_used_per_setting.size() > limits_.max_items) { 189 return MakeWriteResult(QuotaExceededError(MAX_ITEMS, util::NoKey()));
185 return QuotaExceededFor(MAX_ITEMS);
186 }
187 } 190 }
188 191
189 WriteResult result = delegate_->Set(options, values); 192 WriteResult result = delegate_->Set(options, values);
190 if (result->HasError()) { 193 if (result->HasError()) {
191 return result.Pass(); 194 return result.Pass();
192 } 195 }
193 196
194 used_total_ = new_used_total; 197 used_total_ = new_used_total;
195 used_per_setting_ = new_used_per_setting; 198 used_per_setting_ = new_used_per_setting;
196 return result.Pass(); 199 return result.Pass();
(...skipping 29 matching lines...) Expand all
226 return result.Pass(); 229 return result.Pass();
227 } 230 }
228 231
229 while (!used_per_setting_.empty()) { 232 while (!used_per_setting_.empty()) {
230 Free(&used_total_, &used_per_setting_, used_per_setting_.begin()->first); 233 Free(&used_total_, &used_per_setting_, used_per_setting_.begin()->first);
231 } 234 }
232 return result.Pass(); 235 return result.Pass();
233 } 236 }
234 237
235 } // namespace extensions 238 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698