Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
concurrency.sx: persist/append-expect refuses an append when the stream
advanced past the caller's expected seq, returning {:conflict :expected
:actual} instead of crashing or overwriting. persist/conflict? + accessors.
Phase 2 complete, 54/54.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
97 lines
2.3 KiB
Plaintext
97 lines
2.3 KiB
Plaintext
; Phase 2 — optimistic concurrency: conflict is a real result, not a crash.
|
|
|
|
(persist-test
|
|
"append-expect 0 on empty stream succeeds"
|
|
(persist/event-seq
|
|
(persist/append-expect
|
|
(persist/open)
|
|
"s"
|
|
0
|
|
"x"
|
|
0
|
|
{}))
|
|
1)
|
|
(persist-test
|
|
"append-expect with correct seq succeeds"
|
|
(let
|
|
((b (persist/open)))
|
|
(begin
|
|
(persist/append b "s" "x" 0 {})
|
|
(persist/event-seq
|
|
(persist/append-expect b "s" 1 "x" 0 {}))))
|
|
2)
|
|
(persist-test
|
|
"append-expect with stale seq returns a conflict"
|
|
(let
|
|
((b (persist/open)))
|
|
(begin
|
|
(persist/append b "s" "x" 0 {})
|
|
(persist/append b "s" "x" 0 {})
|
|
(persist/conflict?
|
|
(persist/append-expect b "s" 1 "x" 0 {}))))
|
|
true)
|
|
(persist-test
|
|
"a successful append is not a conflict"
|
|
(persist/conflict?
|
|
(persist/append-expect
|
|
(persist/open)
|
|
"s"
|
|
0
|
|
"x"
|
|
0
|
|
{}))
|
|
false)
|
|
(persist-test
|
|
"conflict carries expected and actual"
|
|
(let
|
|
((b (persist/open)))
|
|
(begin
|
|
(persist/append b "s" "x" 0 {})
|
|
(persist/append b "s" "x" 0 {})
|
|
(let
|
|
((r (persist/append-expect b "s" 0 "x" 0 {})))
|
|
(list (persist/conflict-expected r) (persist/conflict-actual r)))))
|
|
(list 0 2))
|
|
(persist-test
|
|
"a conflicting append does not write"
|
|
(let
|
|
((b (persist/open)))
|
|
(begin
|
|
(persist/append b "s" "x" 0 {})
|
|
(persist/append-expect b "s" 0 "x" 0 {})
|
|
(persist/count b "s")))
|
|
1)
|
|
(persist-test
|
|
"two writers: first wins, second conflicts"
|
|
(let
|
|
((b (persist/open)))
|
|
(let
|
|
((seen (persist/last-seq b "s")))
|
|
(begin
|
|
(persist/append-expect b "s" seen "x" 0 {:who "A"})
|
|
(persist/conflict?
|
|
(persist/append-expect b "s" seen "x" 0 {:who "B"})))))
|
|
true)
|
|
(persist-test
|
|
"retry after conflict succeeds"
|
|
(let
|
|
((b (persist/open)))
|
|
(let
|
|
((seen (persist/last-seq b "s")))
|
|
(begin
|
|
(persist/append-expect b "s" seen "x" 0 {:who "A"})
|
|
(let
|
|
((r (persist/append-expect b "s" seen "x" 0 {:who "B"})))
|
|
(if
|
|
(persist/conflict? r)
|
|
(persist/event-seq
|
|
(persist/append-expect
|
|
b
|
|
"s"
|
|
(persist/conflict-actual r)
|
|
"x"
|
|
0
|
|
{:who "B"}))
|
|
(persist/event-seq r))))))
|
|
2)
|