Index: chrome/browser/metrics/metrics_log_serializer.cc |
diff --git a/chrome/browser/metrics/metrics_log_serializer.cc b/chrome/browser/metrics/metrics_log_serializer.cc |
index bbddf601eb77710ae0e2ea2fae460a83c747425f..3369f85a7a630d2fb4048732e554a3b5d0a8c320 100644 |
--- a/chrome/browser/metrics/metrics_log_serializer.cc |
+++ b/chrome/browser/metrics/metrics_log_serializer.cc |
@@ -12,10 +12,12 @@ |
#include "chrome/browser/prefs/scoped_user_pref_update.h" |
#include "chrome/common/pref_names.h" |
+namespace { |
+ |
// The number of "initial" logs we're willing to save, and hope to send during |
// a future Chrome session. Initial logs contain crash stats, and are pretty |
// small. |
-static const size_t kMaxInitialLogsPersisted = 20; |
+const size_t kMaxInitialLogsPersisted = 20; |
// The number of ongoing logs we're willing to save persistently, and hope to |
// send during a this or future sessions. Note that each log may be pretty |
@@ -26,15 +28,14 @@ static const size_t kMaxInitialLogsPersisted = 20; |
// A "standard shutdown" will create a small log, including just the data that |
// was not yet been transmitted, and that is normal (to have exactly one |
// ongoing_log_ at startup). |
-static const size_t kMaxOngoingLogsPersisted = 8; |
+const size_t kMaxOngoingLogsPersisted = 8; |
// We append (2) more elements to persisted lists: the size of the list and a |
// checksum of the elements. |
-static const size_t kChecksumEntryCount = 2; |
+const size_t kChecksumEntryCount = 2; |
-namespace { |
-// TODO(ziadh): This is here temporarily for a side experiment. Remove later |
-// on. |
+// TODO(isherman): Remove this histogram once it's confirmed that there are no |
+// encoding failures for protobuf logs. |
enum LogStoreStatus { |
STORE_SUCCESS, // Successfully presisted log. |
ENCODE_FAIL, // Failed to encode log. |
@@ -43,17 +44,23 @@ enum LogStoreStatus { |
}; |
MetricsLogSerializer::LogReadStatus MakeRecallStatusHistogram( |
- MetricsLogSerializer::LogReadStatus status) { |
- UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecall", status, |
- MetricsLogSerializer::END_RECALL_STATUS); |
+ MetricsLogSerializer::LogReadStatus status, |
+ bool is_xml) { |
+ if (is_xml) { |
+ UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecall", |
+ status, MetricsLogSerializer::END_RECALL_STATUS); |
+ } else { |
+ UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecallProtobufs", |
+ status, MetricsLogSerializer::END_RECALL_STATUS); |
+ } |
return status; |
} |
-// TODO(ziadh): Remove this when done with experiment. |
void MakeStoreStatusHistogram(LogStoreStatus status) { |
UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogStore2", status, |
END_STORE_STATUS); |
} |
+ |
} // namespace |
@@ -61,52 +68,76 @@ MetricsLogSerializer::MetricsLogSerializer() {} |
MetricsLogSerializer::~MetricsLogSerializer() {} |
-void MetricsLogSerializer::SerializeLogs(const std::vector<std::string>& logs, |
- MetricsLogManager::LogType log_type) { |
+void MetricsLogSerializer::SerializeLogs( |
+ const std::vector<MetricsLogManager::SerializedLog>& logs, |
+ MetricsLogManager::LogType log_type) { |
PrefService* local_state = g_browser_process->local_state(); |
DCHECK(local_state); |
- const char* pref = NULL; |
+ const char* pref_xml = NULL; |
+ const char* pref_proto = NULL; |
size_t max_store_count = 0; |
switch (log_type) { |
case MetricsLogManager::INITIAL_LOG: |
- pref = prefs::kMetricsInitialLogs; |
+ pref_xml = prefs::kMetricsInitialLogsXml; |
+ pref_proto = prefs::kMetricsInitialLogsProto; |
max_store_count = kMaxInitialLogsPersisted; |
break; |
case MetricsLogManager::ONGOING_LOG: |
- pref = prefs::kMetricsOngoingLogs; |
+ pref_xml = prefs::kMetricsOngoingLogsXml; |
+ pref_proto = prefs::kMetricsOngoingLogsProto; |
max_store_count = kMaxOngoingLogsPersisted; |
break; |
default: |
NOTREACHED(); |
return; |
}; |
- ListPrefUpdate update(local_state, pref); |
- ListValue* pref_list = update.Get(); |
- WriteLogsToPrefList(logs, max_store_count, pref_list); |
+ |
+ // Write the XML version. |
+ ListPrefUpdate update_xml(local_state, pref_xml); |
+ WriteLogsToPrefList(logs, true, max_store_count, update_xml.Get()); |
+ |
+ // Write the protobuf version. |
+ ListPrefUpdate update_proto(local_state, pref_proto); |
+ WriteLogsToPrefList(logs, false, max_store_count, update_proto.Get()); |
} |
-void MetricsLogSerializer::DeserializeLogs(MetricsLogManager::LogType log_type, |
- std::vector<std::string>* logs) { |
+void MetricsLogSerializer::DeserializeLogs( |
+ MetricsLogManager::LogType log_type, |
+ std::vector<MetricsLogManager::SerializedLog>* logs) { |
DCHECK(logs); |
PrefService* local_state = g_browser_process->local_state(); |
DCHECK(local_state); |
- const char* pref = (log_type == MetricsLogManager::INITIAL_LOG) ? |
- prefs::kMetricsInitialLogs : prefs::kMetricsOngoingLogs; |
- const ListValue* unsent_logs = local_state->GetList(pref); |
- ReadLogsFromPrefList(*unsent_logs, logs); |
+ const char* pref_xml; |
+ const char* pref_proto; |
+ if (log_type == MetricsLogManager::INITIAL_LOG) { |
+ pref_xml = prefs::kMetricsInitialLogsXml; |
+ pref_proto = prefs::kMetricsInitialLogsProto; |
+ } else { |
+ pref_xml = prefs::kMetricsOngoingLogsXml; |
+ pref_proto = prefs::kMetricsOngoingLogsProto; |
+ } |
+ |
+ const ListValue* unsent_logs_xml = local_state->GetList(pref_xml); |
+ const ListValue* unsent_logs_proto = local_state->GetList(pref_proto); |
+ if (ReadLogsFromPrefList(*unsent_logs_xml, true, logs) == RECALL_SUCCESS) { |
+ // In order to try to keep the data sent to both servers roughly in sync, |
+ // only read the protobuf data if we read the XML data successfully. |
+ ReadLogsFromPrefList(*unsent_logs_proto, false, logs); |
+ } |
} |
// static |
void MetricsLogSerializer::WriteLogsToPrefList( |
- const std::vector<std::string>& local_list, |
- const size_t kMaxLocalListSize, |
- ListValue* list) { |
+ const std::vector<MetricsLogManager::SerializedLog>& local_list, |
+ bool is_xml, |
+ size_t max_list_size, |
+ base::ListValue* list) { |
list->Clear(); |
size_t start = 0; |
- if (local_list.size() > kMaxLocalListSize) |
- start = local_list.size() - kMaxLocalListSize; |
- DCHECK(start <= local_list.size()); |
+ if (local_list.size() > max_list_size) |
+ start = local_list.size() - max_list_size; |
+ DCHECK_LE(start, local_list.size()); |
if (local_list.size() <= start) |
return; |
@@ -116,11 +147,13 @@ void MetricsLogSerializer::WriteLogsToPrefList( |
base::MD5Context ctx; |
base::MD5Init(&ctx); |
std::string encoded_log; |
- for (std::vector<std::string>::const_iterator it = local_list.begin() + start; |
+ for (std::vector<MetricsLogManager::SerializedLog>::const_iterator it = |
+ local_list.begin() + start; |
it != local_list.end(); ++it) { |
+ const std::string& value = is_xml ? it->xml : it->proto; |
// We encode the compressed log as Value::CreateStringValue() expects to |
// take a valid UTF8 string. |
- if (!base::Base64Encode(*it, &encoded_log)) { |
+ if (!base::Base64Encode(value, &encoded_log)) { |
MakeStoreStatusHistogram(ENCODE_FAIL); |
list->Clear(); |
return; |
@@ -140,44 +173,58 @@ void MetricsLogSerializer::WriteLogsToPrefList( |
// static |
MetricsLogSerializer::LogReadStatus MetricsLogSerializer::ReadLogsFromPrefList( |
const ListValue& list, |
- std::vector<std::string>* local_list) { |
- DCHECK(local_list->empty()); |
+ bool is_xml, |
+ std::vector<MetricsLogManager::SerializedLog>* local_list) { |
if (list.GetSize() == 0) |
- return MakeRecallStatusHistogram(LIST_EMPTY); |
+ return MakeRecallStatusHistogram(LIST_EMPTY, is_xml); |
if (list.GetSize() < 3) |
- return MakeRecallStatusHistogram(LIST_SIZE_TOO_SMALL); |
+ return MakeRecallStatusHistogram(LIST_SIZE_TOO_SMALL, is_xml); |
// The size is stored at the beginning of the list. |
int size; |
bool valid = (*list.begin())->GetAsInteger(&size); |
if (!valid) |
- return MakeRecallStatusHistogram(LIST_SIZE_MISSING); |
- |
+ return MakeRecallStatusHistogram(LIST_SIZE_MISSING, is_xml); |
// Account for checksum and size included in the list. |
if (static_cast<unsigned int>(size) != |
list.GetSize() - kChecksumEntryCount) { |
- return MakeRecallStatusHistogram(LIST_SIZE_CORRUPTION); |
+ return MakeRecallStatusHistogram(LIST_SIZE_CORRUPTION, is_xml); |
+ } |
+ |
+ // Allocate strings for all of the logs we are going to read in. |
+ // Do this ahead of time so that we can decode the string values directly into |
+ // the elements of |local_list|, and thereby avoid making copies of the |
+ // serialized logs, which can be fairly large. |
+ if (is_xml) { |
+ DCHECK(local_list->empty()); |
+ local_list->resize(size); |
+ } else if (local_list->size() != static_cast<size_t>(size)) { |
+ return MakeRecallStatusHistogram(XML_PROTO_MISMATCH, false); |
} |
base::MD5Context ctx; |
base::MD5Init(&ctx); |
std::string encoded_log; |
- std::string decoded_log; |
+ size_t local_index = 0; |
for (ListValue::const_iterator it = list.begin() + 1; |
- it != list.end() - 1; ++it) { // Last element is the checksum. |
- valid = (*it)->GetAsString(&encoded_log); |
+ it != list.end() - 1; // Last element is the checksum. |
+ ++it, ++local_index) { |
+ bool valid = (*it)->GetAsString(&encoded_log); |
if (!valid) { |
local_list->clear(); |
- return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION); |
+ return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION, is_xml); |
} |
base::MD5Update(&ctx, encoded_log); |
+ DCHECK_LT(local_index, local_list->size()); |
+ std::string& decoded_log = is_xml ? |
+ (*local_list)[local_index].xml : |
+ (*local_list)[local_index].proto; |
if (!base::Base64Decode(encoded_log, &decoded_log)) { |
local_list->clear(); |
- return MakeRecallStatusHistogram(DECODE_FAIL); |
+ return MakeRecallStatusHistogram(DECODE_FAIL, is_xml); |
} |
- local_list->push_back(decoded_log); |
} |
// Verify checksum. |
@@ -188,11 +235,11 @@ MetricsLogSerializer::LogReadStatus MetricsLogSerializer::ReadLogsFromPrefList( |
valid = (*(list.end() - 1))->GetAsString(&recovered_md5); |
if (!valid) { |
local_list->clear(); |
- return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION); |
+ return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION, is_xml); |
} |
if (recovered_md5 != base::MD5DigestToBase16(digest)) { |
local_list->clear(); |
- return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION); |
+ return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION, is_xml); |
} |
- return MakeRecallStatusHistogram(RECALL_SUCCESS); |
+ return MakeRecallStatusHistogram(RECALL_SUCCESS, is_xml); |
} |