Documentation
¶
Overview ¶
Package store opens Ether's database and applies each component's migrations. Components own their tables: they register migrations under their own name (table names prefixed with it) and receive *sql.DB.
func init() {
store.Register("catalog", 1, `CREATE TABLE catalog_titles (...)`)
}
A standalone server uses SQLite in its data directory. A clustered node uses an owner-supplied PostgreSQL database; component SQL is written once with `?` placeholders (rebound to $n by the "ether-pgx" driver) and migrations are translated from SQLite DDL (see TranslateDDL). DialectOf tells a component which engine it is talking to for the few constructs that differ.
Index ¶
- Constants
- Variables
- func AppliedMigrations(ctx context.Context, db *sql.DB) (map[string]int, error)
- func CaptureCallSites(on bool)
- func Checkpoint(ctx context.Context, db *sql.DB, truncate bool) error
- func ComponentOrder() []string
- func Contains(d Dialect, haystack, needle string) string
- func ExportLogical(ctx context.Context, db *sql.DB, w io.Writer) error
- func HasDependency(component, dependency string) bool
- func ImportLogical(ctx context.Context, db *sql.DB, r io.Reader) (err error)
- func IsCorrupt(err error) bool
- func IsPermanent(err error) bool
- func IsUnavailable(err error) bool
- func JSONInt(d Dialect, col, key string) string
- func JSONRemove(d Dialect, col, key string) string
- func JSONText(d Dialect, col, key string) string
- func KnownMigrations() map[string]int
- func Like(d Dialect) string
- func LockKey(ctx context.Context, d Dialect, tx *sql.Tx, key string) error
- func Maintain(ctx context.Context, db *sql.DB) error
- func Migrate(ctx context.Context, db *sql.DB) error
- func Open(ctx context.Context, dataDir string) (*sql.DB, error)
- func OpenMemory(ctx context.Context) (*sql.DB, error)
- func OpenPath(ctx context.Context, path string) (*sql.DB, error)
- func OpenTest(t TB) *sql.DB
- func OpenTestPostgres(ctx context.Context, rawURL string) (*sql.DB, error)
- func Rebind(q string) (string, int)
- func RedactURL(raw string) string
- func Register(component string, version int, sql string)
- func RegisterAfter(component string, dependsOn ...string)
- func RegisterDialect(component string, version int, d Dialect, sql string)
- func RegisterSQLiteApply(component string, version int, apply func(context.Context, *sql.Tx) error)
- func RunCheckpointer(ctx context.Context, db *sql.DB, truncate func() bool, onErr func(error))
- func SchemaAhead(ctx context.Context, db *sql.DB) ([]string, error)
- func SessionLock(ctx context.Context, db *sql.DB, key string) (unlock func(), err error)
- func SetCallSiteDepth(depth int)
- func TranslateDDL(sqliteSQL string) string
- func UnixDay(d Dialect, expr string) string
- func UnixHour(d Dialect, expr string) string
- func UnknownApplied(ctx context.Context, db *sql.DB) ([]string, error)
- type Availability
- func (a *Availability) Down() bool
- func (a *Availability) Fail(err error)
- func (a *Availability) OK()
- func (a *Availability) Report(err error) bool
- func (a *Availability) State() AvailabilityState
- func (a *Availability) Subscribe(fn func(reachable bool)) (unsubscribe func())
- func (a *Availability) Up() <-chan struct{}
- type AvailabilityState
- type CorruptionError
- type Dialect
- type Integrity
- type LogicalHeader
- type MigrationGate
- type Options
- type Outbox
- type OutboxOptions
- type OutboxStatus
- type Progress
- type Querier
- type QueryStats
- type RetryOptions
- type SnapshotFile
- type StatementStat
- type TB
- type TestProxy
Constants ¶
const ( DefaultOutboxCap = 10000 DefaultOutboxTimeout = 2 * time.Second )
Outbox defaults.
const ( PreMigrateSuffix = ".pre-migrate.bak" PreMigrateFilesSuffix = ".files" PreMigrateKeep = 3 )
PreMigrateSuffix names the snapshot taken next to a SQLite database before pending migrations change its schema (ether.db.pre-migrate.bak). The PreMigrateKeep newest are kept: older ones are renamed .pre-migrate.bak.1, .2 by each upgrade that migrates. Files the caller supplies (the settings and credential key that match the database) are stored with each one in a directory named after it plus PreMigrateFilesSuffix.
PostgreSQL databases get no pre-migrate snapshot; scheduled and manual backups (internal/backup) are their only copies.
const ( StageSnapshot = "snapshot" StageMigrate = "migrate" )
Progress stages.
const PostgresDriverName = "ether-pgx"
PostgresDriverName is the database/sql driver registered by this package: pgx's stdlib driver with `?` placeholders rebound to $n at execute time, so components keep one SQL text for both engines.
const TestPostgresEnv = "ETHER_TEST_POSTGRES"
TestPostgresEnv names the environment variable that points package tests at a PostgreSQL server instead of in-memory SQLite, e.g.
ETHER_TEST_POSTGRES='postgres://ether:ether@127.0.0.1:5432/ether?sslmode=disable' go test ./...
Each test database is a fresh, randomly named schema that is dropped when the *sql.DB is closed.
Variables ¶
var ErrMigrationDeferred = errors.New("store: schema migration deferred")
ErrMigrationDeferred means this node must not migrate the shared schema yet (another live node runs a binary that does not know the pending migrations and the owner asked to wait for it).
var ErrNoLastInsertID = errors.New("store: LastInsertId is not supported on PostgreSQL; use RETURNING")
ErrNoLastInsertID is returned by Result.LastInsertId on PostgreSQL; use INSERT ... RETURNING instead.
var ErrNotEmpty = errors.New("store: restore target database is not empty")
ErrNotEmpty means a logical restore target already holds data.
Functions ¶
func AppliedMigrations ¶
AppliedMigrations returns the recorded (component -> highest version).
func CaptureCallSites ¶ added in v0.3.0
func CaptureCallSites(on bool)
CaptureCallSites makes every statement's first execution in a QueryStats record where it was issued. It costs a stack walk per new statement, so only the performance harness turns it on.
func Checkpoint ¶ added in v0.3.0
Checkpoint copies WAL frames back into the database. truncate also truncates the WAL, and only when this checkpoint itself found no readers in the way and no other connection is inside a query. TRUNCATE takes locks a request would have to wait on, so callers pass false while the server is busy.
PostgreSQL checkpoints in its own background process. There is nothing to run on the client, and this does not issue CHECKPOINT.
func ComponentOrder ¶ added in v0.3.0
func ComponentOrder() []string
ComponentOrder is the migration component sequence Migrate will apply.
func Contains ¶
Contains is a literal (non-pattern) substring test of needle in haystack, both SQL expressions.
func ExportLogical ¶
ExportLogical writes a consistent logical dump of every table in db to w.
func HasDependency ¶ added in v0.3.0
HasDependency reports whether component declared a RegisterAfter dependency that is present. Absent dependencies are ignored, matching Migrate.
func ImportLogical ¶
ImportLogical loads a logical dump into db, which must be migrated and hold no rows in any table the dump contains. It runs in one transaction.
func IsCorrupt ¶ added in v0.3.0
IsCorrupt reports whether err is SQLite reporting a damaged or foreign file (SQLITE_CORRUPT or SQLITE_NOTADB).
func IsPermanent ¶
IsPermanent reports whether a PostgreSQL connection error will never succeed on retry: wrong password or user, a database or schema that does not exist, or missing privileges. A node starting against such a URL should stop and tell the owner instead of retrying forever.
func IsUnavailable ¶
IsUnavailable reports whether err means the database server could not be reached or dropped the connection — a condition that clears on its own (network outage, server restart or failover) — rather than a problem with the statement or the data. Deadline errors count: a write bounded by a short timeout that expires is treated as an outage.
func JSONInt ¶
JSONInt extracts the top-level key from the JSON text column col as an integer (NULL when absent). key is not escaped.
func JSONRemove ¶
JSONRemove is the JSON text column col without the top-level key, as text. key is not escaped.
func JSONText ¶
JSONText extracts the top-level key from the JSON text column col as text. key must be a constant identifier-like name; it is not escaped.
func KnownMigrations ¶
KnownMigrations is the highest migration version this binary registers for each component.
func Like ¶
Like is the case-insensitive pattern operator for user-facing search: SQLite's LIKE already ignores ASCII case, PostgreSQL needs ILIKE.
func LockKey ¶
LockKey serialises transactions that use the same key until tx ends: a check-then-insert ("count a user's streams, then reserve one") done inside the lock is atomic across every node sharing the database. d is the database's dialect (DialectOf; *sql.Tx does not expose its driver).
On PostgreSQL it takes pg_advisory_xact_lock on a 64-bit hash of key (the single-key space, which never overlaps the cluster's two-key leader lock); the lock is released at commit or rollback. On SQLite it is a no-op: Ether opens SQLite with _txlock=immediate, so every transaction already holds the database's write lock from BEGIN.
func Maintain ¶
Maintain is the periodic (daily) upkeep for a long-running database: it checkpoints the WAL and truncates it when no request is using the database, then refreshes query-planner statistics. It deliberately never VACUUMs; that rewrites the whole file and is left to the owner.
On PostgreSQL the server manages its own WAL and autovacuum; Maintain only refreshes planner statistics with ANALYZE.
func OpenMemory ¶
OpenMemory is a migrated, empty database for tests: in-memory SQLite (a single connection), or a fresh PostgreSQL schema when TestPostgresEnv is set.
func OpenPath ¶
OpenPath opens a database file; ":memory:" works for tests (single conn). Like OpenMemory, ":memory:" is a fresh PostgreSQL schema instead when TestPostgresEnv is set.
func OpenTest ¶
OpenTest is OpenMemory for a test: it fails the test on error and closes (on PostgreSQL: drops) the database when the test ends.
func OpenTestPostgres ¶
OpenTestPostgres creates a uniquely named schema on the server at rawURL, migrates it and returns a *sql.DB whose connections use it as their search_path. Closing the DB drops the schema.
func Rebind ¶
Rebind rewrites `?` placeholders as PostgreSQL's $1..$n (a numbered `?NNN` keeps its number), leaving any `?` inside string literals, quoted identifiers and comments untouched. The second result is the number of parameters.
func RedactURL ¶
RedactURL hides the password (and any password query parameter) in a database URL so it can be logged or shown. Non-URL text that looks like a key=value DSN has its password value masked.
func Register ¶
Register adds a migration written in SQLite's dialect. Versions are per component and start at 1. Call from init(); a migration must never change after release. On PostgreSQL the DDL is translated by TranslateDDL unless RegisterDialect supplied an override.
func RegisterAfter ¶ added in v0.3.0
RegisterAfter declares component-level migration dependencies. Every migration of a dependency is applied before any migration of component. Unrelated components retain their alphabetical order. Dependencies absent from a partial binary are ignored; cycles fail migration startup.
func RegisterDialect ¶
RegisterDialect overrides one registered migration for dialect d, for DDL the mechanical translation cannot express. It may be called before or after the matching Register (both from init()).
func RegisterSQLiteApply ¶ added in v0.3.0
RegisterSQLiteApply binds apply to a migration Register or RegisterDialect already recorded. It does not create a version. SQLite Migrate calls apply instead of that version's SQLite SQL. PostgreSQL never calls apply; it still runs the registered SQL or the RegisterDialect override. Success and failure use the same version bookkeeping as every other migration: the schema_migrations row is inserted only after apply returns nil, and an error rolls the version's transaction back with no row written. apply does not disable foreign keys.
func RunCheckpointer ¶ added in v0.3.0
RunCheckpointer PASSIVE-checkpoints until ctx ends. truncate, when it reports true, allows a TRUNCATE on that pass; a nil truncate never truncates. onErr receives checkpoint failures and may be nil.
func SchemaAhead ¶ added in v0.2.48
SchemaAhead lists the components this binary registers whose applied migrations in db go beyond the newest it knows ("auth 9 > 7"): the database was migrated by a newer Ether. Components this binary does not register (removed features, or added by a newer release) are ignored.
It only informs. Migrations are additive, so an older binary keeps working on a newer schema; that is what lets the updater's crash-loop rollback restart the previous version and a cluster run mixed versions during a rolling update, and why Ether never refuses to start over it.
func SessionLock ¶
SessionLock holds the lock for key across every node sharing a PostgreSQL database until unlock is called, for work that spans more than one transaction (a site login, for example). It uses the same key space as LockKey on a connection reserved for the lock; if releasing fails, that connection is discarded, which drops the lock with the session. Waiting honours ctx. On SQLite it returns nil, nil: there is one node, so callers keep their in-process lock.
func SetCallSiteDepth ¶ added in v0.3.0
func SetCallSiteDepth(depth int)
SetCallSiteDepth records up to depth callers per site (default 1), to find which caller issues a statement once per item.
func TranslateDDL ¶
Migrations are written once, in SQLite's dialect. TranslateDDL turns them into PostgreSQL mechanically; a migration the rules cannot express gets a hand-written override through RegisterDialect.
Rules, applied only outside literals and comments, case-insensitively:
- `INTEGER PRIMARY KEY AUTOINCREMENT` becomes `BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY`.
- A bare `id INTEGER PRIMARY KEY` (SQLite's rowid alias used as a generated id) becomes the same identity column. When it is followed by a CHECK (a singleton row such as `CHECK(id=1)`), or the column has any other name (a natural key such as rating_key or user_id that callers always supply), it becomes `BIGINT PRIMARY KEY`.
- INTEGER becomes BIGINT, REAL becomes DOUBLE PRECISION and BLOB becomes BYTEA (SQLite integers are 64-bit, reals are doubles).
Everything else - TEXT, CHECK constraints, DEFAULTs, partial and DESC indexes, REFERENCES ... ON DELETE CASCADE, ALTER TABLE ADD COLUMN and seed INSERTs - is already valid PostgreSQL and passes through unchanged.
Types ¶
type Availability ¶
type Availability struct {
// contains filtered or unexported fields
}
Availability is a node's shared view of whether the database is reachable. Writers that can defer their work (Outbox) and the cluster heartbeat report outcomes to it; once one of them sees an outage the others queue at once instead of each waiting out its own timeout, and all of them flush as soon as any write succeeds again.
A nil *Availability is always available and ignores reports.
func NewAvailability ¶
func NewAvailability(now func() time.Time) *Availability
NewAvailability returns a tracker that starts out available. now may be nil (time.Now).
func (*Availability) Down ¶
func (a *Availability) Down() bool
Down reports whether the database is currently believed unreachable.
func (*Availability) Fail ¶
func (a *Availability) Fail(err error)
Fail marks the database unreachable.
func (*Availability) Report ¶
func (a *Availability) Report(err error) bool
Report records the outcome of a database operation: nil marks the database reachable; an error that IsUnavailable marks it unreachable; any other error says nothing about reachability. It returns whether err was an outage.
func (*Availability) State ¶
func (a *Availability) State() AvailabilityState
State snapshots the tracker.
func (*Availability) Subscribe ¶
func (a *Availability) Subscribe(fn func(reachable bool)) (unsubscribe func())
Subscribe calls fn(reachable) on every transition, synchronously from the reporting goroutine (keep it quick).
func (*Availability) Up ¶
func (a *Availability) Up() <-chan struct{}
Up returns a channel that is closed while (or as soon as) the database is reachable.
type AvailabilityState ¶
type AvailabilityState struct {
Reachable bool `json:"reachable"`
// DownSince is when the current outage was first observed.
DownSince time.Time `json:"downSince,omitzero"`
LastError string `json:"lastError,omitempty"`
}
AvailabilityState is a snapshot for health reports.
type CorruptionError ¶ added in v0.3.0
type CorruptionError struct{ Integrity Integrity }
CorruptionError is returned by Maintain when the database fails its integrity check.
func (*CorruptionError) Error ¶ added in v0.3.0
func (e *CorruptionError) Error() string
type Dialect ¶
type Dialect string
Dialect names the SQL engine behind a *sql.DB. Components write portable SQL with `?` placeholders; the few constructs that differ between engines go through the helpers below.
func DialectOf ¶
DialectOf reports which engine db talks to. Databases opened through this package's PostgreSQL connector report Postgres; everything else SQLite.
func OpenWith ¶
OpenWith opens and migrates the database the options select and reports its dialect.
func OpenWithRetry ¶
OpenWithRetry is OpenWith that keeps retrying a PostgreSQL database that cannot be reached (refused, timed out, shutting down), with backoff, until it opens or ctx ends. It gives up at once on errors retrying cannot fix: an invalid URL, failed authentication, a database that does not exist, an unsupported server or a failing migration. SQLite is opened once, as by OpenWith.
func ParseDialect ¶
ParseDialect maps a configured driver name to a Dialect; anything that is not recognisably PostgreSQL is SQLite.
type Integrity ¶ added in v0.3.0
type Integrity struct {
// OK is false when the database is damaged.
OK bool `json:"ok"`
// Skipped is set on PostgreSQL, which owns its own physical integrity
// (OK is then true).
Skipped bool `json:"skipped,omitempty"`
// Findings are SQLite's first problem reports when OK is false.
Findings []string `json:"findings,omitempty"`
Checked time.Time `json:"checked"`
Took float64 `json:"tookSeconds"`
}
Integrity is the result of an integrity check of a SQLite database.
func QuickCheck ¶ added in v0.3.0
QuickCheck runs SQLite's PRAGMA quick_check, which reads every page and catches the "database disk image is malformed" class of damage without integrity_check's index cross-checks (about twice as fast). It never fails on damage: a database too broken for the check to run is reported as a finding. The error is only for a check that could not run at all (cancelled, or the database is closed). PostgreSQL is skipped.
type LogicalHeader ¶
type LogicalHeader struct {
Format string `json:"format"`
Version int `json:"version"`
Dialect Dialect `json:"dialect"`
Created time.Time `json:"created"`
Migrations map[string]int `json:"migrations"`
}
LogicalHeader is the first line of a logical dump.
func ValidateLogical ¶
func ValidateLogical(r io.Reader) (LogicalHeader, error)
ValidateLogical reads a whole dump and checks its structure and trailer without touching a database. It returns the header.
type MigrationGate ¶
MigrationGate is consulted while the cluster-wide migration lock is held and before any of pending ("component/version", in apply order) is applied. Returning an error wrapping ErrMigrationDeferred makes OpenWithRetry wait and try again; any other error fails the open. q reads inside the migration transaction.
type Options ¶
type Options struct {
// DataDir holds ether.db for SQLite.
DataDir string
// Driver is "sqlite" (default) or "postgres".
Driver string
// URL is the PostgreSQL connection URL (postgres://...). A postgres://
// or postgresql:// URL implies Driver "postgres".
URL string
// Logger receives open-time warnings; nil uses slog.Default().
Logger *slog.Logger
// MigrationGate, when set, decides on PostgreSQL whether this node may
// apply its pending migrations now (see MigrationGate).
MigrationGate MigrationGate
// SnapshotFiles are stored with a SQLite pre-migrate snapshot (the
// settings and credential key matching the database), if one is taken.
SnapshotFiles []SnapshotFile
// Progress, when set, hears what opening is doing: the pre-migrate
// snapshot and each pending migration (for a startup status page).
Progress func(Progress)
}
Options selects and configures the database backend.
type Outbox ¶
type Outbox[K comparable, V any] struct { // contains filtered or unexported fields }
Outbox makes deferrable writes survive a database outage. A write goes straight to the database while it is reachable. When the database cannot be reached (an error IsUnavailable, or the attempt outlives Timeout) the write is kept in memory instead — only the latest value per key, merged with Merge — and replayed oldest key first, with backoff, once the database answers again. While the database is known to be down new writes are queued without being attempted, so callers (HTTP handlers) return at once.
Errors that are not outages (a constraint violation, a bug) are returned to the caller from Write, or logged and dropped during a replay.
func NewOutbox ¶
func NewOutbox[K comparable, V any](o OutboxOptions[K, V]) *Outbox[K, V]
NewOutbox starts an outbox's replay goroutine; Close stops it.
func (*Outbox[K, V]) Close ¶
Close stops the replay goroutine, then makes one last attempt (bounded by ctx) to write what is still held. It returns an error naming how many writes were lost.
func (*Outbox[K, V]) Status ¶
func (ob *Outbox[K, V]) Status() OutboxStatus
Status snapshots the outbox.
type OutboxOptions ¶
type OutboxOptions[K comparable, V any] struct { // Name identifies the outbox in logs and status ("watch progress"). Name string // Apply performs one write. It must be safe to run again for the same // key (a write whose outcome was lost to a timeout is retried). Apply func(ctx context.Context, key K, v V) error // Merge combines a queued value with a newer one for the same key; // nil keeps only the newer value. Merge func(old, new V) V // Cap bounds the number of queued keys (DefaultOutboxCap); when full // the oldest key is dropped. Cap int // Timeout bounds every write attempt (DefaultOutboxTimeout), so a // caller never waits on an outage longer than this. Timeout time.Duration // MinBackoff / MaxBackoff space retries while the database is // unreachable (1s doubling to 30s). MinBackoff, MaxBackoff time.Duration // Availability is shared with the node's other outboxes and the // cluster heartbeat; nil gives this outbox a private tracker. Availability *Availability Logger *slog.Logger }
OutboxOptions configure an Outbox. Apply is required.
type OutboxStatus ¶
type OutboxStatus struct {
Name string `json:"name"`
Depth int `json:"depth"`
Dropped int64 `json:"dropped,omitempty"`
// Oldest is when the oldest held write was queued.
Oldest time.Time `json:"oldest,omitzero"`
LastError string `json:"lastError,omitempty"`
}
OutboxStatus is an outbox's state for health reports.
type Progress ¶ added in v0.3.0
Progress is reported while a database opens. Stage is StageSnapshot (copying a SQLite database before migrating it) or StageMigrate, where Done of Total pending migrations have been applied.
type Querier ¶
type Querier interface {
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
}
Querier is the read side of *sql.DB and *sql.Tx.
type QueryStats ¶ added in v0.3.0
type QueryStats struct {
// contains filtered or unexported fields
}
QueryStats accumulates the database work done on behalf of one unit of work, usually one HTTP request. Both drivers (SQLite and PostgreSQL) record into the QueryStats carried by the statement's context, so a handler's cost is measured where it is paid: statement count, rows read back into Go, time inside the driver, and time spent waiting for the write lock. It is safe for concurrent use; a request may fan out.
The counters are what the performance gate asserts on: a request path whose statement or row count grows with the library is O(library).
func QueryStatsFrom ¶ added in v0.3.0
func QueryStatsFrom(ctx context.Context) *QueryStats
QueryStatsFrom returns the QueryStats ctx carries, or nil.
func WithQueryStats ¶ added in v0.3.0
func WithQueryStats(ctx context.Context) (context.Context, *QueryStats)
WithQueryStats returns ctx carrying a fresh QueryStats. Work already carrying stats keeps recording into the outer one as well, so a nested measurement never hides cost from the request that paid for it.
func (*QueryStats) DBTime ¶ added in v0.3.0
func (s *QueryStats) DBTime() time.Duration
DBTime is the time spent inside the driver (executing, stepping rows).
func (*QueryStats) LockWait ¶ added in v0.3.0
func (s *QueryStats) LockWait() time.Duration
LockWait is the time spent waiting to begin a transaction (SQLite's write lock, a PostgreSQL BEGIN).
func (*QueryStats) Queries ¶ added in v0.3.0
func (s *QueryStats) Queries() int64
Queries is the number of statements executed.
func (*QueryStats) Rows ¶ added in v0.3.0
func (s *QueryStats) Rows() int64
Rows is the number of result rows read back from the database.
func (*QueryStats) Statements ¶ added in v0.3.0
func (s *QueryStats) Statements() []StatementStat
Statements returns the per-SQL breakdown, most expensive first.
func (*QueryStats) Writes ¶ added in v0.3.0
func (s *QueryStats) Writes() int64
Writes is the number of statements executed for their effect (Exec): inserts, updates and deletes. A read path should have none; each one waits for SQLite's single writer.
type RetryOptions ¶
type RetryOptions struct {
MinBackoff time.Duration // first wait (1s), doubling
MaxBackoff time.Duration // longest wait (30s)
// OnRetry is called before every wait with the failed attempt's error
// (attempt counts from 1).
OnRetry func(attempt int, wait time.Duration, err error)
}
RetryOptions configure OpenWithRetry. Zero durations take the defaults in parentheses.
type SnapshotFile ¶ added in v0.2.48
SnapshotFile is a file stored alongside a pre-migrate snapshot. Name is a plain file name; Data is captured by the caller before anything could rewrite it.
type StatementStat ¶ added in v0.3.0
type StatementStat struct {
SQL string `json:"sql"`
// Site is the first caller outside database/sql and this package, set
// only while CaptureCallSites is on (the performance harness).
Site string `json:"site,omitempty"`
Count int64 `json:"count"`
Rows int64 `json:"rows"`
Time time.Duration `json:"time"`
}
StatementStat is one SQL text's share of a QueryStats.
type TestProxy ¶
type TestProxy struct {
// contains filtered or unexported fields
}
TestProxy is an in-process TCP proxy for outage tests: clients connect to Addr and are forwarded to the target until the test cuts or pauses the link. It never touches the database server itself.
func NewTestProxy ¶
NewTestProxy listens on 127.0.0.1 and forwards to target (host:port).
func (*TestProxy) Cut ¶
func (p *TestProxy) Cut()
Cut drops every connection and refuses new ones until Restore.
func (*TestProxy) Pause ¶
func (p *TestProxy) Pause()
Pause stops all traffic (existing connections hang, new ones are accepted and hang) until Restore.