view src/lib-index/mail-cache-private.h @ 2999:1d328531c466 HEAD

mail_cache_decision_*() prototypes were wrong.
author Timo Sirainen <tss@iki.fi>
date Sun, 19 Dec 2004 10:19:00 +0200
parents 89ab5c72430d
children 9c4aa309dbac
line wrap: on
line source

#ifndef __MAIL_CACHE_PRIVATE_H
#define __MAIL_CACHE_PRIVATE_H

#include "mail-index-private.h"
#include "mail-cache.h"

#define MAIL_CACHE_VERSION 1

/* Never compress the file if it's smaller than this */
#define COMPRESS_MIN_SIZE (1024*50)

/* Don't bother remembering holes smaller than this */
#define MAIL_CACHE_MIN_HOLE_SIZE 1024

/* Compress the file when deleted space reaches n% of total size */
#define COMPRESS_PERCENTAGE 20

/* Compress the file when n% of rows contain continued rows.
   200% means that there's 2 continued rows per record. */
#define COMPRESS_CONTINUED_PERCENTAGE 200

/* Initial size for the file */
#define MAIL_CACHE_INITIAL_SIZE (sizeof(struct mail_cache_header) + 10240)

/* When more space is needed, grow the file n% larger than the previous size */
#define MAIL_CACHE_GROW_PERCENTAGE 10

/* When allocating space for transactions, don't use blocks larger than this. */
#define MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE (1024*512)

#define MAIL_CACHE_LOCK_TIMEOUT 120
#define MAIL_CACHE_LOCK_CHANGE_TIMEOUT 60
#define MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT (5*60)

#define CACHE_RECORD(cache, offset) \
	((const struct mail_cache_record *) \
	 ((const char *) (cache)->data + offset))

#define MAIL_CACHE_IS_UNUSABLE(cache) \
	((cache)->hdr == NULL)

struct mail_cache_header {
	/* version is increased only when you can't have backwards
	   compatibility. */
	uint8_t version;
	uint8_t unused[3];

	uint32_t indexid;
	uint32_t file_seq;

	uint32_t continued_record_count;

	uint32_t hole_offset;
	uint32_t used_file_size;
	uint32_t deleted_space;

	uint32_t field_header_offset;
};

struct mail_cache_header_fields {
	uint32_t next_offset;
	uint32_t size;
	uint32_t fields_count;

#if 0
	/* last time the field was accessed. not updated more often than
	   once a day. */
	uint32_t last_used[fields_count];
	/* (uint32_t)-1 for variable sized fields */
	uint32_t size[fields_count];
	/* enum mail_cache_field_type */
	uint8_t type[fields_count];
	/* enum mail_cache_decision_type */
	uint8_t decision[fields_count];
	/* NUL-separated list of field names */
	char name[fields_count][];
#endif
};

#define MAIL_CACHE_FIELD_LAST_USED() \
	(sizeof(uint32_t) * 3)
#define MAIL_CACHE_FIELD_SIZE(count) \
	(MAIL_CACHE_FIELD_LAST_USED() + sizeof(uint32_t) * (count))
#define MAIL_CACHE_FIELD_TYPE(count) \
	(MAIL_CACHE_FIELD_SIZE(count) + sizeof(uint32_t) * (count))
#define MAIL_CACHE_FIELD_DECISION(count) \
	(MAIL_CACHE_FIELD_TYPE(count) + sizeof(uint8_t) * (count))
#define MAIL_CACHE_FIELD_NAMES(count) \
	(MAIL_CACHE_FIELD_DECISION(count) + sizeof(uint8_t) * (count))

struct mail_cache_record {
	uint32_t prev_offset;
	uint32_t size; /* full record size, including this header */
	/* array of { uint32_t field; [ uint32_t size; ] { .. } } */
};

struct mail_cache_hole_header {
	uint32_t next_offset; /* 0 if no holes left */
	uint32_t size; /* including this header */

	/* make sure we notice if we're treating hole as mail_cache_record.
	   magic is a large number so if it's treated as size field, it'll
	   point outside the file */
#define MAIL_CACHE_HOLE_HEADER_MAGIC 0xffeedeff
	uint32_t magic;
};

struct mail_cache_field_private {
	struct mail_cache_field field;

	uint32_t uid_highwater;
	uint32_t last_used;

	unsigned int decision_dirty:1;
};

struct mail_cache {
	struct mail_index *index;
	uint32_t ext_id;

	char *filepath;
	int fd;

	void *mmap_base;
	const void *data;
	size_t mmap_length;
	struct file_cache *file_cache;
	struct dotlock dotlock;

	const struct mail_cache_header *hdr;
	struct mail_cache_header hdr_copy;

	pool_t field_pool;
	struct mail_cache_field_private *fields;
	uint32_t *field_file_map;
	unsigned int fields_count;
	struct hash_table *field_name_hash; /* name -> idx */

	unsigned int *file_field_map;
	unsigned int file_fields_count;

	unsigned int locked:1;
	unsigned int need_compress:1;
	unsigned int hdr_modified:1;
	unsigned int field_header_write_pending:1;
};

struct mail_cache_view {
	struct mail_cache *cache;
	struct mail_index_view *view, *trans_view;

	struct mail_cache_transaction_ctx *transaction;
	uint32_t trans_seq1, trans_seq2;

	buffer_t *offsets_buf; /* temporary buffer, just to avoid mallocs */

	/* if cached_exists_buf[field] == cached_exists_value, it's cached.
	   this allows us to avoid constantly clearing the whole buffer.
	   it needs to be cleared only when cached_exists_value is wrapped. */
	buffer_t *cached_exists_buf;
	uint8_t cached_exists_value;
	uint32_t cached_exists_seq;
	uint32_t cached_offset, cached_offset_seq;
};

typedef int mail_cache_foreach_callback_t(struct mail_cache_view *view,
					  uint32_t field,
					  const void *data, size_t data_size,
					  void *context);

/* Explicitly lock the cache file. Returns -1 if error, 1 if ok, 0 if we
   couldn't lock */
int mail_cache_lock(struct mail_cache *cache);
void mail_cache_unlock(struct mail_cache *cache);

int mail_cache_header_fields_read(struct mail_cache *cache);
int mail_cache_header_fields_update(struct mail_cache *cache);
void mail_cache_header_fields_get(struct mail_cache *cache, buffer_t *dest);
int mail_cache_header_fields_get_next_offset(struct mail_cache *cache,
					     uint32_t *offset_r);

int mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
			  const struct mail_cache_record **rec_r);

int mail_cache_foreach(struct mail_cache_view *view, uint32_t seq,
		       mail_cache_foreach_callback_t *callback, void *context);

int mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx);
void mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx);

int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size);
void mail_cache_file_close(struct mail_cache *cache);
int mail_cache_reopen(struct mail_cache *cache);

/* Update new_offset's prev_offset field to old_offset. */
int mail_cache_link(struct mail_cache *cache, uint32_t old_offset,
		    uint32_t new_offset);
/* Mark record in given offset to be deleted. */
int mail_cache_delete(struct mail_cache *cache, uint32_t offset);

void mail_cache_decision_lookup(struct mail_cache_view *view, uint32_t seq,
				unsigned int field);
void mail_cache_decision_add(struct mail_cache_view *view, uint32_t seq,
			     unsigned int field);

int mail_cache_expunge_handler(struct mail_index_sync_map_ctx *sync_ctx,
			       uint32_t seq, const void *data, void **context);
int mail_cache_sync_handler(struct mail_index_sync_map_ctx *sync_ctx,
			    uint32_t seq, void *old_data, const void *new_data,
			    void **context);
void mail_cache_sync_lost_handler(struct mail_index *index);

void mail_cache_set_syscall_error(struct mail_cache *cache,
				  const char *function);

#endif