Skip to content

Commit 6753c3a

Browse files
committed
Add a script that removes one run's tables
A run of `--wasmjitrunner` or `--fmisimulator` is one job filling several tables under one date: wasm-jit, wasm-jit-me and wasm-jit-cs. Removing a bad run a table at a time leaves the siblings describing a run that no longer exists, and the rows in omcversion and libversion behind either way. `remove-run.py` takes the branch, finds the newest run of it (or the one `--date`/`--omcversion` names), and deletes from every table of that date at once. It prints what it would delete and does nothing until it is given `--write`, then reads the counts back to check. ./remove-run.py --db postgresql://om@localhost/omdb wasm-jit ./remove-run.py --db postgresql://om@localhost/omdb wasm-jit --write Siblings are found by name and skipped when they have no rows of that date; `--also` names a table the prefix does not reach, which is how the `--solver` runners are stored. job_claim is left alone. Its rows say who tested a library last, the next run overwrites them, and a claim that is not running blocks nothing. Assisted-by: Claude Opus 5 (1M context)
1 parent c7a7b4d commit 6753c3a

1 file changed

Lines changed: 125 additions & 0 deletions

File tree

remove-run.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Remove one test run from the database, all of its result tables together.
4+
5+
./remove-run.py --db postgresql://om@localhost/omdb wasm-jit
6+
./remove-run.py --db postgresql://om@localhost/omdb wasm-jit --write
7+
8+
The first says what it would delete, the second deletes it. Without --date or
9+
--omcversion it takes the newest run of that branch.
10+
11+
A run of test.py --wasmjitrunner or --fmisimulator fills several tables from one
12+
job - wasm-jit, wasm-jit-me and wasm-jit-cs share a date - and removing only the
13+
first would leave the others describing a run that no longer exists. So every
14+
table whose name is the branch or begins with it, and that has rows of that
15+
date, goes at once; --also names any further table, for the --solver runners,
16+
whose tables are named after the solver rather than the branch.
17+
18+
The rows of a run are in the result table, in omcversion and in libversion. Its
19+
job_claim rows are left alone: they say who tested a library last, the next run
20+
overwrites them, and a finished claim stops nobody.
21+
"""
22+
23+
import argparse, sys
24+
from datetime import datetime, timezone
25+
import resultsdb, shared
26+
27+
28+
def runDate(cursor, branch, date, omcversion):
29+
"""The date of the run being removed, and the omc that ran it."""
30+
if date and omcversion:
31+
raise SystemExit("Give --date or --omcversion, not both")
32+
if omcversion:
33+
where = "branch=? AND omcversion=?"
34+
params = (branch, omcversion)
35+
elif date:
36+
where = "branch=? AND date=?"
37+
params = (branch, date)
38+
else:
39+
where = "branch=?"
40+
params = (branch,)
41+
rows = cursor.execute("SELECT date, omcversion FROM omcversion WHERE %s ORDER BY date DESC"
42+
% where, params).fetchall()
43+
if not rows:
44+
raise SystemExit("No run of %s in omcversion matching that" % branch)
45+
if omcversion and len(rows) > 1:
46+
raise SystemExit("%s ran %s %d times; name one of them with --date %s"
47+
% (branch, omcversion, len(rows), " --date ".join(str(r[0]) for r in rows)))
48+
return rows[0]
49+
50+
51+
def resultTables(cursor, db, branch, date, also):
52+
"""The tables one job of that branch wrote: itself, whichever of its runners
53+
has rows of that date, and whatever --also names."""
54+
candidates = [t for t in db.tables() if t not in resultsdb.NON_RESULT_TABLES
55+
and t.startswith(branch + "-")]
56+
ran = [t for t in candidates
57+
if cursor.execute("SELECT COUNT(*) FROM %s WHERE date=?" % db.quote(t), (date,)).fetchone()[0]]
58+
return sorted(set([branch] + ran + list(also)))
59+
60+
61+
def counts(cursor, db, tables, date):
62+
"""How many rows each table holds for that run, in the order they are deleted."""
63+
out = []
64+
for table in tables:
65+
out.append((table, "date=?", (date,)))
66+
for table in ("omcversion", "libversion"):
67+
for name in tables:
68+
out.append((table, "branch=? AND date=?", (name, date)))
69+
return [(table, where, params,
70+
cursor.execute("SELECT COUNT(*) FROM %s WHERE %s" % (db.quote(table), where),
71+
params).fetchone()[0])
72+
for (table, where, params) in out]
73+
74+
75+
def main():
76+
parser = argparse.ArgumentParser(
77+
description="Remove one test run, all of its result tables together",
78+
formatter_class=argparse.RawDescriptionHelpFormatter, epilog=__doc__)
79+
parser.add_argument("branch", help="The branch whose run to remove, as it is named in the database")
80+
parser.add_argument("--date", type=int, help="The run to remove, as the epoch second in its date column")
81+
parser.add_argument("--omcversion", help="The run to remove, as the omc version that produced it")
82+
parser.add_argument("--also", action="append", default=[],
83+
help="A further table the same job wrote, for --solver runners, whose tables "
84+
"are named after the solver. Repeatable.")
85+
parser.add_argument("--write", action="store_true", help="Delete, instead of only saying what would be deleted")
86+
resultsdb.addArgument(parser)
87+
args = parser.parse_args()
88+
89+
branch = shared.resultTable(args.branch)
90+
db = resultsdb.connect(args.db)
91+
cursor = db.cursor()
92+
93+
(date, omcversion) = runDate(cursor, branch, args.date, args.omcversion)
94+
tables = resultTables(cursor, db, branch, date, args.also)
95+
print("%s run of %s, date %d (%s)"
96+
% (branch, omcversion, date, datetime.fromtimestamp(date, tz=timezone.utc).isoformat()))
97+
print("Result tables: %s" % ", ".join(tables))
98+
99+
rows = counts(cursor, db, tables, date)
100+
for (table, where, params, n) in rows:
101+
print(" %-24s %6d rows (%s)" % (table, n, " ".join(str(p) for p in params)))
102+
total = sum(n for (_, _, _, n) in rows)
103+
print(" %-24s %6d rows" % ("total", total))
104+
if not total:
105+
raise SystemExit("Nothing to remove")
106+
107+
if not args.write:
108+
print("\nNothing deleted. Run it again with --write to delete.")
109+
return
110+
111+
for (table, where, params, n) in rows:
112+
cursor.execute("DELETE FROM %s WHERE %s" % (db.quote(table), where), params)
113+
db.commit()
114+
115+
left = [(table, n) for (table, where, params, n) in counts(cursor, db, tables, date) if n]
116+
if left:
117+
print("Still there after deleting: %s" % ", ".join("%s (%d)" % t for t in left))
118+
sys.exit(1)
119+
print("Removed %d rows." % total)
120+
db.vacuum()
121+
db.close()
122+
123+
124+
if __name__ == "__main__":
125+
main()

0 commit comments

Comments
 (0)