skip to content
==> src/text.c <==
1/* jobd.rs's jobs_text, job_line, status_text and results_text. */
2#include "mesh/jobd/text.h"
3#include "mesh/jobs/lid.h"
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8
9const char *mjd_role(const mjd_text_cx *cx) {
10    if (mj_node_active(cx->node)) return "leader";
11    if (mj_node_leading(cx->node)) return "leader-merging";
12    return cx->peered ? "follower" : "single";
13}
14
15static void leader_word(const mj_view *v, char out[16]) {
16    if (v->has_leader) snprintf(out, 16, "%u", v->leader);
17    else strcpy(out, "-");
18}
19
20/* Items of job id in the leader's leases (false: not leading). */
21static bool leased_of(const mj_node *n, mj_job_id id, uint64_t *sum) {
22    const momap *ls = mj_node_leases(n);
23    if (!ls) return false;
24    *sum = 0;
25    momap_iter it;
26    momap_iter_init(&it, ls);
27    for (const mj_lease *x = momap_iter_next(&it, NULL); x; x = momap_iter_next(&it, NULL))
28        if (x->job == id) *sum += mj_ranges_len(&x->out);
29    return true;
30}
31
32void mjd_job_line(const mjd_text_cx *cx, const mj_job *j, msb *out) {
33    mj_job_id id = j->spec.id;
34    uint64_t leased, queued, end = j->finished ? j->finish_at : cx->unix_ms;
35    uint64_t elapsed = end > j->spec.submitted_ms ? end - j->spec.submitted_ms : 0;
36    char w[MJ_JOB_WORD_MAX];
37    mj_job_word(id, w);
38    msb_printf(out, "job %s program %s state %s priority %d items ", w, j->spec.program, mj_job_state(j), j->spec.priority);
39    if (mj_spec_endless(&j->spec)) msb_puts(out, "endless");
40    else msb_printf(out, "%llu", (unsigned long long)mj_job_total(j));
41    uint64_t done = mj_ranges_len(&j->done);
42    msb_printf(out, " done %llu failed %zu leased ", (unsigned long long)done, momap_len(j->failed));
43    if (leased_of(cx->node, id, &leased)) msb_printf(out, "%llu", (unsigned long long)leased);
44    else msb_putc(out, '-');
45    msb_puts(out, " queued ");
46    if (mj_node_queued(cx->node, id, &queued)) msb_printf(out, "%llu", (unsigned long long)queued);
47    else msb_putc(out, '-');
48    msb_printf(out, " dupes %llu mode %s elapsed_ms %llu rate %.1f\n", (unsigned long long)j->dupes, mj_mode_word(j->spec.mode),
49               (unsigned long long)elapsed, (double)done * 1000.0 / (double)(elapsed ? elapsed : 1));
50}
51
52char *mjd_jobs_text(const mjd_text_cx *cx) {
53    const mj_node *n = cx->node;
54    const mj_table *t = mj_node_committed(n);
55    size_t jobs = 0, active = 0;
56    uint64_t id;
57    for (const mj_job *j = mj_table_first(t, &id); j; j = mj_table_next(t, &id)) {
58        jobs++;
59        active += mj_job_active(j);
60    }
61    char lw[16];
62    leader_word(&cx->view, lw);
63    msb b = {0};
64    msb_printf(&b, "jobs system %u leader %s role %s lid %llx commit %llu jobs %zu active %zu held %zu unconfirmed %zu staged %zu parked %zu rate %.1f\n",
65               n->cfg.me, lw, mjd_role(cx), (unsigned long long)mj_node_lid(n), (unsigned long long)mj_node_commit_n(n), jobs, active,
66               momap_len(n->held), mj_node_unconfirmed(n), mj_node_staged(n), mj_node_parked(n), mj_node_my_rate(n));
67    for (const mj_job *j = mj_table_first(t, &id); j; j = mj_table_next(t, &id)) mjd_job_line(cx, j, &b);
68    const mj_mpmap *rates = mj_node_rates(n);
69    if (rates)
70        for (size_t i = 0; i < rates->n; i++)
71            msb_printf(&b, "rate system %u program %s items_per_s %.1f\n", rates->v[i].member, rates->v[i].program, rates->v[i].rate.ips);
72    return msb_take(&b);
73}
74
75static bool no_job(mj_job_id id, char **text) {
76    char w[MJ_JOB_WORD_MAX];
77    mj_job_word(id, w);
78    *text = mfmt("no job %s (committed here)", w);
79    return false;
80}
81
82bool mjd_status_text(const mjd_text_cx *cx, mj_job_id id, char **text) {
83    const mj_job *j = mj_table_get(mj_node_committed(cx->node), id);
84    if (!j) return no_job(id, text);
85    msb b = {0};
86    mjd_job_line(cx, j, &b);
87    msb_puts(&b, "spec ");
88    mj_spec_encode(&j->spec, &b);
89    msb_putc(&b, '\n');
90    /* Per member: who ran how many (committed). */
91    uint64_t k;
92    for (const uint64_t *c = momap_first(j->by_member, &k); c; c = momap_next(j->by_member, &k, &k))
93        msb_printf(&b, "member %llu done %llu\n", (unsigned long long)k, (unsigned long long)*c);
94    const momap *ls = mj_node_leases(cx->node);
95    if (ls) {
96        uint64_t lk;
97        for (const mj_lease *x = momap_first(ls, &lk); x; x = momap_next(ls, &lk, &lk)) {
98            if (x->job != id) continue;
99            msb_printf(&b, "lease %llx system %u items %llu left %llu (", (unsigned long long)x->id, x->member, (unsigned long long)x->size,
100                       (unsigned long long)mj_ranges_len(&x->out));
101            mj_ranges_word(&x->out, &b);
102            msb_puts(&b, ")\n");
103        }
104    }
105    /* The lease choice (F4's filter and score), as the leader made it last. */
106    const mj_picks *p = mj_node_picks(cx->node, id);
107    if (p)
108        for (size_t i = 0; i < p->n; i++) {
109            char *l = mj_pick_line(&p->v[i]);
110            msb_printf(&b, "%s\n", l);
111            free(l);
112        }
113    else if (mj_job_active(j)) {
114        char lw[16];
115        leader_word(&cx->view, lw);
116        msb_printf(&b, "pick on the leader (system %s): its `job status` explains the lease choice\n", lw);
117    }
118    if (j->cancel) msb_printf(&b, "cancel %s\n", j->cancel);
119    size_t shown = 0;
120    for (const mj_failed *f = momap_first(j->failed, &k); f && shown < 50; f = momap_next(j->failed, &k, &k), shown++)
121        msb_printf(&b, "failed %llu tries %u %s\n", (unsigned long long)k, f->tries, f->why);
122    size_t retried = momap_len(j->fails);
123    if (retried > 0) msb_printf(&b, "retried %zu item(s)\n", retried);
124    *text = msb_take(&b);
125    return true;
126}
127
128bool mjd_results_text(const mjd_text_cx *cx, mj_job_id id, uint64_t from, uint64_t n, char **text) {
129    const mj_job *j = mj_table_get(mj_node_committed(cx->node), id);
130    if (!j) return no_job(id, text);
131    msb s = {0};
132    uint64_t c = 0, i = 0, item;
133    momap_iter it;
134    momap_iter_init(&it, j->results);
135    for (const mj_res *r = momap_iter_next1(&it, &item); r && c < n; r = momap_iter_next1(&it, &item), i++) {
136        if (i < from) continue;
137        msb_printf(&s, "%llu %u lease %llx member %u", (unsigned long long)item, r->result, (unsigned long long)r->lease, r->member);
138        if (r->out_len) {
139            msb_puts(&s, " out ");
140            for (size_t q = 0; q < r->out_len; q++) msb_printf(&s, "%02x", r->out[q]);
141        }
142        if (r->has_blob) {
143            char x[65];
144            mj_hex(&r->blob.hash, x);
145            msb_printf(&s, " blob %s len %u holders 0x%x", x, r->blob.len, r->blob.holders);
146        }
147        msb_putc(&s, '\n');
148        c++;
149    }
150    char w[MJ_JOB_WORD_MAX];
151    mj_job_word(id, w);
152    msb b = {0};
153    msb_printf(&b, "results %s total %zu from %llu count %llu done %llu failed %zu dupes %llu state %s\n%s", w, momap_len(j->results),
154               (unsigned long long)from, (unsigned long long)c, (unsigned long long)mj_ranges_len(&j->done), momap_len(j->failed),
155               (unsigned long long)j->dupes, mj_job_state(j), msb_str(&s));
156    msb_free(&s);
157    *text = msb_take(&b);
158    return true;
159}