skip to content
==> src/merge.c <==
1/* jobs.rs's Answer and merge. */
2#include "mesh/jobs/merge.h"
3
4#include <stdlib.h>
5#include <string.h>
6
7static void ops_free(void *v) { mj_ops_free(v); }
8static void ops_copy(void *d, const void *s) { *(mj_ops *)d = mj_ops_clone(s); }
9
10void mj_answer_init(mj_answer *a) {
11    memset(a, 0, sizeof *a);
12    mj_table_init(&a->committed);
13    a->entries = momap_new(2, sizeof(mj_ops), ops_free, ops_copy);
14}
15
16void mj_answer_free(mj_answer *a) {
17    mj_table_free(&a->committed);
18    momap_free(a->entries);
19    memset(a, 0, sizeof *a);
20}
21
22mj_ops *mj_answer_entry(mj_answer *a, uint64_t lid, uint64_t n) {
23    uint64_t k[2] = {lid, n};
24    return momap_put(a->entries, k, NULL);
25}
26
27mj_answer mj_answer_of(const mj_replica *r) {
28    mj_answer a;
29    mj_answer_init(&a);
30    a.commit_lid = r->commit_lid;
31    a.commit_n = r->commit_n;
32    mj_table_free(&a.committed);
33    a.committed = mj_table_clone(&r->committed);
34    for (size_t i = 0; i < r->npending; i++) {
35        const mj_entry *e = &r->pending[i];
36        mj_ops ops = {0};
37        if (e->replace) mj_table_ops(&e->table, &ops);
38        else ops = mj_ops_clone(&e->ops);
39        mj_ops *slot = mj_answer_entry(&a, e->lid, e->n);
40        mj_ops_free(slot); /* a later entry under the same key replaces it, as BTreeMap::insert does */
41        *slot = ops;
42    }
43    return a;
44}
45
46mj_table mj_merge(mj_answer *const *answers, size_t n) {
47    mj_table t;
48    mj_table_init(&t);
49    /* The committed tables, the latest commit point first (a stable sort: ties keep member order). */
50    mj_answer **by = n ? mxalloc(n * sizeof *by) : NULL;
51    memcpy(by, answers, n * sizeof *by);
52    for (size_t i = 1; i < n; i++) {
53        mj_answer *x = by[i];
54        size_t j = i;
55        while (j > 0 && (by[j - 1]->commit_lid < x->commit_lid || (by[j - 1]->commit_lid == x->commit_lid && by[j - 1]->commit_n < x->commit_n))) {
56            by[j] = by[j - 1];
57            j--;
58        }
59        by[j] = x;
60    }
61    for (size_t i = 0; i < n; i++) {
62        mj_ops ops = {0};
63        mj_table_ops(&by[i]->committed, &ops);
64        for (size_t k = 0; k < ops.n; k++) mj_table_apply(&t, &ops.v[k]);
65        mj_ops_free(&ops);
66    }
67    free(by);
68    /* The entries not committed yet, keyed (latest leadership first, then number); the first answer's wins. */
69    momap *entries = momap_new(2, sizeof(const mj_ops *), NULL, NULL);
70    for (size_t i = 0; i < n; i++) {
71        uint64_t k[2];
72        for (const mj_ops *ops = momap_first(answers[i]->entries, k); ops; ops = momap_next(answers[i]->entries, k, k)) {
73            uint64_t key[2] = {UINT64_MAX - k[0], k[1]};
74            bool fresh;
75            const mj_ops **slot = momap_put(entries, key, &fresh);
76            if (fresh) *slot = ops;
77        }
78    }
79    uint64_t k[2];
80    for (const mj_ops **ops = momap_first(entries, k); ops; ops = momap_next(entries, k, k))
81        for (size_t j = 0; j < (*ops)->n; j++) mj_table_apply(&t, &(*ops)->v[j]);
82    momap_free(entries);
83    return t;
84}