Skip to content

Commit

Permalink
[Sync] Add a doc about the SharedModelTypeProcessor.
Browse files Browse the repository at this point in the history
Just a brain-dump of my current understanding of how SMTP state works.

BUG=

Review-Url: https://codereview.chromium.org/2672123002
Cr-Commit-Position: refs/heads/master@{#448130}
  • Loading branch information
maxbogue authored and Commit bot committed Feb 4, 2017
1 parent 3c7d832 commit da6bfa3
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 15 deletions.
51 changes: 36 additions & 15 deletions components/sync/model_impl/shared_model_type_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ namespace syncer {
class CommitQueue;
class ProcessorEntityTracker;

// A sync component embedded on the synced type's thread that helps to handle
// communication between sync and model type threads.
// A sync component embedded on the model type's thread that tracks entity
// metadata in the model store and coordinates communication between sync and
// model type threads. See //docs/sync/uss/shared_model_type_processor.md for a
// more thorough description.
class SharedModelTypeProcessor : public ModelTypeProcessor,
public ModelTypeChangeProcessor,
base::NonThreadSafe {
Expand Down Expand Up @@ -138,11 +140,26 @@ class SharedModelTypeProcessor : public ModelTypeProcessor,
// Version of the above that generates a tag for |data|.
ProcessorEntityTracker* CreateEntity(const EntityData& data);

/////////////////////
// Processor state //
/////////////////////

// The model type this object syncs.
const ModelType type_;

// The model type metadata (progress marker, initial sync done, etc).
sync_pb::ModelTypeState model_type_state_;

// Stores the start callback in between OnSyncStarting() and ReadyToConnect().
StartCallback start_callback_;
// ModelTypeSyncBridge linked to this processor. The bridge owns this
// processor instance so the pointer should never become invalid.
ModelTypeSyncBridge* const bridge_;

// Function to capture and upload a stack trace when an error occurs.
const base::RepeatingClosure dump_stack_;

/////////////////
// Model state //
/////////////////

// The first model error that occurred, if any. Stored to track model state
// and so it can be passed to sync if it happened prior to sync being ready.
Expand All @@ -155,13 +172,28 @@ class SharedModelTypeProcessor : public ModelTypeProcessor,
// as false but will be set to true if we detect it's necessary to load data.
bool waiting_for_pending_data_ = false;

////////////////
// Sync state //
////////////////

// Stores the start callback in between OnSyncStarting() and ReadyToConnect().
StartCallback start_callback_;

// The callback used for informing sync of errors; will be non-null after
// OnSyncStarting has been called.
ModelErrorHandler error_handler_;

// Reference to the CommitQueue.
//
// The interface hides the posting of tasks across threads as well as the
// CommitQueue's implementation. Both of these features are
// useful in tests.
std::unique_ptr<CommitQueue> worker_;

//////////////////
// Entity state //
//////////////////

// A map of client tag hash to sync entities known to this processor. This
// should contain entries and metadata for most everything, although the
// entities may not always contain model type data/specifics.
Expand All @@ -173,17 +205,6 @@ class SharedModelTypeProcessor : public ModelTypeProcessor,
// client tag hash. The other direction can use |entities_|.
std::map<std::string, std::string> storage_key_to_tag_hash_;

// ModelTypeSyncBridge linked to this processor. The bridge owns this
// processor instance so the pointer should never become invalid.
ModelTypeSyncBridge* const bridge_;

// Function to capture and upload a stack trace when an error occurs.
const base::RepeatingClosure dump_stack_;

// The callback used for informing sync of errors; will be non-null after
// OnSyncStarting has been called.
ModelErrorHandler error_handler_;

// WeakPtrFactory for this processor which will be sent to sync thread.
base::WeakPtrFactory<SharedModelTypeProcessor> weak_ptr_factory_;

Expand Down
114 changes: 114 additions & 0 deletions docs/sync/uss/shared_model_type_processor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# SharedModelTypeProcessor

The [`SharedModelTypeProcessor`][SMTP] is a crucial piece of the USS codepath.
It lives on the model thread and performs the tracking of sync metadata for the
[`ModelTypeSyncBridge`][MTSB] that owns it by implementing the
[`ModelTypeChangeProcessor`][MTCP] interface, as well as sending commit requests
to the [`ModelTypeWorker`][MTW] on the sync thread via the [`CommitQueue`][CQ]
interface and receiving updates from the same worker via the
[`ModelTypeProcessor`][MTP] interface.

[SMTP]: https://cs.chromium.org/chromium/src/components/sync/model_impl/shared_model_type_processor.h
[MTSB]: https://cs.chromium.org/chromium/src/components/sync/model/model_type_sync_bridge.h
[MTCP]: https://cs.chromium.org/chromium/src/components/sync/model/model_type_change_processor.h
[MTW]: https://cs.chromium.org/chromium/src/components/sync/engine_impl/model_type_worker.h
[CQ]: https://cs.chromium.org/chromium/src/components/sync/engine/commit_queue.h
[MTP]: https://cs.chromium.org/chromium/src/components/sync/engine/model_type_processor.h

[TOC]

## Lifetime

The bridge owns a processor object at all times and operates on the same thread
as it. If sync is disabled, the processor is destroyed but a new one is
immediately created to replace it.

## Processor State Machines

The processor sits between the model bridge and the sync engine. It has
knowledge of what state each is in based on the calls it has receieved and
performed. The states are not stored explicitly, but are implicit based on
state stored in the processor. Here are the states of each, with notes on their
transitions and how to determine them.

### Model States

* `UNREADY`
* Waiting for `ModelReadyToStart` to be called.
* Determined by: `waiting_for_metadata_ && !model_error_`
* `NEEDS_DATA`
* Waiting for data for pending commits to be loaded.
* This state is skipped if there are no pending commits.
* Determined by: `waiting_for_pending_data_ && !model_error_`
* `READY`
* The model is completely ready to sync.
* Determined by: `!waiting_for_metadata_ && !waiting_for_pending_data &&
!model_error`
* `ERROR`
* Something in the model or storage broke.
* This state is permanent until DisableSync destroys the object.
* Determined by: `!!model_error_`

### Sync States

* `DISCONNECTED`
* Sync for this type has not started.
* This state can be re-entered from any other state if Disconnect is
called.
* Determined by: `!error_handler_`.
* `STARTED`
* Sync has started but the model is not yet `READY` (or `ERROR`).
* This state is skipped if the model is ready before sync is.
* Determined by: `error_handler_ && start_callback_`
* `CONNECT_PENDING`
* Both the model and sync are ready. The start callback has been called
and we're waiting to connect to the sync thread.
* If the model was `ERROR`, the error is passed along and the callback is
cleared; we're really waiting for DisableSync instead of connect.
* Determined by: `error_handler_ && !start_callback_`
* `CONNECTED`
* We have a [`CommitQueue`][CQ] that passes changes to the
[`ModelTypeWorker`][MTW] on the sync thread.
* Determined by: `!!worker_`

### Processor States

Based on the interplay of the model and sync states, the processor effectively
progresses through 3 states worth noting:

* `UNINITIALIZED`
* Metadata isn't loaded so we have no knowledge of entities.
* `Put` and `Delete` calls are not allowed in this state (will DCHECK).
* `NOT_TRACKING`
* Indicates that not metadata is being tracked and that `Put` and `Delete`
calls will be ignored.
* This state is entered if the loaded metadata shows an initial merge
hasn't happened (`ModelTypeState::initial_sync_done` is false).
* Exposed via `IsTrackingMetadata` for optimization, not correctness.
* `TRACKING`
* Indicates that metadata is being tracked and `Put` and `Delete` calls
must happen for entity changes.
* This state is entered if the loaded metadata shows an initial merge
has happened (`ModelTypeState::initial_sync_done` is true).
* `SYNCING`
* Indicates that commits can be sent and updates can be received from the
sync server. This is a superstate of `TRACKING`.
* If the processor was in `TRACKING`, it progresses to this state as soon
as it gets connected to the worker.
* If the processor was in `NOT_TRACKING`, it progresses to this state
after `MergeSyncData` is called and the metadata is initialized.

## Entity Tracker

The [`ProcessorEntityTracker`][PET] tracks the state of individual entities for
the processor. It keeps the [`EntityMetadata`][EM] proto in memory, as well as
any pending commit data until it gets acked by the server. It also stores the
special `commit_requested_sequence_number_`, which tracks the sequence number of
the last version that's been sent to the server.

The tracker holds the metadata in memory forever, which is needed so we know
what to update the on-disk memory with when we get a new local or remote change.
Changing this would require being able to handle updates asynchronously.

[PET]: https://cs.chromium.org/chromium/src/components/sync/model_impl/processor_entity_tracker.h
[EM]: https://cs.chromium.org/chromium/src/components/sync/protocol/entity_metadata.proto

0 comments on commit da6bfa3

Please sign in to comment.