Skip to content

Grain directory architecture

The grain directory maps a grain identity to an activation address. It is on the critical path when a caller has no usable cached address and when the runtime creates, moves, or removes an activation. Placement chooses a silo; the directory coordinates which activation address is authoritative.

Orleans uses LocalGrainDirectory by default. DistributedGrainDirectory is experimental and must be enabled explicitly.

LocalGrainDirectory partitions registrations over the membership ring. Hashing a grain identity selects the silo whose local LocalGrainDirectoryPartition is authoritative for that key. This follows the broad consistent-hashing distributed-hash-table model described by Chord, adapted to Orleans membership and activation semantics. Each silo also keeps non-authoritative cache entries to avoid repeated remote lookups.

Rendering diagram.

The default directory preserves these invariants:

  • a directory key is derived from the grain identity, not its current location;
  • the membership view determines the authoritative owner;
  • local cache entries are hints and can be invalidated;
  • registration detects competing single-activation addresses;
  • a failed or deactivated silo’s addresses are removed or rejected; and
  • partition ownership transfers as the membership ring changes.

Message forwarding and invalidation repair stale caches. Forwarding is bounded and is not an application-level retry policy.

Source: LocalGrainDirectory and LocalGrainDirectoryPartition.

The runtime resolves a directory per grain type. The unnamed default resolves to LocalGrainDirectory unless the silo has explicitly replaced it. A named implementation of IGrainDirectory can be registered and selected using grain-type metadata.

Custom directories own their consistency, availability, and cleanup behavior. They should define what concurrent registration means, how failed silos are removed, and whether stale reads are possible. The surrounding message router cannot turn an eventually consistent custom directory into a strongly consistent one.

CoreHostingExtensions.AddDistributedGrainDirectory opts into a view-synchronous directory marked with compiler warning ORLEANSEXP003:

It is not the default. The experimental status allows its API and protocol to evolve.

The implementation divides the hash ring into configurable ranges, analogous to the virtual-node partitioning described by Dynamo. GrainDirectoryOptions.PartitionsPerSilo defaults to 1, not 30. A partition normally serves requests locally. During a membership view change, old and new owners coordinate range locks, snapshots, and ownership transfer. The design applies the virtually synchronous methodology for dynamic service replication and has similarities to Vertical Paxos and primary-backup replication.

Rendering diagram.

Requests and responses carry view information. A range cannot serve a request under an incompatible ownership view. If an orderly transfer is impossible, the new owner recovers registrations by querying active silos rather than assuming the failed owner’s state.

API: CoreHostingExtensions.AddDistributedGrainDirectory and GrainDirectoryOptions. Implementation: hosting registration and DistributedGrainDirectory.

PropertyDefault LocalGrainDirectoryExperimental DistributedGrainDirectory
StatusDefaultOpt-in, ORLEANSEXP003
OwnershipMembership consistent-hash ringVersioned ranges over membership views
Normal lookupOwner partition plus per-silo cacheOwner partition plus view coordination
View changePartition split/merge and cache repairSealed ranges and snapshot transfer
Recovery emphasisDuplicate detection and invalidationExplicit range recovery
ConfigurationExisting default behaviorGrainDirectoryOptions.PartitionsPerSilo, default 1

More partitions can improve ownership granularity but increase transfer and coordination work. This page documents the mechanism; any production rollout of an experimental component should include compatibility, failure, and load testing.