| // 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 |