view src/lib-index/mail-index-private.h @ 5626:d1de7c486763 HEAD

Removed mmap_no_write setting. The only OS requiring it is OpenBSD, so we're now forcing mmap_disable=yes with it instead. dovecot.index.cache file is the most important file to mmap(), but since this didn't work with mmap_no_write, there's not much point in keeping special code paths for minimal gains.
author Timo Sirainen <tss@iki.fi>
date Wed, 16 May 2007 18:25:28 +0300
parents a0a1432bb4e8
children c46edae0e454
line wrap: on
line source

#ifndef __MAIL_INDEX_PRIVATE_H
#define __MAIL_INDEX_PRIVATE_H

#include "file-lock.h"
#include "mail-index.h"
#include "mail-index-view-private.h"
#include "mail-index-transaction-private.h"

struct mail_transaction_header;
struct mail_transaction_log_view;
struct mail_index_sync_map_ctx;

/* How many seconds to wait a lock for index file. */
#define MAIL_INDEX_LOCK_SECS 120
/* Index file is grown exponentially when we're adding less than this many
   records. */
#define MAIL_INDEX_MAX_POWER_GROW (1024*1024 / sizeof(struct mail_index_record))
/* How many times to retry opening index files if read/fstat returns ESTALE.
   This happens with NFS when the file has been deleted (ie. index file was
   rewritten by another computer than us). */
#define MAIL_INDEX_ESTALE_RETRY_COUNT NFS_ESTALE_RETRY_COUNT

#define MAIL_INDEX_IS_IN_MEMORY(index) \
	((index)->dir == NULL)

#define MAIL_INDEX_MAP_IS_IN_MEMORY(map) \
	((map)->buffer != NULL)

#define MAIL_INDEX_MAP_IDX(map, idx) \
	((struct mail_index_record *) \
		PTR_OFFSET((map)->records, (idx) * (map)->hdr.record_size))

typedef int mail_index_expunge_handler_t(struct mail_index_sync_map_ctx *ctx,
					 uint32_t seq, const void *data,
					 void **sync_context, void *context);
typedef int mail_index_sync_handler_t(struct mail_index_sync_map_ctx *ctx,
				      uint32_t seq, void *old_data,
				      const void *new_data, void **context);
typedef void mail_index_sync_lost_handler_t(struct mail_index *index);

ARRAY_DEFINE_TYPE(seq_array, uint32_t);

#define MAIL_INDEX_HEADER_SIZE_ALIGN(size) \
	(((size) + 7) & ~7)

struct mail_index_ext {
	const char *name;
	uint32_t index_idx; /* index ext_id */
	uint32_t reset_id;
	uint32_t hdr_offset; /* points to mail_index_ext_header.data[] */
	uint32_t hdr_size; /* size of mail_index_ext_header.data[] */
	uint16_t record_offset;
	uint16_t record_size;
	uint16_t record_align;
};

struct mail_index_ext_header {
	uint32_t hdr_size; /* size of data[] */
	uint32_t reset_id;
	uint16_t record_offset;
	uint16_t record_size;
	uint16_t record_align;
	uint16_t name_size;
	/* unsigned char name[name_size] */
	/* unsigned char data[hdr_size] (starting 64bit aligned) */
};

struct mail_index_keyword_header {
	uint32_t keywords_count;
	/* struct mail_index_keyword_header_rec[] */
	/* char name[][] */
};

struct mail_index_keyword_header_rec {
	uint32_t unused; /* for backwards compatibility */
	uint32_t name_offset; /* relative to beginning of name[] */
};

enum mail_index_sync_handler_type {
	MAIL_INDEX_SYNC_HANDLER_FILE	= 0x01,
	MAIL_INDEX_SYNC_HANDLER_HEAD	= 0x02,
	MAIL_INDEX_SYNC_HANDLER_VIEW	= 0x04
};

struct mail_index_sync_handler {
	mail_index_sync_handler_t *callback;
        enum mail_index_sync_handler_type type;
};

struct mail_index_registered_ext {
	const char *name;
	uint32_t index_idx; /* index ext_id */
	uint32_t hdr_size; /* size of mail_index_ext_header.data[] */
	uint16_t record_size;
	uint16_t record_align;

	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 {
	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;

	buffer_t *buffer;
	buffer_t *hdr_copy_buf;

	ARRAY_DEFINE(keyword_idx_map, unsigned int); /* file -> index */

	/* If write_to_disk=TRUE and write_atomic=FALSE, these sequences
	   specify the range that needs to be written. Header should always
	   be rewritten. */
	uint32_t write_seq_first, write_seq_last;

	unsigned int keywords_read:1;
	unsigned int write_to_disk:1;
	unsigned int write_atomic:1; /* copy to 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;
	const struct mail_index_header *hdr;
	uint32_t indexid;

	int lock_type, shared_lock_count, excl_lock_count;
	unsigned int lock_id;
	char *copy_lock_path;
	enum file_lock_method lock_method;

	struct file_lock *file_lock;
	struct dotlock *dotlock;

	/* These are typically same as map->hdr->log_file_*, but with
	   mmap_disable we may have synced more than index */
	uint32_t sync_log_file_seq;
	uoff_t sync_log_file_offset;

	pool_t keywords_pool;
	ARRAY_TYPE(keywords) keywords;
	struct hash_table *keywords_hash; /* name -> idx */

	uint32_t keywords_ext_id;
	unsigned int last_grow_count;

	/* 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 readonly:1;
	unsigned int fsck:1;
	unsigned int sync_update: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_write_base_header(struct mail_index *index,
				 const struct mail_index_header *hdr);

int mail_index_reopen(struct mail_index *index, int fd);
int mail_index_create_tmp_file(struct mail_index *index, const char **path_r);

/* Returns 0 = ok, -1 = error. If update_index is TRUE, reopens the index
   file if needed to get later version of it (not necessarily latest due to
   races, unless transaction log is exclusively locked). */
int mail_index_lock_shared(struct mail_index *index, bool update_index,
			   unsigned int *lock_id_r);
/* Returns 0 = ok, -1 = error. */
int mail_index_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);

/* Reopen index file if it has changed. */
int mail_index_reopen_if_needed(struct mail_index *index);

/* Map index file to memory, replacing the previous mapping for index.
   Returns 1 = ok, 0 = corrupted, -1 = error. If index needs fscking, it
   returns 1 but sets index->fsck = TRUE. */
int mail_index_map(struct mail_index *index, bool force);
/* Read the latest available header. Normally this is pretty much the same as
   calling mail_index_map(), but with mmap_disable the header can be generated
   by reading just log files, so eg. log_file_*_offset values can be wrong.
   Returns 1 = ok, 0 = EOF, -1 = error. */
int mail_index_get_latest_header(struct mail_index *index,
				 struct mail_index_header *hdr_r);
/* Unreference given mapping and unmap it if it's dropped to zero. */
void mail_index_unmap(struct mail_index *index, struct mail_index_map **map);
struct mail_index_map *
mail_index_map_clone(const struct mail_index_map *map,
		     uint32_t new_record_size);

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 *index,
			    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);
void mail_index_view_recalc_counters(struct mail_index_view *view);

int mail_index_map_parse_keywords(struct mail_index *index,
                                  struct mail_index_map *map);

int mail_index_fix_header(struct mail_index *index, struct mail_index_map *map,
			  struct mail_index_header *hdr, const char **error_r);
bool mail_index_is_ext_synced(struct mail_transaction_log_view *log_view,
			      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);

void mail_index_set_inconsistent(struct mail_index *index);

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