• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Cross-Device Synchronization of KV Stores
2
3
4## When to Use
5
6KV Stores are suitable for storing service data with simple relationships. It provides higher read and write performance than the SQL database. KV stores are widely used because the simplicity of the KV data model poses fewer database version compatibility issues in distributed scenarios and simplifies conflict handling in data synchronization.
7
8
9## Basic Concepts
10
11Before implementing cross-device synchronization of KV stores, understand the following concepts:
12
13
14### Single KV Store
15
16In a single KV store, data is saved in the unit of a single entry. When data is modified locally, the data entry is updated no matter whether it has been synchronized. Only one copy of data is retained globally for multiple devices. The data of the latest time is kept for the same entry (with the same primary code) of multiple devices. The data in single KV stores is not differentiated by device. If the data modified on multiple devices has the same key, the value will be overwritten. For the data written or modified locally, the data with the latest time is synchronized to other devices. Single KV stores are used to store information, such as the Contacts and weather application data.
17
18![singleKVStore](figures/singleKVStore.jpg)
19
20
21### Device KV Store
22
23In a device KV store, the local device ID is added before the key of the KV pair stored by an application. In this way, the data of different devices is isolated. Data is managed by device and can be queried by device.
24
25The underlying devices manage the data by device. The device KV stores support distributed data query by device, but do not support modification of the data synchronized from peer devices. Device KV stores are used to store the data that needs to be accessed by device, such as the Gallery thumbnails.
26
27![deviceKVStore](figures/deviceKVStore.jpg)
28
29
30## Synchronization Types
31
32The **DatamgrService** provides the following synchronization types:
33
34
35- Manual synchronization: The application calls **sync()** to trigger a synchronization. The list of devices to be synchronized and the synchronization mode must be specified. The synchronization mode can be **PULL_ONLY** (pulling remote data to the local end), **PUSH_ONLY** (pushing local data to the remote end), or **PUSH_PULL** (pushing local data to the remote end and pulling remote data to the local end). You can use the [**sync()** with the **query** parameter](../reference/apis-arkdata/js-apis-distributedKVStore.md#sync-1) to synchronize the data that meets the specified conditions.
36
37- Automatic synchronization: The distributed database automatically pushes local data to the remote end and pulls remote data to the local end. An automatic synchronization is triggered when a device goes online or an application updates data.
38
39
40## Working Principles
41
42After completing device discovery and authentication, the underlying communication component notifies the application that the device goes online. The **DatamgrService** then establishes an encrypted transmission channel to synchronize data between the two devices.
43
44
45### Cross-Device Data Synchronization Mechanism
46
47![kvStore](figures/kvStore.jpg)
48
49When **put()** or **delete()** is called successfully, an automatic synchronization is triggered. The distributed data is sent to the peer device through the communication adaptation layer for synchronization.
50
51If **sync()** is called successfully, a manual synchronization is triggered to send distributed data to the peer device through the communication adaptation layer.
52
53
54### Data Change Notification Mechanism
55
56When data is added, deleted, or modified, a notification is sent to the subscriber. The notifications can be classified into the following types:
57
58- Local data change notification: subscription of the application data changes on the local device. When the data in the local KV store is added, deleted, or modified in the database, a notification is received.
59
60- Distributed data change notification: subscription of the application data changes of other devices in the network. When the data in the local KV store changes after being synchronized with data from another device in the same network, a notification is received.
61
62
63## Constraints
64
65- For each record in a device KV store, the key cannot exceed 896 bytes and the value cannot exceed 4 MB.
66
67- For each record in a single KV store, the key cannot exceed 1 KB and the value cannot exceed 4 MB.
68
69- The KV stores do not support custom conflict resolution policies for applications.
70
71- A maximum of 16 KV stores can be opened simultaneously for an application.
72
73- Each KV store supports a maximum of eight callbacks for subscription of data change notifications.
74
75
76## Available APIs
77
78The following table lists the APIs for cross-device data synchronization of the single KV store. Most of the APIs are executed asynchronously, using a callback or promise to return the result. The following table uses the callback-based APIs as an example. For more information about the APIs, see [Distributed KV Store](../reference/apis-arkdata/js-apis-distributedKVStore.md).
79
80| API| Description|
81| -------- | -------- |
82| createKVManager(config: KVManagerConfig): KVManager | Creates a **KvManager** instance to manage database objects.|
83| getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void | Creates and obtains a KV store of the specified type.|
84| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void | Inserts and updates data.|
85| on(event: 'dataChange', type: SubscribeType, listener: Callback<ChangeNotification>): void | Subscribes to data changes in the KV store.|
86| get(key: string, callback: AsyncCallback<boolean \| string \| number \| Uint8Array>): void | Queries the value of the specified key.|
87| sync(deviceIds: string[], mode: SyncMode, delayMs?: number): void | Triggers a manual synchronization of the KV store.|
88
89
90## How to Develop
91
92The following uses a single KV store as an example to describe how to implement cross-device data synchronization. The development process is as follows.
93
94![kvStore_development_process](figures/kvStore_development_process.png)
95
96> **NOTE**
97>
98> The data on a device can be synchronized only to the devices whose data security labels are not higher than the security level of the device. For details, see [Access Control Mechanism in Cross-Device Synchronization](sync-app-data-across-devices-overview.md#access-control-mechanism-in-cross-device-synchronization).
99
1001. Import the module.
101
102   ```ts
103   import distributedKVStore from '@ohos.data.distributedKVStore';
104   ```
105
1062. Request permissions.
107
108   a) Declare the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
109   b) Display a dialog box to ask for user authorization when the application is started for the first time. For details, see [Requesting User Authorization](../security/AccessToken/request-user-authorization.md).
110
1113. Create a **KvManager** instance based on the specified **KvManagerConfig** object.
112
113   a) Create a **kvManagerConfig** object based on the application context.
114   b) Create a **KvManager** instance.
115
116
117   ```ts
118   // Obtain the context of the stage model.
119   import window from '@ohos.window';
120   import UIAbility from '@ohos.app.ability.UIAbility';
121   import { BusinessError } from '@ohos.base';
122
123   let kvManager: distributedKVStore.KVManager | undefined = undefined;
124
125   class EntryAbility extends UIAbility {
126     onWindowStageCreate(windowStage:window.WindowStage) {
127       let context = this.context;
128     }
129   }
130
131    // Obtain the context of the FA model.
132   import featureAbility from '@ohos.ability.featureAbility';
133   import { BusinessError } from '@ohos.base';
134
135   let context = featureAbility.getContext();
136
137   // Construct a kvManager instance.
138   try {
139     const kvManagerConfig: distributedKVStore.KVManagerConfig = {
140       bundleName: 'com.example.datamanagertest',
141       context: context
142     }
143     kvManager = distributedKVStore.createKVManager(kvManagerConfig);
144     console.info('Succeeded in creating KVManager.');
145     // Create and obtain the KV store.
146   } catch (e) {
147     let error = e as BusinessError;
148     console.error(`Failed to create KVManager. Code:${error.code},message:${error.message}`);
149   }
150
151   if (kvManager !== undefined) {
152     kvManager = kvManager as distributedKVStore.KVManager;
153     // Perform subsequent operations such as creating a KV store.
154     // ...
155   }
156   ```
157
1584. Obtain the KV store of the specified type.
159
160   a) Declare the ID of the distributed KV store to create.
161   b) Disable the auto synchronization function (**autoSync:false**) to facilitate subsequent verification of the synchronization function. If synchronization is required, call the **sync()** interface.
162
163
164   ```ts
165   let kvStore: distributedKVStore.SingleKVStore | undefined = undefined;
166   try {
167     const options: distributedKVStore.Options = {
168       createIfMissing: true,
169       encrypt: false,
170       backup: false,
171       autoSync: false,
172       // If kvStoreType is left empty, a device KV store is created by default.
173       kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
174       // Device KV store: kvStoreType: distributedKVStore.KVStoreType.DEVICE_COLLABORATION,
175       securityLevel: distributedKVStore.SecurityLevel.S1
176     };
177     kvManager.getKVStore<distributedKVStore.SingleKVStore>('storeId', options, (err, store: distributedKVStore.SingleKVStore) => {
178       if (err) {
179         console.error(`Failed to get KVStore: Code:${err.code},message:${err.message}`);
180         return;
181       }
182       console.info('Succeeded in getting KVStore.');
183       kvStore = store;
184       // Before performing related data operations, obtain a KV store instance.
185     });
186   } catch (e) {
187     let error = e as BusinessError;
188     console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
189   }
190   if (kvStore !== undefined) {
191     kvStore = kvStore as distributedKVStore.SingleKVStore;
192       // Perform subsequent data operations, such as adding, deleting, modifying, and querying data, and subscribing to data changes.
193       // ...
194   }
195   ```
196
1975. Subscribe to distributed data changes. To unsubscribe from the data changes, call [off('dataChange')](../reference/apis-arkdata/js-apis-distributedKVStore.md#offdatachange).
198
199   ```ts
200   try {
201     kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => {
202       console.info(`dataChange callback call data: ${data}`);
203     });
204   } catch (e) {
205     let error = e as BusinessError;
206     console.error(`An unexpected error occurred. code:${error.code},message:${error.message}`);
207   }
208   ```
209
2106. Write data to the single KV store.
211
212   a) Construct the key and value to be written to the single KV store.
213   b) Write KV pairs to the single KV store.
214
215
216   ```ts
217   const KEY_TEST_STRING_ELEMENT = 'key_test_string';
218   const VALUE_TEST_STRING_ELEMENT = 'value_test_string';
219   try {
220     kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => {
221       if (err !== undefined) {
222         console.error(`Failed to put data. Code:${err.code},message:${err.message}`);
223         return;
224       }
225       console.info('Succeeded in putting data.');
226     });
227   } catch (e) {
228     let error = e as BusinessError;
229     console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
230   }
231   ```
232
2337. Query data in the single KV store.
234
235   a) Construct the key to be queried from the single KV store.
236   b) Query data from the single KV store.
237
238
239   ```ts
240   const KEY_TEST_STRING_ELEMENT = 'key_test_string';
241   const VALUE_TEST_STRING_ELEMENT = 'value_test_string';
242   try {
243     kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => {
244       if (err !== undefined) {
245         console.error(`Failed to put data. Code:${err.code},message:${err.message}`);
246         return;
247       }
248       console.info('Succeeded in putting data.');
249       kvStore = kvStore as distributedKVStore.SingleKVStore;
250       kvStore.get(KEY_TEST_STRING_ELEMENT, (err, data) => {
251         if (err != undefined) {
252           console.error(`Failed to get data. Code:${err.code},message:${err.message}`);
253           return;
254         }
255         console.info(`Succeeded in getting data. Data:${data}`);
256       });
257     });
258   } catch (e) {
259     let error = e as BusinessError;
260     console.error(`Failed to get data. Code:${error.code},message:${error.message}`);
261   }
262   ```
263
2648. Synchronize data to other devices.
265
266   Select the devices to be synchronized with data and the synchronization mode. The user needs to confirm the synchronization mode when the application is started for the first time.
267
268   > **NOTE**
269   >
270   > In manual synchronization mode, **deviceIds** can be obtained by [devManager.getAvailableDeviceListSync](../reference/apis-distributedservice-kit/js-apis-distributedDeviceManager.md#getavailabledevicelistsync).
271
272   ```ts
273   import deviceManager from '@ohos.distributedDeviceManager';
274
275   let devManager: deviceManager.DeviceManager;
276   try {
277     // create deviceManager
278     devManager = deviceManager.createDeviceManager(context.applicationInfo.name);
279     // deviceIds is obtained by devManager.getAvailableDeviceListSync.
280     let deviceIds: string[] = [];
281     if (devManager != null) {
282       let devices = devManager.getAvailableDeviceListSync();
283       for (let i = 0; i < devices.length; i++) {
284         deviceIds[i] = devices[i].networkId as string;
285       }
286     }
287     try {
288       // 1000 indicates the maximum delay, in ms.
289       kvStore.sync(deviceIds, distributedKVStore.SyncMode.PUSH_ONLY, 1000);
290     } catch (e) {
291       let error = e as BusinessError;
292       console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
293     }
294
295   } catch (err) {
296     let error = err as BusinessError;
297     console.error("createDeviceManager errCode:" + error.code + ",errMessage:" + error.message);
298   }
299   ```
300<!--no_check-->