readsync

package
v0.4.3 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package readsync moves read state between an account's devices: it publishes each object's seen-heads frontier to the TECH space's key-value store and merges other devices' published frontiers into the local per-space readstate engines. The tech space keeps read positions private (owner-only ACL) — nothing here is visible to other members of the target space.

One KV key per tracked object, `read/<spaceId>/<objectId>`; the store keys rows per (key, peerId), so every device owns its row (LWW on the writer timestamp) and the logical frontier is the union of all rows, folded in by the engine's idempotent MergeHeads.

A merge NEVER loads the object: it runs against the readstate rows (plus point lookups into any-sync's change storage for gap traversal), serialized per object by keyed mutexes, in its own write transaction. The live hook (App.OnKeyValues) hands work to a single worker goroutine; durability comes from Reconcile, which replays every published frontier for a space through the same idempotent merge (one state read per already-merged object).

Index

Constants

This section is empty.

Variables

View Source
var ErrUntracked = errors.New("readsync: space read state not tracked")

ErrUntracked is returned by marks when EngineFor yields no engine: the space tracks no datasets, or the liveness gate dropped it (deleted / pending / unknown at mark time). spaceimpl maps it to the public space.ErrSpaceNotTracked.

Functions

This section is empty.

Types

type EngineFor

type EngineFor func(spaceId string) *readstate.Engine

EngineFor routes a merge to the target space's readstate engine. nil = space unknown here or tracks nothing (the value is dropped; Reconcile picks it up if the space registers tracking later).

type KVStore

type KVStore func(ctx context.Context) (keyvaluestorage.Storage, error)

KVStore returns the tech space's default key-value store.

type Service

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

func New

func New(engineFor EngineFor, kvStore KVStore, selfPeerId string) *Service

func (*Service) Close

func (s *Service) Close()

func (*Service) MarkRead

func (s *Service) MarkRead(ctx context.Context, spaceId, objectId string, changeIds []string) (readstate.MarkResult, error)

MarkRead covers the given changes (and ancestry) locally, then publishes the advanced frontier. The local commit is the durable step; publishing writes the device's KV row, which any-sync persists locally and syncs when connectivity allows.

func (*Service) MarkReadUpTo

func (s *Service) MarkReadUpTo(ctx context.Context, spaceId, objectId, upTo string) (readstate.MarkResult, error)

MarkReadUpTo covers everything at or below upTo in local display order ("" = all) in bounded per-chunk transactions, then publishes the final frontier once.

func (*Service) OnKeyValues

func (s *Service) OnKeyValues(decryptor keyvaluestorage.Decryptor, kvs []innerstorage.KeyValue)

OnKeyValues is the live hook for the tech space's applied KV writes (wire via App.OnKeyValues). Runs on any-sync's apply path — it only decodes and enqueues; merging happens on the service worker.

func (*Service) PruneSpace

func (s *Service) PruneSpace(ctx context.Context, spaceId string) error

PruneSpace publishes a deletion watermark for the space's read/ keys when any visible frontier row remains — the cleanup for removed spaces (SYN-104). Joining re-seeds read state, so removed spaces' frontiers have no restore value; the watermark physically drops them on every replica. Idempotent and self-clearing: once applied the prefix reads empty and further calls are no-ops, and a row published later by a device that had not yet seen the removal makes the next reconcile pass re-issue the watermark.

func (*Service) PublishedFrontiers

func (s *Service) PublishedFrontiers(ctx context.Context, spaceId, objectId string) ([][]string, error)

PublishedFrontiers returns every device's published frontier for the object — own rows included (a rebuilt device's previous publishes are valid coverage). nil when nothing was published. Used by the first-load seed to prefer the account's real read state over first-sight seeding.

func (*Service) Reconcile

func (s *Service) Reconcile(ctx context.Context, spaceId string) error

Reconcile replays every frontier published for spaceId through the idempotent merge — the durable complement to the best-effort live hook. Call on boot after the space's store is up. Already-merged frontiers cost one state read each (engine fast path).

Own-device rows are merged too: after a local DB rebuild our own published frontier is the record of this device's reads. And when the local frontier has advanced past our published row (a publish that failed after its mark committed, or marks made before a rebuild), Reconcile republishes — so boot is the healing pass for both directions of divergence.

func (*Service) ReconcileAll

func (s *Service) ReconcileAll(ctx context.Context) error

ReconcileAll is the boot form: ONE pass over the tech-space store covering every space (keys route by their embedded spaceId; spaces without a tracked engine are skipped), instead of a full store scan per space.

Jump to

Keyboard shortcuts

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