shard

package
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package shard routes a tenant's source-of-truth operations to the Postgres shard that holds it. A tenant lives entirely on one shard (ADR 0007), so routing is a directory lookup, never a distributed transaction or a scatter-gather read.

The router is engine-neutral: it speaks only the fabriq capability ports (command.Store, query.RelationalQuerier/VectorQuerier/TSQuerier/SpatialQuerier) and implements those same ports by delegating to the resolved shard. The facade, executor and every call site are therefore unchanged — sharding is one more adapter behind a port. Single-Postgres deployments use the degenerate one-shard Set (Single), for which routing is a no-op.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Directory

type Directory interface {
	Shard(ctx context.Context, tenantID string) (string, error)
}

Directory resolves a tenant to its shard id. Implementations range from a constant (one shard) to a cached, versioned table (many shards) — the router does not care which.

func Cached

func Cached(inner Directory, ttl time.Duration) Directory

Cached memoizes a directory's tenant→shard answers for ttl, so the hot path does not pay a lookup per operation. Placement is stable (a tenant's shard does not change without an explicit move), so a short TTL is purely a freshness bound for future catalog-backed directories; the hash directory is constant and caching it is free insurance.

func HashDirectory

func HashDirectory(ids ...string) Directory

HashDirectory places tenants across a fixed set of shards by hashing the tenant id — stateless and deterministic, so every replica routes a tenant the same way without coordination. It is the simplest directory: it needs no catalog table, but changing the shard set re-places tenants (and so requires a data move). A catalog-backed directory with explicit placement (ADR 0007) is the drop-in upgrade when tenants must be moved individually.

type Relational

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

Relational routes query.RelationalQuerier (reads of the source of truth).

func NewRelational

func NewRelational(set *Set) *Relational

NewRelational wraps a Set as a routing query.RelationalQuerier.

func (*Relational) Get

func (r *Relational) Get(ctx context.Context, entity, id string, into any) error

Get routes a single-row read.

func (*Relational) GetMany

func (r *Relational) GetMany(ctx context.Context, entity string, ids []string, into any) error

GetMany routes a batched read (the hydration primitive).

func (*Relational) List

func (r *Relational) List(ctx context.Context, entity string, q query.ListQuery, into any) error

List routes a structured query.

func (*Relational) Query

func (r *Relational) Query(ctx context.Context, into any, sql string, args ...any) error

Query routes the raw-SQL escape hatch.

type Set

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

Set is the tenant -> shard routing table: a directory plus the shards it can name.

func New

func New(dir Directory, shards ...Shard) (*Set, error)

New builds a routing Set from a directory and its shards. Every shard needs a non-empty, unique id; the set needs at least one.

func Single

func Single(sh Shard) *Set

Single builds the degenerate one-shard Set: every tenant routes to sh. This is what single-Postgres deployments use, so the routing layer is a no-op until a second shard is configured. An empty sh.ID defaults to "0".

func (*Set) All

func (s *Set) All() []Shard

All returns the shards, ordered by id — for the worker plane to start a per-shard relay / reconciler against each.

func (*Set) For

func (s *Set) For(ctx context.Context) (Shard, error)

For resolves the shard owning the ctx tenant. It requires a tenant (the same precondition every source-of-truth port already enforces) and fails loudly if the directory names a shard the set does not hold.

func (*Set) ForTenant

func (s *Set) ForTenant(ctx context.Context, tenantID string) (Shard, error)

ForTenant resolves the shard owning an explicit tenant id — the seam the worker plane uses to route by the tenant carried in a method argument (projection bookkeeping, snapshot, reconcile) rather than on ctx.

func (*Set) IDs

func (s *Set) IDs() []string

IDs returns the shard ids, sorted — for building per-shard worker runners.

func (*Set) Len

func (s *Set) Len() int

Len reports the number of shards.

func (*Set) ResolveID

func (s *Set) ResolveID(ctx context.Context, tenantID string) (string, error)

ResolveID returns just the shard id a tenant routes to — for the worker plane to pick the matching concrete adapter (relay, reconcile, snapshot) from its own per-shard map.

type Shard

type Shard struct {
	ID         string
	Store      command.Store
	Relational query.RelationalQuerier
	Vector     query.VectorQuerier
	Timeseries query.TSQuerier
	Spatial    query.SpatialQuerier
}

Shard is one tenant-home: the source-of-truth ports for the tenants that live on it. In production a single Postgres adapter satisfies all five; tests supply stubs.

type Spatial

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

Spatial routes query.SpatialQuerier (geometry upsert/search/delete).

func NewSpatial

func NewSpatial(set *Set) *Spatial

NewSpatial wraps a Set as a routing query.SpatialQuerier.

func (*Spatial) Delete

func (s *Spatial) Delete(ctx context.Context, entity, id string) error

Delete routes a geometry delete to the tenant's shard.

func (*Spatial) Get added in v0.0.5

func (s *Spatial) Get(ctx context.Context, entity, id string) (geom query.Geometry, meta map[string]any, ok bool, err error)

Get routes a single-geometry read to the tenant's shard.

func (*Spatial) Upsert

func (s *Spatial) Upsert(ctx context.Context, entity, id string, geom query.Geometry, meta map[string]any) error

Upsert routes a geometry write to the tenant's shard.

func (*Spatial) Within

func (s *Spatial) Within(ctx context.Context, q query.SpatialQuery, into any) error

Within routes a radius/nearest search to the tenant's shard.

type Store

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

Store routes command.Store (the write path) by tenant.

func NewStore

func NewStore(set *Set) *Store

NewStore wraps a Set as a routing command.Store.

func (*Store) InTenantTx

func (s *Store) InTenantTx(ctx context.Context, fn func(ctx context.Context, tx command.Tx) error) error

InTenantTx routes the write transaction to the tenant's shard. The whole transaction (aggregate row + event + outbox) runs there, so atomicity is preserved without any distributed transaction.

type Timeseries

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

Timeseries routes query.TSQuerier (telemetry ingest/range reads).

func NewTimeseries

func NewTimeseries(set *Set) *Timeseries

NewTimeseries wraps a Set as a routing query.TSQuerier.

func (*Timeseries) BulkWrite

func (t *Timeseries) BulkWrite(ctx context.Context, series string, points []query.Point) error

BulkWrite routes a telemetry batch.

func (*Timeseries) Range

func (t *Timeseries) Range(ctx context.Context, q query.RangeQuery, into any) error

Range routes a time-window read.

type Vector

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

Vector routes query.VectorQuerier (embedding upsert/search).

func NewVector

func NewVector(set *Set) *Vector

NewVector wraps a Set as a routing query.VectorQuerier.

func (*Vector) Delete

func (v *Vector) Delete(ctx context.Context, entity, id string) error

Delete routes an embedding delete to the tenant's shard.

func (*Vector) DeleteByMeta added in v0.0.3

func (v *Vector) DeleteByMeta(ctx context.Context, entity string, filter map[string]string) error

DeleteByMeta routes a metadata-filtered delete to the tenant's shard.

func (*Vector) Get added in v0.0.3

func (v *Vector) Get(ctx context.Context, entity, id string) ([]float32, error)

Get routes an embedding lookup to the tenant's shard.

func (*Vector) Similar

func (v *Vector) Similar(ctx context.Context, q query.VectorQuery, into any) error

Similar routes a nearest-neighbour search.

func (*Vector) Upsert

func (v *Vector) Upsert(ctx context.Context, entity, id string, embedding []float32, meta map[string]any) error

Upsert routes an embedding write.

Jump to

Keyboard shortcuts

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