// 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.
// The 'sessions' namespace comprises all the pieces of state that are
// combined to form a SyncSession instance. In that way, it can be thought of
// as an extension of the SyncSession type itself. Session scoping gives
// context to things like "conflict progress", "update progress", etc, and the
// separation this file provides allows clients to only include the parts they
// need rather than the entire session stack.
#ifndef CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
#define CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
#pragma once
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/basictypes.h"
#include "chrome/browser/sync/engine/syncer_types.h"
#include "chrome/browser/sync/engine/syncproto.h"
#include "chrome/browser/sync/sessions/ordered_commit_set.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/syncable/model_type_payload_map.h"
#include "chrome/browser/sync/syncable/syncable.h"
class DictionaryValue;
namespace syncable {
class DirectoryManager;
}
namespace browser_sync {
namespace sessions {
class UpdateProgress;
// A container for the source of a sync session. This includes the update
// source, the datatypes triggering the sync session, and possible session
// specific payloads which should be sent to the server.
struct SyncSourceInfo {
SyncSourceInfo();
explicit SyncSourceInfo(const syncable::ModelTypePayloadMap& t);
SyncSourceInfo(
const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& u,
const syncable::ModelTypePayloadMap& t);
~SyncSourceInfo();
// Caller takes ownership of the returned dictionary.
DictionaryValue* ToValue() const;
sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source;
syncable::ModelTypePayloadMap types;
};
// Data pertaining to the status of an active Syncer object.
struct SyncerStatus {
SyncerStatus();
~SyncerStatus();
// Caller takes ownership of the returned dictionary.
DictionaryValue* ToValue() const;
// True when we get such an INVALID_STORE error from the server.
bool invalid_store;
// True iff we're stuck.
bool syncer_stuck;
bool syncing;
int num_successful_commits;
// This is needed for monitoring extensions activity.
int num_successful_bookmark_commits;
// Download event counters.
int num_updates_downloaded_total;
int num_tombstone_updates_downloaded_total;
// If the syncer encountered a MIGRATION_DONE code, these are the types that
// the client must now "migrate", by purging and re-downloading all updates.
syncable::ModelTypeSet types_needing_local_migration;
};
// Counters for various errors that can occur repeatedly during a sync session.
struct ErrorCounters {
ErrorCounters();
// Caller takes ownership of the returned dictionary.
DictionaryValue* ToValue() const;
int num_conflicting_commits;
// Number of commits hitting transient errors since the last successful
// commit.
int consecutive_transient_error_commits;
// Incremented when get_updates fails, commit fails, and when hitting
// transient errors. When any of these succeed, this counter is reset.
// TODO(chron): Reduce number of weird counters we use.
int consecutive_errors;
};
// Caller takes ownership of the returned dictionary.
DictionaryValue* DownloadProgressMarkersToValue(
const std::string
(&download_progress_markers)[syncable::MODEL_TYPE_COUNT]);
// An immutable snapshot of state from a SyncSession. Convenient to use as
// part of notifications as it is inherently thread-safe.
struct 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);
~SyncSessionSnapshot();
// Caller takes ownership of the returned dictionary.
DictionaryValue* ToValue() const;
const SyncerStatus syncer_status;
const ErrorCounters errors;
const int64 num_server_changes_remaining;
const bool is_share_usable;
const syncable::ModelTypeBitSet initial_sync_ended;
const std::string download_progress_markers[syncable::MODEL_TYPE_COUNT];
const bool has_more_to_sync;
const bool is_silenced;
const int64 unsynced_count;
const int num_conflicting_updates;
const bool did_commit_items;
const SyncSourceInfo source;
};
// Tracks progress of conflicts and their resolution using conflict sets.
class ConflictProgress {
public:
explicit ConflictProgress(bool* dirty_flag);
~ConflictProgress();
// Various iterators, size, and retrieval functions for conflict sets.
IdToConflictSetMap::const_iterator IdToConflictSetBegin() const;
IdToConflictSetMap::const_iterator IdToConflictSetEnd() const;
IdToConflictSetMap::size_type IdToConflictSetSize() const;
IdToConflictSetMap::const_iterator IdToConflictSetFind(
const syncable::Id& the_id) const;
const ConflictSet* IdToConflictSetGet(const syncable::Id& the_id);
std::set<ConflictSet*>::const_iterator ConflictSetsBegin() const;
std::set<ConflictSet*>::const_iterator ConflictSetsEnd() const;
std::set<ConflictSet*>::size_type ConflictSetsSize() const;
// Various mutators for tracking commit conflicts.
void AddConflictingItemById(const syncable::Id& the_id);
void EraseConflictingItemById(const syncable::Id& the_id);
int ConflictingItemsSize() const { return conflicting_item_ids_.size(); }
std::set<syncable::Id>::iterator ConflictingItemsBegin();
std::set<syncable::Id>::const_iterator ConflictingItemsBeginConst() const;
std::set<syncable::Id>::const_iterator ConflictingItemsEnd() const;
void MergeSets(const syncable::Id& set1, const syncable::Id& set2);
void CleanupSets();
private:
// TODO(sync): move away from sets if it makes more sense.
std::set<syncable::Id> conflicting_item_ids_;
std::map<syncable::Id, ConflictSet*> id_to_conflict_set_;
std::set<ConflictSet*> conflict_sets_;
// Whether a conflicting item was added or removed since
// the last call to reset_progress_changed(), if any. In practice this
// points to StatusController::is_dirty_.
bool* dirty_;
};
typedef std::pair<VerifyResult, sync_pb::SyncEntity> VerifiedUpdate;
typedef std::pair<UpdateAttemptResponse, syncable::Id> AppliedUpdate;
// Tracks update application and verification.
class UpdateProgress {
public:
UpdateProgress();
~UpdateProgress();
void AddVerifyResult(const VerifyResult& verify_result,
const sync_pb::SyncEntity& entity);
// Log a successful or failing update attempt.
void AddAppliedUpdate(const UpdateAttemptResponse& response,
const syncable::Id& id);
// Various iterators.
std::vector<AppliedUpdate>::iterator AppliedUpdatesBegin();
std::vector<VerifiedUpdate>::const_iterator VerifiedUpdatesBegin() const;
std::vector<AppliedUpdate>::const_iterator AppliedUpdatesEnd() const;
std::vector<VerifiedUpdate>::const_iterator VerifiedUpdatesEnd() const;
// Returns the number of update application attempts. This includes both
// failures and successes.
int AppliedUpdatesSize() const { return applied_updates_.size(); }
int VerifiedUpdatesSize() const { return verified_updates_.size(); }
bool HasVerifiedUpdates() const { return !verified_updates_.empty(); }
bool HasAppliedUpdates() const { return !applied_updates_.empty(); }
// Count the number of successful update applications that have happend this
// cycle. Note that if an item is successfully applied twice, it will be
// double counted here.
int SuccessfullyAppliedUpdateCount() const;
// Returns true if at least one update application failed due to a conflict
// during this sync cycle.
bool HasConflictingUpdates() const;
private:
// Container for updates that passed verification.
std::vector<VerifiedUpdate> verified_updates_;
// Stores the result of the various ApplyUpdate attempts we've made.
// May contain duplicate entries.
std::vector<AppliedUpdate> applied_updates_;
};
struct SyncCycleControlParameters {
SyncCycleControlParameters() : conflict_sets_built(false),
conflicts_resolved(false),
items_committed(false) {}
// Set to true by BuildAndProcessConflictSetsCommand if the RESOLVE_CONFLICTS
// step is needed.
bool conflict_sets_built;
// Set to true by ResolveConflictsCommand if any forward progress was made.
bool conflicts_resolved;
// Set to true by PostCommitMessageCommand if any commits were successful.
bool items_committed;
};
// DirtyOnWrite wraps a value such that any write operation will update a
// specified dirty bit, which can be used to determine if a notification should
// be sent due to state change.
template <typename T>
class DirtyOnWrite {
public:
explicit DirtyOnWrite(bool* dirty) : dirty_(dirty) {}
DirtyOnWrite(bool* dirty, const T& t) : t_(t), dirty_(dirty) {}
T* mutate() {
*dirty_ = true;
return &t_;
}
const T& value() const { return t_; }
private:
T t_;
bool* dirty_;
};
// The next 3 structures declare how all the state involved in running a sync
// cycle is divided between global scope (applies to all model types),
// ModelSafeGroup scope (applies to all data types in a group), and single
// model type scope. Within this breakdown, each struct declares which bits
// of state are dirty-on-write and should incur dirty bit updates if changed.
// Grouping of all state that applies to all model types. Note that some
// components of the global grouping can internally implement finer grained
// scope control (such as OrderedCommitSet), but the top level entity is still
// a singleton with respect to model types.
struct AllModelTypeState {
explicit AllModelTypeState(bool* dirty_flag);
~AllModelTypeState();
// Commits for all model types are bundled together into a single message.
ClientToServerMessage commit_message;
ClientToServerResponse commit_response;
// We GetUpdates for some combination of types at once.
// requested_update_types stores the set of types which were requested.
syncable::ModelTypeBitSet updates_request_types;
ClientToServerResponse updates_response;
// Used to build the shared commit message.
DirtyOnWrite<std::vector<int64> > unsynced_handles;
DirtyOnWrite<SyncerStatus> syncer_status;
DirtyOnWrite<ErrorCounters> error_counters;
SyncCycleControlParameters control_params;
DirtyOnWrite<int64> num_server_changes_remaining;
OrderedCommitSet commit_set;
};
// Grouping of all state that applies to a single ModelSafeGroup.
struct PerModelSafeGroupState {
explicit PerModelSafeGroupState(bool* dirty_flag);
~PerModelSafeGroupState();
UpdateProgress update_progress;
ConflictProgress conflict_progress;
};
} // namespace sessions
} // namespace browser_sync
#endif // CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_