1 #ifndef MAIL_CACHE_PRIVATE_H 2 #define MAIL_CACHE_PRIVATE_H 3 4 #include "file-dotlock.h" 5 #include "mail-index-private.h" 6 #include "mail-cache.h" 7 8 #define MAIL_CACHE_MAJOR_VERSION 1 9 #define MAIL_CACHE_MINOR_VERSION 1 10 11 #define MAIL_CACHE_LOCK_TIMEOUT 10 12 #define MAIL_CACHE_LOCK_CHANGE_TIMEOUT 300 13 14 #define MAIL_CACHE_MAX_WRITE_BUFFER (1024*256) 15 16 #define MAIL_CACHE_IS_UNUSABLE(cache) \ 17 ((cache)->hdr == NULL) 18 19 struct mail_cache_header { 20 /* Major version is increased only when you can't have backwards 21 compatibility. If the field doesn't match MAIL_CACHE_MAJOR_VERSION, 22 don't even try to read it. */ 23 uint8_t major_version; 24 /* If this isn't the same as sizeof(uoff_t), the cache file can't be 25 safely used with the current implementation. */ 26 uint8_t compat_sizeof_uoff_t; 27 /* Minor version is increased when the file format changes in a 28 backwards compatible way. */ 29 uint8_t minor_version; 30 uint8_t unused; 31 32 /* Unique index file ID, which must match the main index's indexid. 33 See mail_index_header.indexid. */ 34 uint32_t indexid; 35 /* Cache file sequence. Increased on every purge. This must match the 36 main index's reset_id for "cache" extension or the cache offsets 37 aren't valid. When creating the first cache file, use the current 38 UNIX timestamp as the file_seq. */ 39 uint32_t file_seq; 40 41 /* Number of cache records that are linked inside the cache file, 42 instead of being directly pointed from the main index. */ 43 uint32_t continued_record_count; 44 45 /* Number of messages cached in this file. This does not include 46 the continuation records. 47 48 NOTE: <=v2.1 used this for hole offset, so we can't fully 49 rely on it */ 50 uint32_t record_count; 51 /* Currently unused. */ 52 uint32_t backwards_compat_used_file_size; 53 /* Number of already expunged messages that currently have cache 54 content in this file. */ 55 uint32_t deleted_record_count; 56 57 /* Offset to the first mail_cache_header_fields. */ 58 uint32_t field_header_offset; 59 }; 60 61 struct mail_cache_header_fields { 62 /* Offset to the updated version of this header. Use 63 mail_index_offset_to_uint32() to decode it. */ 64 uint32_t next_offset; 65 /* Full size of this header. */ 66 uint32_t size; 67 /* Number of fields in this header. */ 68 uint32_t fields_count; 69 70 #if 0 71 /* Last time the field was accessed. Not updated more often than 72 once a day. This field may be overwritten later on, which in theory 73 could cause reading to see a partially updated (corrupted) value. 74 Don't fully trust this field unless it was read while cache is 75 locked. */ 76 uint32_t last_used[fields_count]; 77 /* (uint32_t)-1 for variable sized fields */ 78 uint32_t size[fields_count]; 79 /* enum mail_cache_field_type */ 80 uint8_t type[fields_count]; 81 /* enum mail_cache_decision_type. This field can be overwritten 82 later on to update the caching decision. */ 83 uint8_t decision[fields_count]; 84 /* NUL-separated list of field names */ 85 char name[fields_count][]; 86 #endif 87 }; 88 89 /* Macros to return offsets to the fields in mail_cache_header_fields. */ 90 #define MAIL_CACHE_FIELD_LAST_USED() \ 91 (sizeof(uint32_t) * 3) 92 #define MAIL_CACHE_FIELD_SIZE(count) \ 93 (MAIL_CACHE_FIELD_LAST_USED() + sizeof(uint32_t) * (count)) 94 #define MAIL_CACHE_FIELD_TYPE(count) \ 95 (MAIL_CACHE_FIELD_SIZE(count) + sizeof(uint32_t) * (count)) 96 #define MAIL_CACHE_FIELD_DECISION(count) \ 97 (MAIL_CACHE_FIELD_TYPE(count) + sizeof(uint8_t) * (count)) 98 #define MAIL_CACHE_FIELD_NAMES(count) \ 99 (MAIL_CACHE_FIELD_DECISION(count) + sizeof(uint8_t) * (count)) 100 101 struct mail_cache_record { 102 uint32_t prev_offset; 103 uint32_t size; /* full record size, including this header */ 104 /* array of { uint32_t field; [ uint32_t size; ] { .. } } */ 105 }; 106 107 struct mail_cache_field_private { 108 struct mail_cache_field field; 109 110 /* Highest message UID whose cache field of this type have been 111 accessed within this session. This is used to track whether messages 112 are accessed in non-ascending order, which indicates an IMAP client 113 that doesn't have a local cache. That will result in the caching 114 decision to change from TEMP to YES. */ 115 uint32_t uid_highwater; 116 117 /* Unused fields aren't written to cache file */ 118 bool used:1; 119 /* field.decision is pending a write to cache file header. If the 120 cache header is read from disk, don't overwrite it. */ 121 bool decision_dirty:1; 122 }; 123 124 struct mail_cache { 125 struct mail_index *index; 126 struct event *event; 127 /* Registered "cache" extension ID */ 128 uint32_t ext_id; 129 130 char *filepath; 131 int fd; 132 133 struct dotlock_settings dotlock_settings; 134 struct file_lock *file_lock; 135 136 /* Cache file's inode, device and size when it was last fstat()ed. */ 137 ino_t st_ino; 138 dev_t st_dev; 139 uoff_t last_stat_size; 140 141 /* Used to avoid logging mmap() errors too rapidly. */ 142 time_t last_mmap_error_time; 143 144 /* a) mmaping the whole file */ 145 void *mmap_base; 146 /* b) using file cache */ 147 struct file_cache *file_cache; 148 /* c) using small read() calls with MAIL_INDEX_OPEN_FLAG_SAVEONLY */ 149 uoff_t read_offset; 150 buffer_t *read_buf; 151 /* Size of the cache file as currently mapped to memory. Used for all 152 of a), b), and c). */ 153 size_t mmap_length; 154 /* mail_cache_map() increases this always. Used only for asserts. */ 155 unsigned int remap_counter; 156 /* Linked list of all cache views. */ 157 struct mail_cache_view *views; 158 159 /* mmap_disable=no: hdr points to data / NULL when cache is invalid. 160 mmap_disable=yes: hdr points to hdr_ro_copy. this is needed because 161 cache invalidation can zero the data any time */ 162 const struct mail_cache_header *hdr; 163 struct mail_cache_header hdr_ro_copy; 164 /* hdr_copy gets updated when cache is locked and written when 165 unlocking and hdr_modified=TRUE */ 166 struct mail_cache_header hdr_copy; 167 /* If non-0, the offset for the last seen mail_cache_header_fields. 168 Used as a cache to avoid reading through multiple next_offset 169 pointers. */ 170 uint32_t last_field_header_offset; 171 172 /* Memory pool used for permanent field allocations. Currently this 173 means mail_cache_field.name and field_name_hash. */ 174 pool_t field_pool; 175 /* Size of fields[] and field_file_map[] */ 176 unsigned int fields_count; 177 /* All the registered cache fields. */ 178 struct mail_cache_field_private *fields; 179 /* mail_cache_field.idx -> file-specific header index. The reverse 180 of this is file_field_map[]. */ 181 uint32_t *field_file_map; 182 /* mail_cache_field.name -> mail_cache_field.idx */ 183 HASH_TABLE(char *, void *) field_name_hash; /* name -> idx */ 184 185 /* file-specific header index -> mail_cache_fields.idx. The reverse 186 of this is field_file_map[]. */ 187 unsigned int *file_field_map; 188 /* Size of file_field_map[] */ 189 unsigned int file_fields_count; 190 191 /* mail_cache_purge_later() sets these values to trigger purging on 192 the next index sync. need_purge_file_seq is set to the current 193 cache file_seq. If at sync time the file_seq differs, it means 194 the cache was already purged and another purge isn't necessary. */ 195 uint32_t need_purge_file_seq; 196 /* Human-readable reason for purging. Used for debugging and events. */ 197 char *need_purge_reason; 198 199 /* Cache has been opened (or it doesn't exist). */ 200 bool opened:1; 201 /* Cache has been locked with mail_cache_lock(). */ 202 bool locked:1; 203 /* TRUE if the last lock attempt failed. The next locking attempt will 204 be non-blocking to avoid unnecessarily waiting on a cache that has 205 been locked for a long time. Since cache isn't strictly required, 206 this could avoid unnecessarily long waits with some edge cases. */ 207 bool last_lock_failed:1; 208 /* cache->hdr_copy has been modified. This must be used only while 209 cache is locked. */ 210 bool hdr_modified:1; 211 /* At least one of the cache fields' last_used or cache decision has 212 changed. mail_cache_header_fields_update() will be used to overwrite 213 these to the latest mail_cache_header_fields. */ 214 bool field_header_write_pending:1; 215 /* Cache is currently being purged. */ 216 bool purging:1; 217 /* Access the cache file by reading as little as possible from it 218 (as opposed to mmap()ing it or using file-cache.h API to cache 219 larger parts of it). This is used with MAIL_INDEX_OPEN_FLAG_SAVEONLY 220 to avoid unnecessary cache reads. */ 221 bool map_with_read:1; 222 }; 223 224 struct mail_cache_loop_track { 225 /* we're looping if size_sum > (max_offset-min_offset) */ 226 uoff_t min_offset, max_offset; 227 uoff_t size_sum; 228 }; 229 230 struct mail_cache_missing_reason_cache { 231 uint32_t highest_checked_seq; 232 uint32_t highest_seq_with_cache; 233 234 uint32_t reset_id; 235 uint32_t log_file_head_seq; 236 uoff_t log_file_head_offset; 237 }; 238 239 struct mail_cache_view { 240 struct mail_cache *cache; 241 struct mail_cache_view *prev, *next; 242 struct mail_index_view *view, *trans_view; 243 244 struct mail_cache_transaction_ctx *transaction; 245 /* mail_cache_add() has been called for some of the messages between 246 trans_seq1..trans_seq2 in an uncommitted transaction. Check also 247 the transaction contents when looking up cache fields for these 248 mails. */ 249 uint32_t trans_seq1, trans_seq2; 250 251 /* Used to avoid infinite loops in case cache records point to each 252 others, causing a loop. FIXME: New cache files no longer support 253 overwriting existing data, so this could be removed and replaced 254 with a simple check that prev_offset is always smaller than the 255 current record's offset. */ 256 struct mail_cache_loop_track loop_track; 257 /* Used for optimizing mail_cache_get_missing_reason() */ 258 struct mail_cache_missing_reason_cache reason_cache; 259 260 /* if cached_exists_buf[field] == cached_exists_value, it's cached. 261 this allows us to avoid constantly clearing the whole buffer. 262 it needs to be cleared only when cached_exists_value is wrapped. */ 263 buffer_t *cached_exists_buf; 264 uint8_t cached_exists_value; 265 uint32_t cached_exists_seq; 266 267 /* mail_cache_view_update_cache_decisions() has been used to disable 268 updating cache decisions. */ 269 bool no_decision_updates:1; 270 }; 271 272 /* mail_cache_lookup_iter_next() returns the next found field. */ 273 struct mail_cache_iterate_field { 274 /* mail_cache_field.idx */ 275 unsigned int field_idx; 276 /* Size of data */ 277 unsigned int size; 278 /* Cache field content in the field type-specific format */ 279 const void *data; 280 /* Offset to data in cache file */ 281 uoff_t offset; 282 }; 283 284 struct mail_cache_lookup_iterate_ctx { 285 struct mail_cache_view *view; 286 /* This must match mail_cache.remap_counter or the iterator is 287 invalid. */ 288 unsigned int remap_counter; 289 /* Message sequence as given to mail_cache_lookup_iter_init() */ 290 uint32_t seq; 291 292 /* Pointer to current cache record being iterated. This may point 293 to the cache file or uncommitted transaction. */ 294 const struct mail_cache_record *rec; 295 /* Iterator's current position in the cache record. Starts from 296 sizeof(mail_cache_record). */ 297 unsigned int pos; 298 /* Copy of rec->size */ 299 unsigned int rec_size; 300 /* Cache file offset to the beginning of rec, or 0 if it points to 301 an uncommitted transaction. */ 302 uint32_t offset; 303 304 /* Used to loop through all changes in the uncommited transaction, 305 in case there are multiple changes to the same message. */ 306 unsigned int trans_next_idx; 307 308 /* Cache has become unusable. Stop the iteration. */ 309 bool stop:1; 310 /* I/O error or lock timeout occurred during iteration. Normally there 311 is no locking during iteration, but it may happen while cache is 312 being purged to wait for the purging to finish before cache can be 313 accessed again. */ 314 bool failed:1; 315 /* Iteration has finished returning changes from uncommitted 316 transaction's in-memory buffer. */ 317 bool memory_appends_checked:1; 318 /* Iteration has finished returning changes from uncommitted 319 transaction that were already written to cache file, but not 320 to main index. */ 321 bool disk_appends_checked:1; 322 /* TRUE if the field index numbers in rec as the internal 323 mail_cache_field.idx (instead of the file-specific indexes). 324 This indicates that the rec points to uncommited transaction's 325 in-memory buffer. */ 326 bool inmemory_field_idx:1; 327 }; 328 329 /* Explicitly lock the cache file. Returns -1 if error / timed out, 330 1 if ok, 0 if cache is broken/doesn't exist */ 331 int mail_cache_lock(struct mail_cache *cache); 332 /* Flush pending header updates and unlock. Returns -1 if cache is / just got 333 corrupted, 0 if ok. */ 334 int mail_cache_flush_and_unlock(struct mail_cache *cache); 335 /* Unlock the cache without any header updates. */ 336 void mail_cache_unlock(struct mail_cache *cache); 337 338 int mail_cache_write(struct mail_cache *cache, const void *data, size_t size, 339 uoff_t offset); 340 int mail_cache_append(struct mail_cache *cache, const void *data, size_t size, 341 uint32_t *offset); 342 343 int mail_cache_header_fields_read(struct mail_cache *cache); 344 int mail_cache_header_fields_update(struct mail_cache *cache); 345 void mail_cache_header_fields_get(struct mail_cache *cache, buffer_t *dest); 346 int mail_cache_header_fields_get_next_offset(struct mail_cache *cache, 347 uint32_t *offset_r); 348 void mail_cache_expunge_count(struct mail_cache *cache, unsigned int count); 349 350 uint32_t mail_cache_lookup_cur_offset(struct mail_index_view *view, 351 uint32_t seq, uint32_t *reset_id_r); 352 int mail_cache_get_record(struct mail_cache *cache, uint32_t offset, 353 const struct mail_cache_record **rec_r); 354 uint32_t mail_cache_get_first_new_seq(struct mail_index_view *view); 355 356 /* Returns TRUE if offset..size area has been tracked before. 357 Returns FALSE if the area may or may not have been tracked before, 358 but we don't know for sure yet. */ 359 bool mail_cache_track_loops(struct mail_cache_loop_track *loop_track, 360 uoff_t offset, uoff_t size); 361 362 /* Iterate through a message's cached fields. */ 363 void mail_cache_lookup_iter_init(struct mail_cache_view *view, uint32_t seq, 364 struct mail_cache_lookup_iterate_ctx *ctx_r); 365 /* Returns 1 if field was returned, 0 if end of fields, or -1 if error */ 366 int mail_cache_lookup_iter_next(struct mail_cache_lookup_iterate_ctx *ctx, 367 struct mail_cache_iterate_field *field_r); 368 const struct mail_cache_record * 369 mail_cache_transaction_lookup_rec(struct mail_cache_transaction_ctx *ctx, 370 unsigned int seq, 371 unsigned int *trans_next_idx); 372 bool mail_cache_transactions_have_changes(struct mail_cache *cache); 373 374 /* Return data from the specified position in the cache file. Returns 1 if 375 successful, 0 if offset/size points outside the cache file, -1 if I/O 376 error. */ 377 int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size, 378 const void **data_r); 379 /* Map the whole cache file into memory. Returns 1 if ok, 0 if corrupted 380 (and deleted), -1 if I/O error. */ 381 int mail_cache_map_all(struct mail_cache *cache); 382 void mail_cache_file_close(struct mail_cache *cache); 383 int mail_cache_reopen(struct mail_cache *cache); 384 int mail_cache_sync_reset_id(struct mail_cache *cache); 385 386 /* Notify the decision handling code that field was looked up for seq. 387 This should be called even for fields that aren't currently in cache file. 388 This is used to update caching decisions for fields that already exist 389 in the cache file. */ 390 void mail_cache_decision_state_update(struct mail_cache_view *view, 391 uint32_t seq, unsigned int field); 392 const char *mail_cache_decision_to_string(enum mail_cache_decision_type dec); 393 struct event_passthrough * 394 mail_cache_decision_changed_event(struct mail_cache *cache, struct event *event, 395 unsigned int field); 396 397 struct mail_cache_purge_drop_ctx { 398 struct mail_cache *cache; 399 time_t max_yes_downgrade_time; 400 time_t max_temp_drop_time; 401 }; 402 enum mail_cache_purge_drop_decision { 403 MAIL_CACHE_PURGE_DROP_DECISION_NONE, 404 MAIL_CACHE_PURGE_DROP_DECISION_DROP, 405 MAIL_CACHE_PURGE_DROP_DECISION_TO_TEMP, 406 }; 407 void mail_cache_purge_drop_init(struct mail_cache *cache, 408 const struct mail_index_header *hdr, 409 struct mail_cache_purge_drop_ctx *ctx_r); 410 enum mail_cache_purge_drop_decision 411 mail_cache_purge_drop_test(struct mail_cache_purge_drop_ctx *ctx, 412 unsigned int field); 413 414 int mail_cache_expunge_handler(struct mail_index_sync_map_ctx *sync_ctx, 415 const void *data, void **sync_context); 416 417 void mail_cache_set_syscall_error(struct mail_cache *cache, 418 const char *function); 419 420 #endif 421