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
- Use the local
put/get/all/remove/sizecontract. - Distinguish updating one key from creating another key.
- Explain why removal also participates in replication and conflict ordering.
- Define a stale-read policy for a route hint.
Prerequisites
- The two-node delta from Chapter 4 has been observed.
- Locator identity and entry keys are understood.
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
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 testExperiment 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
- A Register represents one current logical value per key, not complete history.
- Queries expose the local node's current view.
- Removal is a state change that requires ordering, propagation, and repair.
- The business defines fallback behavior for missing, stale, and failed hints.
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.