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