]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
plugins: fts-expunge-log - subtraction from and dumping of a flattened log
authorPhil Carmody <phil@dovecot.fi>
Mon, 29 Feb 2016 17:29:14 +0000 (19:29 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 16 Mar 2016 01:31:20 +0000 (12:31 +1100)
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 <phil@dovecot.fi>
src/plugins/fts/fts-expunge-log.c
src/plugins/fts/fts-expunge-log.h

index 37f5fdbe388ffc120ae931cc00dd20840f423198..27ce54ee88ec12ce792a49d4964517a3512d9e23 100644 (file)
@@ -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;
+}
index 0b4647fb748453154a105c2e737062ae9eb89f95..557dbe2d8d6c34b5c50289a3ed194aef03d1f498 100644 (file)
@@ -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