Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // NewReplicator binds the DB at key to its store slot. NewReplicator = replica.NewReplicator // WithEncryption seals every pushed snapshot with the org's per-org key. WithEncryption = replica.WithEncryption // Owner returns the single writer for orgID (HRW), fail-closed on empty. Owner = replica.Owner // IsOwner reports whether selfID owns the writer for orgID. IsOwner = replica.IsOwner // Replicas returns the owner then ordered failover successors. Replicas = replica.Replicas // DBPath is the canonical object-store location of an org's SQLite DB. DBPath = replica.DBPath )
Functions ¶
func ConstantTimeEqual ¶ added in v1.786.12
ConstantTimeEqual compares two secrets without leaking timing — exported for callers verifying wrapped-key material.
Types ¶
type Cipher ¶ added in v1.786.12
type Cipher struct {
// contains filtered or unexported fields
}
Cipher seals each org's SQLite snapshot at rest with a distinct 256-bit key, so the object in SeaweedFS is ciphertext and orgs are cryptographically isolated — a leaked file is useless without the KMS master key.
Envelope model: the KMS master (KMSMasterKeyRef, 32 bytes) never leaves the process. A per-org key is DERIVED from it via HKDF(master, label, orgID); it is held only in-memory, never stored, never on the wire. Rotating the master re-keys every org. AES-256-GCM provides confidentiality + integrity; the orgID is bound in as AAD so a sealed blob cannot be replayed under a different org.
The GCM nonce is DERIVED from (key, plaintext) — HMAC(key,"nonce"||plaintext), so identical plaintext seals to identical ciphertext (content-addressable, keeps the Replicator's version-skip working) while distinct plaintexts get distinct nonces (GCM safety: the same (key,nonce) never covers two different messages).
func NewCipher ¶ added in v1.786.12
NewCipher builds a Cipher from the KMS master key. master must be exactly 32 bytes (derive it from KMSMasterKeyRef, e.g. SHA-256 of the raw secret).
type Membership ¶
type Membership struct {
// contains filtered or unexported fields
}
Membership caches the latest replica snapshot and refreshes it from a Source on an interval. Reads are lock-free via an atomic snapshot pointer, so the per-request AmOwner hot-path never blocks on the refresher.
func NewMembership ¶
func NewMembership(selfID string, src Source, interval time.Duration) *Membership
NewMembership builds a Membership over src. selfID is this replica's stable id (see Member.ID). interval<=0 defaults to 5s.
func (*Membership) AmOwner ¶
func (m *Membership) AmOwner(orgID string) bool
AmOwner reports whether THIS replica owns orgID's writer right now — the per-write hot-path check. Lock-free.
func (*Membership) Members ¶
func (m *Membership) Members() []Member
Members returns the current membership snapshot (never nil; may be empty).
func (*Membership) OwnerOf ¶
func (m *Membership) OwnerOf(orgID string) (Member, bool)
OwnerOf resolves the writer-owner replica for orgID under the live set.
func (*Membership) Start ¶
func (m *Membership) Start(ctx context.Context) error
Start does an initial synchronous refresh (so Members() is populated before the first request) then refreshes on the interval until Stop or ctx cancel. Returns the initial refresh error, if any; callers may serve with a stale or self-only set regardless.
type Replicator ¶
type Replicator = replica.Replicator
Replicator binds one per-org SQLite to its object-store slot.
type Source ¶
Source yields the current live replica set. It is the ONE thing in the horizontally-scaled cloud that needs a peer view — everything else is a pure function of (org, members). Any discovery mechanism plugs in as a Source without touching the ownership core: a static list (dev), a K8s Endpoints poll (prod), or a zapd gossip view.
func StaticSource ¶
StaticSource yields a fixed set — single-node / local dev. With no explicit members it reads CLOUD_REPLICAS ("id@addr,id2@addr2", or bare "id" with addr==id).