1 #ifndef MAIL_CACHE_H 2 #define MAIL_CACHE_H 3 4 #include "mail-index.h" 5 6 #define MAIL_CACHE_FILE_SUFFIX ".cache" 7 8 struct mail_cache; 9 struct mail_cache_view; 10 struct mail_cache_transaction_ctx; 11 12 enum mail_cache_decision_type { 13 /* Not needed currently */ 14 MAIL_CACHE_DECISION_NO = 0x00, 15 /* Needed only for new mails. Drop when purging. */ 16 MAIL_CACHE_DECISION_TEMP = 0x01, 17 /* Needed. */ 18 MAIL_CACHE_DECISION_YES = 0x02, 19 20 /* This decision has been forced manually, don't change it. */ 21 MAIL_CACHE_DECISION_FORCED = 0x80 22 }; 23 24 enum mail_cache_field_type { 25 /* Fixed size cache field. The size is specified only in the cache 26 field header, not separately for each record. */ 27 MAIL_CACHE_FIELD_FIXED_SIZE, 28 /* Variable sized binary data. */ 29 MAIL_CACHE_FIELD_VARIABLE_SIZE, 30 /* Variable sized string. There is no difference internally to how 31 MAIL_CACHE_FIELD_VARIABLE_SIZE is handled, but it helps at least 32 "doveadm dump" to know whether to hex-encode the output. */ 33 MAIL_CACHE_FIELD_STRING, 34 /* A fixed size bitmask field. It's possible to add new bits by 35 updating this field. All the added fields are ORed together. */ 36 MAIL_CACHE_FIELD_BITMASK, 37 /* Variable sized message header. The data begins with a 0-terminated 38 uint32_t line_numbers[]. The line number exists only for each 39 header, header continuation lines in multiline headers don't get 40 listed. After the line numbers comes the list of headers, including 41 the "header-name: " prefix for each line, LFs and the TABs or spaces 42 for continued lines. */ 43 MAIL_CACHE_FIELD_HEADER, 44 45 MAIL_CACHE_FIELD_COUNT 46 }; 47 48 struct mail_cache_field { 49 /* Unique name for the cache field. The field name doesn't matter 50 internally. */ 51 const char *name; 52 /* Field index name. Used to optimize accessing the cache field. */ 53 unsigned int idx; 54 55 /* Type of the field */ 56 enum mail_cache_field_type type; 57 /* Size of the field, if it's a fixed size type. */ 58 unsigned int field_size; 59 /* Current caching decision */ 60 enum mail_cache_decision_type decision; 61 /* Timestamp when the cache field was last intentionally read (e.g. 62 by an IMAP client). Saving new mails doesn't update this field. 63 This is used to track when an unaccessed field should be dropped. */ 64 time_t last_used; 65 }; 66 67 struct mail_cache *mail_cache_open_or_create(struct mail_index *index); 68 struct mail_cache * 69 mail_cache_open_or_create_path(struct mail_index *index, const char *path); 70 void mail_cache_free(struct mail_cache **cache); 71 72 /* Register fields. fields[].idx is updated to contain field index. 73 If field already exists and its caching decision is NO, the decision is 74 updated to the input field's decision. */ 75 void mail_cache_register_fields(struct mail_cache *cache, 76 struct mail_cache_field *fields, 77 unsigned int fields_count); 78 /* Returns registered field index, or UINT_MAX if not found. */ 79 unsigned int 80 mail_cache_register_lookup(struct mail_cache *cache, const char *name); 81 /* Returns specified field */ 82 const struct mail_cache_field * 83 mail_cache_register_get_field(struct mail_cache *cache, unsigned int field_idx); 84 /* Returns a list of all registered fields */ 85 struct mail_cache_field * 86 mail_cache_register_get_list(struct mail_cache *cache, pool_t pool, 87 unsigned int *count_r); 88 89 /* Returns TRUE if cache should be purged. */ 90 bool mail_cache_need_purge(struct mail_cache *cache, const char **reason_r); 91 /* Set cache file to be purged later. */ 92 void mail_cache_purge_later(struct mail_cache *cache, const char *reason); 93 /* Don't try to purge the cache file later after all. */ 94 void mail_cache_purge_later_reset(struct mail_cache *cache); 95 /* Purge cache file. Offsets are updated to given transaction. 96 The transaction log must already be exclusively locked. 97 98 The cache purging is done only if the current cache file's file_seq 99 matches purge_file_seq. The idea is that purging isn't done if 100 another process had just purged it. 0 means the cache file is created 101 only if it didn't already exist. (uint32_t)-1 means that purging is 102 done always regardless of file_seq. */ 103 int mail_cache_purge_with_trans(struct mail_cache *cache, 104 struct mail_index_transaction *trans, 105 uint32_t purge_file_seq, const char *reason); 106 int mail_cache_purge(struct mail_cache *cache, uint32_t purge_file_seq, 107 const char *reason); 108 /* Returns TRUE if there is at least something in the cache. */ 109 bool mail_cache_exists(struct mail_cache *cache); 110 /* Open and read cache header. Returns 1 if ok, 0 if cache doesn't exist or it 111 was corrupted and just got deleted, -1 if I/O error. */ 112 int mail_cache_open_and_verify(struct mail_cache *cache); 113 114 struct mail_cache_view * 115 mail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview); 116 void mail_cache_view_close(struct mail_cache_view **view); 117 118 /* Normally cache decisions are updated on lookup/add. Use this function to 119 enable/disable this (useful for precaching data). */ 120 void mail_cache_view_update_cache_decisions(struct mail_cache_view *view, 121 bool update); 122 123 /* Copy caching decisions. This is expected to be called only for a newly 124 created empty mailbox. */ 125 int mail_cache_decisions_copy(struct mail_cache *src, struct mail_cache *dst); 126 127 /* Get index transaction specific cache transaction. */ 128 struct mail_cache_transaction_ctx * 129 mail_cache_get_transaction(struct mail_cache_view *view, 130 struct mail_index_transaction *t); 131 132 void mail_cache_transaction_reset(struct mail_cache_transaction_ctx *ctx); 133 int mail_cache_transaction_commit(struct mail_cache_transaction_ctx **ctx); 134 void mail_cache_transaction_rollback(struct mail_cache_transaction_ctx **ctx); 135 136 /* Add new field to given record. Updates are not allowed. Fixed size fields 137 must be exactly the expected size. */ 138 void mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq, 139 unsigned int field_idx, const void *data, size_t data_size); 140 /* Returns TRUE if field is wanted to be added and it doesn't already exist. 141 If current caching decisions say not to cache this field, FALSE is returned. 142 If seq is 0, the existence isn't checked. */ 143 bool mail_cache_field_want_add(struct mail_cache_transaction_ctx *ctx, 144 uint32_t seq, unsigned int field_idx); 145 /* Like mail_cache_field_want_add(), but in caching decisions FALSE is 146 returned only if the decision is a forced no. */ 147 bool mail_cache_field_can_add(struct mail_cache_transaction_ctx *ctx, 148 uint32_t seq, unsigned int field_idx); 149 /* Notify cache that the mail is now closed. Any records added with 150 mail_cache_add() are unlikely to be required again. This mainly tells 151 INDEX=MEMORY that it can free up the memory used by the mail. */ 152 void mail_cache_close_mail(struct mail_cache_transaction_ctx *ctx, 153 uint32_t seq); 154 155 /* Returns 1 if field exists, 0 if not, -1 if error. */ 156 int mail_cache_field_exists(struct mail_cache_view *view, uint32_t seq, 157 unsigned int field_idx); 158 /* Returns TRUE if something is cached for the message, FALSE if not. */ 159 bool mail_cache_field_exists_any(struct mail_cache_view *view, uint32_t seq); 160 /* Returns current caching decision for given field. */ 161 enum mail_cache_decision_type 162 mail_cache_field_get_decision(struct mail_cache *cache, unsigned int field_idx); 163 /* Notify the decision handling code when field is committed to cache. 164 If this is the first time the field is added to cache, its caching decision 165 is updated to TEMP. */ 166 void mail_cache_decision_add(struct mail_cache_view *view, uint32_t seq, 167 unsigned int field); 168 169 /* Set data_r and size_r to point to wanted field in cache file. 170 Returns 1 if field was found, 0 if not, -1 if error. */ 171 int mail_cache_lookup_field(struct mail_cache_view *view, buffer_t *dest_buf, 172 uint32_t seq, unsigned int field_idx); 173 174 /* Return specified cached headers. Returns 1 if all fields were found, 175 0 if not, -1 if error. dest is updated only if all fields were found. */ 176 int mail_cache_lookup_headers(struct mail_cache_view *view, string_t *dest, 177 uint32_t seq, const unsigned int field_idxs[], 178 unsigned int fields_count); 179 180 /* "Error in index cache file %s: ...". */ 181 void mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...) 182 ATTR_FORMAT(2, 3); 183 void mail_cache_set_seq_corrupted_reason(struct mail_cache_view *cache_view, 184 uint32_t seq, const char *reason); 185 186 /* Returns human-readable reason for why a cached field is missing for 187 the specified mail. This is mainly for debugging purposes, so the exact 188 field doesn't matter here. */ 189 const char * 190 mail_cache_get_missing_reason(struct mail_cache_view *view, uint32_t seq); 191 192 #endif 193