#include "lib.h"
#include "array.h"
+#include "hash.h"
#include "ostream.h"
#include "mkdir-parents.h"
#include "dbox-storage.h"
return 0;
}
+struct dbox_file_size {
+ uoff_t file_size;
+ uoff_t ref0_size;
+};
+
+static void dbox_map_filter_zero_refs(struct dbox_map *map)
+{
+ ARRAY_TYPE(seq_range) new_ref0_file_ids;
+ struct hash_table *hash;
+ struct dbox_file_size *size;
+ struct seq_range_iter iter;
+ const struct mail_index_header *hdr;
+ const struct dbox_mail_index_map_record *rec;
+ const uint16_t *ref16_p;
+ const void *data;
+ uint32_t seq, file_id;
+ unsigned int i;
+ bool expunged;
+ pool_t pool;
+
+ pool = pool_alloconly_create("dbox zero ref count", 8*1024);
+ hash = hash_table_create(default_pool, pool, 0, NULL, NULL);
+
+ /* count file sizes */
+ 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;
+
+ if (!seq_range_exists(&map->ref0_file_ids, rec->file_id))
+ continue;
+
+ /* this file has at least some zero references. count how many
+ bytes it has in total and how much of it has refcount=0. */
+ mail_index_lookup_ext(map->view, seq, map->ref_ext_id,
+ &data, &expunged);
+ if (data == NULL || expunged)
+ continue;
+ ref16_p = data;
+
+ size = hash_table_lookup(hash, POINTER_CAST(rec->file_id));
+ if (size == NULL) {
+ size = p_new(pool, struct dbox_file_size, 1);
+ hash_table_insert(hash, POINTER_CAST(rec->file_id),
+ size);
+ }
+ if (*ref16_p == 0)
+ size->ref0_size += rec->size;
+ if (size->file_size < rec->offset + rec->size)
+ size->file_size = rec->offset + rec->size;
+ }
+
+ /* now drop the files that don't have enough deleted space */
+ seq_range_array_iter_init(&iter, &map->ref0_file_ids); i = 0;
+ p_array_init(&new_ref0_file_ids, pool,
+ array_count(&map->ref0_file_ids));
+ while (seq_range_array_iter_nth(&iter, i++, &file_id)) {
+ size = hash_table_lookup(hash, POINTER_CAST(file_id));
+ if (size->ref0_size*100 / size->file_size >=
+ map->storage->purge_min_percentage)
+ seq_range_array_add(&new_ref0_file_ids, 0, file_id);
+ }
+ seq_range_array_intersect(&map->ref0_file_ids, &new_ref0_file_ids);
+
+ hash_table_destroy(&hash);
+ pool_unref(&pool);
+}
+
const ARRAY_TYPE(seq_range) *dbox_map_get_zero_ref_files(struct dbox_map *map)
{
const struct mail_index_header *hdr;
else
i_array_init(&map->ref0_file_ids, 64);
+ if (map->storage->purge_min_percentage >= 100) {
+ /* we're never purging anything */
+ return &map->ref0_file_ids;
+ }
+
if (dbox_map_open(map, FALSE) < 0) {
/* some internal error */
return &map->ref0_file_ids;
rec->file_id);
}
}
+ if (map->storage->purge_min_percentage > 0 &&
+ array_count(&map->ref0_file_ids) > 0)
+ dbox_map_filter_zero_refs(map);
return &map->ref0_file_ids;
}
/* Delete temp files having ctime older than this. */
#define DBOX_TMP_DELETE_SECS (36*60*60)
-/* Default rotation settings */
+/* Default dbox settings */
#define DBOX_DEFAULT_ROTATE_SIZE (2*1024*1024)
#define DBOX_DEFAULT_ROTATE_MIN_SIZE (1024*16)
#define DBOX_DEFAULT_ROTATE_DAYS 0
#define DBOX_DEFAULT_MAX_OPEN_FILES 64
+#define DBOX_DEFAULT_PURGE_MIN_PERCENTAGE 0
/* Flag specifies if the message should be in primary or alternative storage */
#define DBOX_INDEX_FLAG_ALT MAIL_INDEX_MAIL_FLAG_BACKEND
uoff_t rotate_size, rotate_min_size;
unsigned int rotate_days;
unsigned int max_open_files;
+ unsigned int purge_min_percentage;
ARRAY_DEFINE(open_files, struct dbox_file *);
unsigned int sync_rebuild:1;