summaryrefslogtreecommitdiff
path: root/chromium/docs/website/site/developers/design-documents/sync/model-api/index.md
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/docs/website/site/developers/design-documents/sync/model-api/index.md')
-rw-r--r--chromium/docs/website/site/developers/design-documents/sync/model-api/index.md317
1 files changed, 0 insertions, 317 deletions
diff --git a/chromium/docs/website/site/developers/design-documents/sync/model-api/index.md b/chromium/docs/website/site/developers/design-documents/sync/model-api/index.md
deleted file mode 100644
index ed26ea6b7bd..00000000000
--- a/chromium/docs/website/site/developers/design-documents/sync/model-api/index.md
+++ /dev/null
@@ -1,317 +0,0 @@
----
-breadcrumbs:
-- - /developers
- - For Developers
-- - /developers/design-documents
- - Design Documents
-- - /developers/design-documents/sync
- - Sync
-page_name: model-api
-title: Chrome Sync's Model API
----
-
-Chrome Sync operates on discrete, explicitly defined model types (bookmarks,
-preferences, tabs, etc). These model types are individually responsible for
-implementing their own local storage and responding to remote changes. This
-guide is for developers interested in syncing data for their model type to the
-cloud using Chrome Sync. It describes the newest version of the API, known as
-Unified Sync and Storage (USS). There is also the deprecated [SyncableService
-API] (aka Directory), which as of early 2022 is still used by several legacy
-model types, but "wrapped into" USS (see [SyncableServiceBasedBridge]).
-
-[SyncableService API]: https://www.chromium.org/developers/design-documents/sync/syncable-service-api
-[SyncableServiceBasedBridge]: https://cs.chromium.org/chromium/src/components/sync/model/syncable_service_based_bridge.h
-
-[TOC]
-
-## Overview
-
-To correctly sync data, USS requires that sync metadata be stored alongside your
-model data in a way such that they are written together atomically. **This is
-very important!** Sync must be able to update the metadata for any local data
-changes as part of the same write to disk. If you attempt to write data to disk
-and only notify sync afterwards, a crash in between the two writes can result in
-changes being dropped and never synced to the server, or data being duplicated
-due to being committed more than once.
-
-[`ModelTypeSyncBridge`][Bridge] is the interface the model code must implement.
-The bridge is usually owned by a [`KeyedService`][KeyedService].
-The correct place for the bridge generally lies as close to where your model
-data is stored as possible, as the bridge needs to be able to inject metadata
-updates into any local data changes that occur.
-
-The bridge owns a [`ModelTypeChangeProcessor`][MTCP] object, which it uses to
-communicate local changes to sync using the `Put` and `Delete` methods.
-The processor will communicate remote changes from sync to the bridge using the
-`MergeSyncData` and `ApplySyncChanges` methods, respectively for the initial
-merge of remote and local data, and for incremental changes coming from sync.
-[`MetadataChangeList`][MCL] is the way sync communicates metadata changes to the
-storage mechanism. Note that it is typically implemented on a per-storage basis,
-not a per-type basis.
-
-[Bridge]: https://cs.chromium.org/chromium/src/components/sync/model/model_type_sync_bridge.h
-[KeyedService]: https://cs.chromium.org/chromium/src/components/keyed_service/core/keyed_service.h
-[MTCP]: https://cs.chromium.org/chromium/src/components/sync/model/model_type_change_processor.h
-[MCL]: https://cs.chromium.org/chromium/src/components/sync/model/metadata_change_list.h
-
-## Data
-
-### Specifics
-
-Model types will define a proto that contains the necessary fields of the
-corresponding native type (e.g. [`TypedUrlSpecifics`][TypedUrlSpecifics]
-contains a URL and a list of visit timestamps) and include it as a field in the
-generic [`EntitySpecifics`][EntitySpecifics] proto. This is the form that all
-communications with sync will use. This proto form of the model data is referred
-to as the specifics.
-
-[TypedUrlSpecifics]: https://cs.chromium.org/chromium/src/components/sync/protocol/typed_url_specifics.proto
-[EntitySpecifics]: https://cs.chromium.org/search/?q="message+EntitySpecifics"+file:sync.proto
-
-### Identifiers
-
-There are two primary identifiers for entities: **storage key** and **client
-tag**. The bridge will need to take an [`EntityData`][EntityData] object (which
-contains the specifics) and be able generate both of these from it. For
-non-legacy types without significant performance concerns, these will generally
-be the same.
-
-The storage key is meant to be the primary key in the local model/database.
-It’s what’s used to refer to entities most of the time and, as its name implies,
-the bridge needs to be able to look up local data and metadata entries in the
-store using it. Because it is a local identifier, it can change as part of
-database migrations, etc. This may be desirable for efficiency reasons.
-
-The client tag is used to generate the **client tag hash**, which will identify
-entities **across clients**. This means that its implementation can **never
-change** once entities have begun to sync, without risking massive duplication
-of entities. This means it must be generated using only immutable data in the
-specifics. If your type does not have any immutable fields to use, you will need
-to add one (e.g. a GUID, though be wary as they have the potential to conflict).
-While the hash gets written to disk as part of the metadata, the tag itself is
-never persisted locally.
-
-[EntityData]: https://cs.chromium.org/chromium/src/components/sync/protocol/entity_data.h
-
-## Storage
-
-A crucial requirement of USS is that the model must add support for keeping
-sync’s metadata in the same storage as its normal data. The metadata consists of
-one [`EntityMetadata`][EntityMetadata] proto for each data entity, and one
-[`ModelTypeState`][ModelTypeState] proto containing metadata pertaining to the
-state of the entire type (the progress marker, for example). This typically
-requires two extra tables in a database to do (one for each type of proto).
-
-Since the processor doesn’t know anything about the store, the bridge provides
-it with an implementation of the [`MetadataChangeList`][MCL] interface. The
-change processor writes metadata through this interface when changes occur, and
-the bridge simply has to ensure it gets passed along to the store and written
-along with the data changes.
-
-[EntityMetadata]: https://cs.chromium.org/chromium/src/components/sync/protocol/entity_metadata.proto
-[ModelTypeState]: https://cs.chromium.org/chromium/src/components/sync/protocol/model_type_state.proto
-
-### ModelTypeStore
-
-While the model type may store its data however it chooses, many types use
-[`ModelTypeStore`][Store], which was created specifically to provide a
-convenient persistence solution. It’s backed by a [LevelDB] to store serialized
-protos to disk. `ModelTypeStore` provides two `MetadataChangeList`
-implementations for convenience; both accessed via
-[`ModelTypeStore::WriteBatch`][WriteBatch]. One passes metadata changes directly
-into an existing `WriteBatch` and another caches them in memory until a
-`WriteBatch` exists to consume them.
-
-The store interface abstracts away the type and will handle setting up tables
-for the type’s data, so multiple `ModelTypeStore` objects for different types
-can share the same LevelDB backend just by specifying the same path and task
-runner. Sync already has a backend it uses for DeviceInfo that can be shared by
-other types via the [`ModelTypeStoreService`][StoreService].
-
-[Store]: https://cs.chromium.org/chromium/src/components/sync/model/model_type_store.h
-[LevelDB]: https://github.com/google/leveldb/blob/master/doc/index.md
-[WriteBatch]: https://cs.chromium.org/search/?q="class+WriteBatch"+file:model_type_store_base.h
-[StoreService]: https://cs.chromium.org/chromium/src/components/sync/model/model_type_store_service.h
-
-## Implementing ModelTypeSyncBridge
-
-### Initialization
-
-The bridge is required to load all of the metadata for its type from storage and
-provide it to the processor via the [`ModelReadyToSync`][ModelReadyToSync]
-method **before any local changes occur**. This can be tricky if the thread the
-bridge runs on is different from the storage mechanism. No data will be synced
-with the server if the processor is never informed that the model is ready.
-
-Since the tracking of changes and updating of metadata is completely
-independent, there is no need to wait for the sync engine to start before
-changes can be made. This prevents the need for an expensive association step in
-the initialization.
-
-[ModelReadyToSync]: https://cs.chromium.org/search/?q=ModelReadyToSync+file:/model_type_change_processor.h
-
-### MergeSyncData
-
-This method is called only once, when a type is first enabled. Sync will
-download all the data it has for the type from the server and provide it to the
-bridge using this method. Sync filters out any tombstones for this call, so
-`EntityData::is_deleted()` will never be true for the provided entities. The
-bridge must then examine the sync data and the local data and merge them
-together:
-
-* Any remote entities that don’t exist locally must be be written to local
- storage.
-* Any local entities that don’t exist remotely must be provided to sync via
- [`ModelTypeChangeProcessor::Put`][Put].
-* Any entities that appear in both sets must be merged and the model and sync
- informed accordingly. Decide which copy of the data to use (or a merged
- version or neither) and update the local store and sync as necessary to
- reflect the decision. How the decision is made can vary by model type.
-
-The [`MetadataChangeList`][MCL] passed into the function is already populated
-with metadata for all the data passed in (note that neither the data nor the
-metadata have been committed to storage yet at this point). It must be given to
-the processor for any `Put` or `Delete` calls so the relevant metadata can be
-added/updated/deleted, and then passed to the store for persisting along with
-the data.
-
-Note that if sync gets disabled and the metadata cleared, entities that
-originated from other clients will exist as “local” entities the next time sync
-starts and merge is called. Since tombstones are not provided for merge, this
-can result in reviving the entity if it had been deleted on another client in
-the meantime.
-
-[Put]: https://cs.chromium.org/search/?q=Put+file:/model_type_change_processor.h
-
-### ApplySyncChanges
-
-While `MergeSyncData` provides the state of sync data using `EntityData`
-objects, `ApplySyncChanges` provides changes to the state using
-[`EntityChange`][EntityChange] objects. These changes must be applied to the
-local state.
-
-Here’s an example implementation of a type using `ModelTypeStore`:
-
-```cpp
-absl::optional<ModelError> DeviceInfoSyncBridge::ApplySyncChanges(
- std::unique_ptr<MetadataChangeList> metadata_change_list,
- EntityChangeList entity_changes) {
- std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch();
- for (const EntityChange& change : entity_changes) {
- if (change.type() == EntityChange::ACTION_DELETE) {
- batch->DeleteData(change.storage_key());
- } else {
- batch->WriteData(change.storage_key(),
- change.data().specifics.your_type().SerializeAsString());
- }
- }
-
- batch->TakeMetadataChangesFrom(std::move(metadata_change_list));
- store_->CommitWriteBatch(std::move(batch), base::BindOnce(...));
- NotifyModelOfChanges();
- return {};
-}
-```
-
-A conflict can occur when an entity has a pending local commit when an update
-for the same entity comes from another client. In this case, the bridge’s
-[`ResolveConflict`][ResolveConflict] method will have been called prior to the
-`ApplySyncChanges` call in order to determine what should happen. This method
-defaults to having the remote version overwrite the local version unless the
-remote version is a tombstone, in which case the local version wins.
-
-[EntityChange]: https://cs.chromium.org/chromium/src/components/sync/model/entity_change.h
-[ResolveConflict]: https://cs.chromium.org/search/?q=ResolveConflict+file:/model_type_sync_bridge.h
-
-### Local changes
-
-The [`ModelTypeChangeProcessor`][MTCP] must be informed of any local changes via
-its `Put` and `Delete` methods. Since the processor cannot do any useful
-metadata tracking until `MergeSyncData` is called, the `IsTrackingMetadata`
-method is provided. It can be checked as an optimization to prevent unnecessary
-processing preparing the parameters to a `Put` or `Delete` call.
-
-Here’s an example of handling a local write using `ModelTypeStore`:
-
-```cpp
-void WriteLocalChange(std::string key, ModelData data) {
- std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch();
- if (change_processor()->IsTrackingMetadata()) {
- change_processor()->Put(key, ModelToEntityData(data),
- batch->GetMetadataChangeList());
- }
- batch->WriteData(key, data.specifics->SerializeAsString());
- store_->CommitWriteBatch(std::move(batch), base::BindOnce(...));
-}
-```
-
-## Error handling
-
-If any errors occur during store operations that could compromise the
-consistency of the data and metadata, the processor’s
-[`ReportError`][ReportError] method should be called. The only exception to this
-is errors during `MergeSyncData` or `ApplySyncChanges`, which should just return
-a [`ModelError`][ModelError].
-
-This will inform sync of the error, which will stop all communications with the
-server so bad data doesn’t get synced. Since the metadata might no longer be
-valid, the bridge will asynchronously receive an `ApplyStopSyncChanges` call
-with a non-null `MetadataChangeList` parameter. All the metadata will be cleared
-from the store (if possible), and the type will be started again from scratch on
-the next client restart.
-
-[ReportError]: https://cs.chromium.org/search/?q=ReportError+file:/model_type_change_processor.h
-[ModelError]: https://cs.chromium.org/chromium/src/components/sync/model/model_error.h
-
-## Sync Integration Checklist
-
-Before starting any integration work, please reach out to us at
-chrome-sync-dev@google.com and share your plans / design doc!
-
-* Define your specifics proto in [`//components/sync/protocol/`][protocol].
-* Add it to the [proto value conversions][conversions] files.
-* Add a field for it to [`EntitySpecifics`][EntitySpecifics].
-* At this point, there are also some server-side integration steps to be done.
- Reach out to chrome-sync-dev@google.com for details.
-* Add it to the [`ModelType`][ModelType] enum and
- [`kModelTypeInfoMap`][info_map].
-* Register a [`ModelTypeController`][ModelTypeController] for your type in
- [`SyncApiComponentFactoryImpl::CreateCommonDataTypeControllers`][CreateCommonDataTypeControllers] or platform-specific equivalent in
- [`ChromeSyncClient::CreateDataTypeControllers`][CreateDataTypeControllers].
-* Add your KeyedService dependency to
- [`SyncServiceFactory`][SyncServiceFactory].
-* Add an field for encrypted data to [`NigoriSpecifics`][NigoriSpecifics].
-* If your type should have its own toggle in sync settings, add an entry to
- the [`UserSelectableType`][UserSelectableType] enum, add a
- [preference][pref_names] for tracking whether your type is enabled, and
- map your type to the pref in [`GetPrefNameForType`][GetPrefName].
-* Otherwise, if your type should be included in an existing toggle in sync
- settings, add it in [`GetUserSelectableTypeInfo`]
- [GetUserSelectableTypeInfo].
-* Add to the `SyncModelTypes` enum in [`enums.xml`][enums] and to the
- `SyncModelType` suffix in [`histograms.xml`][histograms].
-
-[protocol]: https://cs.chromium.org/chromium/src/components/sync/protocol/
-[ModelType]: https://cs.chromium.org/chromium/src/components/sync/base/model_type.h
-[info_map]: https://cs.chromium.org/search/?q="kModelTypeInfoMap%5B%5D"+file:model_type.cc
-[conversions]: https://cs.chromium.org/chromium/src/components/sync/protocol/proto_value_conversions.h
-[ModelTypeController]: https://cs.chromium.org/chromium/src/components/sync/driver/model_type_controller.h
-[CreateCommonDataTypeControllers]: https://cs.chromium.org/search/?q="SyncApiComponentFactoryImpl::CreateCommonDataTypeControllers"
-[CreateDataTypeControllers]: https://cs.chromium.org/search/?q="ChromeSyncClient::CreateDataTypeControllers"
-[SyncServiceFactory]: https://cs.chromium.org/search/?q=:SyncServiceFactory%5C(%5C)
-[NigoriSpecifics]: https://cs.chromium.org/chromium/src/components/sync/protocol/nigori_specifics.proto
-[UserSelectableType]: https://cs.chromium.org/chromium/src/components/sync/base/user_selectable_type.h?type=cs&q="enum+class+UserSelectableType"
-[pref_names]: https://cs.chromium.org/chromium/src/components/sync/base/pref_names.h
-[GetPrefName]: https://cs.chromium.org/search/?q=GetPrefNameForType+file:sync_prefs.cc
-[GetUserSelectableTypeInfo]: https://cs.chromium.org/chromium/src/components/sync/base/user_selectable_type.cc?type=cs&q="UserSelectableTypeInfo+GetUserSelectableTypeInfo"+f:components/sync/base/user_selectable_type.cc
-[enums]: https://cs.chromium.org/chromium/src/tools/metrics/histograms/enums.xml
-[histograms]: https://cs.chromium.org/chromium/src/tools/metrics/histograms/histograms.xml
-[DataTypeHistogram]: https://cs.chromium.org/chromium/src/components/sync/base/data_type_histogram.h
-
-## Testing
-
-The [`TwoClientTypedUrlsSyncTest`][UssTest] suite is probably a good place to start
-for integration testing. Especially note the use of a `StatusChangeChecker` to
-wait for events to happen.
-
-[UssTest]: https://cs.chromium.org/chromium/src/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc