Documentation
¶
Overview ¶
Package appdata is an app's own data: a key-value store per app, kept BESIDE filex and never in filex's own database (docs/APP-PLUGINS-API.md → An app's own data). An app reaches it only through the data_* host functions; it cannot name a table, see one of filex's, or run a query.
Two places it can live:
- a file per app under the data directory (SQLite, the default). Fast (a point read is single-digit microseconds) and simple, but the data directory is per node (docs/DEPLOYMENT.md → Scaling): behind several filex replicas each node keeps its own, which is why NodeLocal says so;
- a PostgreSQL database of its own (FILEX_APP_DATA_DSN), which every replica shares. Never filex's own database: an app's rows have no business beside filex's tables, and an operator who points this at filex's DSN is refused.
Every key is in a scope the HOST chooses (`app`, `t:<tenant>`), so an app cannot read another tenant's keys by spelling them. Keys are printable ASCII, so every engine orders and compares them byte for byte.
Index ¶
- Constants
- Variables
- func CheckKey(key string) error
- func TenantScope(tenant int64) string
- type Cond
- type Entry
- type Postgres
- func (p *Postgres) Close() error
- func (p *Postgres) Delete(ctx context.Context, app, scope, key string, ifRev int64) (bool, error)
- func (p *Postgres) Driver() string
- func (p *Postgres) Drop(ctx context.Context, app string) error
- func (p *Postgres) Get(ctx context.Context, app, scope, key string) (Entry, bool, error)
- func (p *Postgres) Incr(ctx context.Context, app, scope, key string, by int64) (int64, error)
- func (p *Postgres) List(ctx context.Context, app, scope, prefix, after string, limit int) ([]Entry, string, error)
- func (p *Postgres) NodeLocal() bool
- func (p *Postgres) Put(ctx context.Context, app, scope, key, value string, c Cond) (int64, error)
- func (p *Postgres) Usage(ctx context.Context, app string) (int64, int64, error)
- type SQLite
- func (s *SQLite) Close() error
- func (s *SQLite) Delete(ctx context.Context, app, scope, key string, ifRev int64) (bool, error)
- func (s *SQLite) Driver() string
- func (s *SQLite) Drop(_ context.Context, app string) error
- func (s *SQLite) Get(ctx context.Context, app, scope, key string) (Entry, bool, error)
- func (s *SQLite) Incr(ctx context.Context, app, scope, key string, by int64) (int64, error)
- func (s *SQLite) List(ctx context.Context, app, scope, prefix, after string, limit int) ([]Entry, string, error)
- func (s *SQLite) NodeLocal() bool
- func (s *SQLite) Put(ctx context.Context, app, scope, key, value string, c Cond) (int64, error)
- func (s *SQLite) Usage(ctx context.Context, app string) (int64, int64, error)
- type Store
Constants ¶
const ( MaxKeyBytes = 512 MaxValueBytes = 64 << 10 MaxList = 500 // DefaultMaxBytes is an app's store when the operator says nothing // (FILEX_APP_DATA_MAX_MB). DefaultMaxBytes = 256 << 20 )
Limits (the wire contract's, repeated here so the store holds them whoever calls it).
const AppScope = "app"
AppScope is the scope every tenant shares.
Variables ¶
var ( // ErrConflict: a condition did not hold (busy). ErrConflict = errors.New("appdata: the condition does not hold") // ErrQuota: the app's store is full (too_large). ErrQuota = errors.New("appdata: the app's data is at its size limit") // ErrCounter: a value written to a counter key, or a counter added to a // value key (invalid). ErrCounter = errors.New("appdata: a counter key is written by incr only") // ErrKey / ErrScope / ErrValue: what was asked cannot be stored (invalid). ErrKey = errors.New("appdata: a key is 1 to 512 printable ASCII characters") ErrScope = errors.New("appdata: no such scope") ErrValue = errors.New("appdata: a value is valid UTF-8, at most 64 KiB") // ErrApp: not an app name. ErrApp = errors.New("appdata: not an app name") )
Errors the host functions answer with their wire codes.
var ErrSameDatabase = errors.New("appdata: FILEX_APP_DATA_DSN names filex's own database; give apps a database of their own")
ErrSameDatabase: FILEX_APP_DATA_DSN names filex's own database.
Functions ¶
func CheckKey ¶
CheckKey refuses a key that is empty, longer than MaxKeyBytes or holds a byte outside printable ASCII (0x21-0x7E; no space).
func TenantScope ¶
TenantScope is the scope of a tenant's keys (0: the platform's own).
Types ¶
type Cond ¶
type Cond struct {
// IfAbsent: only when the key does not exist.
IfAbsent bool
// IfRev: only when the key is at this revision (0 asks nothing).
IfRev int64
}
Cond makes a write conditional.
type Postgres ¶
type Postgres struct {
// contains filtered or unexported fields
}
Postgres keeps every app's data in a database of the apps' own.
func OpenPostgres ¶
OpenPostgres connects and creates the two tables. filexDSN is filex's own database's DSN when it is PostgreSQL ("" otherwise): naming the same database (host, port and database name) is refused.
type SQLite ¶
type SQLite struct {
// contains filtered or unexported fields
}
SQLite keeps every app's data in a file of its own.
func OpenSQLite ¶
OpenSQLite stores apps' data under dir (created 0700). maxBytes is each app's limit (0: DefaultMaxBytes).
func (*SQLite) Drop ¶
Drop closes the app's file and removes it. The path is built from a validated app name under the store's own directory, never from input.
type Store ¶
type Store interface {
Get(ctx context.Context, app, scope, key string) (Entry, bool, error)
Put(ctx context.Context, app, scope, key, value string, c Cond) (int64, error)
Delete(ctx context.Context, app, scope, key string, ifRev int64) (bool, error)
// List answers the keys that start with prefix, after `after`, in byte
// order, at most limit; next is "" on the last page.
List(ctx context.Context, app, scope, prefix, after string, limit int) ([]Entry, string, error)
Incr(ctx context.Context, app, scope, key string, by int64) (int64, error)
// Usage is how many keys an app keeps and their bytes (keys + values).
Usage(ctx context.Context, app string) (keys, bytes int64, err error)
// Drop erases everything an app keeps.
Drop(ctx context.Context, app string) error
// Driver is "sqlite" or "postgres"; NodeLocal is true when the data is
// this node's alone.
Driver() string
NodeLocal() bool
Close() error
}
Store is where every app's data lives.