src/SortedRun.bend
mylsm-lsm-store@0.6.0.1 · 419 lines · 45 definitions
1import Base
2import mylsm-lsm-store@0.6.0.1/src/Keys.bend as Keys
3import mylsm-lsm-store@0.6.0.1/src/MemTable.bend as MemTable
4
5
6
7
8
9def bool_not(rhs: Bool) -> Bool:
10 match rhs:
11 case False{}:
12 True{}
13 case True{}:
14 False{}
15
16
17def bool_and(lhs: Bool, rhs: Bool) -> Bool:
18 match lhs:
19 case False{}:
20 False{}
21 case True{}:
22 rhs
23
24
25def bool_or(lhs: Bool, rhs: Bool) -> Bool:
26 match lhs:
27 case False{}:
28 rhs
29 case True{}:
30 True{}
31
32
33def entry_cmp(e1: MemTable.Entry, e2: MemTable.Entry) -> Cmp:
34 match e1:
35 case MemTable.Entry{k1, v1}:
36 match e2:
37 case MemTable.Entry{k2, v2}:
38 Keys.cmp(k1, k2)
39
40
41def entry_key_eq(entry: MemTable.Entry, +key: String) -> Bool:
42 match entry:
43 case MemTable.Entry{k, v}:
44 Keys.eq(k, key)
45
46
47
48
49def contains_key(+entry: MemTable.Entry, entries: List<&2, MemTable.Entry>) -> Bool:
50 match entry:
51 case MemTable.Entry{+key, val}:
52 match entries:
53 case Nil{}:
54 False{}
55 case Con{h, t}:
56 bool_or(entry_key_eq(h, key), contains_key(MemTable.Entry{key, val}, t))
57
58
59def is_unique(entries: List<&2, MemTable.Entry>) -> Bool:
60 match entries:
61 case Nil{}:
62 True{}
63 case Con{+h, +t}:
64 bool_and(bool_not(contains_key(h, t)), is_unique(t))
65
66
67def is_strict(entries: List<&2, MemTable.Entry>) -> Bool:
68 match entries:
69 case Nil{}:
70 True{}
71 case Con{h, Nil{}}:
72 True{}
73 case Con{+h, Con{+next, +rest}}:
74 bool_and(Keys.cmp_is_lt(entry_cmp(h, next)), is_strict(Con{next, rest}))
75
76
77def resolve_step(
78 done: Bool,
79 hit: Bool,
80 val: Maybe<&2, String>,
81 ans: Maybe<&2, Maybe<&2, String>>
82) -> Bool & Maybe<&2, Maybe<&2, String>>:
83 match done:
84 case True{}:
85 (True{}, ans)
86 case False{}:
87 match hit:
88 case True{}:
89 (True{}, Some{val})
90 case False{}:
91 (False{}, ans)
92
93
94def resolve_state(
95 entries: List<&2, MemTable.Entry>,
96 +key: String,
97 state: Bool & Maybe<&2, Maybe<&2, String>>
98) -> Bool & Maybe<&2, Maybe<&2, String>>:
99 match entries:
100 case Nil{}:
101 state
102 case Con{MemTable.Entry{k, val}, t}:
103 (done, ans) = state
104 resolve_state(t, key, resolve_step(done, Keys.eq(k, key), val, ans))
105
106
107def resolve_answer(state: Bool & Maybe<&2, Maybe<&2, String>>) -> Maybe<&2, Maybe<&2, String>>:
108 match state:
109 case (done, ans):
110 ans
111
112
113def resolve(entries: List<&2, MemTable.Entry>, key: String) -> Maybe<&2, Maybe<&2, String>>:
114 resolve_answer(resolve_state(entries, key, (False{}, None{})))
115
116
117def resolve_newest_go(
118 runs: List<&2, List<&2, MemTable.Entry>>,
119 +key: String,
120 state: Bool & Maybe<&2, Maybe<&2, String>>
121) -> Bool & Maybe<&2, Maybe<&2, String>>:
122 match runs:
123 case Nil{}:
124 state
125 case Con{run, rest}:
126 resolve_newest_go(rest, key, resolve_state(run, key, state))
127
128
129def resolve_newest(runs: List<&2, List<&2, MemTable.Entry>>, key: String) -> Maybe<&2, Maybe<&2, String>>:
130 resolve_answer(resolve_newest_go(runs, key, (False{}, None{})))
131
132
133
134def runs_well_formed(runs: List<&2, List<&2, MemTable.Entry>>) -> Bool:
135 match runs:
136 case Nil{}:
137 True{}
138 case Con{+run, rest}:
139 bool_and(bool_and(is_strict(run), is_unique(run)), runs_well_formed(rest))
140
141
142def first_key(entries: List<&2, MemTable.Entry>) -> Maybe<&2, String>:
143 match entries:
144 case Nil{}:
145 None{}
146 case Con{MemTable.Entry{key, val}, t}:
147 Some{key}
148
149
150def last_key_go(entries: List<&2, MemTable.Entry>, last: String) -> Maybe<&2, String>:
151 match entries:
152 case Nil{}:
153 Some{last}
154 case Con{MemTable.Entry{key, val}, t}:
155 last_key_go(t, key)
156
157
158def last_key(entries: List<&2, MemTable.Entry>) -> Maybe<&2, String>:
159 match entries:
160 case Nil{}:
161 None{}
162 case Con{MemTable.Entry{key, val}, t}:
163 last_key_go(t, key)
164
165
166def range_disjoint_bounds(
167 af: Maybe<&2, String>,
168 al: Maybe<&2, String>,
169 bf: Maybe<&2, String>,
170 bl: Maybe<&2, String>
171) -> Bool:
172 match af al bf bl:
173 case None{} _ _ _:
174 True{}
175 case _ None{} _ _:
176 True{}
177 case _ _ None{} _:
178 True{}
179 case _ _ _ None{}:
180 True{}
181 case Some{a_first} Some{a_last} Some{b_first} Some{b_last}:
182 bool_or(Keys.lt(a_last, b_first), Keys.lt(b_last, a_first))
183
184
185def range_disjoint(+xs: List<&2, MemTable.Entry>, +ys: List<&2, MemTable.Entry>) -> Bool:
186 range_disjoint_bounds(first_key(xs), last_key(xs), first_key(ys), last_key(ys))
187
188
189def disjoint_with(+run: List<&2, MemTable.Entry>, runs: List<&2, List<&2, MemTable.Entry>>) -> Bool:
190 match runs:
191 case Nil{}:
192 True{}
193 case Con{+h, t}:
194 bool_and(range_disjoint(run, h), disjoint_with(run, t))
195
196
197def pairwise_disjoint(runs: List<&2, List<&2, MemTable.Entry>>) -> Bool:
198 match runs:
199 case Nil{}:
200 True{}
201 case Con{+h, +t}:
202 bool_and(disjoint_with(h, t), pairwise_disjoint(t))
203
204
205
206
207def merge_step(
208 order: Cmp,
209 +newer_head: MemTable.Entry,
210 newer_tail: List<&2, MemTable.Entry>,
211 +older_head: MemTable.Entry,
212 older_tail: List<&2, MemTable.Entry>,
213 acc: List<&2, MemTable.Entry>
214) -> List<&2, MemTable.Entry> & List<&2, MemTable.Entry> & List<&2, MemTable.Entry>:
215 match order:
216 case LT{}:
217 (Con{newer_head, acc}, newer_tail, Con{older_head, older_tail})
218 case EQ{}:
219 (Con{newer_head, acc}, newer_tail, older_tail)
220 case GT{}:
221 (Con{older_head, acc}, Con{newer_head, newer_tail}, older_tail)
222
223
224def merge_go(
225 fuel: Nat,
226 state: List<&2, MemTable.Entry> & List<&2, MemTable.Entry> & List<&2, MemTable.Entry>
227) -> List<&2, MemTable.Entry>:
228 match fuel:
229 case 0n:
230 (acc, newer, older) = state
231 List.reverse.go(&2, MemTable.Entry, acc, List.append(&2, MemTable.Entry, newer, older))
232 case 1n+f:
233 (acc, newer, older) = state
234 match newer older:
235 case Nil{} Nil{}:
236 List.reverse(&2, MemTable.Entry, acc)
237 case Nil{} rest:
238 List.reverse.go(&2, MemTable.Entry, acc, rest)
239 case rest Nil{}:
240 List.reverse.go(&2, MemTable.Entry, acc, rest)
241 case Con{+nh, nt} Con{+oh, ot}:
242 merge_go(f, merge_step(entry_cmp(nh, oh), nh, nt, oh, ot, acc))
243
244
245def merge_newer(+newer: List<&2, MemTable.Entry>, +older: List<&2, MemTable.Entry>) -> List<&2, MemTable.Entry>:
246 fuel = Nat.add(Nat.add(List.length(&2, MemTable.Entry, newer), List.length(&2, MemTable.Entry, older)), 1n)
247 merge_go(fuel, (Nil{}, newer, older))
248
249
250
251
252type RunGroup is Data:
253 RunGroup{
254 newest_rank: Nat,
255 oldest_rank: Nat,
256 entries: List<&2, MemTable.Entry>
257 }
258
259
260def rank_runs(runs: List<&2, List<&2, MemTable.Entry>>, +rank: Nat) -> List<&2, RunGroup>:
261 match runs:
262 case Nil{}:
263 Nil{}
264 case Con{entries, rest}:
265 Con{RunGroup{rank, rank, entries}, rank_runs(rest, 1n+rank)}
266
267
268def merge_groups(newer: RunGroup, older: RunGroup) -> RunGroup:
269 match newer:
270 case RunGroup{newest_rank, oldest_rank, newer_entries}:
271 match older:
272 case RunGroup{older_newest, older_oldest, older_entries}:
273 RunGroup{newest_rank, older_oldest, merge_newer(newer_entries, older_entries)}
274
275
276def merge_round(groups: List<&2, RunGroup>) -> List<&2, RunGroup>:
277 match groups:
278 case Nil{}:
279 Nil{}
280 case Con{group, Nil{}}:
281 Con{group, Nil{}}
282 case Con{newer, Con{older, rest}}:
283 merged tail = merge_groups(newer, older) merge_round(rest)
284 Con{merged, tail}
285
286
287def group_entries(groups: List<&2, RunGroup>) -> List<&2, MemTable.Entry>:
288 match groups:
289 case Nil{}:
290 Nil{}
291 case Con{RunGroup{newest_rank, oldest_rank, entries}, rest}:
292 entries
293
294
295def merge_many_go(fuel: Nat, groups: List<&2, RunGroup>) -> List<&2, MemTable.Entry>:
296 match fuel:
297 case 0n:
298 group_entries(groups)
299 case 1n+f:
300 merge_many_go(f, merge_round(groups))
301
302
303def merge_many_newest(+runs: List<&2, List<&2, MemTable.Entry>>) -> List<&2, MemTable.Entry>:
304 fuel = Nat.add(List.length(&2, List<&2, MemTable.Entry>, runs), 1n)
305 merge_many_go(fuel, rank_runs(runs, 0n))
306
307
308
309def singleton_runs(entries: List<&2, MemTable.Entry>) -> List<&2, List<&2, MemTable.Entry>>:
310 match entries:
311 case Nil{}:
312 Nil{}
313 case Con{entry, rest}:
314 Con{Con{entry, Nil{}}, singleton_runs(rest)}
315
316
317def sort_newest(entries: List<&2, MemTable.Entry>) -> List<&2, MemTable.Entry>:
318 merge_many_newest(singleton_runs(entries))
319
320
321
322
323
324
325def partition_target(target: Nat) -> Nat:
326 match target:
327 case 0n:
328 1n
329 case 1n+n:
330 1n+n
331
332
333def partition_finish(
334 current_rev: List<&2, MemTable.Entry>,
335 chunks_rev: List<&2, List<&2, MemTable.Entry>>
336) -> List<&2, List<&2, MemTable.Entry>>:
337 match current_rev:
338 case Nil{}:
339 List.reverse(&2, List<&2, MemTable.Entry>, chunks_rev)
340 case Con{entry, rest}:
341 chunk = List.reverse(&2, MemTable.Entry, Con{entry, rest})
342 List.reverse(&2, List<&2, MemTable.Entry>, Con{chunk, chunks_rev})
343
344
345type PartitionState is Data:
346 PartitionState{
347 room: Nat,
348 entries: List<&2, MemTable.Entry>,
349 current_rev: List<&2, MemTable.Entry>,
350 chunks_rev: List<&2, List<&2, MemTable.Entry>>
351 }
352
353
354def partition_step(
355 full: Bool,
356 target: Nat,
357 room_after: Nat,
358 entry: MemTable.Entry,
359 rest: List<&2, MemTable.Entry>,
360 current_rev: List<&2, MemTable.Entry>,
361 chunks_rev: List<&2, List<&2, MemTable.Entry>>
362) -> PartitionState:
363 match full:
364 case False{}:
365 PartitionState{room_after, rest, Con{entry, current_rev}, chunks_rev}
366 case True{}:
367 chunk = List.reverse(&2, MemTable.Entry, Con{entry, current_rev})
368 PartitionState{target, rest, Nil{}, Con{chunk, chunks_rev}}
369
370
371def partition_go(
372 fuel: Nat,
373 +target: Nat,
374 state: PartitionState
375) -> List<&2, List<&2, MemTable.Entry>>:
376 match fuel state:
377 case 0n PartitionState{room, entries, current_rev, chunks_rev}:
378 partition_finish(current_rev, chunks_rev)
379 case 1n+f PartitionState{0n, entries, current_rev, chunks_rev}:
380 partition_finish(current_rev, chunks_rev)
381 case 1n+f PartitionState{1n+r, Nil{}, current_rev, chunks_rev}:
382 partition_finish(current_rev, chunks_rev)
383 case 1n+f PartitionState{1n++r, Con{entry, rest}, current_rev, chunks_rev}:
384 partition_go(f, target, partition_step(Nat.is_eq(r, 0n), target, r, entry, rest, current_rev, chunks_rev))
385
386
387def partition(+target: Nat, +entries: List<&2, MemTable.Entry>) -> List<&2, List<&2, MemTable.Entry>>:
388 +size = partition_target(target)
389 partition_go(List.length(&2, MemTable.Entry, entries), size, PartitionState{size, entries, Nil{}, Nil{}})
390
391
392def concat_chunks(chunks: List<&2, List<&2, MemTable.Entry>>) -> List<&2, MemTable.Entry>:
393 match chunks:
394 case Nil{}:
395 Nil{}
396 case Con{chunk, rest}:
397 List.append(&2, MemTable.Entry, chunk, concat_chunks(rest))
398
399
400def chunks_bounded_go(+target: Nat, chunks: List<&2, List<&2, MemTable.Entry>>) -> Bool:
401 match chunks:
402 case Nil{}:
403 True{}
404 case Con{chunk, rest}:
405 bool_and(
406 Nat.is_le(List.length(&2, MemTable.Entry, chunk), target),
407 chunks_bounded_go(target, rest))
408
409
410def chunks_bounded(target: Nat, chunks: List<&2, List<&2, MemTable.Entry>>) -> Bool:
411 chunks_bounded_go(partition_target(target), chunks)
412
413
414def chunks_strict_unique(chunks: List<&2, List<&2, MemTable.Entry>>) -> Bool:
415 runs_well_formed(chunks)
416
417
418def chunks_pairwise_disjoint(chunks: List<&2, List<&2, MemTable.Entry>>) -> Bool:
419 pairwise_disjoint(chunks)