text: // Copyright (c) 2009 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.
  
  #ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_
  #define CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_
  
  #include <string>
  #include <utility>
  #include <vector>
  
  #include "base/basictypes.h"
  #include "base/scoped_ptr.h"
  #include "chrome/browser/sync/engine/conflict_resolver.h"
  #include "chrome/browser/sync/engine/syncer_types.h"
  #include "chrome/browser/sync/engine/syncproto.h"
  #include "chrome/browser/sync/sessions/sync_session.h"
  #include "chrome/browser/sync/syncable/directory_event.h"
  #include "chrome/browser/sync/util/closure.h"
  #include "chrome/browser/sync/util/event_sys-inl.h"
  #include "chrome/browser/sync/util/event_sys.h"
  #include "chrome/browser/sync/util/extensions_activity_monitor.h"
  #include "testing/gtest/include/gtest/gtest_prod.h"  // For FRIEND_TEST
  
  namespace syncable {
  class Directory;
  class DirectoryManager;
  class Entry;
  class Id;
  class MutableEntry;
  class WriteTransaction;
  }  // namespace syncable
  
  namespace browser_sync {
  
  class ModelSafeWorker;
  class ServerConnectionManager;
  class SyncProcessState;
  class URLFactory;
  struct HttpResponse;
  
  static const int kDefaultMaxCommitBatchSize = 25;
  
  enum SyncerStep {
    SYNCER_BEGIN,
    DOWNLOAD_UPDATES,
    PROCESS_CLIENT_COMMAND,
    VERIFY_UPDATES,
    PROCESS_UPDATES,
    APPLY_UPDATES,
    BUILD_COMMIT_REQUEST,
    POST_COMMIT_MESSAGE,
    PROCESS_COMMIT_RESPONSE,
    BUILD_AND_PROCESS_CONFLICT_SETS,
    RESOLVE_CONFLICTS,
    APPLY_UPDATES_TO_RESOLVE_CONFLICTS,
    SYNCER_END
  };
  
  // A Syncer provides a control interface for driving the individual steps
  // of the sync cycle.  Each cycle (hopefully) moves the client into closer
  // synchronization with the server.  The individual steps are modeled
  // as SyncerCommands, and the ordering of the steps is expressed using
  // the SyncerStep enum.
  //
  // A Syncer instance expects to run on a dedicated thread.  Calls
  // to SyncShare() may take an unbounded amount of time, as SyncerCommands
  // may block on network i/o, on lock contention, or on tasks posted to
  // other threads.
  class Syncer {
   public:
    typedef std::vector<int64> UnsyncedMetaHandles;
  
    // The constructor may be called from a thread that is not the Syncer's
    // dedicated thread, to allow some flexibility in the setup.
    explicit Syncer(sessions::SyncSessionContext* context);
    ~Syncer() {}
  
    // Called by other threads to tell the syncer to stop what it's doing
    // and return early from SyncShare, if possible.
    bool ExitRequested() { return early_exit_requested_; }
    void RequestEarlyExit() { early_exit_requested_ = true; }
  
    // SyncShare(...) variants cause one sync cycle to occur.  The return value
    // indicates whether we should sync again.  If we should not sync again,
    // it doesn't necessarily mean everything is OK; we could be throttled for
    // example.  Like a good parent, it is the caller's responsibility to clean up
    // after the syncer when it finishes a sync share operation and honor
    // server mandated throttles.
    // The zero-argument version of SyncShare is provided for unit tests.
    // When |sync_process_state| is provided, it is used as the syncer state
    // for the sync cycle.  It is treated as an input/output parameter.
    // When |first_step| and |last_step| are provided, this means to perform
    // a partial sync cycle, stopping after |last_step| is performed.
    bool SyncShare(sessions::SyncSession::Delegate* delegate);
    bool SyncShare(SyncerStep first_step, SyncerStep last_step,
                   sessions::SyncSession::Delegate* delegate);
  
    // Limit the batch size of commit operations to a specified number of items.
    void set_max_commit_batch_size(int x) { max_commit_batch_size_ = x; }
  
    ShutdownChannel* shutdown_channel() const { return shutdown_channel_.get(); }
  
    // Syncer will take ownership of this channel and it will be destroyed along
    // with the Syncer instance.
    void set_shutdown_channel(ShutdownChannel* channel) {
      shutdown_channel_.reset(channel);
    }
  
    // Volatile reader for the source member of the syncer session object.  The
    // value is set to the SYNC_CYCLE_CONTINUATION value to signal that it has
    // been read.
    sync_pb::GetUpdatesCallerInfo::GET_UPDATES_SOURCE TestAndSetUpdatesSource() {
      sync_pb::GetUpdatesCallerInfo::GET_UPDATES_SOURCE old_source =
          updates_source_;
      set_updates_source(sync_pb::GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION);
      return old_source;
    }
  
    void set_updates_source(
        sync_pb::GetUpdatesCallerInfo::GET_UPDATES_SOURCE source) {
      updates_source_ = source;
    }
  
   private:
    void RequestNudge(int milliseconds);
  
    // Implements the PROCESS_CLIENT_COMMAND syncer step.
    void ProcessClientCommand(sessions::SyncSession *session);
  
    // Resets transient state and runs from SYNCER_BEGIN to SYNCER_END.
    bool SyncShare(sessions::SyncSession* session);
  
    // This is the bottom-most SyncShare variant, and does not cause transient
    // state to be reset in session.
    void SyncShare(sessions::SyncSession* session,
                   SyncerStep first_step,
                   SyncerStep last_step);
  
    bool early_exit_requested_;
  
    int32 max_commit_batch_size_;
  
    ConflictResolver resolver_;
    scoped_ptr<SyncerEventChannel> syncer_event_channel_;
    sessions::ScopedSessionContextConflictResolver resolver_scoper_;
    sessions::ScopedSessionContextSyncerEventChannel event_channel_scoper_;
    sessions::SyncSessionContext* context_;
  
    scoped_ptr<ShutdownChannel> shutdown_channel_;
  
    // The source of the last nudge.
    sync_pb::GetUpdatesCallerInfo::GET_UPDATES_SOURCE updates_source_;
  
    // A callback hook used in unittests to simulate changes between conflict set
    // building and conflict resolution.
    Closure* pre_conflict_resolution_closure_;
  
    friend class SyncerTest;
    FRIEND_TEST(SyncerTest, NameClashWithResolver);
    FRIEND_TEST(SyncerTest, IllegalAndLegalUpdates);
    FRIEND_TEST(SusanDeletingTest,
                NewServerItemInAFolderHierarchyWeHaveDeleted3);
    FRIEND_TEST(SyncerTest, TestCommitListOrderingAndNewParent);
    FRIEND_TEST(SyncerTest, TestCommitListOrderingAndNewParentAndChild);
    FRIEND_TEST(SyncerTest, TestCommitListOrderingCounterexample);
    FRIEND_TEST(SyncerTest, TestCommitListOrderingWithNesting);
    FRIEND_TEST(SyncerTest, TestCommitListOrderingWithNewItems);
    FRIEND_TEST(SyncerTest, TestGetUnsyncedAndSimpleCommit);
    FRIEND_TEST(SyncerTest, UnappliedUpdateDuringCommit);
    FRIEND_TEST(SyncerTest, DeletingEntryInFolder);
    FRIEND_TEST(SyncerTest, LongChangelistCreatesFakeOrphanedEntries);
    FRIEND_TEST(SyncerTest, QuicklyMergeDualCreatedHierarchy);
    FRIEND_TEST(SyncerTest, LongChangelistWithApplicationConflict);
  
    DISALLOW_COPY_AND_ASSIGN(Syncer);
  };
  
  // Inline utility functions.
  
  // Given iterator ranges from two collections sorted according to a common
  // strict weak ordering, return true if the two ranges contain any common
  // items, and false if they do not. This function is in this header so that it
  // can be tested.
  template <class Iterator1, class Iterator2>
  bool SortedCollectionsIntersect(Iterator1 begin1, Iterator1 end1,
                                  Iterator2 begin2, Iterator2 end2) {
    Iterator1 i1 = begin1;
    Iterator2 i2 = begin2;
    while (i1 != end1 && i2 != end2) {
      if (*i1 == *i2)
        return true;
      if (*i1 > *i2)
        ++i2;
      else
        ++i1;
    }
    return false;
  }
  // Utility function declarations.
  void SplitServerInformationIntoNewEntry(syncable::WriteTransaction* trans,
                                          syncable::MutableEntry* entry);
  void CopyServerFields(syncable::Entry* src, syncable::MutableEntry* dest);
  void ClearServerData(syncable::MutableEntry* entry);
  
  // Get update contents as a string. Intended for logging, and intended
  // to have a smaller footprint than the protobuf's built-in pretty printer.
  std::string SyncEntityDebugString(const sync_pb::SyncEntity& entry);
  
  }  // namespace browser_sync
  
  #endif  // CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_
  