OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/metrics/persisted_logs.h" | 5 #include "components/metrics/persisted_logs.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/md5.h" | 10 #include "base/md5.h" |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 const char* pref_name, | 79 const char* pref_name, |
80 const char* old_pref_name, | 80 const char* old_pref_name, |
81 size_t min_log_count, | 81 size_t min_log_count, |
82 size_t min_log_bytes, | 82 size_t min_log_bytes, |
83 size_t max_log_size) | 83 size_t max_log_size) |
84 : local_state_(local_state), | 84 : local_state_(local_state), |
85 pref_name_(pref_name), | 85 pref_name_(pref_name), |
86 old_pref_name_(old_pref_name), | 86 old_pref_name_(old_pref_name), |
87 min_log_count_(min_log_count), | 87 min_log_count_(min_log_count), |
88 min_log_bytes_(min_log_bytes), | 88 min_log_bytes_(min_log_bytes), |
89 max_log_size_(max_log_size), | 89 max_log_size_(max_log_size != 0 ? max_log_size : static_cast<size_t>(-1)), |
90 last_provisional_store_index_(-1) { | 90 last_provisional_store_index_(-1) { |
91 DCHECK(local_state_); | 91 DCHECK(local_state_); |
92 // One of the limit arguments must be non-zero. | 92 // One of the limit arguments must be non-zero. |
93 DCHECK(min_log_count_ > 0 || min_log_bytes_ > 0); | 93 DCHECK(min_log_count_ > 0 || min_log_bytes_ > 0); |
94 } | 94 } |
95 | 95 |
96 PersistedLogs::~PersistedLogs() {} | 96 PersistedLogs::~PersistedLogs() {} |
97 | 97 |
98 void PersistedLogs::SerializeLogs() { | 98 void PersistedLogs::SerializeLogs() const { |
99 // Remove any logs that are over the serialization size limit. | |
100 if (max_log_size_) { | |
101 for (std::vector<LogHashPair>::iterator it = list_.begin(); | |
102 it != list_.end();) { | |
103 size_t log_size = it->compressed_log_data.length(); | |
104 if (log_size > max_log_size_) { | |
105 UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted", | |
106 static_cast<int>(log_size)); | |
107 it = list_.erase(it); | |
108 } else { | |
109 ++it; | |
110 } | |
111 } | |
112 } | |
113 | |
114 ListPrefUpdate update(local_state_, pref_name_); | 99 ListPrefUpdate update(local_state_, pref_name_); |
115 WriteLogsToPrefList(update.Get()); | 100 WriteLogsToPrefList(update.Get()); |
116 | 101 |
117 // Clear the old pref now that we've written to the new one. | 102 // Clear the old pref now that we've written to the new one. |
118 // TODO(asvitkine): Remove the old pref in M39. | 103 // TODO(asvitkine): Remove the old pref in M39. |
119 local_state_->ClearPref(old_pref_name_); | 104 local_state_->ClearPref(old_pref_name_); |
120 } | 105 } |
121 | 106 |
122 PersistedLogs::LogReadStatus PersistedLogs::DeserializeLogs() { | 107 PersistedLogs::LogReadStatus PersistedLogs::DeserializeLogs() { |
123 // First, try reading from old pref. If it's empty, read from the new one. | 108 // First, try reading from old pref. If it's empty, read from the new one. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 } | 147 } |
163 | 148 |
164 void PersistedLogs::DiscardLastProvisionalStore() { | 149 void PersistedLogs::DiscardLastProvisionalStore() { |
165 if (last_provisional_store_index_ == -1) | 150 if (last_provisional_store_index_ == -1) |
166 return; | 151 return; |
167 DCHECK_LT(static_cast<size_t>(last_provisional_store_index_), list_.size()); | 152 DCHECK_LT(static_cast<size_t>(last_provisional_store_index_), list_.size()); |
168 list_.erase(list_.begin() + last_provisional_store_index_); | 153 list_.erase(list_.begin() + last_provisional_store_index_); |
169 last_provisional_store_index_ = -1; | 154 last_provisional_store_index_ = -1; |
170 } | 155 } |
171 | 156 |
172 void PersistedLogs::WriteLogsToPrefList(base::ListValue* list_value) { | 157 void PersistedLogs::WriteLogsToPrefList(base::ListValue* list_value) const { |
173 list_value->Clear(); | 158 list_value->Clear(); |
174 // Leave the list completely empty if there are no storable values. | |
175 if (list_.empty()) | |
176 return; | |
177 | 159 |
178 size_t start = 0; | 160 // Keep the most recent logs which are smaller than |max_log_size_|. |
179 // If there are too many logs, keep the most recent logs up to the length | 161 // We keep at least |min_log_bytes_| and |min_log_count_| of logs before |
180 // limit, and at least to the minimum number of bytes. | 162 // discarding older logs. |
181 if (list_.size() > min_log_count_) { | 163 size_t start = list_.size(); |
182 start = list_.size(); | 164 size_t saved_log_count = 0; |
183 size_t bytes_used = 0; | 165 size_t bytes_used = 0; |
184 std::vector<LogHashPair>::const_reverse_iterator end = list_.rend(); | 166 for (; start > 0; --start) { |
185 for (std::vector<LogHashPair>::const_reverse_iterator it = list_.rbegin(); | 167 size_t log_size = list_[start - 1].compressed_log_data.length(); |
186 it != end; ++it) { | 168 if (bytes_used >= min_log_bytes_ && |
187 const size_t log_size = it->compressed_log_data.length(); | 169 saved_log_count >= min_log_count_) { |
188 if (bytes_used >= min_log_bytes_ && | 170 break; |
189 (list_.size() - start) >= min_log_count_) { | |
190 break; | |
191 } | |
192 bytes_used += log_size; | |
193 --start; | |
194 } | 171 } |
| 172 // Oversized logs won't be persisted, so don't count them. |
| 173 if (log_size > max_log_size_) |
| 174 continue; |
| 175 bytes_used += log_size; |
| 176 ++saved_log_count; |
195 } | 177 } |
196 DCHECK_LT(start, list_.size()); | |
197 | 178 |
198 for (size_t i = start; i < list_.size(); ++i) { | 179 for (size_t i = start; i < list_.size(); ++i) { |
| 180 size_t log_size = list_[i].compressed_log_data.length(); |
| 181 if (log_size > max_log_size_) { |
| 182 UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted", |
| 183 static_cast<int>(log_size)); |
| 184 continue; |
| 185 } |
199 AppendBase64String(list_[i].compressed_log_data, list_value); | 186 AppendBase64String(list_[i].compressed_log_data, list_value); |
200 AppendBase64String(list_[i].hash, list_value); | 187 AppendBase64String(list_[i].hash, list_value); |
201 } | 188 } |
202 } | 189 } |
203 | 190 |
204 PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromPrefList( | 191 PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromPrefList( |
205 const base::ListValue& list_value) { | 192 const base::ListValue& list_value) { |
206 if (list_value.empty()) | 193 if (list_value.empty()) |
207 return MakeRecallStatusHistogram(LIST_EMPTY); | 194 return MakeRecallStatusHistogram(LIST_EMPTY); |
208 | 195 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION); | 276 return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION); |
290 } | 277 } |
291 if (recovered_md5 != base::MD5DigestToBase16(digest)) { | 278 if (recovered_md5 != base::MD5DigestToBase16(digest)) { |
292 list_.clear(); | 279 list_.clear(); |
293 return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION); | 280 return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION); |
294 } | 281 } |
295 return MakeRecallStatusHistogram(RECALL_SUCCESS); | 282 return MakeRecallStatusHistogram(RECALL_SUCCESS); |
296 } | 283 } |
297 | 284 |
298 } // namespace metrics | 285 } // namespace metrics |
OLD | NEW |