Resolve the head once a flush, not once a node
The identity map holds weak references. A branch row nobody keeps a strong reference to is collected between two nodes, so resolving the head inside the placement loop read it back from the database for every node in the flush: 201 SELECTs on `branches` to write 200 actions, and 36 s -> 45 s on the same 297 tests. Nothing about any result changed, which is why only a stopwatch found it, and why there is now a test counting the reads. Also: the two reads left un-pathed on purpose say so where they live — `max_action_index` allocates the legacy `index` and must stay adventure-wide or two branches issue the same number, and export is a flat v1 bundle whose reader has no idea branches exist. And `Adventure.actions` keeps its `index` ordering, because ordering the collection by depth would not make it a story: it is every branch's actions, and a path is a selection out of it. 318 tests green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Dvvqn9ZDR4ixeFPHNbww7
This commit is contained in:
committed by
Parth
co-authored by
Claude Opus 5
parent
563b9af9cf
commit
05a2a77e4c
@@ -350,6 +350,28 @@ def test_a_memory_written_without_a_branch_is_placed_anyway(forked):
|
||||
assert memory.depth == 3
|
||||
|
||||
|
||||
def test_placing_a_flush_of_nodes_reads_the_branch_once(forked, emitted_sql):
|
||||
"""The guard resolves the head once per flush, not once per node.
|
||||
|
||||
The identity map holds weak references, so a branch row nobody keeps a
|
||||
strong reference to is collected between two nodes and read back for the
|
||||
next one. Writing two hundred actions in one flush was two hundred SELECTs
|
||||
on `branches` before the head was hoisted out of the loop, and nothing
|
||||
about the result would have told you.
|
||||
"""
|
||||
db, adventure, _ = forked
|
||||
emitted_sql.clear()
|
||||
for i in range(50):
|
||||
db.add(models.Action(
|
||||
adventure_id=adventure.id, index=500 + i, type="do", text=f"bulk {i}"
|
||||
))
|
||||
db.commit()
|
||||
branch_reads = [s for s in emitted_sql if s.startswith("SELECT") and "FROM branches" in s]
|
||||
assert len(branch_reads) <= 2, (
|
||||
f"{len(branch_reads)} reads of `branches` to place 50 nodes"
|
||||
)
|
||||
|
||||
|
||||
def test_an_adventure_with_no_branch_at_all_reads_as_empty(forked):
|
||||
"""The loud version of a missing branch: nothing, rather than everything.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user