Skip to content

Commit

Permalink
Remove the provisional store and just keep the staged log in the queu…
Browse files Browse the repository at this point in the history
…e while uploading it.

BUG=372911

Review URL: https://codereview.chromium.org/290103005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285684 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
holte@chromium.org committed Jul 25, 2014
1 parent 6c9a96d commit faa8d22
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 225 deletions.
16 changes: 0 additions & 16 deletions components/metrics/metrics_log_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,22 +115,6 @@ void MetricsLogManager::StoreLog(const std::string& log_data,
}
}

void MetricsLogManager::StoreStagedLogAsUnsent(
PersistedLogs::StoreType store_type) {
DCHECK(has_staged_log());
if (initial_log_queue_.has_staged_log())
initial_log_queue_.StoreStagedLogAsUnsent(store_type);
else
ongoing_log_queue_.StoreStagedLogAsUnsent(store_type);
}

void MetricsLogManager::DiscardLastProvisionalStore() {
// We have at most one provisional store, (since at most one log is being
// uploaded at a time), so at least one of these will be a no-op.
initial_log_queue_.DiscardLastProvisionalStore();
ongoing_log_queue_.DiscardLastProvisionalStore();
}

void MetricsLogManager::PersistUnsentLogs() {
DCHECK(unsent_logs_loaded_);
if (!unsent_logs_loaded_)
Expand Down
14 changes: 0 additions & 14 deletions components/metrics/metrics_log_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,6 @@ class MetricsLogManager {
// This should only be called if there is not a current log.
void ResumePausedLog();

// Saves the staged log, then clears staged_log().
// If |store_type| is PROVISIONAL_STORE, it can be dropped from storage with
// a later call to DiscardLastProvisionalStore (if it hasn't already been
// staged again).
// This is intended to be used when logs are being saved while an upload is in
// progress, in case the upload later succeeds.
// This can only be called if has_staged_log() is true.
void StoreStagedLogAsUnsent(PersistedLogs::StoreType store_type);

// Discards the last log stored with StoreStagedLogAsUnsent with |store_type|
// set to PROVISIONAL_STORE, as long as it hasn't already been re-staged. If
// the log is no longer present, this is a no-op.
void DiscardLastProvisionalStore();

// Saves any unsent logs to persistent storage.
void PersistUnsentLogs();

Expand Down
64 changes: 4 additions & 60 deletions components/metrics/metrics_log_manager_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ TEST(MetricsLogManagerTest, StoreAndLoad) {
log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
"id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
log_manager.StageNextLogForUpload();
log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
log_manager.FinishCurrentLog();

// Nothing should be written out until PersistUnsentLogs is called.
Expand Down Expand Up @@ -238,7 +237,6 @@ TEST(MetricsLogManagerTest, StoreStagedLogTypes) {
"id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
log_manager.PersistUnsentLogs();

EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
Expand All @@ -254,7 +252,6 @@ TEST(MetricsLogManagerTest, StoreStagedLogTypes) {
"id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
log_manager.PersistUnsentLogs();

EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
Expand Down Expand Up @@ -282,10 +279,10 @@ TEST(MetricsLogManagerTest, LargeLogDiscarding) {
EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
}

TEST(MetricsLogManagerTest, ProvisionalStoreStandardFlow) {
TEST(MetricsLogManagerTest, DiscardOrder) {
// Ensure that the correct log is discarded if new logs are pushed while
// a log is staged.
TestMetricsServiceClient client;

// Ensure that provisional store works, and discards the correct log.
{
TestLogPrefService pref_service;
MetricsLogManager log_manager(&pref_service, 0);
Expand All @@ -297,64 +294,11 @@ TEST(MetricsLogManagerTest, ProvisionalStoreStandardFlow) {
log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
"id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
log_manager.StageNextLogForUpload();
log_manager.StoreStagedLogAsUnsent(PersistedLogs::PROVISIONAL_STORE);
log_manager.FinishCurrentLog();
log_manager.DiscardLastProvisionalStore();

log_manager.PersistUnsentLogs();
EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
}
}

TEST(MetricsLogManagerTest, ProvisionalStoreNoop) {
TestMetricsServiceClient client;

// Ensure that trying to drop a sent log is a no-op, even if another log has
// since been staged.
{
TestLogPrefService pref_service;
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();

log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
"id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.StoreStagedLogAsUnsent(PersistedLogs::PROVISIONAL_STORE);
log_manager.StageNextLogForUpload();
log_manager.DiscardStagedLog();
log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
"id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
log_manager.DiscardLastProvisionalStore();

log_manager.PersistUnsentLogs();
EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
}

// Ensure that trying to drop more than once is a no-op
{
TestLogPrefService pref_service;
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();

log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
"id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.StoreStagedLogAsUnsent(PersistedLogs::NORMAL_STORE);
log_manager.BeginLoggingWithLog(make_scoped_ptr(new MetricsLog(
"id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.StoreStagedLogAsUnsent(PersistedLogs::PROVISIONAL_STORE);
log_manager.DiscardLastProvisionalStore();
log_manager.DiscardLastProvisionalStore();

log_manager.PersistUnsentLogs();
EXPECT_EQ(0U, pref_service.TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(1U, pref_service.TypeCount(MetricsLog::ONGOING_LOG));
}
}
Expand Down
14 changes: 0 additions & 14 deletions components/metrics/metrics_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -773,16 +773,6 @@ void MetricsService::PushPendingLogsToPersistentStorage() {
if (state_ < SENDING_INITIAL_STABILITY_LOG)
return; // We didn't and still don't have time to get plugin list etc.

if (log_manager_.has_staged_log()) {
// We may race here, and send second copy of the log later.
metrics::PersistedLogs::StoreType store_type;
if (log_upload_in_progress_)
store_type = metrics::PersistedLogs::PROVISIONAL_STORE;
else
store_type = metrics::PersistedLogs::NORMAL_STORE;
log_manager_.StoreStagedLogAsUnsent(store_type);
}
DCHECK(!log_manager_.has_staged_log());
CloseCurrentLog();
log_manager_.PersistUnsentLogs();

Expand Down Expand Up @@ -1035,10 +1025,6 @@ void MetricsService::OnLogUploadComplete(int response_code) {
ResponseCodeToStatus(response_code),
NUM_RESPONSE_STATUSES);

// If the upload was provisionally stored, drop it now that the upload is
// known to have gone through.
log_manager_.DiscardLastProvisionalStore();

bool upload_succeeded = response_code == 200;

// Provide boolean for error recovery (allow us to ignore response_code).
Expand Down
38 changes: 5 additions & 33 deletions components/metrics/persisted_logs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,6 @@ void PersistedLogs::LogHashPair::Init(const std::string& log_data) {
hash = base::SHA1HashString(log_data);
}

void PersistedLogs::LogHashPair::Clear() {
compressed_log_data.clear();
hash.clear();
}

void PersistedLogs::LogHashPair::Swap(PersistedLogs::LogHashPair* input) {
compressed_log_data.swap(input->compressed_log_data);
hash.swap(input->hash);
}

PersistedLogs::PersistedLogs(PrefService* local_state,
const char* pref_name,
const char* old_pref_name,
Expand All @@ -87,7 +77,7 @@ PersistedLogs::PersistedLogs(PrefService* local_state,
min_log_count_(min_log_count),
min_log_bytes_(min_log_bytes),
max_log_size_(max_log_size != 0 ? max_log_size : static_cast<size_t>(-1)),
last_provisional_store_index_(-1) {
staged_log_index_(-1) {
DCHECK(local_state_);
// One of the limit arguments must be non-zero.
DCHECK(min_log_count_ > 0 || min_log_bytes_ > 0);
Expand Down Expand Up @@ -125,33 +115,15 @@ void PersistedLogs::StageLog() {
// hard-to-identify crashes much later.
CHECK(!list_.empty());
DCHECK(!has_staged_log());
staged_log_.Swap(&list_.back());
list_.pop_back();

// If the staged log was the last provisional store, clear that.
if (static_cast<size_t>(last_provisional_store_index_) == list_.size())
last_provisional_store_index_ = -1;
staged_log_index_ = list_.size() - 1;
DCHECK(has_staged_log());
}

void PersistedLogs::DiscardStagedLog() {
DCHECK(has_staged_log());
staged_log_.Clear();
}

void PersistedLogs::StoreStagedLogAsUnsent(StoreType store_type) {
list_.push_back(LogHashPair());
list_.back().Swap(&staged_log_);
if (store_type == PROVISIONAL_STORE)
last_provisional_store_index_ = list_.size() - 1;
}

void PersistedLogs::DiscardLastProvisionalStore() {
if (last_provisional_store_index_ == -1)
return;
DCHECK_LT(static_cast<size_t>(last_provisional_store_index_), list_.size());
list_.erase(list_.begin() + last_provisional_store_index_);
last_provisional_store_index_ = -1;
DCHECK_LT(static_cast<size_t>(staged_log_index_), list_.size());
list_.erase(list_.begin() + staged_log_index_);
staged_log_index_ = -1;
}

void PersistedLogs::WriteLogsToPrefList(base::ListValue* list_value) const {
Expand Down
46 changes: 6 additions & 40 deletions components/metrics/persisted_logs.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@ class PersistedLogs {
END_RECALL_STATUS // Number of bins to use to create the histogram.
};

enum StoreType {
NORMAL_STORE, // A standard store operation.
PROVISIONAL_STORE, // A store operation that can be easily reverted later.
};

// Constructs a PersistedLogs that stores data in |local_state| under the
// preference |pref_name| and also reads from legacy pref |old_pref_name|.
// Calling code is responsible for ensuring that the lifetime of |local_state|
Expand Down Expand Up @@ -76,35 +71,19 @@ class PersistedLogs {
// Remove the staged log.
void DiscardStagedLog();

// Saves the staged log, then clears staged_log().
// If |store_type| is PROVISIONAL_STORE, it can be dropped from storage with
// a later call to DiscardLastProvisionalStore (if it hasn't already been
// staged again).
// This is intended to be used when logs are being saved while an upload is in
// progress, in case the upload later succeeds.
// This can only be called if has_staged_log() is true.
void StoreStagedLogAsUnsent(StoreType store_type);

// Discards the last log stored with StoreStagedLogAsUnsent with |store_type|
// set to PROVISIONAL_STORE, as long as it hasn't already been re-staged. If
// the log is no longer present, this is a no-op.
void DiscardLastProvisionalStore();

// True if a log has been staged.
bool has_staged_log() const {
return !staged_log_.compressed_log_data.empty();
}
bool has_staged_log() const { return staged_log_index_ != -1; };

// Returns the element in the front of the list.
const std::string& staged_log() const {
DCHECK(has_staged_log());
return staged_log_.compressed_log_data;
return list_[staged_log_index_].compressed_log_data;
}

// Returns the element in the front of the list.
const std::string& staged_log_hash() const {
DCHECK(has_staged_log());
return staged_log_.hash;
return list_[staged_log_index_].hash;
}

// The number of elements currently stored.
Expand Down Expand Up @@ -149,12 +128,6 @@ class PersistedLogs {
// Initializes the members based on uncompressed |log_data|.
void Init(const std::string& log_data);

// Clears the struct members.
void Clear();

// Swap both log and hash from another LogHashPair.
void Swap(LogHashPair* input);

// Compressed log data - a serialized protobuf that's been gzipped.
std::string compressed_log_data;

Expand All @@ -165,16 +138,9 @@ class PersistedLogs {
// corruption while they are stored in memory.
std::vector<LogHashPair> list_;

// The log staged for upload.
LogHashPair staged_log_;

// The index and type of the last provisional store. If nothing has been
// provisionally stored, or the last provisional store has already been
// re-staged, the index will be -1;
// This is necessary because during an upload there are two logs (staged
// and current) and a client might store them in either order, so it's
// not necessarily the case that the provisional store is the last store.
int last_provisional_store_index_;
// The index and type of the log staged for upload. If nothing has been
// staged, the index will be -1.
int staged_log_index_;

DISALLOW_COPY_AND_ASSIGN(PersistedLogs);
};
Expand Down
Loading

0 comments on commit faa8d22

Please sign in to comment.