Skip to content

Commit 0a84930

Browse files
worldevaMark-Simulacrum
authored andcommitted
Lock x.py build state
Prevent spurious build failures and other bugs caused by parallel runs of x.py. We back the lock with sqlite, so that we have a cross-platform locking strategy, and which can be done nearly first in the build process (from Python), which helps move the lock as early as possible.
1 parent 477fd70 commit 0a84930

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

src/bootstrap/bootstrap.py

+35
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,38 @@
1212
import sys
1313
import tarfile
1414
import tempfile
15+
import sqlite3
1516

1617
from time import time
1718

19+
# Acquire a lock on the build directory to make sure that
20+
# we don't cause a race condition while building
21+
# Lock is created in `build_dir/lock.db`
22+
def acquire_lock(build_dir):
23+
path = os.path.join(build_dir, "lock.db")
24+
try:
25+
con = sqlite3.Connection(path, timeout=0)
26+
curs = con.cursor()
27+
curs.execute("BEGIN EXCLUSIVE")
28+
# The lock is released when the cursor is dropped
29+
return curs
30+
# If the database is busy then lock has already been acquired
31+
# so we wait for the lock.
32+
# We retry every quarter second so that execution is passed back to python
33+
# so that it can handle signals
34+
except sqlite3.OperationalError:
35+
del con
36+
del curs
37+
print("Waiting for lock on build directory")
38+
con = sqlite3.Connection(path, timeout=0.25)
39+
curs = con.cursor()
40+
while True:
41+
try:
42+
curs.execute("BEGIN EXCLUSIVE")
43+
except sqlite3.OperationalError:
44+
pass
45+
return curs
46+
1847
def support_xz():
1948
try:
2049
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
@@ -1225,6 +1254,12 @@ def bootstrap(help_triggered):
12251254
build.set_dist_environment(data["dist_server"])
12261255

12271256
build.build = args.build or build.build_triple()
1257+
1258+
# Acquire the lock before doing any build actions
1259+
# The lock is released when `lock` is dropped
1260+
if not os.path.exists(build.build_dir):
1261+
os.makedirs(build.build_dir)
1262+
lock = acquire_lock(build.build_dir)
12281263
build.update_submodules()
12291264

12301265
# Fetch/build the bootstrap

0 commit comments

Comments
 (0)