==> tests/merge.c <==1/* The merge: random answers (committed tables at random commit points, entries of random
2 * leaderships) merged here and in the Rust to the same table; an answer built from a replica. */
3#include "mesh/jobs/merge.h"
4#include "mesh/check.h"
5#include "gen.h"
6#include "gold_merge.h"
7
8static uint64_t fnv(const void *p, size_t n) {
9 const uint8_t *b = p;
10 uint64_t h = 0xcbf29ce484222325u;
11 for (size_t i = 0; i < n; i++) {
12 h ^= b[i];
13 h *= 0x100000001b3u;
14 }
15 return h;
16}
17
18int main(void) {
19 size_t g = 0, ng = sizeof GOLD / sizeof *GOLD;
20 char line[128];
21 for (uint64_t seeds[] = {2, 4, 8, 16, 32}, *sd = seeds; sd < seeds + 5; sd++) {
22 rs = *sd * 0x9e3779b97f4a7c15u | 1;
23 for (int round = 0; round < 20; round++) {
24 mj_answer slot[6];
25 bool have[6] = {0};
26 uint64_t k = 1 + rnd(4);
27 for (uint64_t i = 0; i < k; i++) {
28 uint32_t m = (uint32_t)rnd(6);
29 mj_answer a;
30 mj_answer_init(&a);
31 uint64_t cl = rnd(3) << 40;
32 a.commit_lid = cl;
33 a.commit_n = rnd(4);
34 uint64_t nops = rnd(30);
35 for (uint64_t j = 0; j < nops; j++) {
36 mj_op o = gen();
37 mj_table_apply(&a.committed, &o);
38 mj_op_free(&o);
39 }
40 uint64_t ne = rnd(4);
41 for (uint64_t j = 0; j < ne; j++) {
42 uint64_t lid = (1 + rnd(3)) << 40;
43 uint64_t n = rnd(5), c = rnd(6);
44 mj_ops ops = {0};
45 for (uint64_t q = 0; q < c; q++) mj_ops_push(&ops, gen());
46 mj_ops *e = mj_answer_entry(&a, lid, n);
47 mj_ops_free(e);
48 *e = ops;
49 }
50 if (have[m]) mj_answer_free(&slot[m]);
51 slot[m] = a;
52 have[m] = true;
53 }
54 mj_answer *in[6];
55 size_t n = 0;
56 for (int m = 0; m < 6; m++)
57 if (have[m]) in[n++] = &slot[m];
58 mj_table t = mj_merge(in, n);
59 mj_ops to = {0};
60 mj_table_ops(&t, &to);
61 msb enc = {0};
62 mj_encode_ops(to.v, to.n, &enc);
63 snprintf(line, sizeof line, "%llu %d %zu %016llx %zu", (unsigned long long)*sd, round, n, (unsigned long long)fnv(enc.p, enc.n), enc.n);
64 if (CHECK(g < ng)) CHECK_S(line, GOLD[g]);
65 g++;
66 msb_free(&enc);
67 mj_ops_free(&to);
68 mj_table_free(&t);
69 for (int m = 0; m < 6; m++)
70 if (have[m]) mj_answer_free(&slot[m]);
71 }
72 }
73 CHECK_U(g, ng);
74 /* A replica's own answer: its committed table, and each pending entry under (lid, n). */
75 mj_replica r;
76 mj_replica_init(&r);
77 mj_spec s = gspec(0);
78 mj_ops one = {0};
79 mj_ops_push(&one, mj_op_submit(&s));
80 mj_log e1 = mj_log_entry((uint64_t)2 << 40, 1, true, one);
81 mj_replica_apply(&r, &e1);
82 mj_answer a = mj_answer_of(&r);
83 uint64_t key[2] = {(uint64_t)2 << 40, 1};
84 mj_ops *got = momap_get(a.entries, key);
85 CHECK(got && got->n == 1 && got->v[0].kind == MJ_OP_SUBMIT);
86 mj_answer *in[1] = {&a};
87 mj_table t = mj_merge(in, 1);
88 CHECK(mj_table_get(&t, s.id) != NULL);
89 mj_table_free(&t);
90 mj_answer_free(&a);
91 mj_log_free(&e1);
92 mj_spec_free(&s);
93 mj_replica_free(&r);
94 return mesh_check_done();
95}