From 96fbb1f42531ac0aad339ed0cb1c6416d4dee92d Mon Sep 17 00:00:00 2001 From: Phil Carmody Date: Mon, 29 Feb 2016 19:29:14 +0200 Subject: [PATCH] plugins: fts-expunge-log - subtraction from and dumping of a flattened log This permits you to read a whole expunge log, remove records from the in-memory copy of it, and write it back out to file. NOTE: Inefficiently implemented. The hash is effectively rebuilt, this time backed by a file, a record at a time, which implies O(n^2) possibilities. Signed-off-by: Phil Carmody --- src/plugins/fts/fts-expunge-log.c | 53 +++++++++++++++++++++++++++++++ src/plugins/fts/fts-expunge-log.h | 10 +++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/plugins/fts/fts-expunge-log.c b/src/plugins/fts/fts-expunge-log.c index 37f5fdbe38..27ce54ee88 100644 --- a/src/plugins/fts/fts-expunge-log.c +++ b/src/plugins/fts/fts-expunge-log.c @@ -253,6 +253,14 @@ void fts_expunge_log_append_record(struct fts_expunge_log_append_ctx *ctx, array_foreach(&record->uids, range) fts_expunge_log_append_range(ctx, record->mailbox_guid, range); } +static void fts_expunge_log_append_mailbox_record(struct fts_expunge_log_append_ctx *ctx, + struct fts_expunge_log_mailbox *mailbox) +{ + const struct seq_range *range; + /* FIXME: Optimise with a merge */ + array_foreach(&mailbox->uids, range) + fts_expunge_log_append_range(ctx, mailbox->guid, range); +} static void fts_expunge_log_export(struct fts_expunge_log_append_ctx *ctx, @@ -556,3 +564,48 @@ bool fts_expunge_log_contains(const struct fts_expunge_log_append_ctx *ctx, return FALSE; return seq_range_exists(&mailbox->uids, uid); } +void fts_expunge_log_append_remove(struct fts_expunge_log_append_ctx *from, + const struct fts_expunge_log_read_record *record) +{ + const uint8_t *guid_p = record->mailbox_guid; + struct fts_expunge_log_mailbox *mailbox = hash_table_lookup(from->mailboxes, guid_p); + i_assert(mailbox != NULL); /* may only remove things that exist */ + mailbox->uids_count -= seq_range_array_remove_seq_range(&mailbox->uids, &record->uids); +} +int fts_expunge_log_subtract(struct fts_expunge_log_append_ctx *from, + struct fts_expunge_log *subtract) +{ + struct fts_expunge_log_read_ctx *read_ctx = fts_expunge_log_read_begin(subtract); + read_ctx->unlink = FALSE; + + const struct fts_expunge_log_read_record *record; + while ((record = fts_expunge_log_read_next(read_ctx)) != NULL) + fts_expunge_log_append_remove(from, record); + + return fts_expunge_log_read_end(&read_ctx); +} +/* It could be argued that somehow adding a log (file) to the append context + and then calling the _write() helper would be easier. But then there's the + _commit() vs. _abort() cleanup that would need to be addressed. Just creating + a copy is simpler. */ +int fts_expunge_log_flat_write(const struct fts_expunge_log_append_ctx *read_log, + const char *path) +{ + int ret; + struct fts_expunge_log *nlog = fts_expunge_log_init(path); + struct fts_expunge_log_append_ctx *nappend = fts_expunge_log_append_begin(nlog); + + struct hash_iterate_context *iter; + uint8_t *guid_p; + struct fts_expunge_log_mailbox *mailbox; + + iter = hash_table_iterate_init(read_log->mailboxes); + while (hash_table_iterate(iter, read_log->mailboxes, &guid_p, &mailbox)) + fts_expunge_log_append_mailbox_record(nappend, mailbox); + + hash_table_iterate_deinit(&iter); + ret = fts_expunge_log_append_commit(&nappend); + fts_expunge_log_deinit(&nlog); + + return ret; +} diff --git a/src/plugins/fts/fts-expunge-log.h b/src/plugins/fts/fts-expunge-log.h index 0b4647fb74..557dbe2d8d 100644 --- a/src/plugins/fts/fts-expunge-log.h +++ b/src/plugins/fts/fts-expunge-log.h @@ -22,6 +22,9 @@ void fts_expunge_log_append_range(struct fts_expunge_log_append_ctx *ctx, const struct seq_range *uids); void fts_expunge_log_append_record(struct fts_expunge_log_append_ctx *ctx, const struct fts_expunge_log_read_record *record); +/* in-memory flattened structures may have records removed from them, file-backed ones may not */ +void fts_expunge_log_append_remove(struct fts_expunge_log_append_ctx *ctx, + const struct fts_expunge_log_read_record *record); int fts_expunge_log_append_commit(struct fts_expunge_log_append_ctx **ctx); /* Do not commit non-backed structures, abort them after use. */ int fts_expunge_log_append_abort(struct fts_expunge_log_append_ctx **ctx); @@ -43,5 +46,10 @@ int fts_expunge_log_flatten(const char *path, struct fts_expunge_log_append_ctx **flattened_r); bool fts_expunge_log_contains(const struct fts_expunge_log_append_ctx *ctx, const guid_128_t mailbox_guid, uint32_t uid); - +/* Modify in-place a flattened log. */ +int fts_expunge_log_subtract(struct fts_expunge_log_append_ctx *from, + struct fts_expunge_log *subtract); +/* Write a modified flattened log as a new file. */ +int fts_expunge_log_flat_write(const struct fts_expunge_log_append_ctx *flattened, + const char *path); #endif