Skip to content

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.

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:

kotlin
interface MutableStore<Key : Any, Output : Any> {
    fun <Response : Any> stream(
        request: StoreReadRequest<Key>,
    ): Flow<StoreReadResponse<Output>>

    suspend fun <Response : Any> write(
        request: StoreWriteRequest<Key, Output, Response>,
    ): StoreWriteResponse

    suspend fun clear(key: Key)

    suspend fun clearAll()
}
Parameter
Key
Type
Any
Required
Required
Description

The type representing the key used to identify the data item.

Parameter
Output
Type
Any
Required
Required
Description

The type representing the domain data model representation of the item being retrieved.

Parameter
Response
Type
Any
Required
Required
Description

The type representing the response received after updating the remote data source.

stream

A function that returns a Flow of StoreReadResponse.

Parameter
request
Type
StoreReadRequest<Key>
Required
Required
Description

The request configuration for the data retrieval.

write

A function that returns a StoreWriteResponse.

Parameter
request
Type
StoreWriteRequest<Key, Output, Response>
Required
Required
Description

The request configuration for the data mutation.

clear

A function that clears the data item identified by the given key.

Parameter
key
Type
Key
Required
Required
Description

The key identifying the data item to be cleared.

clearAll

A function that clears all data items.

Key Components

The RealMutableStore is the default implementation of the MutableStore interface. It’s composed of the following components:

  1. 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.

  2. Updater: Handles applying local changes to the remote data source. It defines the logic for how data mutations are synchronized with the server.

  3. 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.

  4. 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.

  5. 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.

  6. 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

Writing Data