pub struct ShardOwnershipCatalog { /* private fields */ }Expand description
The global shard ownership catalog held by every data member.
This single type plays both roles in ADR 0037’s model: it is the authoritative
state the Cluster Supervisor leader writes through, and it is the replica each
data member holds and routes against. Both write through
apply_update, so the stale-version rejection that
makes leader writes versioned is the same rule that makes replica
application order-independent. Nothing here needs user-data sharding to find
an entry: ranges are addressed directly by (collection, range_id), and
routing (route) is a local scan of the replica.
Implementations§
Source§impl ShardOwnershipCatalog
impl ShardOwnershipCatalog
Sourcepub fn plan_write_transaction(
&self,
targets: &[KeyTarget],
) -> Result<WriteTransactionPlan, WriteTransactionReject>
pub fn plan_write_transaction( &self, targets: &[KeyTarget], ) -> Result<WriteTransactionPlan, WriteTransactionReject>
Plan a write transaction over targets in the first multi-writer cut
(issue #1002).
Resolves every targeted key to its owning range and groups by writer:
- all targets owned by one writer →
WriteTransactionPlan(the transaction commits atomically on that owner, even across several of its own ranges); - targets span ranges of different writers →
WriteTransactionReject::CrossRangenaming every writer — this cut has no atomic cross-writer commit; - a target routes nowhere →
WriteTransactionReject::Unroutable.
Pure: it reads the catalog and returns intent. Each admitted write still
passes admit_public_write at the owner’s
current epoch, so a stale plan cannot smuggle a write past fencing.
Sourcepub fn plan_read_fanout(
&self,
targets: &[KeyTarget],
) -> Result<ReadFanout, ReadFanoutReject>
pub fn plan_read_fanout( &self, targets: &[KeyTarget], ) -> Result<ReadFanout, ReadFanoutReject>
Plan a simple, best-effort cross-range read fanout over targets
(issue #1002).
Collects the resolved targets into one ReadLeg per owner so the caller
can scatter the read across every range owner and gather the results. This
is not a consistent snapshot — see ReadFanout. Err only when the
read is empty or a target routes nowhere; spanning many owners is the
expected, successful case.
Sourcepub fn plan_consistent_read(
&self,
targets: &[KeyTarget],
snapshot: Option<&GlobalReadWatermark>,
) -> Result<ConsistentReadPlan, ConsistentReadReject>
pub fn plan_consistent_read( &self, targets: &[KeyTarget], snapshot: Option<&GlobalReadWatermark>, ) -> Result<ConsistentReadPlan, ConsistentReadReject>
Plan a globally consistent cross-range read over targets, pinned to
snapshot (issue #1002).
A consistent read must pin every range it touches to a single safe point:
snapshotisNone→ConsistentReadReject::NoSafeSnapshot; the caller must obtain a global watermark first;- a targeted range is absent from
snapshot→ConsistentReadReject::WatermarkGap; - a target routes nowhere →
ConsistentReadReject::Unroutable; - otherwise → a
ConsistentReadPlanwith each leg pinned to its range’s watermark.
This is the explicit safe-snapshot path: without it a cross-range read may
only be served as a best-effort ReadFanout, never as a consistent one.
Source§impl ShardOwnershipCatalog
impl ShardOwnershipCatalog
Sourcepub fn new() -> ShardOwnershipCatalog
pub fn new() -> ShardOwnershipCatalog
An empty catalog — a cluster with no collections placed yet.
Sourcepub fn declare_collection(
&mut self,
collection: CollectionId,
mode: ShardKeyMode,
) -> Result<(), CatalogError>
pub fn declare_collection( &mut self, collection: CollectionId, mode: ShardKeyMode, ) -> Result<(), CatalogError>
Declare a collection’s shard key mode up front. Hash is the default, so
this is mainly how an operator opts a collection into
Ordered mode before any range exists. Declaring
the same mode twice is idempotent; redeclaring a different mode for a
collection that already has a mode is a ShardKeyModeMismatch.
Sourcepub fn shard_key_mode(&self, collection: &CollectionId) -> Option<ShardKeyMode>
pub fn shard_key_mode(&self, collection: &CollectionId) -> Option<ShardKeyMode>
The declared shard key mode of collection, if it has any ranges or was
explicitly declared.
Sourcepub fn apply_update(
&mut self,
entry: RangeOwnership,
) -> Result<UpdateOutcome, CatalogError>
pub fn apply_update( &mut self, entry: RangeOwnership, ) -> Result<UpdateOutcome, CatalogError>
Apply a versioned ownership update — the single write path for both leader writes and replica application.
Creation (the range does not yet exist) auto-declares the collection’s
mode from the entry and checks the new range does not overlap a sibling.
Updating an existing range requires the entry’s version to strictly
advance the current version; anything else is a
StaleVersion rejection that leaves the
catalog untouched. Either way the entry’s mode must match the collection’s
declared mode.
Sourcepub fn range(
&self,
collection: &CollectionId,
range_id: RangeId,
) -> Option<&RangeOwnership>
pub fn range( &self, collection: &CollectionId, range_id: RangeId, ) -> Option<&RangeOwnership>
The current ownership of one range, addressed directly by identity — no routing required, because the catalog is what routing is built on.
Sourcepub fn ranges_for<'a>(
&'a self,
collection: &CollectionId,
) -> impl Iterator<Item = &'a RangeOwnership>
pub fn ranges_for<'a>( &'a self, collection: &CollectionId, ) -> impl Iterator<Item = &'a RangeOwnership>
Every range of collection, in range-id order.
Sourcepub fn route(
&self,
collection: &CollectionId,
key: &[u8],
) -> Option<&RangeOwnership>
pub fn route( &self, collection: &CollectionId, key: &[u8], ) -> Option<&RangeOwnership>
Route a normalized range key to the range that owns it — the catalog read
every routing decision makes. Returns the owning RangeOwnership (whose
owner, epoch, and replicas the caller uses to send and fence the
write), or None if no range covers the key yet.
Sourcepub fn route_shard_key(
&self,
collection: &CollectionId,
shard_key: &[u8],
) -> Option<&RangeOwnership>
pub fn route_shard_key( &self, collection: &CollectionId, shard_key: &[u8], ) -> Option<&RangeOwnership>
Route a logical shard key according to the collection’s declared mode.
Ordered collections route the shard key bytes directly. Hash collections
first map the shard key into a stable hash slot and route that slot’s
range key through the same collection -> range catalog.
Sourcepub fn role_at(
&self,
node: &NodeIdentity,
collection: &CollectionId,
range_id: RangeId,
) -> Option<RangeRole>
pub fn role_at( &self, node: &NodeIdentity, collection: &CollectionId, range_id: RangeId, ) -> Option<RangeRole>
Sourcepub fn admit_public_write(
&self,
node: &NodeIdentity,
collection: &CollectionId,
key: &[u8],
expected_epoch: OwnershipEpoch,
) -> Result<&RangeOwnership, RangeWriteReject>
pub fn admit_public_write( &self, node: &NodeIdentity, collection: &CollectionId, key: &[u8], expected_epoch: OwnershipEpoch, ) -> Result<&RangeOwnership, RangeWriteReject>
Ownership-aware gate for a public write (issue #990, PRD #987).
Routes key to its range, then admits the write only when node is the
range’s current Owner and expected_epoch
matches the range’s current ownership epoch. On success returns the owned
RangeOwnership (so the caller can proceed with the write against the
authoritative epoch); otherwise a RangeWriteReject explaining why.
This is the public surface’s gate — the counterpart of the instance-wide
WriteGate for multi-writer,
per-range ownership. The internal replica-apply path does not consult
it: replicated changes flow into a replica through the privileged apply
path (fenced by issue #991’s range-authority watermark), so a node that
rejects a public write here can still legitimately apply the owner’s
replicated changes for the very same range.
Sourcepub fn range_count(&self) -> usize
pub fn range_count(&self) -> usize
Total number of owned ranges across all collections.
Sourcepub fn entries(&self) -> impl Iterator<Item = &RangeOwnership>
pub fn entries(&self) -> impl Iterator<Item = &RangeOwnership>
All ranges, in (collection, range_id) order — the full catalog content
a joining member adopts as its starting replica
(see ControlPlaneSnapshot).
Source§impl ShardOwnershipCatalog
impl ShardOwnershipCatalog
Sourcepub fn plan_route(
&self,
local: &NodeIdentity,
request: &RoutedRequest,
policy: &RoutingPolicy,
) -> RouteDecision
pub fn plan_route( &self, local: &NodeIdentity, request: &RoutedRequest, policy: &RoutingPolicy, ) -> RouteDecision
Plan how local should handle request under policy — the any-node
routing decision (issue #993).
Resolves the target range from the catalog, then:
- owner of the range →
Local; - non-owner, forwarding enabled, safe point op within budget →
Forwardto the owner; - non-owner but the op is unsafe to forward / oversized / forwarding
disabled →
Redirectwith the owner+epoch hint; - no range covers the key →
Unroutable.
The decision is pure: it reads the catalog and returns intent. Fencing is
still enforced below routing — a forwarded or locally-executed write lands
on admit_public_write at the owner’s current
epoch, so a stale routing decision cannot smuggle a write past ownership.
Source§impl ShardOwnershipCatalog
impl ShardOwnershipCatalog
Sourcepub fn topology_snapshot(&self) -> TopologySnapshot
pub fn topology_snapshot(&self) -> TopologySnapshot
Project the catalog into a driver-facing TopologySnapshot — the payload
a topology poll serves (issue #994).
The snapshot carries every range’s bounds, owner, replicas, ownership
epoch, and catalog version, and stamps a generation
(version) drivers use to tell a newer
snapshot from a stale one.
Trait Implementations§
Source§impl Clone for ShardOwnershipCatalog
impl Clone for ShardOwnershipCatalog
Source§fn clone(&self) -> ShardOwnershipCatalog
fn clone(&self) -> ShardOwnershipCatalog
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ShardOwnershipCatalog
impl Debug for ShardOwnershipCatalog
Source§impl Default for ShardOwnershipCatalog
impl Default for ShardOwnershipCatalog
Source§fn default() -> ShardOwnershipCatalog
fn default() -> ShardOwnershipCatalog
Auto Trait Implementations§
impl Freeze for ShardOwnershipCatalog
impl RefUnwindSafe for ShardOwnershipCatalog
impl Send for ShardOwnershipCatalog
impl Sync for ShardOwnershipCatalog
impl Unpin for ShardOwnershipCatalog
impl UnsafeUnpin for ShardOwnershipCatalog
impl UnwindSafe for ShardOwnershipCatalog
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request