distributed

package
v0.3.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 3, 2026 License: MIT Imports: 17 Imported by: 0

README

distributed

A sharded, replicated store facade over multiple in-process nodes: consistent hashing for shard assignment, scatter-gather search with partial-failure tolerance, replication, and cluster health.

Core

cluster := distributed.NewCluster(distributed.DefaultClusterConfig())
sm := /* ShardManager: shards keyed to nodes via consistent hash ring */
store := distributed.NewDistributedStore(clusterCfg, embedder, ...) // Store-compatible
  • Cluster / Node — node membership on a consistent-hash ring (MD5-based key hashing — uniformity, not security).
  • ScatterGatherSearch / ScatterGatherSearchHybrid — fan out a query to the responsible shards and merge; tolerate partial node failure.
  • Quorum(n) / QuorumMet(succeeded, n) — quorum math for reads/writes.

Replication & operations

  • ReplicationManager + ReplicationStrategy (sync/async) — ReplicateOp writes to replicas, reports per-node results.
  • AutoRebalancer — periodic shard rebalancing when nodes join/leave.
  • NodeHealth / Consensus — liveness probing and simple consensus helpers.
  • Diagnostics(c, sm) / HealthHandler — cluster-wide health for the cluster status CLI command.

Documentation

Overview

Package distributed provides a sharded, replicated store facade over multiple in-process nodes: consistent hashing for shard assignment, scatter-gather search with partial-failure tolerance, and cluster diagnostics.

Index

Constants

This section is empty.

Variables

View Source
var ErrShardExists = errors.New("shard already exists")

ErrShardExists is returned by CreateShardWithID when a shard with the same explicit ID is already registered with the manager.

Functions

func HealthHandler

func HealthHandler(c *Cluster, sm *ShardManager) http.Handler

HealthHandler returns an http.Handler exposing cluster health and diagnostics:

GET /healthz      -> 200 when healthy or degraded, 503 when down (JSON body)
GET /diagnostics  -> 200 with a JSON cluster diagnostics snapshot

Other paths return 404.

func Quorum

func Quorum(n int) int

Quorum returns the majority quorum size for n replicas.

func QuorumMet

func QuorumMet(succeeded, n int) bool

QuorumMet reports whether succeeded replicas meet the quorum for n replicas.

func ReplicateOp

func ReplicateOp(ctx context.Context, nodes []*Node, op func(ctx context.Context, node *Node) error) (succeeded int, firstErr error)

ReplicateOp applies op to each node, returning how many succeeded and the first error encountered. A replicated write is considered durable when at least Quorum(len(nodes)) nodes succeed (see QuorumMet).

func ScatterGatherSearch

func ScatterGatherSearch(ctx context.Context, sm *ShardManager, query []float32, opts index.SearchOptions, config *ScatterGatherConfig) ([]index.SearchResult, error)

ScatterGatherSearch performs a scatter-gather search across multiple shards.

func ScatterGatherSearchHybrid

func ScatterGatherSearchHybrid(ctx context.Context, sm *ShardManager, query string, queryEmb []float32, opts index.SearchOptions, config *ScatterGatherConfig) ([]index.SearchResult, error)

ScatterGatherSearchHybrid performs a scatter-gather hybrid search across multiple shards. query is the raw query text and queryEmb its embedding; both are fanned out so each shard can rank vector and keyword signals independently.

Types

type AutoRebalancer

type AutoRebalancer struct {
	// contains filtered or unexported fields
}

AutoRebalancer watches cluster membership and re-runs an active rebalance whenever the set of active (non-offline) nodes changes, so the hash ring tracks node availability automatically.

func NewAutoRebalancer

func NewAutoRebalancer(cluster *Cluster, interval time.Duration) *AutoRebalancer

NewAutoRebalancer creates an AutoRebalancer that watches the cluster's active node set. A non-positive interval uses 2s.

func (*AutoRebalancer) MaybeRebalance

func (r *AutoRebalancer) MaybeRebalance(ctx context.Context) (bool, error)

MaybeRebalance checks whether the active node set changed since the last check and, if so, runs an active rebalance. It returns true when a rebalance occurred.

func (*AutoRebalancer) Rebalances

func (r *AutoRebalancer) Rebalances() int

Rebalances returns how many rebalances have been performed.

func (*AutoRebalancer) Start

func (r *AutoRebalancer) Start(ctx context.Context)

Start begins the background rebalance watcher. It is a no-op if already running and stops when ctx is cancelled or Stop is called.

func (*AutoRebalancer) Stop

func (r *AutoRebalancer) Stop()

Stop halts the watcher and waits for it to finish. Safe to call when not running.

type Cluster

type Cluster struct {
	// contains filtered or unexported fields
}

Cluster manages the distributed cluster of nodes.

func NewCluster

func NewCluster(config *ClusterConfig) *Cluster

NewCluster creates a new distributed cluster.

func (*Cluster) ActiveNodeIDs

func (c *Cluster) ActiveNodeIDs() []string

ActiveNodeIDs returns the sorted IDs of nodes that are not offline (i.e. "online" or "degraded"), which are the nodes eligible to hold and serve data.

func (*Cluster) AddNode

func (c *Cluster) AddNode(node *Node) error

AddNode adds a node to the cluster.

func (*Cluster) GetAllNodes

func (c *Cluster) GetAllNodes() []*Node

GetAllNodes returns all nodes in the cluster.

func (*Cluster) GetNode

func (c *Cluster) GetNode(nodeID string) (*Node, bool)

GetNode returns a node by its ID.

func (*Cluster) GetNodeCount

func (c *Cluster) GetNodeCount() int

GetNodeCount returns the number of nodes in the cluster.

func (*Cluster) GetNodeForChunk

func (c *Cluster) GetNodeForChunk(chunkID string) string

GetNodeForChunk returns the node responsible for storing a chunk with the given ID: the first virtual node clockwise from the chunk ID's hash. Returns "" when the cluster has no nodes.

func (*Cluster) GetOnlineNodeCount

func (c *Cluster) GetOnlineNodeCount() int

GetOnlineNodeCount returns the number of online nodes.

func (*Cluster) GetOnlineNodes

func (c *Cluster) GetOnlineNodes() []*Node

GetOnlineNodes returns all online nodes.

func (*Cluster) GetReplicaNodes

func (c *Cluster) GetReplicaNodes(key string) []*Node

GetReplicaNodes returns the nodes responsible for a given key: the primary (the first virtual node clockwise from the key's hash) followed by up to ReplicationFactor-1 further distinct nodes, walking the ring with wrap-around. The result contains at most len(nodes) distinct nodes and is empty only when the cluster has no nodes.

func (*Cluster) Health

func (c *Cluster) Health() ClusterHealth

Health returns a summary of cluster node health and the cluster's overall operability.

func (*Cluster) Rebalance

func (c *Cluster) Rebalance(ctx context.Context) error

Rebalance rebuilds the hash ring from the current node set. It is idempotent — with a consistent ring it is a no-op — but it also self-heals if the ring ever drifts out of sync with the node map, so it is safe to call after node churn.

func (*Cluster) RebalanceActive

func (c *Cluster) RebalanceActive(ctx context.Context) error

RebalanceActive rebuilds the hash ring from the set of active (non-offline) nodes only, so routing automatically skips failed nodes. It is idempotent.

func (*Cluster) RemoveNode

func (c *Cluster) RemoveNode(nodeID string) error

RemoveNode removes a node from the cluster.

func (*Cluster) SetNodeStatus

func (c *Cluster) SetNodeStatus(nodeID, status string) error

SetNodeStatus updates a node's status ("online", "degraded", "offline"). It is the thread-safe way for health monitors to reflect node availability without corrupting the shared Node state.

type ClusterConfig

type ClusterConfig struct {
	// ReplicationFactor is the number of replicas for each shard.
	ReplicationFactor int `json:"replication_factor"`

	// ConsistentHashingVirtualNodes is the number of virtual nodes for consistent hashing.
	ConsistentHashingVirtualNodes int `json:"consistent_hashing_virtual_nodes"`
}

ClusterConfig holds configuration for the distributed cluster.

func DefaultClusterConfig

func DefaultClusterConfig() *ClusterConfig

DefaultClusterConfig returns a default cluster configuration.

type ClusterDiagnostics

type ClusterDiagnostics struct {
	// Health summarizes node status and overall cluster operability.
	Health ClusterHealth `json:"health"`
	// Shards summarizes shard distribution.
	Shards ShardStats `json:"shards"`
	// GeneratedAt is when the snapshot was taken.
	GeneratedAt time.Time `json:"generated_at"`
}

ClusterDiagnostics combines cluster node health with shard distribution into a single operator-facing snapshot.

func Diagnostics

func Diagnostics(c *Cluster, sm *ShardManager) *ClusterDiagnostics

Diagnostics builds a ClusterDiagnostics snapshot from the cluster and its shard manager. A nil sm yields zero shard stats.

type ClusterHealth

type ClusterHealth struct {
	Total    int
	Online   int
	Degraded int
	Offline  int

	// Overall is "healthy", "degraded", or "down". A cluster is "down" when it
	// cannot reach a write quorum; "degraded" when operating with some nodes
	// offline; otherwise "healthy".
	Overall string
}

ClusterHealth summarizes the health of a cluster.

type Consensus

type Consensus struct {
	// contains filtered or unexported fields
}

Consensus provides deterministic leader election for writes over the cluster's online nodes. The leader is the online node with the lexicographically smallest ID, which is stable across calls and changes only when node availability changes. A monotonically increasing term is bumped whenever the leader changes so writers can detect leadership transitions.

func NewConsensus

func NewConsensus(cluster *Cluster) *Consensus

NewConsensus creates a Consensus for the cluster.

func (*Consensus) Elect

func (c *Consensus) Elect(ctx context.Context) (string, int, error)

Elect runs leader election among online nodes and updates the recorded leader and term. It returns the leader ID and the current term. When no node is online it returns ("", term).

func (*Consensus) IsLeader

func (c *Consensus) IsLeader(nodeID string) bool

IsLeader reports whether nodeID is the current leader.

func (*Consensus) Leader

func (c *Consensus) Leader() string

Leader returns the current leader ID ("" when there is no online node).

func (*Consensus) Term

func (c *Consensus) Term() int

Term returns the current leadership term.

type DistributedStore

type DistributedStore struct {
	// contains filtered or unexported fields
}

DistributedStore implements the store.Store interface for distributed storage.

func NewDistributedStore

func NewDistributedStore(config *ClusterConfig, embedder embedder.Embedder, chunkerFactory chunker.Factory, namespace string) *DistributedStore

NewDistributedStore creates a new distributed store.

func (*DistributedStore) AddNode

func (ds *DistributedStore) AddNode(node *Node) error

AddNode adds a node to the distributed cluster.

func (*DistributedStore) Close

func (ds *DistributedStore) Close() error

Close cleans up any resources held by the store.

func (*DistributedStore) Count

func (ds *DistributedStore) Count() int

Count returns the total number of chunks across all namespaces.

func (*DistributedStore) DeleteChunk

func (ds *DistributedStore) DeleteChunk(ctx context.Context, id string) error

DeleteChunk removes a chunk from the store.

func (*DistributedStore) DeleteDocument

func (ds *DistributedStore) DeleteDocument(ctx context.Context, docID string) error

DeleteDocument removes all chunks belonging to a document across every active shard. It returns core.ErrNotFound if the document has no chunks in any shard.

func (*DistributedStore) GetChunk

func (ds *DistributedStore) GetChunk(id string) (*core.Chunk, bool)

GetChunk returns a chunk by its ID.

func (*DistributedStore) GetCluster

func (ds *DistributedStore) GetCluster() *Cluster

GetCluster returns the underlying cluster.

func (*DistributedStore) GetReplicationManager

func (ds *DistributedStore) GetReplicationManager() *ReplicationManager

GetReplicationManager returns the underlying replication manager.

func (*DistributedStore) GetShardManager

func (ds *DistributedStore) GetShardManager() *ShardManager

GetShardManager returns the underlying shard manager.

func (*DistributedStore) Namespaces

func (ds *DistributedStore) Namespaces() []string

Namespaces returns the list of namespaces in the store.

func (*DistributedStore) RemoveNode

func (ds *DistributedStore) RemoveNode(nodeID string) error

RemoveNode removes a node from the distributed cluster.

func (*DistributedStore) Search

func (ds *DistributedStore) Search(ctx context.Context, query string, opts index.SearchOptions) ([]index.SearchResult, error)

Search finds the most relevant chunks for a query string (vector similarity only). The query is embedded with the store's embedder.

func (*DistributedStore) SearchHybrid

func (ds *DistributedStore) SearchHybrid(ctx context.Context, query string, opts index.SearchOptions) ([]index.SearchResult, error)

SearchHybrid performs hybrid search combining vector similarity and BM25 keyword scores. The query is embedded with the store's embedder, and both the query text and its embedding are fanned out to the shards.

func (*DistributedStore) Upload

func (ds *DistributedStore) Upload(ctx context.Context, doc *core.Document, content string) error

Upload processes a document: chunks it, embeds the chunks, and indexes them.

type HealthProbe

type HealthProbe func(ctx context.Context, node *Node) error

HealthProbe checks a single node's health, returning nil when healthy and a non-nil error otherwise.

type Node

type Node struct {
	ID      string `json:"id"`
	Address string `json:"address"`
	Status  string `json:"status"` // "online", "offline", "degraded"
}

Node represents a node in the distributed cluster.

type NodeHealth

type NodeHealth struct {
	// contains filtered or unexported fields
}

NodeHealth periodically probes cluster nodes and updates their status based on consecutive failures, letting the cluster detect node failures and react (via AutoRebalancer) while a node is down.

func NewNodeHealth

func NewNodeHealth(cluster *Cluster, cfg NodeHealthConfig) *NodeHealth

NewNodeHealth creates a NodeHealth monitor for the cluster.

func (*NodeHealth) Check

func (h *NodeHealth) Check(ctx context.Context) (int, error)

Check runs a single health-check round over all nodes, updating each node's status. It returns the number of nodes that transitioned to offline in this round.

func (*NodeHealth) Failures

func (h *NodeHealth) Failures(nodeID string) int

Failures returns the current consecutive-failure count for a node.

func (*NodeHealth) Start

func (h *NodeHealth) Start(ctx context.Context)

Start begins the background health-check loop. It is a no-op if already running. The loop stops when ctx is cancelled or Stop is called.

func (*NodeHealth) Stop

func (h *NodeHealth) Stop()

Stop halts the background loop and waits for it to finish. It is safe to call when not running.

type NodeHealthConfig

type NodeHealthConfig struct {
	// Interval between health-check rounds. Zero uses 5s.
	Interval time.Duration

	// FailureThreshold is the number of consecutive failed probes that marks a
	// node offline. Zero uses 3.
	FailureThreshold int

	// Probe is the per-node health check. Required.
	Probe HealthProbe
}

NodeHealthConfig controls NodeHealth behavior.

type ReplicationManager

type ReplicationManager struct {
	// contains filtered or unexported fields
}

ReplicationManager manages data replication across the cluster.

func NewReplicationManager

func NewReplicationManager(cluster *Cluster, shardManager *ShardManager, strategy ReplicationStrategy, replicationFactor int) *ReplicationManager

NewReplicationManager creates a new replication manager.

func (*ReplicationManager) GetReplicationStatus

func (rm *ReplicationManager) GetReplicationStatus(ctx context.Context, shardID string) (int, int, error)

GetReplicationStatus returns the replication status for a shard.

func (*ReplicationManager) ReplicateData

func (rm *ReplicationManager) ReplicateData(ctx context.Context, shardID string, data map[string]*core.Chunk) ([]ReplicationResult, error)

ReplicateData replicates data to the appropriate nodes based on the strategy.

type ReplicationResult

type ReplicationResult struct {
	ShardID   string `json:"shard_id"`
	NodeID    string `json:"node_id"`
	Success   bool   `json:"success"`
	Error     string `json:"error,omitempty"`
	ReplicaID string `json:"replica_id,omitempty"`
}

ReplicationResult represents the result of a replication operation.

type ReplicationStrategy

type ReplicationStrategy string

ReplicationStrategy defines the strategy for data replication.

const (
	// StrategyPrimaryReplica uses a primary node with replica nodes.
	StrategyPrimaryReplica ReplicationStrategy = "primary_replica"

	// StrategyQuorum uses a quorum-based approach.
	StrategyQuorum ReplicationStrategy = "quorum"

	// StrategyAllNodes replicates to all nodes.
	StrategyAllNodes ReplicationStrategy = "all_nodes"
)

type ScatterGatherConfig

type ScatterGatherConfig struct {
	// FanOut is the number of shards to query in parallel.
	FanOut int

	// MaxResultsPerShard is the maximum number of results to collect from each shard.
	MaxResultsPerShard int

	// TotalResults is the total number of results to return.
	TotalResults int

	// Timeout is the maximum time to wait for all shards to respond.
	Timeout int64 // milliseconds
}

ScatterGatherConfig holds configuration for scatter-gather search.

func DefaultScatterGatherConfig

func DefaultScatterGatherConfig() *ScatterGatherConfig

DefaultScatterGatherConfig returns a default scatter-gather configuration.

type Shard

type Shard struct {
	ID     string
	NodeID string
	Status string // "active", "inactive", "degraded"
	Data   map[string]*core.Chunk
	// contains filtered or unexported fields
}

Shard represents a shard in the distributed storage.

func NewShard

func NewShard(id, nodeID string) *Shard

NewShard creates a new shard.

func (*Shard) Search

func (s *Shard) Search(ctx context.Context, query []float32, opts index.SearchOptions) ([]index.SearchResult, error)

Search searches within this shard using vector similarity. It searches a snapshot taken under the shard's read lock (see NewShardIndex), so it is safe to call concurrently with writes to the shard.

func (*Shard) SearchHybrid

func (s *Shard) SearchHybrid(ctx context.Context, query string, queryEmb []float32, opts index.SearchOptions) ([]index.SearchResult, error)

SearchHybrid performs hybrid search within this shard, combining vector similarity (queryEmb against stored chunk embeddings) with BM25 keyword scores (query against chunk content). See ShardIndex.SearchHybrid for the score combination semantics.

type ShardIndex

type ShardIndex struct {
	// contains filtered or unexported fields
}

ShardIndex provides vector similarity and hybrid (vector + BM25) search over a snapshot of a shard's chunk map.

The snapshot is an independent copy taken under the shard's read lock at construction time (see NewShardIndex), so ShardIndex methods are safe to call concurrently with writes to the live shard and never require holding the shard's lock. Results reflect the shard's state at snapshot time, not its current state.

func NewShardIndex

func NewShardIndex(shard *Shard) *ShardIndex

NewShardIndex creates a new ShardIndex from a snapshot of the shard's current chunk map. A nil shard yields an empty index.

func (*ShardIndex) Add

func (si *ShardIndex) Add(ctx context.Context, chunk *core.Chunk) error

Add is not implemented for ShardIndex (read-only).

func (*ShardIndex) AddBatch

func (si *ShardIndex) AddBatch(ctx context.Context, chunks []*core.Chunk) error

AddBatch is not implemented for ShardIndex (read-only).

func (*ShardIndex) Count

func (si *ShardIndex) Count() int

Count returns the number of chunks in the snapshot.

func (*ShardIndex) Delete

func (si *ShardIndex) Delete(ctx context.Context, id string) error

Delete is not implemented for ShardIndex (read-only).

func (*ShardIndex) Dimension

func (si *ShardIndex) Dimension() int

Dimension returns the embedding dimension (0 if no chunks have embeddings).

func (*ShardIndex) Namespace

func (si *ShardIndex) Namespace() string

Namespace returns the shard ID the snapshot was taken from.

func (*ShardIndex) Search

func (si *ShardIndex) Search(ctx context.Context, query []float32, opts index.SearchOptions) ([]index.SearchResult, error)

Search performs vector similarity search over the shard snapshot.

func (*ShardIndex) SearchHybrid

func (si *ShardIndex) SearchHybrid(ctx context.Context, query string, queryEmb []float32, opts index.SearchOptions) ([]index.SearchResult, error)

SearchHybrid performs hybrid search over the shard snapshot, combining vector similarity (queryEmb against each chunk's stored embedding) with BM25 keyword scores (query against each chunk's content).

The combination mirrors index.HybridIndex: a custom opts.Fusion when set, otherwise a weighted sum over opts.BM25Weight (0.5/0.5 when unset). Results with a non-positive fused score are dropped, MinScore applies to the fused score, and at most TopK results are returned. Because the vector and keyword scores are independent, chunks with no vector match can still surface on a strong keyword hit (and vice versa).

The BM25 index is built per call over the snapshot — O(n) per query, which is acceptable for in-process shards; very large shards at high query rates should use an incrementally maintained keyword index (see ROADMAP).

type ShardManager

type ShardManager struct {
	// contains filtered or unexported fields
}

ShardManager manages shards across the cluster.

func NewShardManager

func NewShardManager(cluster *Cluster) *ShardManager

NewShardManager creates a new shard manager.

func (*ShardManager) Count

func (sm *ShardManager) Count() int

Count returns the total number of chunks across all active shards.

func (*ShardManager) CreateShard

func (sm *ShardManager) CreateShard(nodeID string) (*Shard, error)

CreateShard creates a new shard and assigns it to a node.

func (*ShardManager) CreateShardWithID

func (sm *ShardManager) CreateShardWithID(nodeID string, shardID string) (*Shard, error)

CreateShardWithID creates a new shard with a specific ID and assigns it to a node. An empty shardID is generated from a monotonic per-manager counter, so IDs are unique across the manager's lifetime even after deletions. An explicit shardID that is already registered returns ErrShardExists instead of silently overwriting the existing shard.

func (*ShardManager) DeleteChunk

func (sm *ShardManager) DeleteChunk(ctx context.Context, chunkID string) error

DeleteChunk deletes a chunk from the appropriate shard.

func (*ShardManager) DeleteDocument

func (sm *ShardManager) DeleteDocument(ctx context.Context, docID string) (int, error)

DeleteDocument removes all chunks whose DocumentRef matches docID from every active shard. It returns the number of chunks removed; zero means the document was not present in any shard.

func (*ShardManager) DeleteShard

func (sm *ShardManager) DeleteShard(shardID string) error

DeleteShard deletes a shard.

func (*ShardManager) GetActiveShardCount

func (sm *ShardManager) GetActiveShardCount() int

GetActiveShardCount returns the number of active shards.

func (*ShardManager) GetActiveShards

func (sm *ShardManager) GetActiveShards() []*Shard

GetActiveShards returns all active shards.

func (*ShardManager) GetAllShards

func (sm *ShardManager) GetAllShards() []*Shard

GetAllShards returns all shards regardless of status.

func (*ShardManager) GetChunk

func (sm *ShardManager) GetChunk(ctx context.Context, chunkID string) (*core.Chunk, bool)

GetChunk retrieves a chunk from the appropriate shard.

func (*ShardManager) GetShard

func (sm *ShardManager) GetShard(shardID string) (*Shard, bool)

GetShard returns a shard by its ID.

func (*ShardManager) GetShardCount

func (sm *ShardManager) GetShardCount() int

GetShardCount returns the number of shards.

func (*ShardManager) GetShardForChunk

func (sm *ShardManager) GetShardForChunk(chunkID string) *Shard

GetShardForChunk returns the shard responsible for a chunk.

func (*ShardManager) GetShardForNode

func (sm *ShardManager) GetShardForNode(nodeID string) []*Shard

GetShardForNode returns all shards for a node.

func (*ShardManager) Search

func (sm *ShardManager) Search(ctx context.Context, query []float32, opts index.SearchOptions) ([]index.SearchResult, error)

func (*ShardManager) SearchHybrid

func (sm *ShardManager) SearchHybrid(ctx context.Context, query string, queryEmb []float32, opts index.SearchOptions) ([]index.SearchResult, error)

SearchHybrid performs hybrid search combining vector similarity and BM25 keyword scores across all active shards. query is the raw query text and queryEmb its embedding; both are required for true hybrid ranking.

func (*ShardManager) StoreChunk

func (sm *ShardManager) StoreChunk(ctx context.Context, chunk *core.Chunk) error

StoreChunk stores a chunk in the appropriate shard.

type ShardStats

type ShardStats struct {
	// Total is the number of shards of any status.
	Total int `json:"total"`
	// Active is the number of active shards.
	Active int `json:"active"`
	// Inactive is the number of inactive shards.
	Inactive int `json:"inactive"`
	// Degraded is the number of degraded shards.
	Degraded int `json:"degraded"`
	// Chunks is the total number of chunks across all shards.
	Chunks int `json:"chunks"`
	// PerNode maps a node ID to its shard count.
	PerNode map[string]int `json:"per_node,omitempty"`
}

ShardStats summarizes shard distribution across the cluster.

func ShardDistribution

func ShardDistribution(sm *ShardManager) ShardStats

ShardDistribution returns statistics about the shards managed by sm. A nil sm yields zero stats.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL