Skip to content

Commit f702554

Browse files
committed
docs: Add write lifecycle documentation and update schema details
1 parent cb8def1 commit f702554

File tree

4 files changed

+71
-12
lines changed

4 files changed

+71
-12
lines changed

packages/firestore/devdocs/overview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ To navigate the internals of the SDK, use the following guide:
4242
### Core Concepts
4343
* **[Architecture](./architecture.md)**: The high-level block diagram of the system (API -> Core -> Local -> Remote).
4444
* **[Query Lifecycle](./query-lifecycle.md)**: The state machine of a query. **Read this** to understand how querying and offline capabilities work.
45+
* **[Write Lifecycle](./write-lifecycle.md)**: How writes work (Mutations, Batches, Overlays).
4546

4647
### Subsystem Deep Dives
4748
* **[Persistence Schema](./persistence-schema.md)**: A reference guide for the IndexedDB tables.

packages/firestore/devdocs/persistence-schema.md

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@ While the Android/iOS SDKs use SQLite, the JS SDK uses IndexedDB Object Stores.
1212
* **Value**:
1313
* **Document Data**: The serialized Protobuf of the document.
1414
* **ReadTime**: The snapshot version at which this document was read.
15-
* **Note**: This store **never** contains local, unacknowledged writes. It only contains data confirmed by the server. To see what the developer sees, we overlay the `mutation_queues` on top of this.
15+
* **Note**: This store **never** contains local, unacknowledged writes. It only contains data confirmed by the server. To see what the developer sees, we overlay the `mutation_queue` on top of this.
1616

17-
### `mutation_queues`
18-
* **Concept**: The "Pending Writes" queue.
19-
* **Key**: `BatchID` (Integer, auto-incrementing).
20-
* **Grouping**: Queues are partitioned by **UID**. When a developer logs out, the SDK switches to a different queue.
21-
* **Value**:
22-
* **Mutation**: The serialized operation (Set, Patch, Delete).
23-
* **Metadata**: Timestamp, offsets.
24-
* **Behavior**: When the network is available, the `RemoteStore` reads from this queue to send write batches to the backend. Once acknowledged, entries are removed.
17+
### `mutation_queue`
18+
* **Concept**: The "Pending Writes" queue. An ordered log of all local writes that have not yet been acknowledged by the server.
19+
* **Key**: `(user_id, batch_id)`. Segregating by User ID ensures that if a user logs out, their pending writes do not leak to the next user.
20+
* **Value**: A serialized `MutationBatch` containing one or more mutations (Set, Patch, Delete).
21+
* **Behavior**: This is the "Single Source of Truth" for local changes. If the app restarts, the SDK replays these mutations to rebuild the Overlays. When the network is available, the `RemoteStore` reads from this queue to send write batches to the backend. Once acknowledged, entries are removed.
22+
23+
### `document_overlays`
24+
* **Concept**: A cache of the *result* of applying pending mutations.
25+
* **Key**: `(user_id, document_key)`.
26+
* **Purpose**: Read Performance. Without this table, the SDK would have to read the Remote Document and re-apply every pending mutation from the queue every time a query ran.
27+
* **Lifecycle**: Created immediately when a user writes. Deleted immediately when the backend acknowledges the write (or rejects it).
28+
* **Priority**: When the `LocalStore` reads a document, it checks this table first. If an entry exists, it takes precedence over `remote_documents`.
2529

2630
### `targets`
2731
* **Concept**: Metadata about active and cached queries.
@@ -54,5 +58,5 @@ While the Android/iOS SDKs use SQLite, the JS SDK uses IndexedDB Object Stores.
5458

5559
## Data Relationships
5660

57-
1. **The "View"**: To construct a document for the developer, the SDK reads `remote_documents[key]` and applies any mutations found in `mutation_queues` matching that key.
61+
1. **The "View"**: To construct a document for the developer, the SDK reads `remote_documents[key]` and applies any mutations found in `mutation_queue` matching that key.
5862
2. **Garbage Collection**: The `LruGarbageCollector` uses `target_globals.last_sequence_number` and `targets.last_sequence_number` to determine which targets are old and can be evicted. It then uses `target_documents` to find which documents are no longer referenced by *any* target and deletes them from `remote_documents`.

packages/firestore/devdocs/query-lifecycle.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ When a query runs (initially or after a remote update), the **Local Store** perf
4141
* *Deep Dive*: For details on Index Scans, Full Scans, and Optimization strategies, see [Query Execution & Indexing](./query-execution.md).
4242
2. **Base State**: The store retrieves the confirmed server state from the `remote_documents` table.
4343
3. **Overlay Application**:
44-
* The store checks the `mutation_queues` for any pending writes associated with these keys.
44+
* The store checks the `mutation_queue` for any pending writes associated with these keys.
4545
* These mutations are converted into **Overlays**.
4646
* The Overlay is applied on top of the Remote Document.
4747
4. **Projection**: The final composed documents are sent to the Event Manager.
@@ -94,5 +94,5 @@ For a detailed walkthrough of the algorithm, Sequence Numbers, and Orphaned Docu
9494
If you are debugging a **"Zombie Document"** (data appearing that should be gone) or **"Missing Data"**:
9595

9696
1. **Check `targets`**: Is there an active target (valid `resumeToken`) covering that document?
97-
2. **Check `mutation_queues`**: Is there a pending mutation (BatchID) that hasn't been acknowledged? This creates an Overlay that persists even if the remote doc is deleted.
97+
2. **Check `mutation_queue`**: Is there a pending mutation (BatchID) that hasn't been acknowledged? This creates an Overlay that persists even if the remote doc is deleted.
9898
3. **Check `target_documents`**: Is the document explicitly linked to a TargetID that you thought was closed?
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Write Lifecycle & Latency Compensation
2+
3+
This document details the lifecycle of a write operation (Set, Update, Delete) from the moment the API is called to when it is committed to the backend. It focuses on **Mutations**, **Overlays**, and how the SDK achieves instant **Latency Compensation**.
4+
5+
## Key Concepts
6+
7+
* **Mutation**: An operation that modifies a document (e.g., `SetMutation`, `PatchMutation`, `DeleteMutation`).
8+
* **Mutation Batch**: A group of mutations that must be applied atomically. Every user write creates a new Batch with a unique `BatchID`.
9+
* **Overlay**: A "Materialized View" of the changes applied to a document. Instead of re-calculating the result of a mutation every time a query runs, the SDK calculates the result *once* at write time and saves it as an Overlay.
10+
11+
## Phase 1: Mutation Creation & Batching
12+
13+
When a user calls `setDoc` or `updateDoc`:
14+
1. **Validation**: The SDK validates the data locally.
15+
2. **Batching**: The operation is wrapped in a `MutationBatch`.
16+
3. **Persistence**: The batch is serialized and saved to the `mutation_queue` table in IndexedDB.
17+
* **Partitioning**: Queues are partitioned by User ID. If the user is offline, these batches accumulate in the queue.
18+
19+
## Phase 2: Overlay Calculation (Optimization)
20+
21+
To ensure queries run fast, the SDK does not apply raw mutations to remote documents during every query execution. Instead, it pre-calculates the result.
22+
23+
1. **Base State**: The SDK retrieves the current state of the document (from `remote_documents`).
24+
2. **Apply**: It applies the new `Mutation` to the base state to determine what the document *should* look like locally.
25+
3. **Persist Overlay**: This resulting state is saved to the `document_overlays` table.
26+
* **Field Mask**: The overlay tracks specifically which fields were modified.
27+
4. **Latency Compensation**: The `Event Manager` immediately triggers active listeners. The listeners read the `Overlay` instead of the `Remote Document`, giving the user the illusion of instant updates.
28+
29+
> **Formula:** `Local View = Remote Document + Overlay`
30+
31+
## Phase 3: Synchronization (The Write Pipeline)
32+
33+
The `SyncEngine` manages the flow of data to the server:
34+
35+
1. **Filling the Pipeline**: The `RemoteStore` reads the `mutation_queue` in order of `BatchID` (FIFO).
36+
2. **Transmission**: Mutations are sent to the backend via gRPC (or REST in Lite).
37+
3. **Atomicity**: If a batch contains multiple writes, the backend guarantees they are applied together or not at all.
38+
39+
## Phase 4: Acknowledgement & Cleanup
40+
41+
When the backend responds:
42+
43+
### Scenario A: Success (Ack)
44+
1. **Commit**: The backend commits the change and returns the authoritative version of the document (and transformation results, like server timestamps).
45+
2. **Update Remote**: The SDK updates the `remote_documents` table with this new server version.
46+
3. **Cleanup**:
47+
* The `MutationBatch` is removed from `mutation_queue`.
48+
* The corresponding `Overlay` is removed from `document_overlays` (since the Remote Document now matches the desired state).
49+
4. **Re-Evaluation**: Active queries are re-run. Since the Overlay is gone, they now read the updated Remote Document.
50+
51+
### Scenario B: Rejection
52+
1. The `MutationBatch` is removed.
53+
2. The `Overlay` is removed.
54+
3. The Local View reverts to the `Remote Document` state (rolling back the optimistic update).

0 commit comments

Comments
 (0)