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