mail_cache_register_get_list(src, pool_datastack_create(), &count);
i_assert(fields != NULL || count == 0);
if (count > 0)
- mail_cache_register_fields(dst, fields, count);
+ mail_cache_register_fields(dst, fields, count,
+ unsafe_data_stack_pool);
/* Destination cache isn't expected to exist yet, so use purging
to create it. Setting field_header_write_pending also guarantees
void mail_cache_register_fields(struct mail_cache *cache,
struct mail_cache_field *fields,
- unsigned int fields_count)
+ unsigned int fields_count,
+ pool_t fields_modify_pool)
{
char *name;
void *value;
unsigned int new_idx;
unsigned int i, j, registered_count;
+ struct mail_index_cache_optimization_settings *set =
+ &cache->index->optimization_set.cache;
+
+ if (set->max_header_name_length > 0) {
+ if (fields_modify_pool == NULL)
+ fields_modify_pool = cache->field_pool;
+
+ unsigned int maxlen = strlen("hdr.") + set->max_header_name_length;
+ for (i = 0; i < fields_count; i++) {
+ if (fields[i].type == MAIL_CACHE_FIELD_HEADER &&
+ strlen(fields[i].name) > maxlen) {
+ i_assert(fields_modify_pool !=
+ MAIL_CACHE_TRUNCATE_NAME_FAIL);
+ fields[i].name = p_strndup(
+ fields_modify_pool,
+ fields[i].name, maxlen);
+ }
+ }
+ }
+
new_idx = cache->fields_count;
for (i = 0; i < fields_count; i++) {
if (hash_table_lookup_full(cache->field_name_hash,
char *key;
void *value;
+ struct mail_index_cache_optimization_settings *set =
+ &cache->index->optimization_set.cache;
+
+ if (set->max_header_name_length > 0) {
+ unsigned int maxlen = strlen("hdr.") + set->max_header_name_length;
+ if (str_begins_icase_with(name, "hdr.") &&
+ strlen(name) > maxlen)
+ name = t_strndup(name, maxlen);
+ }
+
if (hash_table_lookup_full(cache->field_name_hash, name, &key, &value))
return POINTER_CAST_TO(value, unsigned int);
else
field.type = types[i];
field.field_size = sizes[i];
field.decision = file_dec;
- mail_cache_register_fields(cache, &field, 1);
+ mail_cache_register_fields(cache, &field, 1,
+ cache->field_pool);
fidx = field.idx;
}
if (cache->field_file_map[fidx] != (uint32_t)-1) {
mail_cache_open_or_create_path(struct mail_index *index, const char *path);
void mail_cache_free(struct mail_cache **cache);
-/* Register fields. fields[].idx is updated to contain field index.
- If field already exists and its caching decision is NO, the decision is
- updated to the input field's decision. */
+/* Register fields. fields[].idx is updated to contain field index. If field
+ already exists and its caching decision is NO, the decision is updated to
+ the input field's decision.
+
+ If a header field name is too long, a truncated version replaces the original
+ in the passed fields array. The new string is from the passed pool */
+#define MAIL_CACHE_TRUNCATE_NAME_FAIL NULL
void mail_cache_register_fields(struct mail_cache *cache,
struct mail_cache_field *fields,
- unsigned int fields_count);
+ unsigned int fields_count,
+ pool_t fields_modify_pool);
/* Returns registered field index, or UINT_MAX if not found. */
unsigned int
mail_cache_register_lookup(struct mail_cache *cache, const char *name);
if (set->cache.record_max_size != 0)
dest->cache.record_max_size = set->cache.record_max_size;
+ dest->cache.max_header_name_length = set->cache.max_header_name_length;
dest->cache.max_headers_count = set->cache.max_headers_count;
}
/* If cache record becomes larger than this, don't add it. */
unsigned int record_max_size;
+ /* Maximum length for cacheable headers */
+ unsigned int max_header_name_length;
/* Maximum number of headers to cache */
unsigned int max_headers_count;
by randomizing the registration order. This only works for the 2nd
index that is opened, because the initial cache is always created
with all cache fields in the same order. */
+ pool_t pool = MAIL_CACHE_TRUNCATE_NAME_FAIL;
if (i_rand_limit(2) == 0) {
- mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field, 1);
- mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field2, 1);
- mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field3, 1);
+ mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field, 1, pool);
+ mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field2, 1, pool);
+ mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field3, 1, pool);
} else {
- mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field3, 1);
- mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field2, 1);
- mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field, 1);
+ mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field3, 1, pool);
+ mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field2, 1, pool);
+ mail_cache_register_fields(ctx_r->cache, &ctx_r->cache_field, 1, pool);
}
}
test_begin("mail cache fields read-write");
test_mail_cache_init(test_mail_index_init(), &ctx);
- mail_cache_register_fields(ctx.cache, &cache_field, 1);
+ mail_cache_register_fields(ctx.cache, &cache_field, 1,
+ unsafe_data_stack_pool);
test_assert(mail_cache_purge(ctx.cache, (uint32_t)-1, "test") == 0);
/* after writing the initial cache file, register another cache field
that doesn't exist in it. */
- mail_cache_register_fields(ctx.cache, &cache_field2, 1);
+ mail_cache_register_fields(ctx.cache, &cache_field2, 1,
+ unsafe_data_stack_pool);
struct mail_cache_field_private *priv =
&ctx.cache->fields[cache_field.idx];
by purging (which is called to auto-create the cache). */
test_assert(mail_cache_purge(ctx.cache, (uint32_t)-1, "test") == 0);
mail_cache_register_fields(ctx.cache, cache_fields,
- N_ELEMENTS(cache_fields));
+ N_ELEMENTS(cache_fields),
+ unsafe_data_stack_pool);
trans = mail_index_transaction_begin(ctx.view, 0);
cache_view = mail_cache_view_open(ctx.cache, ctx.view);
test_mail_cache_add_mail(&ctx, UINT_MAX, NULL);
test_mail_cache_add_mail(&ctx, UINT_MAX, NULL);
test_assert(mail_cache_purge(ctx.cache, (uint32_t)-1, "test") == 0);
- mail_cache_register_fields(ctx.cache, &bitmask_field, 1);
+ mail_cache_register_fields(ctx.cache, &bitmask_field, 1,
+ unsafe_data_stack_pool);
test_mail_cache_update_day_first_uid7(&ctx, 3);
test_begin("mail cache uncommitted lookups");
test_mail_cache_init(test_mail_index_init(), &ctx);
mail_cache_register_fields(ctx.cache, cache_fields,
- N_ELEMENTS(cache_fields));
+ N_ELEMENTS(cache_fields),
+ unsafe_data_stack_pool);
test_mail_cache_add_mail(&ctx, UINT_MAX, NULL);
test_mail_cache_init(test_mail_index_init(), &ctx);
memcpy(cache_fields, decision_cache_fields, sizeof(cache_fields));
- mail_cache_register_fields(ctx.cache, cache_fields, TEST_FIELD_COUNT);
+ mail_cache_register_fields(ctx.cache, cache_fields, TEST_FIELD_COUNT,
+ unsafe_data_stack_pool);
for (i = 0; i < TEST_FIELD_COUNT; i++)
expected_decisions[i] = cache_fields[i].decision;
/* register fields after the initial purge create the cache */
memcpy(cache_fields, decision_cache_fields, sizeof(cache_fields));
- mail_cache_register_fields(ctx.cache, cache_fields, TEST_FIELD_COUNT);
+ mail_cache_register_fields(ctx.cache, cache_fields, TEST_FIELD_COUNT,
+ unsafe_data_stack_pool);
for (i = 0; i < TEST_FIELD_COUNT; i++) {
expected_decisions[i] = cache_fields[i].decision;
expected_uid_highwater[i] = 0;
test_begin("mail cache duplicate fields");
test_mail_cache_init(test_mail_index_init(), &ctx);
mail_cache_register_fields(ctx.cache, cache_fields,
- N_ELEMENTS(cache_fields));
+ N_ELEMENTS(cache_fields),
+ unsafe_data_stack_pool);
test_mail_cache_add_mail(&ctx, UINT_MAX, NULL);
header_field.decision = MAIL_CACHE_DECISION_NO;
T_BEGIN {
header_field.name = t_strconcat("hdr.", field, NULL);
- mail_cache_register_fields(box->cache, &header_field, 1);
+ mail_cache_register_fields(box->cache, &header_field, 1,
+ unsafe_data_stack_pool);
} T_END;
return header_field.idx;
}
}
field.decision = dec;
- mail_cache_register_fields(cache, &field, 1);
+ mail_cache_register_fields(cache, &field, 1,
+ unsafe_data_stack_pool);
}
}
ibox->cache_fields = index_mail_global_cache_fields_dup();
mail_cache_register_fields(cache, ibox->cache_fields,
- MAIL_INDEX_CACHE_FIELD_COUNT);
+ MAIL_INDEX_CACHE_FIELD_COUNT,
+ MAIL_CACHE_TRUNCATE_NAME_FAIL);
if (strcmp(set->mail_never_cache_fields, "*") == 0) {
/* all caching disabled for now */
.cache = {
.unaccessed_field_drop_secs = set->mail_cache_unaccessed_field_drop,
.record_max_size = set->mail_cache_record_max_size,
+ .max_header_name_length = set->mail_cache_max_header_name_length,
.max_headers_count = set->mail_cache_max_headers_count,
.max_size = set->mail_cache_max_size,
.purge_min_size = set->mail_cache_purge_min_size,
if (array_count(&new_fields) > 0) {
mail_cache_register_fields(box->cache,
array_front_modifiable(&new_fields),
- array_count(&new_fields));
+ array_count(&new_fields),
+ unsafe_data_stack_pool);
}
}
DEF(STR, mail_server_admin),
DEF(TIME_HIDDEN, mail_cache_unaccessed_field_drop),
DEF(SIZE_HIDDEN, mail_cache_record_max_size),
+ DEF(UINT_HIDDEN, mail_cache_max_header_name_length),
DEF(UINT_HIDDEN, mail_cache_max_headers_count),
DEF(SIZE_HIDDEN, mail_cache_max_size),
DEF(UINT_HIDDEN, mail_cache_min_mail_count),
.mail_cache_min_mail_count = 0,
.mail_cache_unaccessed_field_drop = 60*60*24*30,
.mail_cache_record_max_size = 64 * 1024,
+ .mail_cache_max_header_name_length = 100,
.mail_cache_max_headers_count = 100,
.mail_cache_max_size = 1024 * 1024 * 1024,
.mail_cache_purge_min_size = 32 * 1024,
unsigned int mail_cache_min_mail_count;
unsigned int mail_cache_unaccessed_field_drop;
uoff_t mail_cache_record_max_size;
+ unsigned int mail_cache_max_header_name_length;
unsigned int mail_cache_max_headers_count;
uoff_t mail_cache_max_size;
uoff_t mail_cache_purge_min_size;
fields[j++] = header_field;
}
count = j;
- mail_cache_register_fields(box->cache, fields, count);
+ mail_cache_register_fields(box->cache, fields, count,
+ unsafe_data_stack_pool);
pool = pool_alloconly_create("mailbox_header_lookup_ctx", 1024);
ctx = p_new(pool, struct mailbox_header_lookup_ctx, 1);
mbox->cache_field.name = "pop3-migration.hdr";
mbox->cache_field.type = MAIL_CACHE_FIELD_FIXED_SIZE;
mbox->cache_field.field_size = SHA1_RESULTLEN;
- mail_cache_register_fields(mail->box->cache, &mbox->cache_field, 1);
+ mail_cache_register_fields(mail->box->cache, &mbox->cache_field, 1,
+ MAIL_CACHE_TRUNCATE_NAME_FAIL);
mbox->cache_field_registered = TRUE;
return mbox->cache_field.idx;
}