ARC 2Choose Consistency SemanticsChapters 5–9

Chapter 5 — Register: Current Values and Stale Reads

Chapter objective: After this chapter, a developer can use a Register to represent the current logical value for a key and avoid treating a local query as a strongly consistent cluster read.

Learning objectives

  1. Use the local put/get/all/remove/size contract.
  2. Distinguish updating one key from creating another key.
  3. Explain why removal also participates in replication and conflict ordering.
  4. Define a stale-read policy for a route hint.

Prerequisites

Case progress

The fulfillment service rolls from 10.0.0.1 to 10.0.0.2. The gateway updates the existing fulfillment-primary entry and removes the hint after the old service retires.

One visible value per key

Visible operations on a Register

put(v2) submits a candidate with lineage metadata. It does not provide database row-lock overwrite semantics. The local node sees v2 immediately; peers catch up through online deltas or later repair.

register.put(route("fulfillment-primary", "10.0.0.1:8080"));
register.put(route("fulfillment-primary", "10.0.0.2:8080"));
Optional<RouteHint> current = register.get("fulfillment-primary");
Optional<RouteHint> removed = register.remove("fulfillment-primary");

all(), size(), and get() inspect the state currently known by one node. They support local routing and diagnosis. They do not create a cluster-wide snapshot or issue a read quorum.

The business stale-read policy

"Read from the Register" is incomplete as an operating rule. The gateway also defines whether a missing entry triggers an authoritative lookup, whether a failed connection tries a secondary address, and when a hint becomes too old to trust. DSM should not decide alone when a routing error can cause an irreversible effect.

In this case, a failed route hint triggers one lookup in the authoritative service directory and one retry. The fulfillment service's transactional API remains responsible for idempotent order submission.

Counterexample and fault injection

A poor design writes every health probe under a random key and calls all().get(0) to select an address. Entries grow without bound, and their order carries no business meaning. A stable service key should identify the current hint; auditable history belongs in a history system.

Another weak assertion expects every node to be empty immediately after a removal. Removal propagates like a write and can meet concurrent candidates.

Experiment

Run the two-node put/remove/reverse-put test and record the local commit, remote put, and remote removal:

cd submodule/dsm
mvn -q -pl dsm-integration-test -am \
  -Dtest=TwoNodeIntegrationTest#runtimeFirstRegisterDeltasReplicateAcrossTwoNodes \
  -Dsurefire.failIfNoSpecifiedTests=false test

Experiment acceptance card

Field Content
Command The focused Maven command above
Input or fault Put and remove on the same key; a reverse-direction write
Observable result The peer's visible value follows each operation; the remote removal has a source event
Evidence level E3: controlled two-node integration test
This experiment does not prove Strongly consistent cluster reads, history queries, or transactional conditional updates

Review

Next

Chapter 6 lets nodes A and B update the same key during a partition and explains how both nodes later select the same winner.