/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "array.h"
+#include "mail-cache.h"
#include "index-storage.h"
#include "mail-index-modseq.h"
+static void
+index_storage_get_status_cache_fields(struct index_mailbox *ibox,
+ struct mailbox_status *status_r)
+{
+ const struct mail_cache_field *fields;
+ enum mail_cache_decision_type dec;
+ ARRAY_TYPE(const_string) *cache_fields;
+ unsigned int i, count;
+
+ fields = mail_cache_register_get_list(ibox->cache,
+ pool_datastack_create(), &count);
+
+ /* a bit leaky to allocate memory from mailbox pool every time, but this
+ is unlikely to be called more than once for the mailbox anyway. */
+ cache_fields = p_new(ibox->box.pool, ARRAY_TYPE(const_string), 1);
+ p_array_init(cache_fields, ibox->box.pool, count);
+ for (i = 0; i < count; i++) {
+ dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
+ if (dec != MAIL_CACHE_DECISION_NO)
+ array_append(cache_fields, &fields[i].name, 1);
+ }
+ status_r->cache_fields = cache_fields;
+}
+
void index_storage_get_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status_r)
}
}
- if (items & STATUS_FIRST_UNSEEN_SEQ) {
+ if ((items & STATUS_FIRST_UNSEEN_SEQ) != 0) {
mail_index_lookup_first(ibox->view, 0, MAIL_SEEN,
&status_r->first_unseen_seq);
}
- if (items & STATUS_KEYWORDS)
+ if ((items & STATUS_KEYWORDS) != 0)
status_r->keywords = mail_index_get_keywords(ibox->index);
+ if ((items & STATUS_CACHE_FIELDS) != 0)
+ index_storage_get_status_cache_fields(ibox, status_r);
}
pool_unref(&box->pool);
}
+static void
+index_storage_mailbox_update_cache_fields(struct index_mailbox *ibox,
+ const struct mailbox_update *update)
+{
+ const char *const *field_names = update->cache_fields;
+ ARRAY_DEFINE(new_fields, struct mail_cache_field);
+ const struct mail_cache_field *old_fields;
+ struct mail_cache_field field;
+ unsigned int i, j, old_count;
+
+ old_fields = mail_cache_register_get_list(ibox->cache,
+ pool_datastack_create(),
+ &old_count);
+
+ /* There shouldn't be many fields, so don't worry about O(n^2). */
+ t_array_init(&new_fields, 32);
+ for (i = 0; field_names[i] != NULL; i++) {
+ /* see if it's an existing field */
+ for (j = 0; j < old_count; j++) {
+ if (strcmp(field_names[i], old_fields[j].name) == 0)
+ break;
+ }
+ if (j != old_count) {
+ field = old_fields[i];
+ if (field.decision == MAIL_CACHE_DECISION_NO)
+ field.decision = MAIL_CACHE_DECISION_TEMP;
+ array_append(&new_fields, &field, 1);
+ } else if (strncmp(field_names[i], "hdr.", 4) == 0) {
+ /* new header */
+ memset(&field, 0, sizeof(field));
+ field.name = field_names[i];
+ field.type = MAIL_CACHE_FIELD_HEADER;
+ field.decision = MAIL_CACHE_DECISION_TEMP;
+ array_append(&new_fields, &field, 1);
+ } else {
+ /* new unknown field. we can't do anything about
+ this since we don't know its type */
+ }
+ }
+ if (array_count(&new_fields) > 0) {
+ mail_cache_register_fields(ibox->cache,
+ array_idx_modifiable(&new_fields, 0),
+ array_count(&new_fields));
+ }
+}
+
int index_storage_mailbox_update(struct mailbox *box,
const struct mailbox_update *update)
{
if (mailbox_open(box) < 0)
return -1;
}
+ if (update->cache_fields != NULL)
+ index_storage_mailbox_update_cache_fields(ibox, update);
/* make sure we get the latest index info */
(void)mail_index_refresh(ibox->index);
STATUS_FIRST_UNSEEN_SEQ = 0x20,
STATUS_KEYWORDS = 0x40,
STATUS_HIGHESTMODSEQ = 0x80,
- STATUS_GUID = 0x100
+ STATUS_GUID = 0x100,
+ STATUS_CACHE_FIELDS = 0x200
};
enum mailbox_search_result_flags {
uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
const ARRAY_TYPE(keywords) *keywords;
+ /* Fields that have "temp" or "yes" caching decision. */
+ const ARRAY_TYPE(const_string) *cache_fields;
/* There are expunges that haven't been synced yet */
unsigned int sync_delayed_expunges:1;
uint32_t uid_validity;
uint32_t min_next_uid;
uint64_t min_highest_modseq;
+ /* Add these fields to be temporarily cached, if they aren't already. */
+ const char *const *cache_fields;
};
struct mail_transaction_commit_changes {