char *orig_key;
void *orig_value;
unsigned int fidx, new_fields_count;
- enum mail_cache_decision_type dec;
- time_t max_drop_time;
+ struct mail_cache_purge_drop_ctx drop_ctx;
uint32_t offset, i;
if (mail_cache_header_fields_get_offset(cache, &offset, &field_hdr) < 0)
for (i = 0; i < cache->fields_count; i++)
cache->field_file_map[i] = (uint32_t)-1;
- max_drop_time = cache->index->map->hdr.day_stamp == 0 ? 0 :
- cache->index->map->hdr.day_stamp -
- cache->index->optimization_set.cache.unaccessed_field_drop_secs;
-
+ mail_cache_purge_drop_init(cache, &cache->index->map->hdr, &drop_ctx);
i_zero(&field);
for (i = 0; i < field_hdr->fields_count; i++) {
for (p = names; p != end && *p != '\0'; p++) ;
if ((time_t)last_used[i] > cache->fields[fidx].field.last_used)
cache->fields[fidx].field.last_used = last_used[i];
- dec = cache->fields[fidx].field.decision;
- if (cache->fields[fidx].field.last_used < max_drop_time &&
- cache->fields[fidx].field.last_used != 0 &&
- (dec & MAIL_CACHE_DECISION_FORCED) == 0 &&
- dec != MAIL_CACHE_DECISION_NO) {
- /* time to drop this field. don't bother dropping
- fields that have never been used. */
+ switch (mail_cache_purge_drop_test(&drop_ctx, fidx)) {
+ case MAIL_CACHE_PURGE_DROP_DECISION_NONE:
+ break;
+ case MAIL_CACHE_PURGE_DROP_DECISION_DROP:
mail_cache_purge_later(cache, t_strdup_printf(
"Drop old field %s (last_used=%"PRIdTIME_T")",
cache->fields[fidx].field.name,
cache->fields[fidx].field.last_used));
+ break;
+ case MAIL_CACHE_PURGE_DROP_DECISION_TO_TEMP:
+ /* This cache decision change can cause the field to be
+ dropped for old mails, so do it via purging. */
+ mail_cache_purge_later(cache, t_strdup_printf(
+ "Change cache decision to temp for old field %s "
+ "(last_used=%"PRIdTIME_T")",
+ cache->fields[fidx].field.name,
+ cache->fields[fidx].field.last_used));
+ break;
}
names = p + 1;
mail_cache_decision_changed_event(struct mail_cache *cache, struct event *event,
unsigned int field);
+struct mail_cache_purge_drop_ctx {
+ struct mail_cache *cache;
+ time_t max_yes_downgrade_time;
+ time_t max_temp_drop_time;
+};
+enum mail_cache_purge_drop_decision {
+ MAIL_CACHE_PURGE_DROP_DECISION_NONE,
+ MAIL_CACHE_PURGE_DROP_DECISION_DROP,
+ MAIL_CACHE_PURGE_DROP_DECISION_TO_TEMP,
+};
+void mail_cache_purge_drop_init(struct mail_cache *cache,
+ const struct mail_index_header *hdr,
+ struct mail_cache_purge_drop_ctx *ctx_r);
+enum mail_cache_purge_drop_decision
+mail_cache_purge_drop_test(struct mail_cache_purge_drop_ctx *ctx,
+ unsigned int field);
+
int mail_cache_expunge_handler(struct mail_index_sync_map_ctx *sync_ctx,
uint32_t seq, const void *data,
void **sync_context, void *context);
struct mail_cache_copy_context {
struct mail_cache *cache;
struct event *event;
- time_t max_temp_drop_time, max_yes_downgrade_time;
+ struct mail_cache_purge_drop_ctx drop_ctx;
buffer_t *buffer, *field_seen;
ARRAY(unsigned int) bitmask_pos;
struct mail_cache_field_private *priv = &ctx->cache->fields[field];
enum mail_cache_decision_type dec = priv->field.decision;
- if ((dec & MAIL_CACHE_DECISION_FORCED) != 0)
- ;
- else if (dec != MAIL_CACHE_DECISION_NO &&
- priv->field.last_used < ctx->max_temp_drop_time) {
- /* YES or TEMP decision field hasn't been accessed for a long
- time now. Drop it. */
+ switch (mail_cache_purge_drop_test(&ctx->drop_ctx, field)) {
+ case MAIL_CACHE_PURGE_DROP_DECISION_NONE:
+ break;
+ case MAIL_CACHE_PURGE_DROP_DECISION_DROP: {
const char *dec_str = mail_cache_decision_to_string(dec);
struct event_passthrough *e =
event_create_passthrough(ctx->event)->
"(decision=%s, last_used=%"PRIdTIME_T")",
priv->field.name, dec_str, priv->field.last_used);
dec = MAIL_CACHE_DECISION_NO;
- } else if (dec == MAIL_CACHE_DECISION_YES &&
- priv->field.last_used < ctx->max_yes_downgrade_time) {
- /* YES decision field hasn't been accessed for a while
- now. Change its decision to TEMP. */
+ break;
+ }
+ case MAIL_CACHE_PURGE_DROP_DECISION_TO_TEMP: {
struct event_passthrough *e =
mail_cache_decision_changed_event(
ctx->cache, ctx->event, field)->
"(last_used=%"PRIdTIME_T")",
priv->field.name, priv->field.last_used);
dec = MAIL_CACHE_DECISION_TEMP;
+ break;
+ }
}
priv->field.decision = dec;
/* @UNSAFE: drop unused fields and create a field mapping for
used fields */
idx_hdr = mail_index_get_header(view);
- if (idx_hdr->day_stamp != 0) {
- ctx.max_yes_downgrade_time = idx_hdr->day_stamp -
- cache->index->optimization_set.cache.unaccessed_field_drop_secs;
- ctx.max_temp_drop_time = idx_hdr->day_stamp -
- 2 * cache->index->optimization_set.cache.unaccessed_field_drop_secs;
- }
+ mail_cache_purge_drop_init(cache, idx_hdr, &ctx.drop_ctx);
orig_fields_count = cache->fields_count;
if (cache->file_fields_count == 0) {
cache->need_purge_file_seq = 0;
i_free(cache->need_purge_reason);
}
+
+void mail_cache_purge_drop_init(struct mail_cache *cache,
+ const struct mail_index_header *hdr,
+ struct mail_cache_purge_drop_ctx *ctx_r)
+{
+ i_zero(ctx_r);
+ ctx_r->cache = cache;
+ if (hdr->day_stamp != 0) {
+ const struct mail_index_cache_optimization_settings *opt =
+ &cache->index->optimization_set.cache;
+ ctx_r->max_yes_downgrade_time = hdr->day_stamp -
+ opt->unaccessed_field_drop_secs;
+ ctx_r->max_temp_drop_time = hdr->day_stamp -
+ 2 * opt->unaccessed_field_drop_secs;
+ }
+}
+
+enum mail_cache_purge_drop_decision
+mail_cache_purge_drop_test(struct mail_cache_purge_drop_ctx *ctx,
+ unsigned int field)
+{
+ struct mail_cache_field_private *priv = &ctx->cache->fields[field];
+ enum mail_cache_decision_type dec = priv->field.decision;
+
+ if ((dec & MAIL_CACHE_DECISION_FORCED) != 0)
+ return MAIL_CACHE_PURGE_DROP_DECISION_NONE;
+ if (dec != MAIL_CACHE_DECISION_NO &&
+ priv->field.last_used < ctx->max_temp_drop_time) {
+ /* YES or TEMP decision field hasn't been accessed for a long
+ time now. Drop it. */
+ return MAIL_CACHE_PURGE_DROP_DECISION_DROP;
+ }
+ if (dec == MAIL_CACHE_DECISION_YES &&
+ priv->field.last_used < ctx->max_yes_downgrade_time) {
+ /* YES decision field hasn't been accessed for a while
+ now. Change its decision to TEMP. */
+ return MAIL_CACHE_PURGE_DROP_DECISION_TO_TEMP;
+ }
+ return MAIL_CACHE_PURGE_DROP_DECISION_NONE;
+}