index

package
v0.0.0-...-cae741c Latest Latest
Warning

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

Go to latest
Published: Jul 27, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package index provides a persistent file index used for offline deletion detection and last-writer-wins conflict resolution.

Index

Constants

View Source
const DefaultTombstoneTTL = 30 * 24 * time.Hour

DefaultTombstoneTTL is how long deletion tombstones are retained before GC.

View Source
const Version = 1

Version is the on-disk schema version.

Variables

This section is empty.

Functions

func Wins

func Wins(local, remote Entry) bool

Wins reports whether remote should replace local under last-writer-wins.

Ordering:

  1. Higher UpdatedAt wins.
  2. On equal UpdatedAt, prefer remote only when the entries differ, using a stable total order: Deleted (true > false), then Hash (string compare), then Mode, then ModTime (later mtime wins). Preferring remote always would flip-flop under concurrent mutual sync; a stable order guarantees both sides converge to the same winner.

Entries that differ only in ModTime are not treated as identical, so a touch-only peer update still participates in LWW (via UpdatedAt first, or the ModTime tie-break when clocks match).

Types

type Entry

type Entry struct {
	// Path is relative to the sync root, using forward slashes.
	Path string `json:"path"`
	// Size is the file size in bytes (0 for tombstones).
	Size int64 `json:"size"`
	// ModTime is the file's modification time as observed locally.
	ModTime time.Time `json:"mod_time"`
	// Mode is the file permission bits.
	Mode os.FileMode `json:"mode"`
	// Hash is the hex-encoded SHA-256 of the file contents (empty for tombstones).
	Hash string `json:"hash,omitempty"`
	// Deleted is true when this entry is a deletion tombstone.
	Deleted bool `json:"deleted,omitempty"`
	// DeletedAt is when the deletion was recorded (zero if not deleted).
	DeletedAt time.Time `json:"deleted_at"`
	// UpdatedAt is when this entry last changed; used for LWW among peers.
	// Callers should keep wall clocks roughly in sync (NTP); ties use a stable
	// total order (see Wins).
	UpdatedAt time.Time `json:"updated_at"`
}

Entry describes a known file (or a deletion tombstone).

func EntryFromManifest

func EntryFromManifest(m ManifestEntry) Entry

EntryFromManifest converts a ManifestEntry to Entry (identity; kept for call sites).

type Index

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

Index is a thread-safe map of relative path → Entry, backed by a JSON file.

Locking: Index uses its own RWMutex for all map access. The daemon holds a separate syncMu around multi-step reconcile/apply so scan→apply and pull→commit stay atomic relative to each other. Holding the daemon lock does not replace Index.mu; methods here still lock. Callers that need a frozen multi-step view relative to disk must serialize at a higher layer (daemon syncMu) in addition to relying on these internal locks.

func Load

func Load(path string) (*Index, error)

Load reads an index from path. Missing files yield an empty index bound to path.

func New

func New() *Index

New returns an empty in-memory index.

func (*Index) All

func (idx *Index) All() map[string]Entry

All returns a snapshot of all entries.

func (*Index) Clone

func (idx *Index) Clone() *Index

Clone returns a deep copy of the index (no path binding).

func (*Index) Delete

func (idx *Index) Delete(path string)

Delete removes an entry entirely (not a tombstone). Prefer MarkDeleted.

func (*Index) GCTombstones

func (idx *Index) GCTombstones(now time.Time, ttl time.Duration) int

GCTombstones removes deleted entries whose DeletedAt is older than ttl (relative to now). Returns the number of entries removed. Tombstones with zero DeletedAt use UpdatedAt as the age basis.

Resurrection risk: once a tombstone is dropped, a lagging peer that still has a live file for that path can re-introduce it as a plain add. Operators should keep the TTL longer than the maximum expected peer offline window, or use -peers with all members regularly online. Peer-ack GC is not implemented.

func (*Index) Get

func (idx *Index) Get(path string) (Entry, bool)

Get returns a copy of the entry for path, if any.

func (*Index) Len

func (idx *Index) Len() int

Len returns the number of entries including tombstones.

func (*Index) Live

func (idx *Index) Live() map[string]Entry

Live returns non-deleted entries only.

func (*Index) Manifest

func (idx *Index) Manifest() []ManifestEntry

Manifest returns all entries as a list suitable for peer exchange.

func (*Index) MarkDeleted

func (idx *Index) MarkDeleted(path string, at time.Time) Entry

MarkDeleted records a tombstone for path.

func (*Index) Path

func (idx *Index) Path() string

Path returns the on-disk path for this index (may be empty).

func (*Index) Save

func (idx *Index) Save() error

Save writes the index atomically (temp file + rename). The mutex is held only while snapshotting; disk I/O runs unlocked.

func (*Index) Set

func (idx *Index) Set(e Entry) (prev Entry, had bool)

Set stores or replaces an entry and returns the previous value if any.

func (*Index) SetIfWins

func (idx *Index) SetIfWins(remote Entry) bool

SetIfWins stores remote only if it wins LWW against the current entry (or the path is unknown). Returns whether the index was updated.

func (*Index) SetPath

func (idx *Index) SetPath(path string)

SetPath binds the index to an on-disk location for Save.

type ManifestEntry

type ManifestEntry = Entry

ManifestEntry is the wire/peer view of an index entry. It is a type alias of Entry so JSON field names stay identical on the wire.

Jump to

Keyboard shortcuts

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