Purpose

This note explains how systems support writes while disconnected from the network, and what it costs. The pattern shows up in file syncing, source control, and offline-capable apps, and the hard part is always the same merge and conflict resolution problem.

Core idea

Always-available writes conflict with keeping a single authoritative copy of the data. To operate while disconnected, a client writes to a local copy and synchronizes with the rest of the system when connectivity returns. Since two clients can modify the same data while apart, writes can conflict, and conflicts get resolved either automatically or by a human.

There are two communication models:

  • Clients only talk to a central service (Coda, SVN). Changes are logged locally and applied on reconnection.
  • Clients talk to the service and to each other (Git). Changes are logged and exchanged with whatever peer you connect to, and merges happen again on each new connection.

Coda

Coda mounts a remote file system as a local directory, keeping a partial replica of the global version and caching aggressively to reduce latency. While disconnected it records changes in a write-ahead log. On reconnection it replays the log to the server and merges the changes atomically.

Coda merges automatically when it can. When two users edit the same file, it creates a conflict file and leaves resolution to the user.

sequenceDiagram
    participant C as Coda client
    participant S as Server

    Note over C,S: Connected: partial replica, aggressive caching
    Note over C,S: Network partition
    C->>C: Record changes in write-ahead log
    Note over C,S: Reconnection
    C->>S: Replay log
    alt No concurrent edit
        S-->>C: Changes merged atomically
    else Two users edited the same file
        S-->>C: Conflict file created, user resolves
    end

Offline-capable web apps

Apps like Gmail and Google Docs support offline editing with a local cache plus a log of changes. On reconnection the log is sent to the server and merged, with conflicts resolved by application-level rules.

Version vectors

A common building block is the version vector: each client has a unique ID, each change is tagged with it, and comparing vectors during a merge tells you which changes are newer and which are concurrent. This is the same mechanism as vector clocks.

Source code control

Source control is disconnected operation as the normal mode, permanently. Each client reads and writes its own local copy, and syncs are occasional and manual. The system tracks the full history of changes plus metadata, which is what makes late merging tractable.

Building apps around local storage

A useful application model: write to a local storage engine (SQLite, LevelDB) and sync with the server when online. The synchronization mechanism carries all the difficulty, specifically how it resolves conflicts.

Conflict resolution

  • Client wins: the client’s changes are always accepted
  • Server wins: the server’s changes are always accepted
  • Merge: changes are combined, and remaining conflicts are resolved manually or automatically

Merge strategies

  • Last write wins: the most recent write is accepted, which requires some form of timestamp or versioning
  • Operation based: changes are represented as operations (add, delete, and so on) and applied in order. CRDTs work this way.