Replication: SYNC + write streaming

Two phases: bulk transfer via SYNC, then live streaming. The wire format is RESP, identical to what redis-cli sends. No new protocol.

08-replication/main.go
go
case "SYNC":
    // Master responds with a SET per key, then keeps the socket alive.
    snap := store.Snapshot()
    log.Printf("  [master] SYNC: sending %d keys to %s", len(snap), conn.RemoteAddr())
    for k, v := range snap {
        conn.Write(encodeRESPArray([]string{"SET", k, v}))
    }
    master.AddReplica(conn)
    return nil // socket stays alive in master.replicas

Phase one: a fresh replica sends SYNC. The master snapshots the store and replays it down the socket as ordinary SET frames, then keeps that socket in its replicas slice so live streaming takes over.

08-replication/main.go
go
func (m *Master) Replicate(args []string) {
    payload := encodeRESPArray(args)
    m.mu.Lock()
    live := m.replicas[:0]
    for _, c := range m.replicas {
        if _, err := c.Write(payload); err == nil {
            live = append(live, c)
        } else {
            c.Close()
        }
    }
    m.replicas = live
    m.mu.Unlock()
}

Master.Replicate fans the write out to every replica conn. Dead replicas are detected by Write error and removed in-place.

A replica refuses client writes. The flag isReplicatedWrite distinguishes "client wrote to replica" (refuse) from "master shipped me this write" (apply). Same boolean dance as Python.