summaryrefslogtreecommitdiffstats
path: root/src/lib-index/mail-cache.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-index/mail-cache.h193
1 files changed, 193 insertions, 0 deletions
diff --git a/src/lib-index/mail-cache.h b/src/lib-index/mail-cache.h
new file mode 100644
index 0000000..09fde29
--- /dev/null
+++ b/src/lib-index/mail-cache.h
@@ -0,0 +1,193 @@
+#ifndef MAIL_CACHE_H
+#define MAIL_CACHE_H
+
+#include "mail-index.h"
+
+#define MAIL_CACHE_FILE_SUFFIX ".cache"
+
+struct mail_cache;
+struct mail_cache_view;
+struct mail_cache_transaction_ctx;
+
+enum mail_cache_decision_type {
+ /* Not needed currently */
+ MAIL_CACHE_DECISION_NO = 0x00,
+ /* Needed only for new mails. Drop when purging. */
+ MAIL_CACHE_DECISION_TEMP = 0x01,
+ /* Needed. */
+ MAIL_CACHE_DECISION_YES = 0x02,
+
+ /* This decision has been forced manually, don't change it. */
+ MAIL_CACHE_DECISION_FORCED = 0x80
+};
+
+enum mail_cache_field_type {
+ /* Fixed size cache field. The size is specified only in the cache
+ field header, not separately for each record. */
+ MAIL_CACHE_FIELD_FIXED_SIZE,
+ /* Variable sized binary data. */
+ MAIL_CACHE_FIELD_VARIABLE_SIZE,
+ /* Variable sized string. There is no difference internally to how
+ MAIL_CACHE_FIELD_VARIABLE_SIZE is handled, but it helps at least
+ "doveadm dump" to know whether to hex-encode the output. */
+ MAIL_CACHE_FIELD_STRING,
+ /* A fixed size bitmask field. It's possible to add new bits by
+ updating this field. All the added fields are ORed together. */
+ MAIL_CACHE_FIELD_BITMASK,
+ /* Variable sized message header. The data begins with a 0-terminated
+ uint32_t line_numbers[]. The line number exists only for each
+ header, header continuation lines in multiline headers don't get
+ listed. After the line numbers comes the list of headers, including
+ the "header-name: " prefix for each line, LFs and the TABs or spaces
+ for continued lines. */
+ MAIL_CACHE_FIELD_HEADER,
+
+ MAIL_CACHE_FIELD_COUNT
+};
+
+struct mail_cache_field {
+ /* Unique name for the cache field. The field name doesn't matter
+ internally. */
+ const char *name;
+ /* Field index name. Used to optimize accessing the cache field. */
+ unsigned int idx;
+
+ /* Type of the field */
+ enum mail_cache_field_type type;
+ /* Size of the field, if it's a fixed size type. */
+ unsigned int field_size;
+ /* Current caching decision */
+ enum mail_cache_decision_type decision;
+ /* Timestamp when the cache field was last intentionally read (e.g.
+ by an IMAP client). Saving new mails doesn't update this field.
+ This is used to track when an unaccessed field should be dropped. */
+ time_t last_used;
+};
+
+struct mail_cache *mail_cache_open_or_create(struct mail_index *index);
+struct mail_cache *
+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. */
+void mail_cache_register_fields(struct mail_cache *cache,
+ struct mail_cache_field *fields,
+ unsigned int fields_count);
+/* Returns registered field index, or UINT_MAX if not found. */
+unsigned int
+mail_cache_register_lookup(struct mail_cache *cache, const char *name);
+/* Returns specified field */
+const struct mail_cache_field *
+mail_cache_register_get_field(struct mail_cache *cache, unsigned int field_idx);
+/* Returns a list of all registered fields */
+struct mail_cache_field *
+mail_cache_register_get_list(struct mail_cache *cache, pool_t pool,
+ unsigned int *count_r);
+
+/* Returns TRUE if cache should be purged. */
+bool mail_cache_need_purge(struct mail_cache *cache, const char **reason_r);
+/* Set cache file to be purged later. */
+void mail_cache_purge_later(struct mail_cache *cache, const char *reason);
+/* Don't try to purge the cache file later after all. */
+void mail_cache_purge_later_reset(struct mail_cache *cache);
+/* Purge cache file. Offsets are updated to given transaction.
+ The transaction log must already be exclusively locked.
+
+ The cache purging is done only if the current cache file's file_seq
+ matches purge_file_seq. The idea is that purging isn't done if
+ another process had just purged it. 0 means the cache file is created
+ only if it didn't already exist. (uint32_t)-1 means that purging is
+ done always regardless of file_seq. */
+int mail_cache_purge_with_trans(struct mail_cache *cache,
+ struct mail_index_transaction *trans,
+ uint32_t purge_file_seq, const char *reason);
+int mail_cache_purge(struct mail_cache *cache, uint32_t purge_file_seq,
+ const char *reason);
+/* Returns TRUE if there is at least something in the cache. */
+bool mail_cache_exists(struct mail_cache *cache);
+/* Open and read cache header. Returns 1 if ok, 0 if cache doesn't exist or it
+ was corrupted and just got deleted, -1 if I/O error. */
+int mail_cache_open_and_verify(struct mail_cache *cache);
+
+struct mail_cache_view *
+mail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview);
+void mail_cache_view_close(struct mail_cache_view **view);
+
+/* Normally cache decisions are updated on lookup/add. Use this function to
+ enable/disable this (useful for precaching data). */
+void mail_cache_view_update_cache_decisions(struct mail_cache_view *view,
+ bool update);
+
+/* Copy caching decisions. This is expected to be called only for a newly
+ created empty mailbox. */
+int mail_cache_decisions_copy(struct mail_cache *src, struct mail_cache *dst);
+
+/* Get index transaction specific cache transaction. */
+struct mail_cache_transaction_ctx *
+mail_cache_get_transaction(struct mail_cache_view *view,
+ struct mail_index_transaction *t);
+
+void mail_cache_transaction_reset(struct mail_cache_transaction_ctx *ctx);
+int mail_cache_transaction_commit(struct mail_cache_transaction_ctx **ctx);
+void mail_cache_transaction_rollback(struct mail_cache_transaction_ctx **ctx);
+
+/* Add new field to given record. Updates are not allowed. Fixed size fields
+ must be exactly the expected size. */
+void mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
+ unsigned int field_idx, const void *data, size_t data_size);
+/* Returns TRUE if field is wanted to be added and it doesn't already exist.
+ If current caching decisions say not to cache this field, FALSE is returned.
+ If seq is 0, the existence isn't checked. */
+bool mail_cache_field_want_add(struct mail_cache_transaction_ctx *ctx,
+ uint32_t seq, unsigned int field_idx);
+/* Like mail_cache_field_want_add(), but in caching decisions FALSE is
+ returned only if the decision is a forced no. */
+bool mail_cache_field_can_add(struct mail_cache_transaction_ctx *ctx,
+ uint32_t seq, unsigned int field_idx);
+/* Notify cache that the mail is now closed. Any records added with
+ mail_cache_add() are unlikely to be required again. This mainly tells
+ INDEX=MEMORY that it can free up the memory used by the mail. */
+void mail_cache_close_mail(struct mail_cache_transaction_ctx *ctx,
+ uint32_t seq);
+
+/* Returns 1 if field exists, 0 if not, -1 if error. */
+int mail_cache_field_exists(struct mail_cache_view *view, uint32_t seq,
+ unsigned int field_idx);
+/* Returns TRUE if something is cached for the message, FALSE if not. */
+bool mail_cache_field_exists_any(struct mail_cache_view *view, uint32_t seq);
+/* Returns current caching decision for given field. */
+enum mail_cache_decision_type
+mail_cache_field_get_decision(struct mail_cache *cache, unsigned int field_idx);
+/* Notify the decision handling code when field is committed to cache.
+ If this is the first time the field is added to cache, its caching decision
+ is updated to TEMP. */
+void mail_cache_decision_add(struct mail_cache_view *view, uint32_t seq,
+ unsigned int field);
+
+/* Set data_r and size_r to point to wanted field in cache file.
+ Returns 1 if field was found, 0 if not, -1 if error. */
+int mail_cache_lookup_field(struct mail_cache_view *view, buffer_t *dest_buf,
+ uint32_t seq, unsigned int field_idx);
+
+/* Return specified cached headers. Returns 1 if all fields were found,
+ 0 if not, -1 if error. dest is updated only if all fields were found. */
+int mail_cache_lookup_headers(struct mail_cache_view *view, string_t *dest,
+ uint32_t seq, const unsigned int field_idxs[],
+ unsigned int fields_count);
+
+/* "Error in index cache file %s: ...". */
+void mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
+ ATTR_FORMAT(2, 3) ATTR_COLD;
+void mail_cache_set_seq_corrupted_reason(struct mail_cache_view *cache_view,
+ uint32_t seq, const char *reason)
+ ATTR_COLD;
+
+/* Returns human-readable reason for why a cached field is missing for
+ the specified mail. This is mainly for debugging purposes, so the exact
+ field doesn't matter here. */
+const char *
+mail_cache_get_missing_reason(struct mail_cache_view *view, uint32_t seq);
+
+#endif