Skip to content

Collection Types

DSM exposes three collection models. Choose based on the coordination problem, not by habit.

Quick Mental Model

REGISTER
	one key -> one replicated value
	best when metadata ordering is enough

LEASE
	one key -> one active owner at a time
	best when fencing and ownership matter

CRDT
	many nodes -> local updates -> mergeable state
	best when convergence matters more than single-writer order

Side-By-Side View

+----------------+----------------------+-------------------------------+
| model          | write pattern        | use when                      |
+----------------+----------------------+-------------------------------+
| register       | one value per key    | metadata and routing hints    |
| lease          | one active owner     | fencing and ownership         |
| crdt           | concurrent updates   | counters and mergeable state  |
+----------------+----------------------+-------------------------------+

Register Collections

Use registers when you need replicated metadata keyed by an entry ID.

Typical workloads:

  • route hints
  • service-local feature state
  • cluster-visible operational metadata

Register collections are created with CollectionSpecBuilder.register(...).

java
CollectionSpecBuilder.<RouteHint>register(
		"shared",
		"gateway",
		"route-hints")
	.schemaId("route-hints/v1")
	.codec(new RouteHintCodec())
	.build();

Default builder behavior:

  • consistency tier: REGISTER
  • replication profile: embeddedRegister()
  • QoS profile: bestEffortMeta()
  • persistence profile: ephemeral()

Think of a register as: "I want the cluster to agree on the latest metadata value for this key."

register example

key = edge-eu-west-1
value = 10.1.0.8:8443

node-a put(route-hint)
	-> delta replicates
	-> peers now resolve edge-eu-west-1 the same way

Lease Collections

Use leases when a single owner must hold a responsibility at a point in time.

Typical workloads:

  • shard ownership
  • leader election
  • ownership handoff with fencing tokens

Lease collections are created with LeaseCollectionSpecBuilder.lease(...). They add lease term, renewal skew, expiry grace, and entity factory options.

java
LeaseCollectionSpecBuilder.<ShardOwner>lease(
				"shared",
				"worker",
				"shard-owner")
		.schemaId("shard-owner/v1")
		.codec(new ShardOwnerCodec())
		.entityFactory(ShardOwner::blank)
		.build();

Default builder behavior:

  • replication profile: embeddedLease()
  • QoS profile: controlCritical()
  • persistence profile: localDurable()
  • lease mode: AUTONOMOUS
  • lease term: 10s
  • renew skew: 3s
  • expiry grace: 500ms

ASCII timeline:

worker-a acquires shard-17
			 |
			 | lease term 10s
			 | renew before final 3s window closes
			 v
[ owned ] ---- renew ---- renew ---- renew ---->

if renew stops:
	wait until term expires
	apply expiry grace
	allow another owner to acquire
lease state intuition

FREE -> ACQUIRED -> RENEWING -> EXPIRED -> FREE
						 \-> TRANSFERRED -> ACQUIRED by another node

Use a lease when "who owns this key right now?" is the core question.

CRDT Collections

Use CRDTs when every node should be able to update locally and the cluster should converge through a merge function.

Typical workloads:

  • counters
  • monotonic aggregates
  • mergeable control-plane views

CRDT collections are created with CrdtCollectionSpecBuilder.crdt(...). They require an update codec, state codec, initial state, and merger.

java
CrdtCollectionSpecBuilder.<PnCounterUpdate, PnCounterState>crdt(
		"shared",
		"worker",
		"request-counter")
	.schemaId("request-counter/v1")
	.codec(new PnCounterUpdateCodec())
	.stateCodec(new PnCounterStateCodec())
	.initialState(PnCounterState.empty())
	.build();

Default builder behavior:

  • replication profile: embeddedCrdt()
  • QoS profile: standard()
  • persistence profile: localDurable()

ASCII convergence picture:

node-a: +3 updates  --->
						\ 
						 > merge -> shared state = 8
						/
node-b: +5 updates  --->
crdt intuition

node-a local state = 3
node-b local state = 5

after merge
cluster-visible state = 8

Use a CRDT when local writes on multiple nodes should merge instead of fighting for one winning write.

How To Choose

Use this rule of thumb:

Need the latest metadata value?      -> register
Need one active owner with fencing?  -> lease
Need concurrent local updates?       -> CRDT

If you are unsure, start with a register. Move to a lease only when ownership matters, and move to a CRDT only when multiple nodes truly need local writes.

Default Operational Profiles

  • Registers default to embedded register replication, best-effort metadata QoS, and ephemeral persistence.
  • Leases default to embedded lease replication, control-critical QoS, and local durable persistence.
  • CRDTs default to embedded CRDT replication, standard QoS, and local durable persistence.