]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dbox: If enough bytes have been expunged, force a purge.
authorTimo Sirainen <tss@iki.fi>
Fri, 10 Apr 2009 18:47:27 +0000 (14:47 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 10 Apr 2009 18:47:27 +0000 (14:47 -0400)
--HG--
branch : HEAD

src/lib-storage/index/dbox/dbox-map.c
src/lib-storage/index/dbox/dbox-map.h
src/lib-storage/index/dbox/dbox-sync.c
src/lib-storage/index/dbox/dbox-sync.h

index 0ad091c27291138cea72bd933bcd907af4f65862..9dd2ff6657802e6f5fbe98e89ac3d3459139ac94 100644 (file)
@@ -11,6 +11,9 @@
 
 #define MAX_BACKWARDS_LOOKUPS 10
 
+#define DBOX_FORCE_PURGE_MIN_BYTES (1024*1024*10)
+#define DBOX_FORCE_PURGE_MIN_RATIO 0.5
+
 struct dbox_map_transaction_context {
        struct dbox_map *map;
        struct mail_index_transaction *trans;
@@ -314,6 +317,48 @@ static void dbox_map_filter_zero_refs(struct dbox_map *map)
        pool_unref(&pool);
 }
 
+bool dbox_map_want_purge(struct dbox_map *map)
+{
+       const struct mail_index_header *hdr;
+       const struct dbox_mail_index_map_record *rec;
+       const uint16_t *ref16_p;
+       const void *data;
+       uoff_t ref0_size, total_size;
+       bool expunged;
+       uint32_t seq;
+
+       if (map->storage->set->dbox_purge_min_percentage >= 100) {
+               /* we never purge anything */
+               return FALSE;
+       }
+
+       ref0_size = total_size = 0;
+       hdr = mail_index_get_header(map->view);
+       for (seq = 1; seq <= hdr->messages_count; seq++) {
+               mail_index_lookup_ext(map->view, seq, map->map_ext_id,
+                                     &data, &expunged);
+               if (data == NULL || expunged)
+                       continue;
+               rec = data;
+
+               mail_index_lookup_ext(map->view, seq, map->ref_ext_id,
+                                     &data, &expunged);
+               if (data == NULL || expunged)
+                       continue;
+               ref16_p = data;
+
+               if (*ref16_p == 0)
+                       ref0_size += rec->size;
+               total_size += rec->size;
+       }
+
+       if (ref0_size < DBOX_FORCE_PURGE_MIN_BYTES)
+               return FALSE;
+       if ((float)ref0_size / (float)total_size < DBOX_FORCE_PURGE_MIN_RATIO)
+               return FALSE;
+       return TRUE;
+}
+
 const ARRAY_TYPE(seq_range) *dbox_map_get_zero_ref_files(struct dbox_map *map)
 {
        const struct mail_index_header *hdr;
index 145d4537d0608c19544c1a4d9f83d52f05c8650c..4339e76efe6e3240f9eca76be3d734d863df70f5 100644 (file)
@@ -55,6 +55,8 @@ int dbox_map_update_refcounts(struct dbox_map_transaction_context *ctx,
                              const ARRAY_TYPE(uint32_t) *map_uids, int diff);
 int dbox_map_remove_file_id(struct dbox_map *map, uint32_t file_id);
 
+/* Returns TRUE if there's enough pressure to purge immediately. */
+bool dbox_map_want_purge(struct dbox_map *map);
 /* Return all files containing messages with zero refcount. */
 const ARRAY_TYPE(seq_range) *dbox_map_get_zero_ref_files(struct dbox_map *map);
 
index fe86c76d06e5275e6de048df98699c9a1199c392..708c93024c8849a9fe41a31a66910f681d88b493 100644 (file)
@@ -83,6 +83,8 @@ static int dbox_sync_add_seq(struct dbox_sync_context *ctx,
                }
                seq_range_array_add(&entry->expunge_seqs, 0, seq);
                array_append(&entry->expunge_map_uids, &map_uid, 1);
+               if (entry->file_id != 0)
+                       ctx->have_storage_expunges = TRUE;
        } else {
                if ((sync_rec->add_flags & DBOX_INDEX_FLAG_ALT) != 0)
                        entry->move_to_alt = TRUE;
@@ -159,6 +161,18 @@ static int dbox_sync_index(struct dbox_sync_context *ctx)
        }
 
        if (ret > 0) {
+               if (ctx->have_storage_expunges) {
+                       /* prevent a user from saving + expunging messages
+                          all the time and using lots of disk space.
+                          but avoid doing this in situations where a user
+                          simply expunges a lot of mail for the first time.
+                          that's why we do this calculation before current
+                          sync: the purging is triggered only after the
+                          second expunge. */
+                       if (dbox_map_want_purge(ctx->mbox->storage->map))
+                               ctx->purge = TRUE;
+               }
+
                /* now sync each file separately */
                iter = hash_table_iterate_init(ctx->syncs);
                while (hash_table_iterate(iter, &key, &value)) {
@@ -319,6 +333,9 @@ int dbox_sync_finish(struct dbox_sync_context **_ctx, bool success)
        }
        if (ctx->path != NULL)
                str_free(&ctx->path);
+
+       if (ctx->purge)
+               (void)dbox_sync_purge(&ctx->mbox->storage->storage);
        i_free(ctx);
        return ret;
 }
index 90f8c287cc65150b2b12d4c29730fe06afc8b3e8..297e8f30a2d36b3d2d0205a0bfebba1e790cd1d6 100644 (file)
@@ -31,6 +31,9 @@ struct dbox_sync_context {
 
        pool_t pool;
        struct hash_table *syncs; /* struct dbox_sync_file_entry */
+
+       unsigned int have_storage_expunges:1;
+       unsigned int purge:1;
 };
 
 int dbox_sync_begin(struct dbox_mailbox *mbox, enum dbox_sync_flags flags,