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 ¶
- type Directory
- type Relational
- func (r *Relational) Get(ctx context.Context, entity, id string, into any) error
- func (r *Relational) GetMany(ctx context.Context, entity string, ids []string, into any) error
- func (r *Relational) List(ctx context.Context, entity string, q query.ListQuery, into any) error
- func (r *Relational) Query(ctx context.Context, into any, sql string, args ...any) error
- type Set
- type Shard
- type Spatial
- func (s *Spatial) Delete(ctx context.Context, entity, id string) error
- func (s *Spatial) Get(ctx context.Context, entity, id string) (geom query.Geometry, meta map[string]any, ok bool, err error)
- func (s *Spatial) Upsert(ctx context.Context, entity, id string, geom query.Geometry, ...) error
- func (s *Spatial) Within(ctx context.Context, q query.SpatialQuery, into any) error
- type Store
- type Timeseries
- type Vector
- func (v *Vector) Delete(ctx context.Context, entity, id string) error
- func (v *Vector) DeleteByMeta(ctx context.Context, entity string, filter map[string]string) error
- func (v *Vector) Get(ctx context.Context, entity, id string) ([]float32, error)
- func (v *Vector) Similar(ctx context.Context, q query.VectorQuery, into any) error
- func (v *Vector) Upsert(ctx context.Context, entity, id string, embedding []float32, ...) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Directory ¶
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 ¶
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 ¶
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.
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 ¶
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 ¶
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 ¶
All returns the shards, ordered by id — for the worker plane to start a per-shard relay / reconciler against each.
func (*Set) For ¶
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 ¶
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.
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 ¶
NewSpatial wraps a Set as a routing query.SpatialQuerier.
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.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store routes command.Store (the write path) by tenant.
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) 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 (*Vector) DeleteByMeta ¶ added in v0.0.3
DeleteByMeta routes a metadata-filtered delete to the tenant's shard.