test(zset-ffi): the rebuild is one tick and its last chunk is Done (improvise-bw4p.1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
committed by
Edward Langley
parent
c024c4bd6e
commit
b3f5cedff0
@@ -33,8 +33,8 @@ link, so they call the `extern "C"` functions as plain functions.
|
|||||||
4. **Failure leaves the Z-set unchanged.** `add`, `sub`, `neg`, `scale` and `decode_add`
|
4. **Failure leaves the Z-set unchanged.** `add`, `sub`, `neg`, `scale` and `decode_add`
|
||||||
compute a new value and then assign it, so an overflow half way through cannot leave a
|
compute a new value and then assign it, so an overflow half way through cannot leave a
|
||||||
half-applied update (`zs_zset_insert` is one addition, so it has no half).
|
half-applied update (`zs_zset_insert` is one addition, so it has no half).
|
||||||
5. **A failed step poisons the circuit.** A panic in `step` can leave operator state half
|
5. **A failed step poisons the circuit.** A panic in `step` leaves operator state half
|
||||||
updated, and the circuit has no rollback (ADR 009 clause 11 is the host's). So the first
|
updated, and the circuit has no rollback (ADR 009 clause 11 is the host's; `zset.md`). So the first
|
||||||
failure in a step, or in a rebuild step, marks the circuit poisoned, and every later call
|
failure in a step, or in a rebuild step, marks the circuit poisoned, and every later call
|
||||||
that uses it returns `ZS_ERR_POISONED`. A caller drops it and builds another. Ids that do
|
that uses it returns `ZS_ERR_POISONED`. A caller drops it and builds another. Ids that do
|
||||||
not exist, and malformed arguments, are refused before any state changes and do not poison.
|
not exist, and malformed arguments, are refused before any state changes and do not poison.
|
||||||
@@ -69,6 +69,10 @@ link, so they call the `extern "C"` functions as plain functions.
|
|||||||
12. **Versioning.** `zs_abi_version()` and `ZS_ABI_VERSION` are 1. A change that breaks a
|
12. **Versioning.** `zs_abi_version()` and `ZS_ABI_VERSION` are 1. A change that breaks a
|
||||||
signature or a code bumps it.
|
signature or a code bumps it.
|
||||||
|
|
||||||
|
A rebuild is one logical tick however many `zs_rebuild_step` calls it takes (`zset.md`,
|
||||||
|
decision 8): a `delay` fed by it shows the previous tick once, and `done` is 1 as soon as the
|
||||||
|
last chunk ran, whatever the deadline callback says.
|
||||||
|
|
||||||
## Calling it from Common Lisp
|
## Calling it from Common Lisp
|
||||||
|
|
||||||
`crates/zset-ffi/tests/smoke.lisp` is a runnable CFFI program (`defcfun` for each call, a
|
`crates/zset-ffi/tests/smoke.lisp` is a runnable CFFI program (`defcfun` for each call, a
|
||||||
|
|||||||
@@ -58,3 +58,10 @@ counts; asserts the scanner saw more than 30 functions, so an empty parse cannot
|
|||||||
|
|
||||||
Every `ZS_ERR_*`, `ZS_ABI_VERSION`, `ZS_OK` and the four `ZS_AGG_*` equal the Rust values; the
|
Every `ZS_ERR_*`, `ZS_ABI_VERSION`, `ZS_OK` and the four `ZS_AGG_*` equal the Rust values; the
|
||||||
last code's number equals the number of codes, so a new code without a header line fails.
|
last code's number equals the number of codes, so a new code without a header line fails.
|
||||||
|
|
||||||
|
### a_chunked_rebuild_through_delay_is_one_tick
|
||||||
|
|
||||||
|
After #345's review the rebuild is one logical tick. A snapshot of two keys, chunks of one,
|
||||||
|
an always-expired deadline: the first call is `done == 0`, the second `done == 1` (the last
|
||||||
|
chunk is Done despite the deadline), and a `delay` sink shows the previous tick's key once.
|
||||||
|
Under the old per-chunk ticking the delay showed the first chunk instead.
|
||||||
|
|||||||
@@ -497,3 +497,36 @@ fn an_index_by_callback_that_emits_nothing_is_a_bad_value() {
|
|||||||
assert_eq!(zs_circuit_step(c.0), Code::BadValue as i32);
|
assert_eq!(zs_circuit_step(c.0), Code::BadValue as i32);
|
||||||
assert!(last_error().contains("exactly one key"), "{}", last_error());
|
assert!(last_error().contains("exactly one key"), "{}", last_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_chunked_rebuild_through_delay_is_one_tick() {
|
||||||
|
let snapshot = zset(&[(b"a", 1), (b"b", 1)]);
|
||||||
|
let c = C::new();
|
||||||
|
let i = c.input();
|
||||||
|
let mut d = 0;
|
||||||
|
assert_eq!(zs_circuit_delay(c.0, i, &mut d), OK);
|
||||||
|
let s = c.sink(d);
|
||||||
|
c.push(i, &[(b"p", 1)]);
|
||||||
|
assert_eq!(zs_circuit_step(c.0), OK);
|
||||||
|
c.take(s);
|
||||||
|
let mut job = null_mut();
|
||||||
|
assert_eq!(zs_rebuild_new(c.0, i, snapshot, 1, &mut job), OK);
|
||||||
|
let (mut calls, mut done) = (0u32, 0);
|
||||||
|
let ctx = (&mut calls as *mut u32).cast();
|
||||||
|
assert_eq!(
|
||||||
|
zs_rebuild_step(job, c.0, Some(out_of_time), ctx, &mut done),
|
||||||
|
OK
|
||||||
|
);
|
||||||
|
assert_eq!(done, 0);
|
||||||
|
assert_eq!(
|
||||||
|
zs_rebuild_step(job, c.0, Some(out_of_time), ctx, &mut done),
|
||||||
|
OK
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
done, 1,
|
||||||
|
"the last chunk is Done though the deadline expired"
|
||||||
|
);
|
||||||
|
assert_eq!(c.take(s), one(&[(b"p", 1)]));
|
||||||
|
zs_rebuild_free(job);
|
||||||
|
zs_zset_free(snapshot);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user