mail-index-private.h revision 51b979b6414b940f04677a7e2d064be119345954
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#ifndef __MAIL_INDEX_PRIVATE_H
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#define __MAIL_INDEX_PRIVATE_H
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
64e244defe74f513ce94f33d000a048ddbe2ea23Timo Sirainen#include "file-lock.h"
1299f2c3723ca9ccf8f9e563ec23ee1a1721fe4cTimo Sirainen#include "mail-index.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "mail-index-view-private.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "mail-index-transaction-private.h"
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include <sys/stat.h>
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstruct mail_transaction_header;
fd7ca4bdc1fb63547d997b6ddd639284cb5a0d01Timo Sirainenstruct mail_transaction_log_view;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstruct mail_index_sync_map_ctx;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen/* How large index files to mmap() instead of reading to memory. */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen#define MAIL_INDEX_MMAP_MIN_SIZE (1024*64)
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen/* How many seconds to wait a lock for index file. */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen#define MAIL_INDEX_LOCK_SECS 120
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen/* How many times to retry opening index files if read/fstat returns ESTALE.
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen This happens with NFS when the file has been deleted (ie. index file was
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen rewritten by another computer than us). */
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#define MAIL_INDEX_ESTALE_RETRY_COUNT NFS_ESTALE_RETRY_COUNT
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#define MAIL_INDEX_IS_IN_MEMORY(index) \
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen ((index)->dir == NULL)
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainen
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainen#define MAIL_INDEX_MAP_IS_IN_MEMORY(map) \
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainen ((map)->buffer != NULL)
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainen
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainen#define MAIL_INDEX_MAP_IDX(map, idx) \
64e244defe74f513ce94f33d000a048ddbe2ea23Timo Sirainen ((struct mail_index_record *) \
64e244defe74f513ce94f33d000a048ddbe2ea23Timo Sirainen PTR_OFFSET((map)->records, (idx) * (map)->hdr.record_size))
87cc5e9025e7fb6408f0de64c48d2d2897773ba5Timo Sirainen
939451389b8e0ad529277b84fe51dab38a8cf77cTimo Sirainentypedef int mail_index_expunge_handler_t(struct mail_index_sync_map_ctx *ctx,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen uint32_t seq, const void *data,
64e244defe74f513ce94f33d000a048ddbe2ea23Timo Sirainen void **sync_context, void *context);
64e244defe74f513ce94f33d000a048ddbe2ea23Timo Sirainentypedef int mail_index_sync_handler_t(struct mail_index_sync_map_ctx *ctx,
9c3577aeb78a27920439ad9f1e62ee03699378c3Timo Sirainen uint32_t seq, void *old_data,
64e244defe74f513ce94f33d000a048ddbe2ea23Timo Sirainen const void *new_data, void **context);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainentypedef void mail_index_sync_lost_handler_t(struct mail_index *index);
64e244defe74f513ce94f33d000a048ddbe2ea23Timo Sirainen
64e244defe74f513ce94f33d000a048ddbe2ea23Timo SirainenARRAY_DEFINE_TYPE(seq_array, uint32_t);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen#define MAIL_INDEX_HEADER_SIZE_ALIGN(size) \
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen (((size) + 7) & ~7)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstruct mail_index_ext {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen const char *name;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen uint32_t index_idx; /* index ext_id */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen uint32_t reset_id;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen uint32_t hdr_offset; /* points to mail_index_ext_header.data[] */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen uint32_t hdr_size; /* size of mail_index_ext_header.data[] */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen uint16_t record_offset;
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen uint16_t record_size;
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen uint16_t record_align;
18ddd4fba186b1b407cae98bb388fa8add7db48dTimo Sirainen};
90ed03ab289947f5576d2c616ada27724f50e9cdTimo Sirainen
63b70dd3e4b4d68a02b1bf7d78e92076210e3e1aTimo Sirainenstruct mail_index_ext_header {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen uint32_t hdr_size; /* size of data[] */
05817ffe09295892e1aa5c4a7f91d060e249563cTimo Sirainen uint32_t reset_id;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen uint16_t record_offset;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen uint16_t record_size;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen uint16_t record_align;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen uint16_t name_size;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen /* unsigned char name[name_size] */
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen /* unsigned char data[hdr_size] (starting 64bit aligned) */
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen};
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstruct mail_index_keyword_header {
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen uint32_t keywords_count;
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen /* struct mail_index_keyword_header_rec[] */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen /* char name[][] */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen};
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstruct mail_index_keyword_header_rec {
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen uint32_t unused; /* for backwards compatibility */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen uint32_t name_offset; /* relative to beginning of name[] */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen};
64e244defe74f513ce94f33d000a048ddbe2ea23Timo Sirainen
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenenum mail_index_sync_handler_type {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen MAIL_INDEX_SYNC_HANDLER_FILE = 0x01,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen MAIL_INDEX_SYNC_HANDLER_HEAD = 0x02,
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen MAIL_INDEX_SYNC_HANDLER_VIEW = 0x04
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen};
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstruct mail_index_sync_handler {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen mail_index_sync_handler_t *callback;
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen enum mail_index_sync_handler_type type;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen};
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstruct mail_index_registered_ext {
66c3f635f2f33905af527d49b27f95322aa7dfa7Timo Sirainen const char *name;
66c3f635f2f33905af527d49b27f95322aa7dfa7Timo Sirainen uint32_t index_idx; /* index ext_id */
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen uint32_t hdr_size; /* size of mail_index_ext_header.data[] */
3b8d05391336c0e4d24c8ddcc962f350409ffbd3Timo Sirainen uint16_t record_size;
3b8d05391336c0e4d24c8ddcc962f350409ffbd3Timo Sirainen uint16_t record_align;
3b8d05391336c0e4d24c8ddcc962f350409ffbd3Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct mail_index_sync_handler sync_handler;
mail_index_expunge_handler_t *expunge_handler;
void *expunge_context;
unsigned int expunge_handler_call_always:1;
};
struct mail_index_map {
struct mail_index *index;
int refcount;
struct mail_index_header hdr;
const void *hdr_base;
void *records; /* struct mail_index_record[] */
unsigned int records_count;
pool_t extension_pool;
ARRAY_DEFINE(extensions, struct mail_index_ext);
ARRAY_DEFINE(ext_id_map, uint32_t); /* index -> file */
void *mmap_base;
size_t mmap_size, mmap_used_size;
unsigned int lock_id;
buffer_t *buffer;
buffer_t *hdr_copy_buf;
ARRAY_DEFINE(keyword_idx_map, unsigned int); /* file -> index */
/* If this mapping is written to disk and write_atomic=FALSE,
write_seq_* specify the message sequence range that needs to be
written. */
uint32_t write_seq_first, write_seq_last;
unsigned int keywords_read:1;
unsigned int write_base_header:1;
unsigned int write_ext_header:1;
unsigned int write_atomic:1; /* write to a new file and rename() */
};
struct mail_index_module_register {
unsigned int id;
};
union mail_index_module_context {
struct mail_index_module_register *reg;
};
struct mail_index {
char *dir, *prefix;
struct mail_cache *cache;
struct mail_transaction_log *log;
mode_t mode;
gid_t gid;
pool_t extension_pool;
ARRAY_DEFINE(extensions, struct mail_index_registered_ext);
ARRAY_DEFINE(sync_lost_handlers, mail_index_sync_lost_handler_t *);
char *filepath;
int fd;
struct mail_index_map *map;
uint32_t indexid;
/* last_read_log_file_* contains the seq/offsets we last read from
the main index file's headers. these are used to figure out when
the main index file should be updated, and if we can update it
by writing on top of it or if we need to recreate it. */
uint32_t last_read_log_file_seq;
uint32_t last_read_log_file_head_offset;
uint32_t last_read_log_file_tail_offset;
struct stat last_read_stat;
/* transaction log head seq/offset when we last fscked */
uint32_t fsck_log_head_file_seq;
uoff_t fsck_log_head_file_offset;
int lock_type, shared_lock_count, excl_lock_count;
unsigned int lock_id_counter;
enum file_lock_method lock_method;
struct file_lock *file_lock;
struct dotlock *dotlock;
pool_t keywords_pool;
ARRAY_TYPE(keywords) keywords;
struct hash_table *keywords_hash; /* name -> idx */
uint32_t keywords_ext_id;
/* Module-specific contexts. */
ARRAY_DEFINE(module_contexts, union mail_index_module_context *);
char *error;
unsigned int nodiskspace:1;
unsigned int index_lock_timeout:1;
unsigned int opened:1;
unsigned int log_locked:1;
unsigned int mmap_disable:1;
unsigned int fsync_disable:1;
unsigned int use_excl_dotlocks:1;
unsigned int nfs_flush:1;
unsigned int readonly:1;
unsigned int fsck:1;
unsigned int mapping:1;
};
extern struct mail_index_module_register mail_index_module_register;
/* Add/replace sync handler for specified extra record. */
void mail_index_register_expunge_handler(struct mail_index *index,
uint32_t ext_id, bool call_always,
mail_index_expunge_handler_t *callback,
void *context);
void mail_index_unregister_expunge_handler(struct mail_index *index,
uint32_t ext_id);
void mail_index_register_sync_handler(struct mail_index *index, uint32_t ext_id,
mail_index_sync_handler_t *cb,
enum mail_index_sync_handler_type type);
void mail_index_unregister_sync_handler(struct mail_index *index,
uint32_t ext_id);
void mail_index_register_sync_lost_handler(struct mail_index *index,
mail_index_sync_lost_handler_t *cb);
void mail_index_unregister_sync_lost_handler(struct mail_index *index,
mail_index_sync_lost_handler_t *cb);
int mail_index_create_tmp_file(struct mail_index *index, const char **path_r);
int mail_index_try_open_only(struct mail_index *index);
int mail_index_reopen_if_changed(struct mail_index *index);
/* Update/rewrite the main index file from index->map */
void mail_index_write(struct mail_index *index, bool want_rotate);
/* Returns 0 = ok, -1 = error. */
int mail_index_lock_shared(struct mail_index *index, unsigned int *lock_id_r);
/* Returns 1 = ok, 0 = already locked, -1 = error. */
int mail_index_try_lock_exclusive(struct mail_index *index,
unsigned int *lock_id_r);
void mail_index_unlock(struct mail_index *index, unsigned int *lock_id);
/* Returns TRUE if given lock_id is valid. */
bool mail_index_is_locked(struct mail_index *index, unsigned int lock_id);
int mail_index_lock_fd(struct mail_index *index, const char *path, int fd,
int lock_type, unsigned int timeout_secs,
struct file_lock **lock_r);
/* Allocate a new empty map. */
struct mail_index_map *mail_index_map_alloc(struct mail_index *index);
/* Replace index->map with the latest index changes. This may reopen the index
file and/or it may read the latest changes from transaction log. The log is
read up to EOF, but non-synced expunges are skipped.
If we mmap()ed the index file, the map is returned locked.
Returns 1 = ok, 0 = corrupted, -1 = error. If non-fatal problems were found,
1 is returned but index->fsck=TRUE is set. */
int mail_index_map(struct mail_index *index,
enum mail_index_sync_handler_type type);
/* Unreference given mapping and unmap it if it's dropped to zero. */
void mail_index_unmap(struct mail_index_map **map);
/* Lock the map if the data is mmaped and map is unlocked. */
int mail_index_map_lock(struct mail_index_map *map);
/* Unlock the map if it's locked. */
void mail_index_map_unlock(struct mail_index_map *map);
/* Clone a map. The returned map is always in memory. */
struct mail_index_map *mail_index_map_clone(const struct mail_index_map *map);
/* Move a mmaped map to memory. */
void mail_index_map_move_to_memory(struct mail_index_map *map);
uint32_t mail_index_map_lookup_ext(struct mail_index_map *map,
const char *name);
uint32_t
mail_index_map_register_ext(struct mail_index_map *map, const char *name,
uint32_t hdr_offset, uint32_t hdr_size,
uint32_t record_offset, uint32_t record_size,
uint32_t record_align, uint32_t reset_id);
int mail_index_map_get_ext_idx(struct mail_index_map *map,
uint32_t ext_id, uint32_t *idx_r);
const struct mail_index_ext *
mail_index_view_get_ext(struct mail_index_view *view, uint32_t ext_id);
int mail_index_map_parse_keywords(struct mail_index_map *map);
void mail_index_view_transaction_ref(struct mail_index_view *view);
void mail_index_view_transaction_unref(struct mail_index_view *view);
int mail_index_set_error(struct mail_index *index, const char *fmt, ...)
__attr_format__(2, 3);
/* "%s failed with index file %s: %m" */
int mail_index_set_syscall_error(struct mail_index *index,
const char *function);
/* "%s failed with file %s: %m" */
int mail_index_file_set_syscall_error(struct mail_index *index,
const char *filepath,
const char *function);
uint32_t mail_index_uint32_to_offset(uint32_t offset);
uint32_t mail_index_offset_to_uint32(uint32_t offset);
#endif