mirror of
https://github.com/simonw/datasette.git
synced 2026-10-21 00:36:59 +02:00
Torture harness: dump all stacks on the first hang; SQLite 3.53 test fix
test_new_memory_database_is_not_scanned_at_registration filled the memory database with VACUUM INTO, which SQLite 3.53 (the free-threaded 3.14 build) refuses for an existing in-memory database; it now uses a plain connection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwkLo2rJWidpkDVT3HkvNv
This commit is contained in:
parent
da523c30e5
commit
6f875274b0
2 changed files with 15 additions and 3 deletions
|
|
@ -362,6 +362,15 @@ class Torture:
|
||||||
with self.lock:
|
with self.lock:
|
||||||
self.problems.append({"kind": kind, "message": message[:2000]})
|
self.problems.append({"kind": kind, "message": message[:2000]})
|
||||||
|
|
||||||
|
def dump_stacks_once(self, why):
|
||||||
|
"""Every thread's stack on stderr, the first time something hangs."""
|
||||||
|
with self.lock:
|
||||||
|
if getattr(self, "_dumped", False):
|
||||||
|
return
|
||||||
|
self._dumped = True
|
||||||
|
sys.stderr.write(f"\n=== {why}: stacks of all threads ===\n")
|
||||||
|
faulthandler.dump_traceback(all_threads=True)
|
||||||
|
|
||||||
def count(self, key):
|
def count(self, key):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
self.counts[key] += 1
|
self.counts[key] += 1
|
||||||
|
|
@ -414,6 +423,7 @@ class Torture:
|
||||||
value = await asyncio.wait_for(awaitable, timeout)
|
value = await asyncio.wait_for(awaitable, timeout)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
self.problem("hang", f"{op} on {group} did not finish in {timeout}s")
|
self.problem("hang", f"{op} on {group} did not finish in {timeout}s")
|
||||||
|
self.dump_stacks_once(f"{op} on {group} hung")
|
||||||
return False, None
|
return False, None
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
raise
|
raise
|
||||||
|
|
|
||||||
|
|
@ -619,10 +619,12 @@ async def test_new_memory_database_is_not_scanned_at_registration():
|
||||||
state = memory._watch_state
|
state = memory._watch_state
|
||||||
assert state.scan_future is None
|
assert state.scan_future is None
|
||||||
assert state in watcher._pending
|
assert state in watcher._pending
|
||||||
# Fill it the way the plugin does
|
# Fill it from a connection of its own, as the plugin does (it uses
|
||||||
conn = sqlite3.connect(":memory:")
|
# VACUUM INTO, which newer SQLite versions refuse for an existing
|
||||||
|
# in-memory database, so a plain connection here)
|
||||||
|
conn = sqlite3.connect("file:review_fixes_copy?mode=memory&cache=shared", uri=True)
|
||||||
conn.execute("create table copied (id integer)")
|
conn.execute("create table copied (id integer)")
|
||||||
conn.execute("VACUUM INTO 'file:review_fixes_copy?mode=memory&cache=shared'")
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
# The next request scans it
|
# The next request scans it
|
||||||
response = await ds.client.get("/copy.json")
|
response = await ds.client.get("/copy.json")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue