| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| library fuchsia.ledger; |
| |
| using fuchsia.mem; |
| using zx; |
| |
| // This file contains definitions of interfaces and data structures to access |
| // the Fuchsia Ledger. |
| |
| /// Response code for ledger operations. |
| enum Status : int32 { |
| OK = 0; |
| PARTIAL_RESULT = 1; |
| INVALID_TOKEN = 2; |
| INVALID_ARGUMENT = 3; |
| PAGE_NOT_FOUND = 4; |
| KEY_NOT_FOUND = 5; |
| REFERENCE_NOT_FOUND = 6; |
| NEEDS_FETCH = 7; |
| IO_ERROR = 8; |
| NETWORK_ERROR = 9; |
| TRANSACTION_ALREADY_IN_PROGRESS = 10; |
| NO_TRANSACTION_IN_PROGRESS = 11; |
| INTERNAL_ERROR = 12; |
| VALUE_TOO_LARGE = 13; |
| ILLEGAL_STATE = 14; |
| UNKNOWN_ERROR = -1; |
| }; |
| |
| /// Size in bytes of Page IDs. |
| const uint32 kPageIdSize = 16; |
| |
| struct PageId { |
| array<uint8>:kPageIdSize id; |
| }; |
| |
| /// Base interface for all services offered by the Ledger. |
| // |
| /// In case of an unexpected error on one of the service offered by the Ledger, |
| /// the service will close the connected channel, sending a |ledger.Status| as an epitaph. |
| /// |
| /// If a client needs to ensure a sequence of operation has been processed by |
| /// the service, it can issue a |Sync| command. The response will be send once |
| /// all request started before the |Sync| request has been processed by the |
| /// service. |
| [FragileBase] |
| interface ErrorNotifier { |
| 1000: Sync() -> (); |
| }; |
| |
| [Discoverable] |
| interface Ledger { |
| /// Retrieves the page with the given identifier, creating it if needed. A |
| /// |null| identifier can be passed to create a new page with a random unique |
| /// identifier. It is allowed to connect to the same page concurrently |
| /// multiple times. |
| |
| /// Parameters: |
| /// |id| the identifier of the page, or |null| to create a new page with a random identifier. |
| /// |
| /// Returns OK and binds |page_request| to the page on success. |
| 1: GetPage(PageId? id, request<Page> page_request) -> (Status status); |
| |
| /// Gets the page with identifier |
| /// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]. |
| /// This is a convenience method equivalent to: |
| /// GetPage([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], page_request). |
| 2: GetRootPage(request<Page> page_request) -> (Status status); |
| |
| /// Sets the |ConflictResolverFactory| to use for resolving conflicts on pages. |
| /// If this method has never been called, a last-one-wins policy will be used |
| /// for every page. If this method is called multiple times, the factories are |
| /// kept and conflict resolver requests are sent to one of the connected |
| /// factories. If all factories are later disconnected, pages that already have |
| /// a conflict resolution strategy (because they were opened before the factory |
| /// disconnected) will continue using their current strategy. The pages for |
| /// which no conflict resolution is set up will not get their conflicts |
| /// resolved until this method is called again. |
| 3: SetConflictResolverFactory(ConflictResolverFactory factory) |
| -> (Status status); |
| }; |
| |
| /// A reference to a value. |
| struct Reference { |
| vector<uint8> opaque_id; |
| }; |
| |
| /// A continuation token for paginated requests. |
| struct Token { |
| vector<uint8> opaque_id; |
| }; |
| |
| /// The result of a wait for conflict resolution. See |
| /// |Page.WaitForConflictResolution| for details. |
| enum ConflictResolutionWaitStatus { |
| /// No conflict was observed when the callback was registered. |
| NO_CONFLICTS = 0; |
| /// Some conflicts were observed when the callback was registered, and all |
| /// have been resolved. |
| CONFLICTS_RESOLVED = 1; |
| }; |
| |
| /// A page is the smallest unit of syncable data. |
| interface Page { |
| /// Returns the identifier for the page. |
| 1: GetId() -> (PageId id); |
| |
| /// Creates a snapshot of the page, allowing the client app to read a |
| /// consistent view of the content of the page. If |key_prefix| is provided, |
| /// the resulting snapshot includes only the entries with matching keys. |
| /// |
| /// If |watcher| is provided, it will receive notifications for changes of the |
| /// page state on this page connection newer than the resulting snapshot. |
| /// Change notifications will only contain the entries matching |key_prefix|. |
| /// To receive all changes, use an empty |key_prefix|. |
| 2: GetSnapshot(request<PageSnapshot> snapshot_request, |
| vector<uint8>:256 key_prefix, PageWatcher? watcher) -> (Status status); |
| |
| // Mutation operations. |
| |
| // Key level operations. |
| /// Mutations are bundled together into atomic commits. If a transaction is in |
| /// progress, the list of mutations bundled together is tied to the current |
| /// transaction. If no transaction is in progress, mutations will be bundled |
| /// with the following rules: |
| /// - A call to either |GetSnapshot()| or |StartTransaction()| will |
| /// commit any pending mutations. |
| /// - All pending mutations will regularly be bundled together and committed. |
| /// They are guaranteed to be persisted as soon as the client receives a |
| /// successful status. |
| /// |Put()| and |PutWithPriority()| can be used for small values that |
| /// fit inside a FIDL message. If the value is bigger, a reference must be |
| /// first created using |CreateReferenceFromSocket()| or |
| /// |CreateReferenceFromBuffer()| and then |PutReference()| can be used. |
| /// |PutWithPriority()| and |PutReference()| have an additional |priority| |
| /// parameter managing the synchronization policy for this value. |Put()| uses |
| /// a default priority of |Priority.EAGER|. For the list of available |
| /// priorities and their definition, see |Priority|. |
| 3: Put(vector<uint8>:256 key, vector<uint8> value) -> (Status status); |
| 4: PutWithPriority(vector<uint8>:256 key, vector<uint8> value, |
| Priority priority) -> (Status status); |
| 5: PutReference(vector<uint8>:256 key, Reference reference, Priority priority) |
| -> (Status status); |
| 6: Delete(vector<uint8>:256 key) -> (Status status); |
| |
| // Page level operations. |
| |
| /// Deletes all entries in the page. |
| /// Outside of a transaction, this operation is equivalent to deleting every |
| /// key currently present on the page in a single transaction. |
| /// In a transaction, this operation is equivalent to deleting every key |
| /// present in the page before the transaction, as well as any new key added |
| /// since the transaction started. |
| 7: Clear() -> (Status status); |
| |
| // References. |
| /// Creates a new reference. The object is not part of any commit. It must be |
| /// associated with a key using |PutReference()|. The content of the reference |
| /// will be the content of the socket. The content size must be equal to |
| /// |size|, otherwise the call will fail. |
| 8: CreateReferenceFromSocket(uint64 size, handle<socket> data) |
| -> (Status status, Reference? reference); |
| /// Creates a new reference. The object is not part of any commit. It must be |
| /// associated with a key using |PutReference()|. The content of the reference |
| /// will be the content of the buffer. |
| 9: CreateReferenceFromBuffer(fuchsia.mem.Buffer buffer) |
| -> (Status status, Reference? reference); |
| |
| // Transactions. |
| |
| /// Transactions allow the client to ensures changes are seen atomically by |
| /// observers of this page. Once a transaction is started with |
| /// |StartTransaction()|, every call to |Put(...)| and |Delete(...)| will not |
| /// be visible until either |Commit()| is called, and all changes are applied |
| /// in a single commit, or |Rollback()| is called and all changes are |
| /// discarded. |
| /// |
| /// Parallel transactions on the same *page connection* are not allowed, and |
| /// calling |StartTransaction()| when a transaction is already in progress |
| /// returns an error. However, a client is free to connect to the same page |
| /// multiple times, and run parallel transactions on the same page using |
| /// separate connections. In this case, commiting each transaction creates |
| /// divergent commits, which are later subject to conflict resolution. |
| /// |
| /// When a transaction is in progress, the page content visible *on this page |
| /// connection* is pinned to the state from when |StartTransaction()| was |
| /// called. In particular, no watch notifications are delivered, and the |
| /// conflict resolution is not invoked while the transaction is in progress. If |
| /// conflicting changes are made or synced while the transaction is in |
| /// progress, conflict resolution is invoked after the transaction is |
| /// committed. |
| /// |
| /// Starting a transaction will block until all watchers registered on this |
| /// page connection have received the current page state, ie. the one that |
| /// will be used as the base of the transaction. Put (with all its variants) |
| /// and Delete calls may be pipelined while StartTransaction() is pending and |
| /// will be taken into account in the transaction while it is pending. |
| 10: StartTransaction() -> (Status status); |
| 11: Commit() -> (Status status); |
| 12: Rollback() -> (Status status); |
| |
| /// Sets a watcher to track the synchronisation state of this page. The |
| /// current state is immediately sent to the watcher when this method is |
| /// called. |
| 13: SetSyncStateWatcher(SyncWatcher watcher) -> (Status status); |
| |
| // Conflict resolution. |
| |
| /// Waits until all conflicts are resolved before calling the callback. |
| /// The client can call this method multiple times, even before the previous |
| /// calls are completed. Callbacks will be executed in the order they were |
| /// added and indicate whether a merge happened between the callback |
| /// registration and its execution. |
| /// If there are no pending conflicts at the time this is called, the callback |
| /// gets executed right away. |
| 14: WaitForConflictResolution() -> (ConflictResolutionWaitStatus wait_status); |
| }; |
| |
| /// The synchronization priority of a reference. |
| enum Priority { |
| /// EAGER values will be downloaded with the commit and have the same |
| /// availability. |
| EAGER = 0; |
| /// LAZY values will not be downloaded with their commit, but only on demand. |
| /// A LAZY value thus may not be available when requested, for example if the |
| /// device has no internet connection at request time. |
| LAZY = 1; |
| }; |
| |
| /// A pair of key and value. |
| struct Entry { |
| vector<uint8>:256 key; |
| /// |value| is null and |size| is 0 if the value requested has the LAZY |
| /// priority and is not present on the device. Clients must use a Fetch call |
| /// to retrieve the contents. |
| fuchsia.mem.Buffer? value; |
| Priority priority; |
| }; |
| |
| /// A value inlined in a message. |
| struct InlinedValue { |
| vector<uint8> value; |
| }; |
| |
| /// A pair of key and an inlined value. |
| struct InlinedEntry { |
| vector<uint8>:256 key; |
| /// |value| is null if the value requested has the LAZY priority and is not |
| /// present on the device. Clients must use a Fetch call to retrieve the |
| /// contents. |
| InlinedValue? inlined_value; |
| Priority priority; |
| }; |
| |
| /// The content of a page at a given time. Closing the connection to a |Page| |
| /// interface closes all |PageSnapshot| interfaces it created. The contents |
| /// provided by this interface are limited to the prefix provided to the |
| /// Page.GetSnapshot() call. |
| interface PageSnapshot { |
| /// Returns the entries in the page with keys greater or equal to |key_start| |
| /// using the lexicographic order. If |key_start| is empty, all entries are |
| /// returned. If the result fits in a single fidl message, |status| will be |
| /// |OK| and |next_token| equal to NULL. Otherwise, |status| will be |
| /// |PARTIAL_RESULT| and |next_token| will have a non-NULL value. To retrieve |
| /// the remaining results, another call to |GetEntries| should be made, |
| /// initializing the optional |token| argument with the value of |next_token| |
| /// returned in the previous call. |status| will be |PARTIAL_RESULT| as long |
| /// as there are more results and |OK| once finished. |
| /// Only |EAGER| values are guaranteed to be returned inside |entries|. |
| /// Missing |LAZY| values can be retrieved over the network using Fetch(). |
| /// The returned |entries| are sorted by |key|. |
| 1: GetEntries(vector<uint8>:256 key_start, Token? token) |
| -> (Status status, vector<Entry> entries, Token? next_token); |
| |
| /// Same as |GetEntries()|. |VALUE_TOO_LARGE| is returned if a value does not |
| /// fit in a FIDL message. |
| 2: GetEntriesInline(vector<uint8>:256 key_start, Token? token) |
| -> (Status status, vector<InlinedEntry> entries, |
| Token? next_token); |
| |
| /// Returns the keys of all entries in the page which are greater or equal to |
| /// |key_start| using the lexicographic order. If |key_start| is empty, all |
| /// keys are returned. If the result fits in a single FIDL message, |status| |
| /// will be |OK| and |next_token| equal to NULL. Otherwise, |status| will be |
| /// |PARTIAL_RESULT| and |next_token| will have a non-NULL value. To retrieve |
| /// the remaining results, another call to |GetKeys| should be made, |
| /// initializing the optional |token| argument with the value of |next_token| |
| /// returned in the previous call. |
| /// The returned |keys| are sorted. |status| will be |PARTIAL_RESULT| as long |
| /// as there are more results and |OK| once finished. |
| 3: GetKeys(vector<uint8>:256 key_start, Token? token) |
| -> (Status status, vector<vector<uint8>:256> keys, |
| Token? next_token); |
| |
| /// Returns the value of a given key. |
| /// Only |EAGER| values are guaranteed to be returned. Calls when the value is |
| /// |LAZY| and not available will return a |NEEDS_FETCH| status. The value can |
| /// be retrieved over the network using a Fetch() call. |
| 4: Get(vector<uint8>:256 key) -> (Status status, fuchsia.mem.Buffer? buffer); |
| |
| /// Returns the value of a given key if it fits in a FIDL message. |
| /// |VALUE_TOO_LARGE| is returned if the value does not fit in a FIDL message. |
| /// See |Get()| for additional information. |
| 5: GetInline(vector<uint8>:256 key) -> (Status status, InlinedValue? value); |
| |
| /// Fetches the value of a given key, over the network if not already present |
| /// locally. |NETWORK_ERROR| is returned if the download fails (e.g.: network |
| /// is not available). |
| 6: Fetch(vector<uint8>:256 key) -> (Status status, fuchsia.mem.Buffer? buffer); |
| |
| /// Fetches the value of a given key, over the network if not already present |
| /// locally, and returns a shared handle of a part of the value of a given |
| /// key, starting at the position that is specified by |offset|. If |offset| |
| /// is less than 0, starts at |-offset| from the end of the value. |
| /// Returns at most |max_size| bytes. If |max_size| is less than 0, returns |
| /// everything. |
| 7: FetchPartial(vector<uint8>:256 key, int64 offset, int64 max_size) |
| -> (Status status, fuchsia.mem.Buffer? buffer); |
| }; |
| |
| enum ResultState { |
| COMPLETED = 0; |
| PARTIAL_STARTED = 1; |
| PARTIAL_CONTINUED = 2; |
| PARTIAL_COMPLETED = 3; |
| }; |
| |
| struct PageChange { |
| /// The timestamp of this change. This represents the number of nanoseconds |
| /// since Unix epoch (i.e., since "1970-01-01 00:00 UTC", ignoring leap |
| /// seconds). This value is set by the device that created the change and is |
| /// not synchronized across devices. In particular, there is no guarantee that |
| /// the |timestamp| of a follow up change is greater than this one's. |
| zx.time timestamp; |
| /// List of new and modified entries. |changed_entries| are sorted by |key|. |
| vector<Entry> changed_entries; |
| /// List of deleted keys, in sorted order. |
| vector<vector<uint8>:256> deleted_keys; |
| }; |
| |
| /// Interface to watch changes to a page. The client will receive changes made by |
| /// itself, as well as other clients or synced from other devices. The contents |
| /// of a transaction will never be split across multiple OnChange() calls, but |
| /// the contents of multiple transactions may be merged into one OnChange() call. |
| interface PageWatcher { |
| /// Called for changes made on the page. If the result fits in a single fidl |
| /// message, |result_state| will be |COMPLETED|. Otherwise, OnChange will be |
| /// called multiple times and |result_state| will be |PARTIAL_STARTED| the |
| /// first time, |PARTIAL_CONTINUED| the following ones and finally |
| /// |PARTIAL_COMPLETED| on the last call. No new OnChange() call will be made |
| /// while the previous one is still active. If clients are interested in the |
| /// full content of the page at the time of the change, they can request a |
| /// PageSnapshot in the callback. This request is optional and can be requested |
| /// in any partial (started, continued or completed) and/or COMPLETED OnChange |
| /// call. In any case, all requests made on a sequence of OnChange calls for |
| /// the same page change, will always return the same snapshot: the one |
| /// including all changes. |
| /// |
| /// Note that calls to Page.StartTransaction() on the page connection on which |
| /// the watcher was registered will block until all OnChange() calls have |
| /// finished. |
| 1: OnChange(PageChange page_change, ResultState result_state) |
| -> (request<PageSnapshot>? snapshot); |
| }; |
| |
| /// This interface lets clients control the conflict resolution policy of the |
| /// ledger. It allows them to either use pre-defined policies, or provide their |
| /// own implementation. This can be decided on a page-by-page basis. |
| interface ConflictResolverFactory { |
| /// Returns the conflict resolution policy for the given page. |
| 1: GetPolicy(PageId page_id) -> (MergePolicy policy); |
| /// Returns a |ConflictResolver| to use for the given page. This will only be |
| /// called if |GetPolicy| for the same page returned |AUTOMATIC_WITH_FALLBACK| |
| /// or |CUSTOM|. |
| 2: NewConflictResolver(PageId page_id, request<ConflictResolver> resolver); |
| }; |
| |
| /// Strategy to be used when resolving conflicts. |
| enum MergePolicy { |
| /// Last one wins. When 2 commits are merged, the resulting commit contains: |
| /// - all keys/values that do not conflict |
| /// - all keys/values of the commit with the biggest timestamp (or biggest |
| /// id, if the timestamps are the same) |
| LAST_ONE_WINS = 0; |
| /// Commits are automatically merged when no key has been modified on both |
| /// sides. When a key has been modified by both commits, conflict resolution is |
| /// delegated to a user-provided |ConflictResolver| that is created by calling |
| /// |ConflictResolverFactory.NewConflictResolver|. A single |ConflictResolver| |
| /// is created for each page. When the |ConflictResolver| is disconnected, a |
| /// new one is requested. |
| AUTOMATIC_WITH_FALLBACK = 1; |
| /// All merges are resolved by a user-provided |ConflictResolver| as described |
| /// above, even when commits to be merged change a disjoined set of keys. |
| CUSTOM = 2; |
| }; |
| |
| /// A value that is either small enough to be directly embedded in |bytes| or |
| /// that is referenced by |reference|. |
| union BytesOrReference { |
| vector<uint8> bytes; |
| Reference reference; |
| }; |
| |
| /// Source of the value used to resolve a conflict. |
| /// |
| /// |DELETE| deletes the key; |NEW| creates a new value; |RIGHT| |
| /// selects the value from the right branch. If no value is sent, the left |
| /// branch is selected. |
| /// Used by |MergedValue|. |
| enum ValueSource { |
| RIGHT = 0; |
| NEW = 1; |
| DELETE = 2; |
| }; |
| |
| /// A change in the page. If |source| is set to |NEW|, |new_value| must be set |
| /// to the new value. If |source| is not |NEW|, |new_value| and |priority| are |
| /// ignored. |
| struct MergedValue { |
| vector<uint8>:256 key; |
| ValueSource source; |
| BytesOrReference? new_value; |
| Priority priority; |
| }; |
| |
| /// An entry in a diff, as returned by |MergeResultProvider|. |
| /// |
| /// If |base|, |left| or |right| are NULL, this means that the corresponding key |
| /// was not present in the base, left or right (respectively) branch of the |
| /// page. |
| struct DiffEntry { |
| vector<uint8>:256 key; |
| |
| Value? base; |
| Value? left; |
| Value? right; |
| }; |
| |
| /// A value in a DiffEntry. |
| /// |
| /// If the value is LAZY and is not present locally, |value| will be NULL. The |
| /// value can be retrieved using a |Fetch()| call on a corresponding snapshot. |
| struct Value { |
| fuchsia.mem.Buffer? value; |
| Priority priority; |
| }; |
| |
| /// Status for methods that return a sequence of values. |
| enum IterationStatus : int8 { |
| /// The iteration has finished. |
| OK = 0; |
| /// The iteration has not finished. The method must be called again to |
| /// retrieve the next batch of responses. |
| PARTIAL_RESULT = 1; |
| }; |
| |
| /// A merge result provider, obtained from |ConflictResolver.Resolve()|. Can be |
| /// used to retrieve data about the conflict, and provide the merge result. When |
| /// all changes have been sent, |Done()| should be called to mark the end of |
| /// incoming merge changes. |
| interface MergeResultProvider : ErrorNotifier { |
| /// |GetFullDiff| returns the set of all key/value pairs (entries) that |
| /// have been modified between the common ancestor (see |
| /// |ConflictResolver.Resolve()|) and the left and right branches. |
| /// |
| /// Values of |LAZY| keys may not be present on the device. In that case, the |
| /// corresponding Value objects within DiffEntry will have a NULL |value| |
| /// field. If needed, |left| and |right|, provided by the |
| /// |ConflictResolver.Resolve()| method can be used by clients to Fetch these |
| /// values. If a key is not present at all in one of the branches, its |
| /// corresponding Value object will be NULL. |
| /// |
| /// The first call to get the |DiffEntry|s should be done using a NULL |
| /// token. If the result does not fit in a single fidl message, |status| will |
| /// be |PARTIAL_RESULT| and |next_token| will have a non-NULL value, which can |
| /// be used to retrieve the rest of the results by calling |GetFullDiff()| |
| /// with that token. |
| 1: GetFullDiff(Token? token) |
| -> (Status status, vector<DiffEntry> changes, Token? next_token); |
| 1001: GetFullDiffNew(Token? token) |
| -> (IterationStatus status, vector<DiffEntry> changes, Token? next_token); |
| |
| /// |GetConflictingDiff| returns the set of all key/value pairs that were |
| /// modified on both sides to different values, or deleted on one side and |
| /// modified on the other. |
| /// |
| /// It behaves like |GetFullDiff| otherwise. |
| 2: GetConflictingDiff(Token? token) |
| -> (Status status, vector<DiffEntry> changes, Token? next_token); |
| 1002: GetConflictingDiffNew(Token? token) |
| -> (IterationStatus status, vector<DiffEntry> changes, Token? next_token); |
| |
| /// Once the result of the merge has been computed |Merge()| can be called with |
| /// all changes that resolve this conflict. If the result does not fit in a |
| /// single fidl message, |Merge()| can be called multiple times. If any of the |
| /// |Merge()| calls fails, i.e. |status| is not |OK|, all following calls will |
| /// fail with the same error. |
| /// |
| /// For all keys for which no merged value has been set (either here or |
| /// through |MergeNonConflictingEntries()| below), the left value will be |
| /// used. It is thus not necessary to send a MergedValue with a |LEFT| value |
| /// source, unless to overwrite a previous MergedValue. |
| 3: Merge(vector<MergedValue> merge_changes) -> (Status status); |
| 1003: MergeNew(vector<MergedValue> merge_changes); |
| |
| /// Automatically merges all non conflicting entries (entries that are |
| /// modified on one side only or identical on both sides). This is equivalent |
| /// to sending, through |Merge()|, a MergedValue with a |RIGHT| ValueSource |
| /// for all non-conflicting keys modified on the right side. Conflicting |
| /// entries can still be merged using the |Merge()| method. |
| 4: MergeNonConflictingEntries() -> (Status status); |
| 1004: MergeNonConflictingEntriesNew(); |
| |
| /// Marks the end of merge changes to resolve this conflict. After |Done()| is |
| /// called |MergeResultProvider| interface cannot be used any more. |
| 5: Done() -> (Status status); |
| 1005: DoneNew(); |
| }; |
| |
| /// Custom conflict resolver. If a |ConflictResolverFactory| is registered, and |
| /// |ConflictResolverFactory.GetPolicy()| returns |AUTOMATIC_WITH_FALLBACK| or |
| /// |CUSTOM| when called for a given page, the |NewConflictResolver| method will |
| /// be called and will provide a |ConflictResolver|. Each time a custom conflict |
| /// resolution is needed according to the chosen policy, the method |
| /// |ConflictResolver.Resolve()| will be called, and the client will resolve the |
| /// conflict by returning the final value for all conflicting keys as well as |
| /// values for any other key that the client wants to change. |
| interface ConflictResolver { |
| /// Method called when a conflict needs to be resolved. |left| and |right| |
| /// contain the snapshots of the two branches and |common_version| that of the |
| /// lowest common ancestor. |common_version| can be NULL if this version is no |
| /// longer available. The result of the merge can be given through the |
| /// |result_provider|, using the left branch as the base of the merge commit, |
| /// i.e. only key/value pairs that are different from the left version of the |
| /// page should be sent. |result_provider| can also be used to retrieve the set |
| /// of differences, i.e. conflicting keys, between the two versions. |
| 1: Resolve(PageSnapshot left, PageSnapshot right, PageSnapshot? common_version, |
| MergeResultProvider new_result_provider); |
| }; |
| |
| /// Synchronization state. |
| enum SyncState { |
| /// There are no pending operations. |
| IDLE = 0; |
| /// There are pending operations, but there is no syncing in progress. This |
| /// could be because of (possibly a combination of): |
| /// - waiting for better connectivity |
| /// - waiting due to internal policies (e.g. batching network requests, |
| /// waiting for a merge to happen before uploading) |
| /// - waiting to determine if synchronization is needed (e.g. during initial |
| /// setup) |
| PENDING = 1; |
| /// Synchronization is in progress. |
| IN_PROGRESS = 2; |
| /// An internal error occurred while trying to sync. |
| ERROR = 3; |
| }; |
| |
| /// Watcher interface to be implemented by clients who wish to follow the |
| /// synchronization status of their ledger. SyncStateChanged callback must be |
| /// called for new state change calls to be sent. |
| interface SyncWatcher { |
| 1: SyncStateChanged(SyncState download_status, SyncState upload_status) -> (); |
| }; |