Mirroring a v4 Instance¶
lnt mirror-v4 copies the contents of a running LNT v4 instance into a local
directory, the mirror, through the instance’s REST API, and keeps that copy up
to date when it is run again. It needs nothing but read access to the instance:
no database credentials, no access to the host, and no authentication token.
The mirror is a faithful copy of what the API returns. Nothing is converted or reinterpreted on the way in, so the mirror can be used later – for example to migrate the data to another LNT instance – without having to fetch it from the instance again, and without committing ahead of time to any particular way of converting it.
A mirror is not a backup: it tracks the instance, so data deleted from the instance is deleted from the mirror the next time it is refreshed (see Mirroring).
Example¶
To mirror the nts and compile suites of https://lnt.llvm.org into
./lnt-mirror:
lnt mirror-v4 https://lnt.llvm.org ./lnt-mirror --suite nts
lnt mirror-v4 https://lnt.llvm.org ./lnt-mirror --suite compile
Running the same commands again later refreshes the mirror, bringing it up to
date. See lnt mirror-v4 --help for the other options.
What is mirrored¶
For the suite being mirrored, the mirror holds:
the suite’s schema, as reported by the instance;
every machine, including the metadata the instance stores for it;
every run on those machines, including its run fields and parameters, and every sample of every test in it.
The following are not mirrored, because the v4 REST API does not expose them, or does not expose them in a form that can be copied:
regressions, field changes, and their triage state;
profiles;
baselines.
The schema is recorded exactly as the instance reports it, and v4 reports some of it inaccurately:
v4 does not store a metric’s
display_name,unitandunit_abbrevin its database. It only knows them for a suite whose schema file it loads at startup; for any other suite, it reports the metric’s name as its display name, and no unit.The
bigger_is_betterof metrics that predate the database migration introducing that setting is stored as null. v4 treats a null as false, but reports it as true. This affects thentsandcompilesuites that v4 creates in every new database, e.g. theirexecution_timeandcompile_timemetrics.
Mirroring¶
After a successful refresh, the suite in the mirror matches the suite on the instance as it was at the time of the refresh:
Runs and machines that are new on the instance are added.
Runs and machines that were deleted from the instance are removed from the mirror.
A run that was replaced on the instance – v4 reuses the run’s identifier when a submission replaces an earlier one – is fetched again.
Every run document embeds its machine’s metadata. A machine whose metadata changed on the instance has all of its runs fetched again.
A suite that no longer exists on the instance is an error; the mirror is left untouched.
Mirror Format¶
A mirror is a directory with the following layout:
MIRROR_DIR/
manifest.json # the manifest
<suite>/
schema.json # GET .../<suite>/schema
machines/<machine id>.json # GET .../<suite>/machines/<machine id>
runs/<run id>.json.gz # GET .../<suite>/runs/<run id>, gzipped
All paths are relative to MIRROR_DIR, and ... stands for
<URL>/api/db_<database>/v4.
A refresh stages the files it writes in MIRROR_DIR/.mirror-tmp/, and clears
that directory when it starts. Its contents are never part of the mirror.
The manifest¶
manifest.json is the authoritative listing of the mirror’s contents: a file
it does not reference is not part of the mirror, and tools reading a mirror must
ignore it. It looks like this:
{
"format_version": "1",
"source": {
"url": "https://lnt.llvm.org",
"database": "default"
},
"suites": {
"nts": {
"schema": {"sha256": "..."},
"machines": {
"1": {
"name": "sifive-p550-rv64gc_zba_zbb-ReleaseLTO__clang_DEV__riscv64",
"fetched_at": "2026-09-29T15:02:11Z",
"sha256": "...",
"runs": {
"601": {"sha256": "..."},
"602": {"sha256": "..."}
}
}
}
}
}
}
format_versionThe version of this format,
"1". It changes whenever the format changes in a way that a tool reading the previous version could misread.lnt mirror-v4refuses to refresh a mirror of any other version, and tools reading a mirror should likewise refuse a version they do not know.sourceThe instance the mirror was copied from: its root
url, without a trailing slash, and thedatabase.suitesOne entry per mirrored suite, keyed by suite name.
suites.<suite>.schema.sha256The SHA-256 of
<suite>/schema.json.suites.<suite>.machinesOne entry per mirrored machine, keyed by the machine’s v4 identifier (a decimal string, since JSON keys are strings). Machines are identified by identifier rather than by name because v4 machine names are not unique.
...machines.<id>.nameThe machine’s name, as the instance reported it at
fetched_at....machines.<id>.fetched_atWhen the machine’s listing,
<suite>/machines/<id>.json, was fetched from the instance: an ISO 8601 timestamp in UTC....machines.<id>.sha256The SHA-256 of
<suite>/machines/<id>.json....machines.<id>.runsOne entry per mirrored run of the machine, keyed by the run’s v4 identifier. Its
sha256is that of the run’s JSON document, i.e. of the decompressed contents of<suite>/runs/<id>.json.gz.
Every hash is the lowercase hexadecimal SHA-256 of the file’s bytes exactly as the instance sent them.
The payload¶
Every other file holds the body of one API response, byte for byte as the
instance sent it; run documents are additionally compressed with gzip, since
they are large and compress well. The documents are therefore in whatever form
the instance’s version of LNT produces, and carry that version under
generated_by.
<suite>/machines/<id>.json holds the machine’s metadata under machine,
and under runs a summary of every run the instance held for that machine
when the listing was fetched. <suite>/runs/<id>.json.gz holds the run under
run, its machine under machine, and its samples under tests, one
entry per sample.
Consistency¶
The manifest is only ever replaced atomically, and a refresh that stops for any reason leaves behind a manifest that satisfies the following:
Every file the manifest references exists.
Every run the manifest lists under a machine is also in that machine’s listing, and its document agrees with the listing: the document’s
runis identical to the listing’s summary of the run, and itsmachineto the listing’smachine.
Here, a machine’s listing means the version of <suite>/machines/<id>.json
whose hash the manifest records (see below). Runs that a refresh could not fetch
are left out of the manifest.
A crash can additionally leave <suite>/schema.json or a machine’s listing
with a hash that no longer matches the manifest; run documents are never
modified while the manifest references them. Tools reading a mirror should
verify the hashes, and treat a mismatch as a damaged mirror. The next refresh of
the affected suite repairs it, and removes the files in <suite>/machines/
and <suite>/runs/ that the manifest does not reference.
Only one refresh may use a mirror at a time; a second concurrent invocation on
the same MIRROR_DIR fails rather than wait.