support concurrent builds
authorHelmut Grohne <helmut@subdivi.de>
Mon, 5 Oct 2020 19:55:42 +0000 (21:55 +0200)
committerHelmut Grohne <helmut@subdivi.de>
Mon, 5 Oct 2020 19:55:42 +0000 (21:55 +0200)
Add new table "building" for recording builds in progress. When a
concurrent build is issued, it will avoid building a source package that
is presently built. It will also avoid building for an architecture that
is presently built for. The latter condition helps reduce the number of
satisfiability issues.

build.py
schema.sql

index 3312bd0..340802b 100755 (executable)
--- a/build.py
+++ b/build.py
@@ -6,6 +6,7 @@ import collections
 import contextlib
 import datetime
 import lzma
+import os
 import os.path
 import sqlite3
 import subprocess
@@ -50,6 +51,7 @@ def main():
     args = argp.parse_args()
     db = sqlite3.connect("db", detect_types=sqlite3.PARSE_DECLTYPES)
     with contextlib.closing(db.cursor()) as cur:
+        cur.execute("BEGIN IMMEDIATE;")
         cur.execute("""
             SELECT d.source, d.version, d.architecture, r.id
                 FROM depstate AS d
@@ -59,6 +61,9 @@ def main():
                     JOIN depcheck
                         ON d.architecture = depcheck.architecture
                 WHERE d.satisfiable = 1 AND depcheck.giveback = 0
+                    AND NOT EXISTS (SELECT 1 FROM building
+                        WHERE d.source = building.source
+                            OR d.architecture = building.architecture)
                 ORDER BY r.priority DESC, r.requesttime ASC, random()
                 LIMIT 1;""")
         row = cur.fetchone()
@@ -70,27 +75,39 @@ def main():
                     WHERE satisfiable = 1 AND giveback = 0
                     ORDER BY random() LIMIT 1;""")
             row = cur.fetchone()
-    if not row:
-        print("no package satisfiable")
-        time.sleep(60)
-        return
-    source, version, architecture, requestid = row
-    print("building %s_%s for %s%s" %
-          (source, version, architecture,
-           "" if requestid is None else " (request %d)" % requestid))
-    timestamp, success, filename, giveback = \
-        do_build(source, version, architecture, args.server)
-    with contextlib.closing(db.cursor()) as cur:
-        cur.execute("INSERT INTO builds (source, version, architecture, success, starttime, filename) VALUES (?, ?, ?, ?, ?, ?);",
-                    (source, version, architecture, success, timestamp,
-                     filename))
-        if requestid is not None:
-            cur.execute("DELETE FROM buildrequests WHERE id = ?;",
-                        (requestid,))
-        if giveback:
-            cur.execute("UPDATE depcheck SET giveback = 1 WHERE architecture = ?;",
-                        (architecture,))
-    db.commit()
+        if not row:
+            cur.execute("ROLLBACK;")
+            print("no package satisfiable")
+            time.sleep(60)
+            return
+        source, version, architecture, requestid = row
+        cur.execute("""INSERT INTO building (source, architecture, pid)
+                           VALUES (?, ?, ?);""",
+                    (source, architecture, os.getpid()))
+        cur.execute("COMMIT;")
+    try:
+        print("building %s_%s for %s%s" %
+              (source, version, architecture,
+               "" if requestid is None else " (request %d)" % requestid))
+        timestamp, success, filename, giveback = \
+            do_build(source, version, architecture, args.server)
+        with contextlib.closing(db.cursor()) as cur:
+            cur.execute("""INSERT INTO builds
+                            (source, version, architecture, success, starttime,
+                             filename) VALUES (?, ?, ?, ?, ?, ?);""",
+                        (source, version, architecture, success, timestamp,
+                         filename))
+            if requestid is not None:
+                cur.execute("DELETE FROM buildrequests WHERE id = ?;",
+                            (requestid,))
+            if giveback:
+                cur.execute("""UPDATE depcheck SET giveback = 1
+                                WHERE architecture = ?;""",
+                            (architecture,))
+    finally:
+        with contextlib.closing(db.cursor()) as cur:
+            cur.execute("DELETE FROM building WHERE pid = ?;", (os.getpid(),))
+        db.commit()
 
 if __name__ == "__main__":
     main()
index d57867b..56184be 100644 (file)
@@ -46,3 +46,8 @@ CREATE TABLE bugs (
        title TEXT,
        patched BOOLEAN NOT NULL CHECK (patched in (0, 1)));
 CREATE INDEX bugs_affects_index ON bugs(affects);
+
+CREATE TABLE building (
+       source TEXT NOT NULL,
+       architecture TEXT NOT NULL,
+       pid INTEGER NOT NULL);