1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
client::ClientData, telemetry, CollectionRequest, Guid, IncomingChangeset, OutgoingChangeset,
ServerTimestamp,
};
use anyhow::Result;
#[derive(Debug, Clone, PartialEq)]
pub struct CollSyncIds {
pub global: Guid,
pub coll: Guid,
}
/// Defines how a store is associated with Sync.
#[derive(Debug, Clone, PartialEq)]
pub enum StoreSyncAssociation {
/// This store is disconnected (although it may be connected in the future).
Disconnected,
/// Sync is connected, and has the following sync IDs.
Connected(CollSyncIds),
}
/// Low-level store functionality. Stores that need custom reconciliation logic
/// should use this.
///
/// Different stores will produce errors of different types. To accommodate
/// this, we force them all to return failure::Error.
pub trait Store {
fn collection_name(&self) -> std::borrow::Cow<'static, str>;
/// Prepares the store for syncing. The tabs store currently uses this to
/// store the current list of clients, which it uses to look up device names
/// and types.
///
/// Note that this method is only called by `sync_multiple`, and only if a
/// command processor is registered. In particular, `prepare_for_sync` will
/// not be called if the store is synced using `sync::synchronize` or
/// `sync_multiple::sync_multiple`. It _will_ be called if the store is
/// synced via the Sync Manager.
///
/// TODO(issue #2590): This is pretty cludgey and will be hard to extend for
/// any case other than the tabs case. We should find another way to support
/// tabs...
fn prepare_for_sync(&self, _get_client_data: &dyn Fn() -> ClientData) -> Result<()> {
Ok(())
}
/// `inbound` is a vector to support the case where
/// `get_collection_requests` returned multiple requests. The changesets are
/// in the same order as the requests were -- e.g. if `vec![req_a, req_b]`
/// was returned from `get_collection_requests`, `inbound` will have the
/// results from `req_a` as its first index, and those from `req_b` as it's
/// second.
fn apply_incoming(
&self,
inbound: Vec<IncomingChangeset>,
telem: &mut telemetry::Engine,
) -> Result<OutgoingChangeset>;
fn sync_finished(
&self,
new_timestamp: ServerTimestamp,
records_synced: Vec<Guid>,
) -> Result<()>;
/// The store is responsible for building the collection request. Engines
/// typically will store a lastModified timestamp and use that to build a
/// request saying "give me full records since that date" - however, other
/// engines might do something fancier. This could even later be extended to
/// handle "backfills" etc
///
/// To support more advanced use cases (e.g. remerge), multiple requests can
/// be returned here. The vast majority of engines will just want to return
/// zero or one item in their vector (zero is a valid optimization when the
/// server timestamp is the same as the engine last saw, one when it is not)
///
/// Important: In the case when more than one collection is requested, it's
/// assumed the last one is the "canonical" one. (That is, it must be for
/// "this" collection, its timestamp is used to represent the sync, etc).
fn get_collection_requests(
&self,
server_timestamp: ServerTimestamp,
) -> Result<Vec<CollectionRequest>>;
/// Get persisted sync IDs. If they don't match the global state we'll be
/// `reset()` with the new IDs.
fn get_sync_assoc(&self) -> Result<StoreSyncAssociation>;
/// Reset the store without wiping local data, ready for a "first sync".
/// `assoc` defines how this store is to be associated with sync.
fn reset(&self, assoc: &StoreSyncAssociation) -> Result<()>;
fn wipe(&self) -> Result<()>;
}
|