hyparview

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package hyparview implements HyParView, the partial-view membership protocol of Leitão, Pereira and Rodrigues (2007). It maintains a small, symmetric, session-backed active view and a larger unconnected passive view, and publishes the protocols/membership contract (NeighborUp/NeighborDown notifications + a GetView reply) so any dissemination protocol written against that contract — Plumtree, the eager-push gossip in cmd/gossip — can run on top of it unchanged.

Mapping HyParView onto protorun sessions

The active view is backed one-to-one by protorun sessions: a peer is in the active view iff we hold a live session with it and an application-level handshake (Join or Neighbor/NeighborReply) has admitted it. protorun sessions are symmetric — Connect yields OnSessionConnected on both ends — which matches HyParView's symmetric active view, but a raw session coming up is only the *transport*; the Join/Neighbor control messages decide membership. This is why an inbound session with no accompanying control message is left dormant.

Failure detection

The session layer is the failure detector — there are no extra heartbeats. A dropped active-view session surfaces as OnSessionDisconnected (or OnSessionGivenUp for a retryable dial that exhausted its budget); either way the peer leaves the active view, NeighborDown is published, and the passive view is promoted to refill.

Shuffle transport (resolves the roadmap open question)

The periodic shuffle is routed entirely over active-view links and never opens a transient session to a passive peer. The Shuffle request is a TTL random walk over active views exactly as in the paper; the twist is the reply: the walk records its path (each forwarder appends itself), and the accepting node returns its ShuffleReply by retracing that path hop-by-hop back to the origin. Every hop — request and reply — is an existing active-view session, so no change to the session layer is needed. A passive peer is contacted only during promotion, which legitimately opens a session because the peer is *becoming* an active-view member. This is option (a) from the roadmap; it needs no framework changes, which is why it is preferred over transient sessions to passive peers.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Contacts are the bootstrap nodes this node JOINs on Init. An empty
	// contact list makes this node a pure rendezvous point that others
	// join (the first node in a cluster has no contacts).
	Contacts []transport.Host

	// ActiveSize is the target active-view size (the paper's log(n)+c).
	// Active-view peers are session-backed and symmetric. Default 5.
	ActiveSize int

	// PassiveSize is the maximum passive-view size — the larger,
	// unconnected sample the shuffle keeps fresh. Default 30.
	PassiveSize int

	// ARWL (Active Random Walk Length) is the initial TTL of a
	// ForwardJoin and of a Shuffle walk. Default 6.
	ARWL int

	// PRWL (Passive Random Walk Length) is the TTL at which a ForwardJoin
	// also files the joining node into the passive view. Must be < ARWL.
	// Default 3.
	PRWL int

	// ShuffleActive (ka) is how many active-view peers a shuffle offers.
	// Default 3.
	ShuffleActive int

	// ShufflePassive (kp) is how many passive-view peers a shuffle
	// offers. Default 4.
	ShufflePassive int

	// ShuffleInterval is how often a node initiates a shuffle. Default
	// 10s.
	ShuffleInterval time.Duration

	// JoinInterval is how often a node with an empty active view
	// re-attempts JOIN to its contacts (bootstrap and full-isolation
	// recovery). Default 5s.
	JoinInterval time.Duration

	// NeighborTimeout bounds how long a pending Neighbor request waits
	// for acceptance before the candidate is abandoned (covers a silent
	// connect failure or a slow/rejecting peer). Default 3s.
	NeighborTimeout time.Duration
}

Config tunes a HyParView instance. The zero value is usable: New fills every unset field with the paper's defaults (scaled for a small cluster). Sizes and walk lengths follow Leitão, Pereira and Rodrigues, "HyParView: A Membership Protocol for Reliable Gossip-Based Broadcast" (2007); the periods are protorun defaults, tuned so the sim tests converge quickly on the virtual clock.

type DebugState

type DebugState struct{ protorun.BaseRequest }

DebugState is a HyParView-specific introspection request that returns both views. It goes beyond the generic membership contract (which exposes only the active view) to surface the passive view for tests and operational tooling. Being IPC, reading a protocol's private views from off the event loop stays on the framework's supported path (a runtime-routed request), rather than a data race on protocol state.

type DebugStateReply

type DebugStateReply struct {
	protorun.BaseReply
	Active  []transport.Host
	Passive []transport.Host
}

DebugStateReply carries snapshots of both views. Both slices are fresh and owned by the caller.

type Disconnect

type Disconnect struct{ protorun.BaseMessage }

Disconnect is a graceful "I am removing you from my active view" notice. The receiver moves the sender from its active view to its passive view (as opposed to a detected session failure, after which the peer is presumed dead and NOT filed into passive).

func (Disconnect) MarshalWire

func (Disconnect) MarshalWire() ([]byte, error)

func (*Disconnect) UnmarshalWire

func (*Disconnect) UnmarshalWire([]byte) error

func (Disconnect) WireName

func (Disconnect) WireName() string

type ForwardJoin

type ForwardJoin struct {
	protorun.BaseMessage
	NewNode transport.Host
	TTL     uint32
}

ForwardJoin propagates a join outward as a random walk over active views. NewNode is the node that joined; TTL is the remaining walk length. At TTL 0 (or a node with an otherwise-empty active view) the walk terminates and the receiver adds NewNode to its active view.

func (*ForwardJoin) MarshalWire

func (m *ForwardJoin) MarshalWire() ([]byte, error)

func (*ForwardJoin) UnmarshalWire

func (m *ForwardJoin) UnmarshalWire(data []byte) error

func (ForwardJoin) WireName

func (ForwardJoin) WireName() string

type Join

type Join struct{ protorun.BaseMessage }

Join is sent by a node bootstrapping into the overlay, to a contact, immediately after the session to that contact comes up. The contact accepts unconditionally (dropping a random active peer if it must make room) and disseminates a ForwardJoin random walk.

func (Join) MarshalWire

func (Join) MarshalWire() ([]byte, error)

func (*Join) UnmarshalWire

func (*Join) UnmarshalWire([]byte) error

func (Join) WireName

func (Join) WireName() string

type Neighbor

type Neighbor struct {
	protorun.BaseMessage
	Priority bool
}

Neighbor asks the receiver to add the sender to its active view. Priority is set when the sender's own active view is empty (a node with no neighbours must be admitted), in which case the receiver accepts even if it has to evict an existing active peer. A low-priority request is rejected when the receiver's active view is full.

func (*Neighbor) MarshalWire

func (m *Neighbor) MarshalWire() ([]byte, error)

func (*Neighbor) UnmarshalWire

func (m *Neighbor) UnmarshalWire(data []byte) error

func (Neighbor) WireName

func (Neighbor) WireName() string

type NeighborReply

type NeighborReply struct {
	protorun.BaseMessage
	Accepted bool
}

NeighborReply answers a Neighbor request. Accepted false means the receiver's active view was full and the request was low priority; the requester drops the session and files the peer back into its passive view.

func (*NeighborReply) MarshalWire

func (m *NeighborReply) MarshalWire() ([]byte, error)

func (*NeighborReply) UnmarshalWire

func (m *NeighborReply) UnmarshalWire(data []byte) error

func (NeighborReply) WireName

func (NeighborReply) WireName() string

type Protocol

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

Protocol is a HyParView instance. Construct with New and Register (or RegisterFactory) it with a runtime. All state is owned by the event loop; every field below is touched only inside handlers, timer callbacks, and session-event callbacks.

func New

func New(self transport.Host, cfg Config) *Protocol

New returns a HyParView protocol configured by cfg. The zero Config is valid — see Config for the defaults New fills in.

func (*Protocol) Init

func (p *Protocol) Init(ctx protorun.ProtocolContext)

func (*Protocol) OnSessionConnected

func (p *Protocol) OnSessionConnected(host transport.Host)

func (*Protocol) OnSessionDisconnected

func (p *Protocol) OnSessionDisconnected(host transport.Host)

func (*Protocol) OnSessionGivenUp

func (p *Protocol) OnSessionGivenUp(host transport.Host, _ int)

OnSessionGivenUp treats an exhausted retryable dial the same as a disconnect: the peer is gone.

func (*Protocol) Start

func (p *Protocol) Start(ctx protorun.ProtocolContext)

type Shuffle

type Shuffle struct {
	protorun.BaseMessage
	Origin  transport.Host
	TTL     uint32
	Active  []transport.Host
	Passive []transport.Host
	Path    []transport.Host
}

Shuffle is the periodic passive-view exchange, propagated as a TTL random walk over active views (never over passive peers — see the shuffle note in protocol.go). Origin is the node that initiated the shuffle; Active/Passive are the sample it offers; Path records the forwarders the walk has visited (Origin first) so the ShuffleReply can retrace it home over the same active links.

func (*Shuffle) MarshalWire

func (m *Shuffle) MarshalWire() ([]byte, error)

func (*Shuffle) UnmarshalWire

func (m *Shuffle) UnmarshalWire(data []byte) error

func (Shuffle) WireName

func (Shuffle) WireName() string

type ShuffleReply

type ShuffleReply struct {
	protorun.BaseMessage
	Nodes []transport.Host
	Route []transport.Host
}

ShuffleReply carries a sample of the accepting node's passive view back to the shuffle's origin. Route is the remaining active-link path to the origin (origin first); each hop forwards the reply to the last element and trims it, until the origin recognises itself at the head.

func (*ShuffleReply) MarshalWire

func (m *ShuffleReply) MarshalWire() ([]byte, error)

func (*ShuffleReply) UnmarshalWire

func (m *ShuffleReply) UnmarshalWire(data []byte) error

func (ShuffleReply) WireName

func (ShuffleReply) WireName() string

Jump to

Keyboard shortcuts

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