Tracking Tables
The registry and per-job logs GoArchive keeps on the destination, their status values, and the checks every run makes against them.
GoArchive keeps all its tracking state on the destination server, in the schema named by destination.job_schema, by default the destination database itself. The tables are the record of what left production: nothing in them is cleaned up automatically.
| Object | Cardinality | Holds |
|---|---|---|
archiver_job | one table, one row per job | The registry: type, root table, binding, status, heartbeat |
archiver_job_log_<id> | one table per job | Each logged root key and its status |
goarchive_meta | one table, one row | The tracking schema’s label, 3.0 |
GoArchive creates the tables but never the schema, and its account holds no DELETE or DROP there: every deletion is a DBA’s act (Tracking Table Maintenance
). The examples below use a job_schema named goarchive and job id 42; substitute yours.
SELECT id, job_name, root_table, job_type FROM goarchive.archiver_job;
-- job id 42 -> goarchive.archiver_job_log_42
The job registry (archiver_job)
CREATE TABLE IF NOT EXISTS archiver_job (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
job_name VARCHAR(255) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
root_table VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
job_type VARCHAR(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
job_status TINYINT NOT NULL DEFAULT 0,
source_server_uuid VARCHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
source_database VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
destination_database VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
destination_server_uuid VARCHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '',
config_fingerprint TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
root_key_columns TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
last_heartbeat_at DATETIME NULL,
UNIQUE KEY uk_job_name (job_name),
KEY idx_status (job_status)
) ENGINE=InnoDB
| Column | Meaning |
|---|---|
id | Surrogate key; names the log table, archiver_job_log_<id> |
job_name | The job’s name in the configuration, unique without regard to letter case |
root_table | The root table; fixed for the job’s life |
job_type | archive, purge or copy-only; fixed for the job’s life |
job_status | 0 idle, 1 running, 3 failed (the last run ended in an error) |
source_server_uuid, source_database | The source the job’s log rows came from |
destination_database | The database the copies went to; it can differ from job_schema |
destination_server_uuid | Reserved; not written by this release ('') |
config_fingerprint | The relations (parents, tables, column pairs) and the where text, as JSON |
root_key_columns | The root key’s column names, in key order, as JSON; empty while registration is incomplete |
last_heartbeat_at | A UTC wall clock refreshed every 15 seconds while running; measure its age with UTC_TIMESTAMP(), never NOW() |
The source and destination columns and config_fingerprint are the job’s binding: the facts that give its log rows their meaning.
The job log (archiver_job_log_<id>)
Created when the job is registered, and typed by the root key: one column k1…kN per root key column, in key order, with the column’s own type, charset and collation. A TIMESTAMP is stored as DATETIME of the same precision, so no session time zone can shift it. For a root key (order_id BIGINT UNSIGNED, line_no INT):
CREATE TABLE IF NOT EXISTS archiver_job_log_42 (
`k1` bigint unsigned NOT NULL COMMENT 'order_id',
`k2` int NOT NULL COMMENT 'line_no',
ga_status TINYINT NOT NULL,
ga_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`k1`, `k2`),
KEY idx_ga_status (ga_status)
) ENGINE=InnoDB
Each comment names the root column, for people; GoArchive never reads it. The table must stay InnoDB, with PRIMARY KEY (k1…kN) and the two ga_ columns as created: a log whose shape changed is refused at startup. Only roots are logged, never child rows.
Status values
ga_status | Name | Written |
|---|---|---|
1 | copied | archive, in the destination transaction with the batch’s copy and verification; the source rows are not yet all deleted |
2 | completed | archive and purge after their deletes; copy-only with its copy |
4 | deleting | purge, in its own transaction, before its deletes |
Each status is written in the transaction that does the work it records. What a rerun does with them is described under Crash Recovery and Resume .
Startup checks
Before anything is recovered or run, every run checks its job against the registry. These are bookkeeping integrity checks: no flag skips them.
The job is fixed. A different
job_typeorroot_tableunder an existing name, or a name that differs from a stored one only in letter case, is refused: use a new name, or retire the job .The root key is fixed.
root_key_columnsand the log’sk1…kNmust match the root table’s current primary key: names, order, types, charsets and collations. A changed key is refused, since the log cannot record it: retire the job or use a new name.The binding. While the job has pending work (archive and purge: any
copiedordeletingroot; copy-only: anycompletedroot, whatever itsresumesetting), a change to the parts that work depends on is refused, naming the parts and the number of roots:Job type Compared archive source server and database, relations, destination database purge source server and database, relations, wherecopy-only source server and database, relations, destination database The refusal lists three ways out: restore the original configuration or source and run once; abandon the roots ; or, after a source failover, re-bind the job . With no pending work, the stored binding is replaced by the current one, so changes between clean runs are free.
Registration takes two steps, because the log is named by the job’s id: the job row is written with an empty root_key_columns, then the log is created, and only then are the key’s names written. A run that finds an empty root_key_columns completes the registration. A table that already exists under the new log’s name and holds rows, or has another shape, is never adopted: the job stays unregistered until a DBA drops that table, after confirming no job uses it, or restores archiver_job.
Lifecycle
- First run in the schema:
goarchive_metaandarchiver_jobare created under the schema lock, and a fresh schema is labelled3.0. - First run of a job: the job is registered and its log created.
- During a run:
job_status = 1, the heartbeat refreshes, and log rows are written per batch. - The end of a run:
job_statusreturns to0, or3after an error. A crash or kill leaves1with a stale heartbeat. A job whose log still holdscopiedordeletingroots, in any status, holds its tables against overlapping jobs until its own rerun finishes them.
The schema label
CREATE TABLE IF NOT EXISTS goarchive_meta (
id TINYINT NOT NULL PRIMARY KEY,
schema_version VARCHAR(16) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB
One row, id = 1. The value is the tracking-schema label, not the program version: a release changes it when it changes the tables’ layout or a column’s meaning. GoArchive 3.0 writes and recognises exactly one label, 3.0. At startup it labels a fresh schema and refuses every other state; there is no automatic migration.
When a schema is refused, stop every GoArchive process that uses it, whatever its version, then follow the row that matches the refusal:
| The refusal says the tables… | Procedure |
|---|---|
report schema_version "2.0" or "2.2", or hold a 2.x archiver_job | Written by GoArchive 2.x or earlier: see Upgrading to 3.0 |
are labelled 3.0 but have no archiver_job table | Restore archiver_job from a backup, or drop every tracking table to start afresh |
hold job rows but no schema_version label | After confirming GoArchive 3.0 wrote them: INSERT INTO goarchive.goarchive_meta (id, schema_version) VALUES (1, '3.0'); or drop every tracking table |
report any other schema_version | Another GoArchive release wrote them, earlier or later: find out which first. An earlier release’s tables: finish its jobs with its binary, then drop them. A later release’s tables: run that release, and do not drop them. Or point job_schema at another schema, which leaves them untouched |
