src/scan/VisibleStats.bend
mylsm-lsm-store@0.6.0.0 · 74 lines · 0 definitions
1import Base
2
3# Stores exact visible record and payload totals.
4type Stats is Data:
5 Stats{entries: Nat, payload_bytes: Nat}
6
7# Reports a deterministic aggregate after one logical key mutation.
8type Decision is Data:
9 Applied{stats: Stats}
10
11# Adds a previously absent live key and its encoded payload.
12def added(current: Stats, key_bytes: Nat, value_bytes: Nat) -> Decision:
13 match current:
14 case Stats{entries, payload_bytes}:
15 Applied{Stats{Nat.add(entries, 1n),
16 Nat.add(payload_bytes, Nat.add(key_bytes, value_bytes))}}
17
18# Preserves totals when a mutation leaves a key absent.
19def unchanged(current: Stats) -> Decision:
20 Applied{current}
21
22# Removes one visible key, its key bytes, and its old value bytes.
23def removed(current: Stats, key_bytes: Nat, value_bytes: Nat) -> Decision:
24 match current:
25 case Stats{entries, payload_bytes}:
26 Applied{Stats{Nat.sub(entries, 1n),
27 Nat.sub(payload_bytes, Nat.add(key_bytes, value_bytes))}}
28
29# Replaces a value without changing the visible key count.
30def replaced(current: Stats, old_bytes: Nat, new_bytes: Nat) -> Decision:
31 match current:
32 case Stats{entries, payload_bytes}:
33 Applied{Stats{entries, Nat.add(Nat.sub(payload_bytes, old_bytes), new_bytes)}}
34
35# Applies the visible effect of one key's before and after states.
36def apply(
37 current: Stats,
38 key_bytes: Nat,
39 before: Maybe<&1, Nat>,
40 after: Maybe<&1, Nat>
41) -> Decision:
42 match before:
43 case None{}:
44 match after:
45 case None{}: unchanged(current)
46 case Some{new_bytes}: added(current, key_bytes, new_bytes)
47 case Some{old_bytes}:
48 match after:
49 case None{}: removed(current, key_bytes, old_bytes)
50 case Some{new_bytes}: replaced(current, old_bytes, new_bytes)
51
52# Projects aggregate totals from a successful mutation decision.
53def result(decision: Decision) -> Stats:
54 match decision:
55 case Applied{stats}: stats
56
57def clone.nat(+value: Nat) -> Nat & Nat:
58 (Nat.mul(1n, value), Nat.mul(1n, value))
59
60def clone.fields(
61 entries: Nat & Nat,
62 payload_bytes: Nat & Nat
63) -> Stats & Stats:
64 match entries:
65 case (entries_left, entries_right):
66 match payload_bytes:
67 case (payload_left, payload_right):
68 (Stats{entries_left, payload_left}, Stats{entries_right, payload_right})
69
70# Rebuilds independent copies of the exact aggregate totals.
71def clone(+stats: Stats) -> Stats & Stats:
72 match stats:
73 case Stats{+entries, +payload_bytes}:
74 clone.fields(clone.nat(entries), clone.nat(payload_bytes))