py: test that an edit releases the GIL

A thread appending timestamps in a loop runs while a 1024x1024 gzip
dataset is rewritten through 'r+': the largest gap between its stamps
during the edit must be under half the edit's duration (an edit holding
the GIL stalls it for the whole edit; checked with a GIL-holding regex
standing in for the edit: one 0.20 s gap in a 0.21 s call). Edits already
ran detached; nothing tested it.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
osobh
2026-09-27 07:48:04 -05:00
co-authored by Claude Opus 5.5
parent 39f25e5d4e
commit 173de3e0d2
+35
View File
@@ -896,3 +896,38 @@ def test_path_replaced_between_edits(h5py, tmp_path):
from pathlib import Path
_held_file_edited(h5py, moved, Path(path), other_bytes)
def test_an_edit_releases_the_gil(h5py, tmp_path):
"""Another Python thread keeps running while a large edit is written:
had the edit held the GIL, the other thread would stall for the whole
edit (Rust code never yields it)."""
import time
path = str(tmp_path / "big.h5")
with h5py.File(path, "w") as f:
f.create_dataset("d", shape=(1024, 1024), dtype="<f8", chunks=(64, 64), compression="gzip")
value = np.random.default_rng(0).standard_normal((1024, 1024))
stamps = []
stop = threading.Event()
def spin():
while not stop.is_set():
stamps.append(time.perf_counter())
with clawhdf5.File(path, "r+") as f:
ds = f["d"]
t = threading.Thread(target=spin)
t.start()
try:
time.sleep(0.05)
t0 = time.perf_counter()
ds[...] = value
t1 = time.perf_counter()
finally:
stop.set()
t.join()
np.testing.assert_array_equal(ds[...], value)
during = [x for x in stamps if t0 <= x <= t1]
gaps = np.diff([t0] + during + [t1])
assert t1 - t0 > 0.1, "the edit is too quick to tell"
assert gaps.max() < 0.5 * (t1 - t0), (
f"the other thread stalled for {gaps.max():.3f} s of a {t1 - t0:.3f} s edit")