From 6435dd636c40d2fbb41c7abfdfda14d50d4cea23 Mon Sep 17 00:00:00 2001 From: Bron Gondwana Date: Sat, 11 Jan 2025 14:27:04 +1100 Subject: [PATCH] ctl_conversationsdb: buffers --- imap/ctl_conversationsdb.c | 87 ++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/imap/ctl_conversationsdb.c b/imap/ctl_conversationsdb.c index df4631130d..bbb60d4a3e 100644 --- a/imap/ctl_conversationsdb.c +++ b/imap/ctl_conversationsdb.c @@ -448,8 +448,8 @@ struct cursor { struct db *db; struct txn **txnp; - const char *key; size_t keylen; - const char *data; size_t datalen; + struct buf keybuf; + struct buf valbuf; int err; }; @@ -463,24 +463,22 @@ static void cursor_init(struct cursor *c, static int cursor_next(struct cursor *c) { - if (!c->err) + if (!c->err) { + const char *key = NULL; + size_t keylen = 0; + const char *val = NULL; + size_t vallen = 0; c->err = cyrusdb_fetchnext(c->db, - c->key, c->keylen, - &c->key, &c->keylen, - &c->data, &c->datalen, + c->keybuf.s, c->keybuf.len, + &key, &keylen, + &val, &vallen, c->txnp); + buf_setmap(&c->keybuf, key, keylen); + buf_setmap(&c->valbuf, val, vallen); + } return c->err; } -static int blob_compare(const char *a, size_t alen, - const char *b, size_t blen) -{ - int d = memcmp(a, b, MIN(alen, blen)); - if (!d) - d = alen - blen; - return d; -} - static int next_diffable_record(struct cursor *c) { for (;;) @@ -490,11 +488,11 @@ static int next_diffable_record(struct cursor *c) /* skip < records, they won't be in the * temp database and we don't care so much */ - if (c->key[0] == '<') + if (c->keybuf.s[0] == '<') continue; /* Subject, not re-calculated */ - if (c->key[0] == 'S') + if (c->keybuf.s[0] == 'S') continue; return 0; @@ -517,13 +515,13 @@ static unsigned int diff_records(struct conversations_state *a, rb = cursor_next(&cb); while (!ra || !rb) { - keydelta = blob_compare(ca.key, ca.keylen, cb.key, cb.keylen); + keydelta = buf_cmp(&ca.keybuf, &cb.keybuf); if (rb || keydelta < 0) { if (ra) break; ndiffs++; if (verbose) printf("REALONLY: \"%.*s\" data \"%.*s\"\n", - (int)ca.keylen, ca.key, (int)ca.datalen, ca.data); + (int)ca.keybuf.len, ca.keybuf.s, (int)ca.valbuf.len, ca.valbuf.s); ra = next_diffable_record(&ca); continue; } @@ -532,26 +530,31 @@ static unsigned int diff_records(struct conversations_state *a, ndiffs++; if (verbose) printf("TEMPONLY: \"%.*s\" data \"%.*s\"\n", - (int)cb.keylen, cb.key, (int)cb.datalen, cb.data); + (int)cb.keybuf.len, cb.keybuf.s, (int)cb.valbuf.len, cb.valbuf.s); rb = next_diffable_record(&cb); continue; } /* both exist an are the same key */ - delta = blob_compare(ca.data, ca.datalen, cb.data, cb.datalen); + delta = buf_cmp(&ca.valbuf, &cb.valbuf); if (delta) { ndiffs++; if (verbose) printf("REAL: \"%.*s\" data \"%.*s\"\n" "TEMP: \"%.*s\" data \"%.*s\"\n", - (int)ca.keylen, ca.key, (int)ca.datalen, ca.data, - (int)cb.keylen, cb.key, (int)cb.datalen, cb.data); + (int)ca.keybuf.len, ca.keybuf.s, (int)ca.valbuf.len, ca.valbuf.s, + (int)cb.keybuf.len, cb.keybuf.s, (int)cb.valbuf.len, cb.valbuf.s); } ra = next_diffable_record(&ca); rb = next_diffable_record(&cb); } + buf_free(&ca.keybuf); + buf_free(&ca.valbuf); + buf_free(&cb.keybuf); + buf_free(&cb.valbuf); + return ndiffs; } @@ -570,20 +573,20 @@ static int fix_modseqs(struct conversations_state *a, rb = cursor_next(&cb); while (!ra || !rb) { - keydelta = blob_compare(ca.key, ca.keylen, cb.key, cb.keylen); + keydelta = buf_cmp(&ca.keybuf, &cb.keybuf); if (rb || keydelta < 0) { if (ra) break; - if (ca.key[0] == 'F') { + if (ca.keybuf.s[0] == 'F') { conv_status_t status = CONV_STATUS_INIT; /* need to add record if it's zero */ - r = conversation_parsestatus(ca.data, ca.datalen, &status); + r = conversation_parsestatus(ca.valbuf.s, ca.valbuf.len, &status); if (r) return r; if (status.threadexists == 0) { - r = conversation_storestatus(b, ca.key, ca.keylen, &status); + r = conversation_storestatus(b, ca.keybuf.s, ca.keybuf.len, &status); if (r) { fprintf(stderr, "Failed to store conversations " "record \"%.*s\" to %s: %s, giving up\n", - (int)ca.keylen, ca.key, + (int)ca.keybuf.len, ca.keybuf.s, b->path, error_message(r)); return r; } @@ -600,37 +603,37 @@ static int fix_modseqs(struct conversations_state *a, } /* folders? Just modseq check */ - if (ca.key[0] == 'F') { + if (ca.keybuf.s[0] == 'F') { /* check if modseq is higher for real */ conv_status_t statusa = CONV_STATUS_INIT; conv_status_t statusb = CONV_STATUS_INIT; /* need to add record if it's zero */ - r = conversation_parsestatus(ca.data, ca.datalen, &statusa); + r = conversation_parsestatus(ca.valbuf.s, ca.valbuf.len, &statusa); if (r) { fprintf(stderr, "Failed to parse conversations " "record \"%.*s\" in %s: %s\n", - (int)ca.keylen, ca.key, + (int)ca.keybuf.len, ca.keybuf.s, a->path, error_message(r)); /* There's no need to report failure to the caller - the * record diffing passing that occurs after this will * also pick up the same problem */ goto next; } - r = conversation_parsestatus(cb.data, cb.datalen, &statusb); + r = conversation_parsestatus(cb.valbuf.s, cb.valbuf.len, &statusb); if (r) { fprintf(stderr, "Failed to parse conversations " "record \"%.*s\" in %s: %s\n", - (int)cb.keylen, cb.key, + (int)cb.keybuf.len, cb.keybuf.s, b->path, error_message(r)); goto next; } if (statusa.threadmodseq > statusb.threadmodseq) { statusb.threadmodseq = statusa.threadmodseq; - r = conversation_storestatus(b, cb.key, cb.keylen, &statusb); + r = conversation_storestatus(b, cb.keybuf.s, cb.keybuf.len, &statusb); if (r) { fprintf(stderr, "Failed to store conversations " "record \"%.*s\" to %s: %s, giving up\n", - (int)cb.keylen, cb.key, + (int)cb.keybuf.len, cb.keybuf.s, b->path, error_message(r)); /* If we cannot write to the temp DB, something is * drastically wrong and we need to report a failure */ @@ -638,7 +641,7 @@ static int fix_modseqs(struct conversations_state *a, } } } - if (ca.key[0] == 'B') { + if (ca.keybuf.s[0] == 'B') { /* B keys - check all the modseqs, both top level and per folder */ conversation_t conva = CONVERSATION_INIT; conversation_t convb = CONVERSATION_INIT; @@ -646,19 +649,19 @@ static int fix_modseqs(struct conversations_state *a, conv_folder_t *folderb; conv_sender_t *sendera; - r = conversation_parse(ca.data, ca.datalen, &conva, CONV_WITHALL); + r = conversation_parse(ca.valbuf.s, ca.valbuf.len, &conva, CONV_WITHALL); if (r) { fprintf(stderr, "Failed to parse conversations " "record \"%.*s\" in %s: %s\n", - (int)ca.keylen, ca.key, + (int)ca.keybuf.len, ca.keybuf.s, a->path, error_message(r)); goto next; } - r = conversation_parse(cb.data, cb.datalen, &convb, CONV_WITHALL); + r = conversation_parse(cb.valbuf.s, cb.valbuf.len, &convb, CONV_WITHALL); if (r) { fprintf(stderr, "Failed to parse conversations " "record \"%.*s\" in %s: %s\n", - (int)cb.keylen, cb.key, + (int)cb.keybuf.len, cb.keybuf.s, b->path, error_message(r)); conversation_fini(&conva); goto next; @@ -688,7 +691,7 @@ static int fix_modseqs(struct conversations_state *a, /* be nice to know if this is needed, but at least twoskip * will dedup for us */ - r = conversation_store(b, cb.key, cb.keylen, &convb); + r = conversation_store(b, cb.keybuf.s, cb.keybuf.len, &convb); /* free first before checking for errors */ conversation_fini(&conva); @@ -697,7 +700,7 @@ static int fix_modseqs(struct conversations_state *a, if (r) { fprintf(stderr, "Failed to store conversations " "record \"%.*s\" to %s: %s, giving up\n", - (int)cb.keylen, cb.key, + (int)cb.keybuf.len, cb.keybuf.s, b->path, error_message(r)); return r; }