Mutable Store
Designed to handle not only data retrieval but also data mutations. Manages the complexities associated with data synchronization between local and remote sources, conflict resolution, and offline support.
Check out Handling CRUD Operations for a guide on supporting:
- Create: Insert One, Insert Many
- Read: Find One, Find Many, Find All, Observe One, Observe Many
- Update: Update One, Update Many, Upsert One, Upsert Many
- Delete: Delete One, Delete Many
Purpose of Mutable Store
- Data Mutations: Supports creating, updating, and deleting data, in addition to reading.
- Synchronization: Manages syncing local changes with remote data sources, handling network failures and retries.
- Conflict Resolution: Works with the Bookkeeper and Updater to resolve conflicts that arise from concrruent modifications or offline changes.
- Offline Support: Allows for local data modifications while offline, ensuring changes are eventually synchronized when connectivity is restored.
APIs
MutableStore
MutableStore has the following structure:
The type representing the key used to identify the data item.
The type representing the domain data model representation of the item being retrieved.
The type representing the response received after updating the remote data source.
stream
A function that returns a Flow of StoreReadResponse.
The request configuration for the data retrieval.
write
A function that returns a StoreWriteResponse.
The request configuration for the data mutation.
clear
A function that clears the data item identified by the given key.
This method only removes data from the delegate Store. It will not update the remote data source.
The key identifying the data item to be cleared.
clearAll
A function that clears all data items.
This method only removes data from the delegate Store. It will not update the remote data source.
Key Components
The RealMutableStore is the default implementation of the MutableStore interface. It’s composed of the following components:
-
Delegate Store: Read operations are delegated to an instance of RealStore. This delegation allows RealMutableStore to leverage the efficient caching and data retrieval mechanisms already implemented in RealStore.
-
Updater: Handles applying local changes to the remote data source. It defines the logic for how data mutations are synchronized with the server.
-
Bookkeeper: Rracks failed synchronization attempts. It ensures that any local changes that could not be synced due to network issues or other failures are retried, maintaining data consistency.
-
Write Request Queue: For each key, RealMutableStore maintains a write request queue (
WriteRequestQueue<Key, Output, *>
). This queue holds pending write operations that need to be synchronized with the remote data source. New write requests are added to the queue. Upon successful synchronization, processed requests are removed. -
Thread Safety Mechanisms: To handle concurrent operations safely, RealMutableStore uses:
-
A global Mutex to synchronize access to per-key ThreadSafety objects.
-
ThreadSafety objects that manage fine-grained locking mechanisms for each key.
-
Lightswitch mechanisms managing read-write locks efficiently.
-
-
Conflict Resolution Logic: Conflict resolution is integral to RealMutableStore. At a high level:
- Checks for conflicts using the Bookkeeper and pending write requests.
- Attempts to synchronize with the remote source to resolve conflicts.
- Updates the local state based on the outcome.
Data Flow
Reading Data
Initialization
Ensures that thead safety mechanisms and write request queues are initialized.
Eager Conflict Resolution
Attempts to resolve any conflicts before proceeding with the read operation.
- If conflicts exist, tries to synchronize local changes with the remote source.
- If no conflicts, proceeds to data retrieval.
Data Retrieval
Delegates the read operation to the RealStore instance.
Writing Data
Request Queueing
The write request is added to the per-key write request queue.
Local Update
The value is immediately written to the local data source.
Server Synchronization Attempt
Attempts to update the remote data source using the Updater.
Handling the Updater Result
Success
- Updates the write request queue, removing processed requests.
- Clears any failed sync records from the Bookkeeper.
Failure
- Records the failed attempt using the Bookkeeper.
Response Emission
Emits a StoreWriteResponse indicating success or failure.