upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/nostr.cpp
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-08-23 11:53:20 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-08-23 11:53:20 +0000
commit111fb886c2a38c8ab76fd064c9dbb1f403fde7c1 (patch)
treecaff3d96d9bd13d9096b5d90169ed908f942dd8f /src/nostr.cpp
parent46864cdf3c90d15d5d21a330bb54f43696aa7d3b (diff)
selftest: make a torn publish structurally invalid, not merely unlucky
Mutation-tested, the concurrency test did not test concurrency. With the per-file write mutex removed from PublishVersioned, `make tests` still went green 2 runs out of 5, and the assertion named "four threads publishing the same file never leave it unparseable" fired 0 times out of 5. It was asserting something true for reasons unrelated to the code it was pointed at. Two causes. The images were 64 arrays of 200 entries, identical in structure and within bytes of each other in length, so an interleaving of any two of them was still a valid JSON array. There was nothing structural for a torn write to break. They now alternate between one entry and five thousand: a write landing on top of another leaves either a truncated array or a small image followed by the tail of a large one, and neither parses. Worse, almost nothing was being written. Each thread walked a permutation of the images and PublishVersioned drops any blob not newer than what is on disk, so only the record highs in each permutation ever reached the disk -- about ten writes in total across four threads, which is not enough contention to produce a race however the images are shaped. Every publish now stamps its sequence number from a shared counter at the moment it is made, so every publish is newer than the last one issued and every publish writes: 400 of them, half of them 600 KB. And the file is now watched while the writers run rather than inspected once after they stop. "The published file is never observed unparseable" is the real invariant -- rename(2) is atomic, so a reader can only ever see a completely written image -- and sampling it only at the end looks at the one moment a torn file is least likely to have survived. Measured on the build host, five runs with the file mutex removed: 5 detections out of 5, every one of them on the unparseable-file assertion, which is the assertion that used to fire never. Five runs with the mutex in place: 5 passes. The whole payout-ledger self-test takes 1.4 s. Property: removing the serialisation this test exists to check fails the test, on every run.
Diffstat (limited to 'src/nostr.cpp')
0 files changed, 0 insertions, 0 deletions