// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/sync/sessions/session_state.h" #include <map> #include <set> #include <string> #include <utility> #include <vector> #include "base/base64.h" #include "base/values.h" #include "chrome/browser/sync/protocol/proto_enum_conversions.h" using std::set; using std::vector; namespace browser_sync { namespace sessions { SyncSourceInfo::SyncSourceInfo() : updates_source(sync_pb::GetUpdatesCallerInfo::UNKNOWN) {} SyncSourceInfo::SyncSourceInfo( const syncable::ModelTypePayloadMap& t) : updates_source(sync_pb::GetUpdatesCallerInfo::UNKNOWN), types(t) {} SyncSourceInfo::SyncSourceInfo( const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& u, const syncable::ModelTypePayloadMap& t) : updates_source(u), types(t) {} SyncSourceInfo::~SyncSourceInfo() {} DictionaryValue* SyncSourceInfo::ToValue() const { DictionaryValue* value = new DictionaryValue(); value->SetString("updatesSource", GetUpdatesSourceString(updates_source)); value->Set("types", syncable::ModelTypePayloadMapToValue(types)); return value; } SyncerStatus::SyncerStatus() : invalid_store(false), syncer_stuck(false), syncing(false), num_successful_commits(0), num_successful_bookmark_commits(0), num_updates_downloaded_total(0), num_tombstone_updates_downloaded_total(0) { } SyncerStatus::~SyncerStatus() { } DictionaryValue* SyncerStatus::ToValue() const { DictionaryValue* value = new DictionaryValue(); value->SetBoolean("invalidStore", invalid_store); value->SetBoolean("syncerStuck", syncer_stuck); value->SetBoolean("syncing", syncing); value->SetInteger("numSuccessfulCommits", num_successful_commits); value->SetInteger("numSuccessfulBookmarkCommits", num_successful_bookmark_commits); value->SetInteger("numUpdatesDownloadedTotal", num_updates_downloaded_total); value->SetInteger("numTombstoneUpdatesDownloadedTotal", num_tombstone_updates_downloaded_total); return value; } DictionaryValue* DownloadProgressMarkersToValue( const std::string (&download_progress_markers)[syncable::MODEL_TYPE_COUNT]) { DictionaryValue* value = new DictionaryValue(); for (int i = syncable::FIRST_REAL_MODEL_TYPE; i < syncable::MODEL_TYPE_COUNT; ++i) { // TODO(akalin): Unpack the value into a protobuf. std::string base64_marker; bool encoded = base::Base64Encode(download_progress_markers[i], &base64_marker); DCHECK(encoded); value->SetString( syncable::ModelTypeToString(syncable::ModelTypeFromInt(i)), base64_marker); } return value; } ErrorCounters::ErrorCounters() : num_conflicting_commits(0), consecutive_transient_error_commits(0), consecutive_errors(0) { } DictionaryValue* ErrorCounters::ToValue() const { DictionaryValue* value = new DictionaryValue(); value->SetInteger("numConflictingCommits", num_conflicting_commits); value->SetInteger("consecutiveTransientErrorCommits", consecutive_transient_error_commits); value->SetInteger("consecutiveErrors", consecutive_errors); return value; } SyncSessionSnapshot::SyncSessionSnapshot( const SyncerStatus& syncer_status, const ErrorCounters& errors, int64 num_server_changes_remaining, bool is_share_usable, const syncable::ModelTypeBitSet& initial_sync_ended, const std::string (&download_progress_markers)[syncable::MODEL_TYPE_COUNT], bool more_to_sync, bool is_silenced, int64 unsynced_count, int num_conflicting_updates, bool did_commit_items, const SyncSourceInfo& source) : syncer_status(syncer_status), errors(errors), num_server_changes_remaining(num_server_changes_remaining), is_share_usable(is_share_usable), initial_sync_ended(initial_sync_ended), download_progress_markers(), has_more_to_sync(more_to_sync), is_silenced(is_silenced), unsynced_count(unsynced_count), num_conflicting_updates(num_conflicting_updates), did_commit_items(did_commit_items), source(source) { for (int i = syncable::FIRST_REAL_MODEL_TYPE; i < syncable::MODEL_TYPE_COUNT; ++i) { const_cast<std::string&>(this->download_progress_markers[i]).assign( download_progress_markers[i]); } } SyncSessionSnapshot::~SyncSessionSnapshot() {} DictionaryValue* SyncSessionSnapshot::ToValue() const { DictionaryValue* value = new DictionaryValue(); value->Set("syncerStatus", syncer_status.ToValue()); value->Set("errors", errors.ToValue()); // We don't care too much if we lose precision here. value->SetInteger("numServerChangesRemaining", static_cast<int>(num_server_changes_remaining)); value->SetBoolean("isShareUsable", is_share_usable); value->Set("initialSyncEnded", syncable::ModelTypeBitSetToValue(initial_sync_ended)); value->Set("downloadProgressMarkers", DownloadProgressMarkersToValue(download_progress_markers)); value->SetBoolean("hasMoreToSync", has_more_to_sync); value->SetBoolean("isSilenced", is_silenced); // We don't care too much if we lose precision here, also. value->SetInteger("unsyncedCount", static_cast<int>(unsynced_count)); value->SetInteger("numConflictingUpdates", num_conflicting_updates); value->SetBoolean("didCommitItems", did_commit_items); value->Set("source", source.ToValue()); return value; } ConflictProgress::ConflictProgress(bool* dirty_flag) : dirty_(dirty_flag) {} ConflictProgress::~ConflictProgress() { CleanupSets(); } IdToConflictSetMap::const_iterator ConflictProgress::IdToConflictSetFind( const syncable::Id& the_id) const { return id_to_conflict_set_.find(the_id); } IdToConflictSetMap::const_iterator ConflictProgress::IdToConflictSetBegin() const { return id_to_conflict_set_.begin(); } IdToConflictSetMap::const_iterator ConflictProgress::IdToConflictSetEnd() const { return id_to_conflict_set_.end(); } IdToConflictSetMap::size_type ConflictProgress::IdToConflictSetSize() const { return id_to_conflict_set_.size(); } const ConflictSet* ConflictProgress::IdToConflictSetGet( const syncable::Id& the_id) { return id_to_conflict_set_[the_id]; } std::set<ConflictSet*>::const_iterator ConflictProgress::ConflictSetsBegin() const { return conflict_sets_.begin(); } std::set<ConflictSet*>::const_iterator ConflictProgress::ConflictSetsEnd() const { return conflict_sets_.end(); } std::set<ConflictSet*>::size_type ConflictProgress::ConflictSetsSize() const { return conflict_sets_.size(); } std::set<syncable::Id>::iterator ConflictProgress::ConflictingItemsBegin() { return conflicting_item_ids_.begin(); } std::set<syncable::Id>::const_iterator ConflictProgress::ConflictingItemsBeginConst() const { return conflicting_item_ids_.begin(); } std::set<syncable::Id>::const_iterator ConflictProgress::ConflictingItemsEnd() const { return conflicting_item_ids_.end(); } void ConflictProgress::AddConflictingItemById(const syncable::Id& the_id) { std::pair<std::set<syncable::Id>::iterator, bool> ret = conflicting_item_ids_.insert(the_id); if (ret.second) *dirty_ = true; } void ConflictProgress::EraseConflictingItemById(const syncable::Id& the_id) { int items_erased = conflicting_item_ids_.erase(the_id); if (items_erased != 0) *dirty_ = true; } void ConflictProgress::MergeSets(const syncable::Id& id1, const syncable::Id& id2) { // There are no single item sets, we just leave those entries == 0 vector<syncable::Id>* set1 = id_to_conflict_set_[id1]; vector<syncable::Id>* set2 = id_to_conflict_set_[id2]; vector<syncable::Id>* rv = 0; if (0 == set1 && 0 == set2) { // Neither item currently has a set so we build one. rv = new vector<syncable::Id>(); rv->push_back(id1); if (id1 != id2) { rv->push_back(id2); } else { LOG(WARNING) << "[BUG] Attempting to merge two identical conflict ids."; } conflict_sets_.insert(rv); } else if (0 == set1) { // Add the item to the existing set. rv = set2; rv->push_back(id1); } else if (0 == set2) { // Add the item to the existing set. rv = set1; rv->push_back(id2); } else if (set1 == set2) { // It's the same set already. return; } else { // Merge the two sets. rv = set1; // Point all the second sets id's back to the first. vector<syncable::Id>::iterator i; for (i = set2->begin() ; i != set2->end() ; ++i) { id_to_conflict_set_[*i] = rv; } // Copy the second set to the first. rv->insert(rv->end(), set2->begin(), set2->end()); conflict_sets_.erase(set2); delete set2; } id_to_conflict_set_[id1] = id_to_conflict_set_[id2] = rv; } void ConflictProgress::CleanupSets() { // Clean up all the sets. set<ConflictSet*>::iterator i; for (i = conflict_sets_.begin(); i != conflict_sets_.end(); i++) { delete *i; } conflict_sets_.clear(); id_to_conflict_set_.clear(); } UpdateProgress::UpdateProgress() {} UpdateProgress::~UpdateProgress() {} void UpdateProgress::AddVerifyResult(const VerifyResult& verify_result, const sync_pb::SyncEntity& entity) { verified_updates_.push_back(std::make_pair(verify_result, entity)); } void UpdateProgress::AddAppliedUpdate(const UpdateAttemptResponse& response, const syncable::Id& id) { applied_updates_.push_back(std::make_pair(response, id)); } std::vector<AppliedUpdate>::iterator UpdateProgress::AppliedUpdatesBegin() { return applied_updates_.begin(); } std::vector<VerifiedUpdate>::const_iterator UpdateProgress::VerifiedUpdatesBegin() const { return verified_updates_.begin(); } std::vector<AppliedUpdate>::const_iterator UpdateProgress::AppliedUpdatesEnd() const { return applied_updates_.end(); } std::vector<VerifiedUpdate>::const_iterator UpdateProgress::VerifiedUpdatesEnd() const { return verified_updates_.end(); } int UpdateProgress::SuccessfullyAppliedUpdateCount() const { int count = 0; for (std::vector<AppliedUpdate>::const_iterator it = applied_updates_.begin(); it != applied_updates_.end(); ++it) { if (it->first == SUCCESS) count++; } return count; } // Returns true if at least one update application failed due to a conflict // during this sync cycle. bool UpdateProgress::HasConflictingUpdates() const { std::vector<AppliedUpdate>::const_iterator it; for (it = applied_updates_.begin(); it != applied_updates_.end(); ++it) { if (it->first == CONFLICT) { return true; } } return false; } AllModelTypeState::AllModelTypeState(bool* dirty_flag) : unsynced_handles(dirty_flag), syncer_status(dirty_flag), error_counters(dirty_flag), num_server_changes_remaining(dirty_flag, 0), commit_set(ModelSafeRoutingInfo()) { } AllModelTypeState::~AllModelTypeState() {} PerModelSafeGroupState::PerModelSafeGroupState(bool* dirty_flag) : conflict_progress(dirty_flag) { } PerModelSafeGroupState::~PerModelSafeGroupState() { } } // namespace sessions } // namespace browser_sync