Documentation
¶
Overview ¶
Package check provides various configuration and health checks that can be run for move operations.
Index ¶
- Constants
- func CutoverOldName(tableName string) string
- func RevertRetiredName(tableName string) string
- func RunChecks(ctx context.Context, r Resources, logger *slog.Logger, scope ScopeFlag, ...) error
- func TargetSchemaDiff(table, sourceCreate, targetCreate string) (string, error)
- type Resources
- type ScopeFlag
- type SourceResource
Constants ¶
const TargetStateCheckName = "target_state"
TargetStateCheckName is the registered name of the target-state check — the one post-setup check that validates target-side state (tables absent, or empty with a matching schema) and therefore the only one that wiping the target can cure. The runner's --force path excludes it (via RunChecksExcluding) when deciding whether a wipe would actually help.
Variables ¶
This section is empty.
Functions ¶
func CutoverOldName ¶ added in v0.15.0
CutoverOldName returns the name the move cutover renames a source table to (`<table>_old`). Unlike the migration package's utils.OldTableName, no truncation is applied — renameSafetyCheck instead rejects tables whose _old name would exceed MySQL's identifier limit before any rows are copied.
func RevertRetiredName ¶ added in v0.16.0
RevertRetiredName returns the name a reverse-window rollback renames a former target table to (`<table>_revert`). It is deliberately distinct from CutoverOldName's `_old` (which retires the *source* on a forward cutover): only a revert ever produces `_revert`, so a later move can unambiguously drop a leftover `_revert` table without risking a forward move's `_old` backup.
func RunChecks ¶
func RunChecks(ctx context.Context, r Resources, logger *slog.Logger, scope ScopeFlag, exclude ...string) error
RunChecks runs all checks registered for the given scope except those named in exclude. The runner's --force recovery path uses it to re-run the post-setup checks minus the target-state check before wiping the target: wiping only cures target-side state, so a failure in any other (source-side) check must surface before the target is destroyed. New checks are deliberately included by default — excluding too little only blocks a wipe, excluding too much could green-light one.
func TargetSchemaDiff ¶ added in v0.17.0
TargetSchemaDiff compares a move's SOURCE table against a pre-created TARGET table and returns a runnable ALTER TABLE statement describing how they differ, or an empty string if the move will accept the target as it stands. It is the comparison the source→target checks use (target_state, resume_state).
Two divergences are tolerated, and only these two. Both are a target that is deliberately stricter or leaner than the unsharded source it moves from, so that a declaratively-managed target does not have to mirror artifacts of its source:
- the source's column-level AUTO_INCREMENT may be absent on the target, whose ids come from elsewhere (e.g. a Vitess sequence);
- a column the source declares nullable may be NOT NULL on the target — a shard key, typically, which cannot be NULL in a sharded keyspace.
Anything else is a difference, the reverse of either included: a target looser than its source fails, as does any change to types, charset, collation, indexes or constraints. See statement.DiffCreateTables for the canonicalization rules underneath.
It is exported because "which divergences does a move tolerate" must have exactly one definition. A caller that wants to know in advance whether a move will accept a given target — strata's `keyspace move-tables` previews it before the operator confirms anything — would otherwise reassemble the option set by hand, and drift in either direction is a bug: the caller blocks a move that would have succeeded, or promises one that fails here in pre-flight. Adding to or removing from the tolerated set is therefore a change in public behaviour, not an internal one.
The nullability tolerance exists because refusing it forced a choice. A Vitess primary vindex cannot map NULL to a keyspace id, so a sharded target must declare its shard key NOT NULL — while the source may still permit NULL because the ALTER to tighten it was never affordable on a multi-terabyte unsharded table. Without this, an operator had to pick between a correct target schema and being able to move into it at all.
The relaxation cannot mask a NULL that actually exists. On a sharded target the row never reaches an INSERT: the applier hashes the shard key first and a NULL fails there. For any other tightened column MySQL does coerce it — Spirit runs a non-strict sql_mode (conn.go sets NO_AUTO_VALUE_ON_ZERO alone) and its copy writes are INSERT IGNORE, so the would-be ER_BAD_NULL_ERROR becomes a warning and the implicit default is stored — but the write does not survive that. RetryableTransaction reads SHOW WARNINGS after every statement and fails on any warning it does not explicitly tolerate, which is what dbconn.UnsafeWarningError is for: on an IGNORE statement the warning is the only evidence the copy lost data. The row's batch takes the whole run down with it, and because the error is fatal it is not retried.
So the outcome is a failed move, never a silently altered value, and the failure is immediate rather than deferred to the checksum. It is still worth probing the tightened columns for NULLs before starting the copy: unchecked, the run dies whenever the copier reaches the chunk holding that row — hours, on a table large enough to want this relaxation — and reports a raw warning code against a batch rather than naming the column.
One note for maintainers: what is exported is this function and not the options it builds, deliberately. The nullability tolerance is directional — statement.IgnoreNotNullRelaxation lets the schema being *validated* be stricter than its *reference*, and here the target is the validated schema, so it must reach DiffCreateTables as "got" with the source as "want". Handing a caller the options would hand them that trap: passed the other way round they forgive the opposite, dangerous direction, silently and with no diff to show for it. The parameter names below are what prevents that, which is why the option and the argument order never leave this function.
Types ¶
type Resources ¶
type Resources struct {
Sources []SourceResource
Targets []applier.Target
SourceTables []*table.TableInfo
DeferCutOver bool
// MoveEverything is true when no explicit table list was supplied (i.e.
// move.SourceTables is empty), so every table in each source database is
// being moved. The source_schema_consistency check uses this to decide
// whether to also require an identical table *set* across all sources: when
// moving everything, an extra/missing table on one shard is a drift error;
// when only a named subset is moved, tables outside that subset are ignored.
MoveEverything bool
}
Resources contains the resources needed for move checks