memory

package
v1.0.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: 22 Imported by: 0

Documentation

Overview

Package memory provides the OniWorks distributed in-memory database. It is the state layer of the framework: sessions, presence, rate limits, pub/sub events, and realtime state. It is NOT a replacement for PostgreSQL.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ClockValue

type ClockValue struct {
	NodeID string
	TS     uint64
	Vector map[string]uint64
}

ClockValue is an immutable snapshot of a vector clock at a point in time.

Fields are EXPORTED so the value survives gob encoding across the gossip transport — with unexported fields the vector was silently dropped on the wire, collapsing last-write-wins to "always overwrite".

func (ClockValue) After

func (cv ClockValue) After(other ClockValue) bool

After reports whether cv should win a last-write-wins conflict against other.

It first does a proper vector-dominance comparison across the union of all node IDs: if cv causally dominates other (cv[n] >= other[n] for every n and strictly greater for at least one), cv is newer. If neither dominates the writes are concurrent, and we break the tie deterministically (by TS, then NodeID) so every node converges on the same winner.

func (ClockValue) Equal

func (cv ClockValue) Equal(other ClockValue) bool

Equal reports whether two clock values are concurrent (neither is after the other).

type Options

type Options struct {
	// NodeID uniquely identifies this node. Auto-generated if empty.
	NodeID string

	// BindAddr is the TCP address this node listens on for gossip (e.g. "0.0.0.0:7946").
	// Leave empty to run in single-node mode (no gossip, no cross-node sync).
	BindAddr string

	// Peers is the list of known peer addresses for gossip bootstrapping.
	// Example: []string{"10.0.0.2:7946", "10.0.0.3:7946"}
	Peers []string

	// GossipSecret is a pre-shared secret used to authenticate peer connections.
	// Every node in a cluster must share the same value. If empty, gossip runs
	// UNAUTHENTICATED (any host that can reach BindAddr can read and inject data)
	// and a loud warning is logged — set this for any non-trusted network.
	GossipSecret string

	// Persist enables snapshot-to-disk on shutdown.
	Persist bool
	// SnapshotPath is the file path for the snapshot (default: "storage/memory.snap").
	SnapshotPath string

	// GracefulSave saves snapshot on SIGTERM/SIGINT.
	GracefulSave bool

	// RedisURL enables the Redis sync adapter instead of the built-in gossip.
	// When set, gossip is disabled and Redis pub/sub is used for cross-node sync.
	// Example: "redis://localhost:6379"
	RedisURL string

	// MaxKeys caps the number of stored keys (0 = unlimited).
	MaxKeys int

	// EvictInterval is how often the TTL eviction loop runs (default: 30s).
	EvictInterval time.Duration
}

Options configures a Store instance.

type PubSub

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

PubSub is a thread-safe, fan-out publish/subscribe engine. Topics support wildcard matching: "user.*" matches "user.login", "user.42.status".

type Store

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

Store is the OniWorks distributed in-memory database. It provides KV storage, pub/sub, TTL eviction, snapshot persistence, and cross-node sync via TCP gossip (or Redis as optional adapter).

func New

func New(opts Options) *Store

New creates and starts a Store.

func (*Store) CompareAndSwap

func (s *Store) CompareAndSwap(key string, expected, newValue any, ttl time.Duration) bool

CompareAndSwap atomically updates key to newValue only if it currently equals expected. Returns true if the swap occurred.

func (*Store) Count

func (s *Store) Count(pattern string) int

Count returns the number of non-expired keys matching a pattern.

func (*Store) Decr

func (s *Store) Decr(key string) int64

Decr atomically decrements a counter key by 1.

func (*Store) Delete

func (s *Store) Delete(key string)

Delete removes a key. The delete is stamped with a fresh clock and recorded as a tombstone so a reordered (causally older) remote set cannot resurrect the key here or on peers.

func (*Store) Expire

func (s *Store) Expire(key string, ttl time.Duration) bool

Expire updates the TTL of an existing key.

func (*Store) Flush

func (s *Store) Flush()

Flush removes all keys. Use only in development/tests.

func (*Store) Get

func (s *Store) Get(key string) (any, bool)

Get retrieves a value. Returns (nil, false) if absent or expired.

func (*Store) GetInt64

func (s *Store) GetInt64(key string) (int64, bool)

GetInt64 retrieves an int64 value.

func (*Store) GetString

func (s *Store) GetString(key string) (string, bool)

GetString retrieves a string value. Returns ("", false) if absent or wrong type.

func (*Store) Has

func (s *Store) Has(key string) bool

Has reports whether a key exists and is not expired.

func (*Store) Incr

func (s *Store) Incr(key string) int64

Incr atomically increments a counter key by 1. Creates with value 1 if absent. Returns the new value.

func (*Store) IncrBy

func (s *Store) IncrBy(key string, n int64) int64

IncrBy atomically increments a counter key by n. Returns the new value.

func (*Store) Keys

func (s *Store) Keys(pattern string) []string

Keys returns all non-expired keys matching the given glob prefix pattern. Use "*" to match all keys. Use "session:*" to match all session keys.

func (*Store) Publish

func (s *Store) Publish(topic string, payload any)

Publish broadcasts payload to all subscribers of topic. Cross-node: the gossip/Redis transport propagates this to peer nodes.

func (*Store) Set

func (s *Store) Set(key string, value any, ttl time.Duration)

Set stores key with value and an optional TTL (0 = no expiry).

If Options.MaxKeys is set, a Set that would create a NEW key while the store is at capacity is rejected (updates to existing keys always succeed). The rejection is logged; callers that need a guaranteed write should provision a larger cap. A zero MaxKeys means unlimited.

func (*Store) Shutdown

func (s *Store) Shutdown() error

Shutdown stops the store, saves snapshot if configured, and closes gossip connections.

func (*Store) Subscribe

func (s *Store) Subscribe(topic string, handler func(topic string, payload any)) func()

Subscribe registers handler to receive messages on topic. Topic can include wildcards: "user.*" matches "user.login", "user.logout". Returns a cancel function that unsubscribes the handler.

type VectorClock

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

VectorClock implements a simple Lamport-style vector clock for last-write-wins conflict resolution across nodes. Each node maintains its own counter and increments it on every write.

func NewVectorClock

func NewVectorClock(nodeID string) *VectorClock

NewVectorClock creates a VectorClock for the given node ID.

func (*VectorClock) Merge

func (vc *VectorClock) Merge(received ClockValue)

Merge updates this clock with a received clock value. Uses max(local[node], received[node]) for each node.

func (*VectorClock) Tick

func (vc *VectorClock) Tick() ClockValue

Tick increments this node's local time and returns a new ClockValue. Call before every local write.

The counter increment happens UNDER the lock: if it were fetched outside, two concurrent Ticks could apply their map writes in the opposite order of their counter values, regressing clocks[nodeID] and snapshotting a vector older than an already-issued ClockValue.

Jump to

Keyboard shortcuts

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