1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/sync/sessions/session_state.h"
6
7#include <map>
8#include <set>
9#include <string>
10#include <utility>
11#include <vector>
12
13#include "base/base64.h"
14#include "base/values.h"
15#include "chrome/browser/sync/protocol/proto_enum_conversions.h"
16
17using std::set;
18using std::vector;
19
20namespace browser_sync {
21namespace sessions {
22
23SyncSourceInfo::SyncSourceInfo()
24    : updates_source(sync_pb::GetUpdatesCallerInfo::UNKNOWN) {}
25
26SyncSourceInfo::SyncSourceInfo(
27    const syncable::ModelTypePayloadMap& t)
28    : updates_source(sync_pb::GetUpdatesCallerInfo::UNKNOWN), types(t) {}
29
30SyncSourceInfo::SyncSourceInfo(
31    const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& u,
32    const syncable::ModelTypePayloadMap& t)
33    : updates_source(u), types(t) {}
34
35SyncSourceInfo::~SyncSourceInfo() {}
36
37DictionaryValue* SyncSourceInfo::ToValue() const {
38  DictionaryValue* value = new DictionaryValue();
39  value->SetString("updatesSource",
40                   GetUpdatesSourceString(updates_source));
41  value->Set("types", syncable::ModelTypePayloadMapToValue(types));
42  return value;
43}
44
45SyncerStatus::SyncerStatus()
46    : invalid_store(false),
47      syncer_stuck(false),
48      syncing(false),
49      num_successful_commits(0),
50      num_successful_bookmark_commits(0),
51      num_updates_downloaded_total(0),
52      num_tombstone_updates_downloaded_total(0) {
53}
54
55SyncerStatus::~SyncerStatus() {
56}
57
58DictionaryValue* SyncerStatus::ToValue() const {
59  DictionaryValue* value = new DictionaryValue();
60  value->SetBoolean("invalidStore", invalid_store);
61  value->SetBoolean("syncerStuck", syncer_stuck);
62  value->SetBoolean("syncing", syncing);
63  value->SetInteger("numSuccessfulCommits", num_successful_commits);
64  value->SetInteger("numSuccessfulBookmarkCommits",
65                num_successful_bookmark_commits);
66  value->SetInteger("numUpdatesDownloadedTotal",
67                num_updates_downloaded_total);
68  value->SetInteger("numTombstoneUpdatesDownloadedTotal",
69                num_tombstone_updates_downloaded_total);
70  return value;
71}
72
73DictionaryValue* DownloadProgressMarkersToValue(
74    const std::string
75        (&download_progress_markers)[syncable::MODEL_TYPE_COUNT]) {
76  DictionaryValue* value = new DictionaryValue();
77  for (int i = syncable::FIRST_REAL_MODEL_TYPE;
78       i < syncable::MODEL_TYPE_COUNT; ++i) {
79    // TODO(akalin): Unpack the value into a protobuf.
80    std::string base64_marker;
81    bool encoded =
82        base::Base64Encode(download_progress_markers[i], &base64_marker);
83    DCHECK(encoded);
84    value->SetString(
85        syncable::ModelTypeToString(syncable::ModelTypeFromInt(i)),
86        base64_marker);
87  }
88  return value;
89}
90
91ErrorCounters::ErrorCounters()
92    : num_conflicting_commits(0),
93      consecutive_transient_error_commits(0),
94      consecutive_errors(0) {
95}
96
97DictionaryValue* ErrorCounters::ToValue() const {
98  DictionaryValue* value = new DictionaryValue();
99  value->SetInteger("numConflictingCommits", num_conflicting_commits);
100  value->SetInteger("consecutiveTransientErrorCommits",
101                consecutive_transient_error_commits);
102  value->SetInteger("consecutiveErrors", consecutive_errors);
103  return value;
104}
105
106SyncSessionSnapshot::SyncSessionSnapshot(
107    const SyncerStatus& syncer_status,
108    const ErrorCounters& errors,
109    int64 num_server_changes_remaining,
110    bool is_share_usable,
111    const syncable::ModelTypeBitSet& initial_sync_ended,
112    const std::string
113        (&download_progress_markers)[syncable::MODEL_TYPE_COUNT],
114    bool more_to_sync,
115    bool is_silenced,
116    int64 unsynced_count,
117    int num_conflicting_updates,
118    bool did_commit_items,
119    const SyncSourceInfo& source)
120    : syncer_status(syncer_status),
121      errors(errors),
122      num_server_changes_remaining(num_server_changes_remaining),
123      is_share_usable(is_share_usable),
124      initial_sync_ended(initial_sync_ended),
125      download_progress_markers(),
126      has_more_to_sync(more_to_sync),
127      is_silenced(is_silenced),
128      unsynced_count(unsynced_count),
129      num_conflicting_updates(num_conflicting_updates),
130      did_commit_items(did_commit_items),
131      source(source) {
132  for (int i = syncable::FIRST_REAL_MODEL_TYPE;
133       i < syncable::MODEL_TYPE_COUNT; ++i) {
134    const_cast<std::string&>(this->download_progress_markers[i]).assign(
135        download_progress_markers[i]);
136  }
137}
138
139SyncSessionSnapshot::~SyncSessionSnapshot() {}
140
141DictionaryValue* SyncSessionSnapshot::ToValue() const {
142  DictionaryValue* value = new DictionaryValue();
143  value->Set("syncerStatus", syncer_status.ToValue());
144  value->Set("errors", errors.ToValue());
145  // We don't care too much if we lose precision here.
146  value->SetInteger("numServerChangesRemaining",
147                    static_cast<int>(num_server_changes_remaining));
148  value->SetBoolean("isShareUsable", is_share_usable);
149  value->Set("initialSyncEnded",
150             syncable::ModelTypeBitSetToValue(initial_sync_ended));
151  value->Set("downloadProgressMarkers",
152             DownloadProgressMarkersToValue(download_progress_markers));
153  value->SetBoolean("hasMoreToSync", has_more_to_sync);
154  value->SetBoolean("isSilenced", is_silenced);
155  // We don't care too much if we lose precision here, also.
156  value->SetInteger("unsyncedCount",
157                    static_cast<int>(unsynced_count));
158  value->SetInteger("numConflictingUpdates", num_conflicting_updates);
159  value->SetBoolean("didCommitItems", did_commit_items);
160  value->Set("source", source.ToValue());
161  return value;
162}
163
164ConflictProgress::ConflictProgress(bool* dirty_flag) : dirty_(dirty_flag) {}
165
166ConflictProgress::~ConflictProgress() {
167  CleanupSets();
168}
169
170IdToConflictSetMap::const_iterator ConflictProgress::IdToConflictSetFind(
171    const syncable::Id& the_id) const {
172  return id_to_conflict_set_.find(the_id);
173}
174
175IdToConflictSetMap::const_iterator
176ConflictProgress::IdToConflictSetBegin() const {
177  return id_to_conflict_set_.begin();
178}
179
180IdToConflictSetMap::const_iterator
181ConflictProgress::IdToConflictSetEnd() const {
182  return id_to_conflict_set_.end();
183}
184
185IdToConflictSetMap::size_type ConflictProgress::IdToConflictSetSize() const {
186  return id_to_conflict_set_.size();
187}
188
189const ConflictSet* ConflictProgress::IdToConflictSetGet(
190    const syncable::Id& the_id) {
191  return id_to_conflict_set_[the_id];
192}
193
194std::set<ConflictSet*>::const_iterator
195ConflictProgress::ConflictSetsBegin() const {
196  return conflict_sets_.begin();
197}
198
199std::set<ConflictSet*>::const_iterator
200ConflictProgress::ConflictSetsEnd() const {
201  return conflict_sets_.end();
202}
203
204std::set<ConflictSet*>::size_type
205ConflictProgress::ConflictSetsSize() const {
206  return conflict_sets_.size();
207}
208
209std::set<syncable::Id>::iterator
210ConflictProgress::ConflictingItemsBegin() {
211  return conflicting_item_ids_.begin();
212}
213std::set<syncable::Id>::const_iterator
214ConflictProgress::ConflictingItemsBeginConst() const {
215  return conflicting_item_ids_.begin();
216}
217std::set<syncable::Id>::const_iterator
218ConflictProgress::ConflictingItemsEnd() const {
219  return conflicting_item_ids_.end();
220}
221
222void ConflictProgress::AddConflictingItemById(const syncable::Id& the_id) {
223  std::pair<std::set<syncable::Id>::iterator, bool> ret =
224    conflicting_item_ids_.insert(the_id);
225  if (ret.second)
226    *dirty_ = true;
227}
228
229void ConflictProgress::EraseConflictingItemById(const syncable::Id& the_id) {
230  int items_erased = conflicting_item_ids_.erase(the_id);
231  if (items_erased != 0)
232    *dirty_ = true;
233}
234
235void ConflictProgress::MergeSets(const syncable::Id& id1,
236                                 const syncable::Id& id2) {
237  // There are no single item sets, we just leave those entries == 0
238  vector<syncable::Id>* set1 = id_to_conflict_set_[id1];
239  vector<syncable::Id>* set2 = id_to_conflict_set_[id2];
240  vector<syncable::Id>* rv = 0;
241  if (0 == set1 && 0 == set2) {
242    // Neither item currently has a set so we build one.
243    rv = new vector<syncable::Id>();
244    rv->push_back(id1);
245    if (id1 != id2) {
246      rv->push_back(id2);
247    } else {
248      LOG(WARNING) << "[BUG] Attempting to merge two identical conflict ids.";
249    }
250    conflict_sets_.insert(rv);
251  } else if (0 == set1) {
252    // Add the item to the existing set.
253    rv = set2;
254    rv->push_back(id1);
255  } else if (0 == set2) {
256    // Add the item to the existing set.
257    rv = set1;
258    rv->push_back(id2);
259  } else if (set1 == set2) {
260    // It's the same set already.
261    return;
262  } else {
263    // Merge the two sets.
264    rv = set1;
265    // Point all the second sets id's back to the first.
266    vector<syncable::Id>::iterator i;
267    for (i = set2->begin() ; i != set2->end() ; ++i) {
268      id_to_conflict_set_[*i] = rv;
269    }
270    // Copy the second set to the first.
271    rv->insert(rv->end(), set2->begin(), set2->end());
272    conflict_sets_.erase(set2);
273    delete set2;
274  }
275  id_to_conflict_set_[id1] = id_to_conflict_set_[id2] = rv;
276}
277
278void ConflictProgress::CleanupSets() {
279  // Clean up all the sets.
280  set<ConflictSet*>::iterator i;
281  for (i = conflict_sets_.begin(); i != conflict_sets_.end(); i++) {
282    delete *i;
283  }
284  conflict_sets_.clear();
285  id_to_conflict_set_.clear();
286}
287
288UpdateProgress::UpdateProgress() {}
289
290UpdateProgress::~UpdateProgress() {}
291
292void UpdateProgress::AddVerifyResult(const VerifyResult& verify_result,
293                                     const sync_pb::SyncEntity& entity) {
294  verified_updates_.push_back(std::make_pair(verify_result, entity));
295}
296
297void UpdateProgress::AddAppliedUpdate(const UpdateAttemptResponse& response,
298    const syncable::Id& id) {
299  applied_updates_.push_back(std::make_pair(response, id));
300}
301
302std::vector<AppliedUpdate>::iterator UpdateProgress::AppliedUpdatesBegin() {
303  return applied_updates_.begin();
304}
305
306std::vector<VerifiedUpdate>::const_iterator
307UpdateProgress::VerifiedUpdatesBegin() const {
308  return verified_updates_.begin();
309}
310
311std::vector<AppliedUpdate>::const_iterator
312UpdateProgress::AppliedUpdatesEnd() const {
313  return applied_updates_.end();
314}
315
316std::vector<VerifiedUpdate>::const_iterator
317UpdateProgress::VerifiedUpdatesEnd() const {
318  return verified_updates_.end();
319}
320
321int UpdateProgress::SuccessfullyAppliedUpdateCount() const {
322  int count = 0;
323  for (std::vector<AppliedUpdate>::const_iterator it =
324       applied_updates_.begin();
325       it != applied_updates_.end();
326       ++it) {
327    if (it->first == SUCCESS)
328      count++;
329  }
330  return count;
331}
332
333// Returns true if at least one update application failed due to a conflict
334// during this sync cycle.
335bool UpdateProgress::HasConflictingUpdates() const {
336  std::vector<AppliedUpdate>::const_iterator it;
337  for (it = applied_updates_.begin(); it != applied_updates_.end(); ++it) {
338    if (it->first == CONFLICT) {
339      return true;
340    }
341  }
342  return false;
343}
344
345AllModelTypeState::AllModelTypeState(bool* dirty_flag)
346    : unsynced_handles(dirty_flag),
347      syncer_status(dirty_flag),
348      error_counters(dirty_flag),
349      num_server_changes_remaining(dirty_flag, 0),
350      commit_set(ModelSafeRoutingInfo()) {
351}
352
353AllModelTypeState::~AllModelTypeState() {}
354
355PerModelSafeGroupState::PerModelSafeGroupState(bool* dirty_flag)
356    : conflict_progress(dirty_flag) {
357}
358
359PerModelSafeGroupState::~PerModelSafeGroupState() {
360}
361
362}  // namespace sessions
363}  // namespace browser_sync
364