etcd

package
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: Jun 29, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package etcd backs the L0 cluster ring with etcd: a node registers itself under a lease and watches the member set, so membership is live and self-healing — a crashed node's lease expires and it drops out of every other node's ring within the TTL, with no manual deregistration. The ring (cluster/ring) is rebuilt locally from the watched member set, so placement stays coordinator-free on the hot path; etcd only distributes membership.

Index

Constants

View Source
const DefaultTTL = 10 * time.Second

DefaultTTL is the lease TTL: a node absent for this long (no keepalive) is evicted from the ring. It bounds failure-detection latency.

Variables

This section is empty.

Functions

This section is empty.

Types

type Member

type Member struct {
	ID   string
	Zone string
	Addr string
}

Member is a cluster node's advertised identity: its ring ID, failure-domain Zone, and the Addr its peers reach it on (used by the replication transport later).

type Membership

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

Membership is a live, etcd-backed view of the cluster. It keeps this node registered (under a keep-alive'd lease) and watches the member set, exposing the current ring.Ring. Safe for concurrent use; Membership.Ring and Membership.Members are lock-free / cheap.

func Join

func Join(ctx context.Context, client *clientv3.Client, root string, self Member, ttl time.Duration) (*Membership, error)

Join registers self in the cluster rooted at root (an etcd key prefix) under a lease of ttl (≤ 0 ⇒ DefaultTTL), snapshots the current members, and starts watching for changes. The returned Membership must be closed to deregister.

func (*Membership) AddrOf

func (m *Membership) AddrOf(id string) string

AddrOf returns the network address of the member with the given ring node ID, or "" if the member is unknown. It is the resolver the cluster write path uses to turn ring owners into transport targets.

func (*Membership) Close

func (m *Membership) Close(ctx context.Context) error

Close stops watching, revokes this node's lease (so its peers drop it immediately rather than after the TTL), and waits for the background goroutines to exit. The revoke is bounded by a derived timeout.

func (*Membership) LeaseID

func (m *Membership) LeaseID() clientv3.LeaseID

LeaseID is this node's membership lease. Ownership claims bind to it so they auto-release when the node dies (the basis for the rebalance handoff).

func (*Membership) Members

func (m *Membership) Members() []Member

Members returns the current members, sorted by ID.

func (*Membership) Ring

func (m *Membership) Ring() *ring.Ring

Ring returns the current ring (lock-free). It is replaced atomically as membership changes.

func (*Membership) SetLogger added in v0.5.0

func (m *Membership) SetLogger(l *zap.Logger)

SetLogger attaches a logger that records member joins and leaves (Info on each change). It must be called before Join starts the watch loop in practice it is set immediately after Join. nil disables logging. Safe only before the watch observes its first event.

type Ownership

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

Ownership coordinates exclusive **compaction ownership** of shards across the cluster via etcd, so a shard (a tenant) is flushed/merged by exactly one node at a time — the rebalance executor. A node claims a shard with a CAS write keyed by the shard and bound to its membership lease; the claim auto-releases if the node dies, so a new primary can take over without manual handoff. Placement still comes from the ring; etcd only arbitrates the claim during the brief windows where nodes disagree on the ring (watch-propagation lag) or a node has failed.

Reconcile is **event-driven and minimal-move**: it tracks the claims this node currently holds and, on each pass, only issues etcd writes for the shards whose ring-primary actually changed since the last pass (plus retrying any wanted-but-uncontended claim). In steady state — an unchanged ring with no new tenants — it makes no etcd round-trips at all, instead of one acquire/release per shard every tick. When the ring does change it records the rebalance.Plan it enacted (see Ownership.LastPlan) for observability/preview.

func NewOwnership

func NewOwnership(client *clientv3.Client, root, id string, leaseID clientv3.LeaseID) *Ownership

NewOwnership returns an ownership coordinator for node id, claiming under root with the node's membership lease (see Membership.LeaseID).

func (*Ownership) Acquire

func (o *Ownership) Acquire(ctx context.Context, shard string) (bool, error)

Acquire tries to claim shard for this node. It returns true if the claim is now held by this node (newly acquired or already ours), false if another live node holds it. The claim is a CAS: create the key only if absent; otherwise it belongs to whoever already created it.

func (*Ownership) LastPlan added in v0.10.0

func (o *Ownership) LastPlan() []rebalance.Reassignment

LastPlan returns the primary handoffs enacted at the most recent ring change (empty if the ring has not changed since open). It is informational — a preview of what the last rebalance moved — for an operator dashboard.

func (*Ownership) Owned added in v0.10.0

func (o *Ownership) Owned() []string

Owned returns a sorted snapshot of the shards this node currently holds a compaction claim on.

func (*Ownership) Reconcile

func (o *Ownership) Reconcile(ctx context.Context, r *ring.Ring, shards []string) ([]string, error)

Reconcile makes this node's claims match the ring: it acquires every shard this node is the ring-primary of and releases the rest. It returns the shards this node now owns — the set it should flush and compact. Idempotent, so it is safe to call on every membership change and on a timer.

The work is minimal: ring-primary lookups are pure in-memory HRW hashing (no etcd), and an etcd write is issued only when a claim must change — a wanted shard not yet held is acquired (retried every pass, which is what lets a stale claim's release converge even under an unchanged ring), and a held shard no longer wanted is released. Steady state issues no etcd writes. On a ring change the enacted primary handoffs are recorded in Ownership.LastPlan.

func (*Ownership) Release

func (o *Ownership) Release(ctx context.Context, shard string) error

Release relinquishes shard, but only if this node still holds the claim (a guarded delete, so it never deletes another node's claim).

Jump to

Keyboard shortcuts

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