peersync

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Overview

Package peersync pulls journal state from peer nodes over the node transport and applies it locally (data sync reconciler).

This is distinct from the workload reconciler (src/reconciler/), which reads local journal events and drives container lifecycle. peersync feeds the journal; the workload reconciler consumes it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyEvents

func ApplyEvents(
	ctx context.Context,
	j journal.Journal,
	views []journalview.View,
	byID EventByID,
	events []journal.Event,
) (applied int, err error)

ApplyEvents appends peer events into the local journal and views, skipping any event whose id is already present (idempotent under pull replay). Returns how many events were newly applied.

func RunPullLoop

func RunPullLoop(
	ctx context.Context,
	logger *zap.Logger,
	selfID uuid.UUID,
	members MemberSource,
	syncer PeerSync,
	j journal.Journal,
	views []journalview.View,
	byID EventByID,
	cursorStore CursorStore,
)

RunPullLoop is the peer journal reconciliation loop.

It does not push our events. Each tick it discovers who is alive via memberlist and pulls their journals over the Noise transport, up to maxPagesPerTick pages per peer while each page comes back full:

  • On meet: peer is newly seen or has become alive again → Sync once now.
  • Periodic: every defaultPullInterval, Sync all still-alive peers (skipped if already synced this tick for a meet).

After each successful Sync, events are applied idempotently (skip known ids) into the local journal and views. The cursor advances only if apply succeeds, in memory and in the store together.

Cursors persist in bbolt through the store, so a restart resumes mid-history instead of re-pulling from event zero. A store load failure starts from empty cursors instead; idempotent apply discards the overlap. A nil store keeps RAM-only behavior and exists for unit tests.

Individual Sync/apply failures are soft-fail (log and continue). The loop blocks until ctx is cancelled.

Types

type CursorStore

type CursorStore interface {
	// contains filtered or unexported methods
}

CursorStore persists per-peer sync cursors so a restart resumes mid-history instead of re-pulling from event zero. The bbolt implementation below is the production one; tests and future segment-scoped stores supply their own. A nil store (not an implementation) keeps RAM-only behavior.

func NewCursorStore

func NewCursorStore(kv *kvstore.KVStore) CursorStore

NewCursorStore creates a cursor store backed by the given KVStore.

type EventByID

type EventByID interface {
	Get(ctx context.Context, id uuid.UUID) (*journal.Event, error)
}

EventByID can check whether this node already stored an event id. That is all apply needs for dedup. *journalview.EventsByID implements it (Get returns nil, nil when the id is unknown).

type MemberSource

type MemberSource interface {
	Members() ([]peerdiscovery.Node, error)
}

MemberSource lists current membership (memberlist). *peerdiscovery.MemberService implements it.

type PeerSync

type PeerSync interface {
	Sync(ctx context.Context, peer netip.AddrPort, expect transport.Peer, req transport.SyncRequest) (transport.SyncResponse, error)
}

PeerSync pulls journal state from a peer over the node transport. The concrete client lives in transport.Client (Noise IK unary).

Jump to

Keyboard shortcuts

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