#ifndef MAIL_INDEX_H
#define MAIL_INDEX_H
#include "file-lock.h"
#include "fsync-mode.h"
#include "guid.h"
#include "mail-types.h"
#include "seq-range-array.h"
/* Log a warning when transaction log has been locked for this many seconds.
This lock is held also between mail_index_sync_begin()..commit(). */
enum mail_index_open_flags {
/* Create index if it doesn't exist */
/* Don't try to mmap() index files */
/* Rely on O_EXCL when creating dotlocks */
/* Open the index read-only */
/* Create backups of dovecot.index files once in a while */
/* If we run out of disk space, fail modifications instead of moving
indexes to memory. */
/* We're only going to save new messages to the index.
Avoid unnecessary reads. */
/* Enable debug logging */
/* MAIL_INDEX_MAIL_FLAG_DIRTY can be used as a backend-specific flag.
All special handling of the flag is disabled by this. */
};
};
enum mail_index_header_flag {
/* Index file is corrupted, reopen or recreate it. */
/* Index has been fsck'd. The caller may want to resync the index
to make sure it's valid and drop this flag. */
};
enum mail_index_mail_flags {
/* For private use by backend. Replacing flags doesn't change this. */
/* Message flags haven't been written to backend. If
MAIL_INDEX_OPEN_FLAG_NO_DIRTY is set, this is treated as a
backend-specific flag with no special internal handling. */
/* Force updating this message's modseq via a flag update record */
};
#define MAIL_INDEX_FLAGS_MASK \
struct mail_index_header {
/* major version is increased only when you can't have backwards
compatibility. minor version is increased when header size is
increased to contain new non-critical fields. */
/* non-external records between tail..head haven't been committed to
mailbox yet. */
/* Timestamp of when .log was rotated into .log.2. This can be used to
optimize checking when it's time to unlink it without stat()ing it.
0 = unknown, -1 = .log.2 doesn't exists. */
/* daily first UIDs that have been added to index. */
};
struct mail_index_record {
};
struct mail_keywords {
unsigned int count;
int refcount;
/* variable sized list of keyword indexes */
};
enum mail_index_transaction_flags {
/* If transaction is marked as hidden, the changes are marked with
hidden=TRUE when the view is synchronized. */
/* External transactions describe changes to mailbox that have already
happened. */
/* Don't add flag updates unless they actually change something.
This is reliable only when syncing, otherwise someone else might
have already committed a transaction that had changed the flags. */
/* fsync() this transaction (unless fsyncs are disabled) */
/* Sync transaction describes changes to mailbox that already happened
to another mailbox with whom we're syncing with (dsync) */
};
enum mail_index_sync_type {
};
enum mail_index_fsync_mask {
};
enum mail_index_sync_flags {
/* Resync all dirty messages' flags. */
/* Drop recent flags from all messages */
/* Create the transaction with AVOID_FLAG_UPDATES flag */
/* If there are no new transactions and nothing else to do,
return 0 in mail_index_sync_begin() */
/* Create the transaction with FSYNC flag */
/* If we see "delete index" request transaction, finish it.
This flag also allows committing more changes to a deleted index. */
/* Same as MAIL_INDEX_SYNC_FLAG_DELETING_INDEX, but finish index
deletion only once and fail the rest (= avoid race conditions when
multiple processes try to mark the index deleted) */
/* Update header's tail_offset to head_offset, even if it's the only
thing we do and there's no strict need for it. */
};
enum mail_index_view_sync_flags {
/* Don't sync expunges */
/* Make sure view isn't inconsistent after syncing. This also means
that you don't care about view_sync_next()'s output, so it won't
return anything. */
};
struct mail_index_sync_rec {
/* MAIL_INDEX_SYNC_TYPE_FLAGS: */
/* MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD, .._REMOVE: */
unsigned int keyword_idx;
/* MAIL_INDEX_SYNC_TYPE_EXPUNGE: */
};
enum mail_index_view_sync_type {
/* Flags or keywords changed */
};
struct mail_index_view_sync_rec {
/* TRUE if this was a hidden transaction. */
};
};
struct mail_index_transaction_commit_result {
/* number of bytes in the written transaction.
all of it was written to the same file. */
unsigned int ignored_modseq_changes;
};
/* Rewrite the index when the number of bytes that needs to be read
};
struct mail_index_log_optimization_settings {
/* Rotate transaction log after it's a) min_size or larger and it was
created at least min_age_secs or b) larger than max_size. */
unsigned int min_age_secs;
/* Delete .log.2 when it's older than log2_stale_secs. Don't be too
eager, because older files are useful for QRESYNC and dsync. */
unsigned int log2_max_age_secs;
};
/* Drop fields that haven't been accessed for n seconds */
unsigned int unaccessed_field_drop_secs;
/* If cache record becomes larger than this, don't add it. */
unsigned int record_max_size;
/* Never compress the file if it's smaller than this */
/* Compress the file when n% of records are deleted */
unsigned int compress_delete_percentage;
/* Compress the file when n% of rows contain continued rows.
For example 200% means that the record has 2 continued rows, i.e.
it exists in 3 separate segments in the cache file. */
unsigned int compress_continued_percentage;
/* Compress the file when we need to follow more than n next_offsets to
find the latest cache header. */
unsigned int compress_header_continue_count;
};
struct mail_index_optimization_settings {
};
struct mail_index;
struct mail_index_map;
struct mail_index_view;
struct mail_index_transaction;
struct mail_index_sync_ctx;
struct mail_index_view_sync_ctx;
/* Change .cache file's directory. */
/* Specify how often to do fsyncs. If mode is FSYNC_MODE_OPTIMIZED, the mask
can be used to specify which transaction types to fsync. */
enum mail_index_fsync_mask mask);
/* Try to set the index's permissions based on its index directory. Returns
TRUE if successful (directory existed), FALSE if mail_index_set_permissions()
should be called. */
/* Set locking method and maximum time to wait for a lock
(UINT_MAX = default). */
enum file_lock_method lock_method,
unsigned int max_timeout_secs);
/* Override the default optimization-related settings. Anything set to 0 will
use the default. */
const struct mail_index_optimization_settings *set);
/* When creating a new index file or reseting an existing one, add the given
extension header data immediately to it. */
/* Open index. Returns 1 if ok, 0 if index doesn't exist and CREATE flags
wasn't given, -1 if error. */
/* Open or create index. Returns 0 if ok, -1 if error. */
enum mail_index_open_flags flags);
/* unlink() all the index files. */
/* Returns TRUE if index is currently in memory. */
/* Move the index into memory. Returns 0 if ok, -1 if error occurred. */
/* Refresh index so mail_index_lookup*() will return latest values. Note that
immediately after this call there may already be changes, so if you need to
rely on validity of the returned values, use some external locking for it. */
/* View can be used to look into index. Sequence numbers inside view change
only when you synchronize it. The view acquires required locks
automatically, but you'll have to drop them manually. */
struct mail_index_view *
const char *source_filename, unsigned int source_linenum);
/* Returns the index for given view. */
/* Returns number of mails in view. */
/* Returns TRUE if we lost track of changes for some reason. */
/* Returns number of transactions open for the view. */
unsigned int
/* Transaction has to be opened to be able to modify index. You can have
multiple transactions open simultaneously. Committed transactions won't
show up until you've synchronized the view. Expunges won't show up until
you've synchronized the mailbox (mail_index_sync_begin). */
struct mail_index_transaction *
int mail_index_transaction_commit(struct mail_index_transaction **t);
int mail_index_transaction_commit_full(struct mail_index_transaction **t,
struct mail_index_transaction_commit_result *result_r);
void mail_index_transaction_rollback(struct mail_index_transaction **t);
/* Discard all changes in the transaction. */
void mail_index_transaction_reset(struct mail_index_transaction *t);
mdoseq is larger than max_modseq. Save those messages' sequences to the
given array. */
void mail_index_transaction_set_max_modseq(struct mail_index_transaction *t,
/* Returns the resulting highest-modseq after this commit. This can be called
only if transaction log is locked, which normally means only during mail
index syncing. If there are any appends, they all must have been assigned
UIDs before calling this. */
/* Returns the view transaction was created for. */
struct mail_index_view *
/* Returns TRUE if the given sequence is being expunged in this transaction. */
bool mail_index_transaction_is_expunged(struct mail_index_transaction *t,
/* Returns a view containing the mailbox state after changes in transaction
are applied. The view can still be used after transaction has been
committed. */
struct mail_index_view *
/* Begin synchronizing mailbox with index file. Returns 1 if ok,
0 if MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES is set and there's nothing to
sync, -1 if error.
mail_index_sync_next() returns all changes from previously committed
transactions which haven't yet been committed to the actual mailbox.
They're returned in ascending order and they never overlap (if we add more
sync types, then they might). You must go through all of them and update
the mailbox accordingly.
Changes done to the returned transaction are expected to describe the
mailbox's current state.
The returned view already contains all the changes (except expunge
requests). After applying sync records on top of backend flags they should
match flags in the view. If they don't, there have been external changes.
Returned expunges are treated as expunge requests. They're not really
removed from the index until you mark them expunged to the returned
transaction. If it's not possible to expunge the message (e.g. permission
denied), simply don't mark them expunged.
Returned sequence numbers describe the mailbox state at the beginning of
synchronization, ie. expunges don't affect them. */
struct mail_index_sync_ctx **ctx_r,
struct mail_index_view **view_r,
struct mail_index_transaction **trans_r,
enum mail_index_sync_flags flags);
/* Like mail_index_sync_begin(), but returns 1 if OK and if index is already
synchronized up to the given log_file_seq+offset, the synchronization isn't
started and this function returns 0. This should be done when you wish to
sync your committed transaction instead of doing a full mailbox
synchronization. */
struct mail_index_sync_ctx **ctx_r,
struct mail_index_view **view_r,
struct mail_index_transaction **trans_r,
enum mail_index_sync_flags flags);
/* Returns TRUE if it currently looks like syncing would return changes. */
enum mail_index_sync_flags flags);
/* Returns TRUE if it currently looks like syncing would return expunges. */
/* Returns the log file seq+offsets for the area which this sync is handling. */
/* Returns -1 if error, 0 if sync is finished, 1 if record was filled. */
struct mail_index_sync_rec *sync_rec);
/* Returns TRUE if there's more to sync. */
/* Returns TRUE if sync has any expunges to handle. */
/* Reset syncing to initial state after mail_index_sync_begin(), so you can
go through all the sync records again with mail_index_sync_next(). */
/* Update result when refreshing index at the end of sync. */
struct mail_index_transaction_commit_result *result);
/* Don't log a warning even if syncing took over
MAIL_TRANSACTION_LOG_LOCK_WARN_SECS seconds. Usually this is called because
the caller itself already logged a warning about it. */
/* If a warning is logged because syncing took over
MAIL_TRANSACTION_LOG_LOCK_WARN_SECS seconds, log this as the reason for the
syncing. */
const char *reason);
/* Commit synchronization by writing all changes to mail index file. */
/* Rollback synchronization - none of the changes listed by sync_next() are
actually written to index file. */
/* Mark index file corrupted. Invalidates all views. */
/* Check and fix any found problems. Returns -1 if we couldn't lock for sync,
0 if everything went ok. */
/* Returns TRUE if mail_index_fsck() has been called since the last
mail_index_reset_fscked() call. */
/* Synchronize changes in view. You have to go through all records, or view
will be marked inconsistent. Only sync_mask type records are
synchronized. */
struct mail_index_view_sync_ctx *
enum mail_index_view_sync_flags flags);
struct mail_index_view_sync_rec *sync_rec);
void
bool *delayed_expunges_r);
/* Returns the index header. */
const struct mail_index_header *
/* Returns the wanted message record. */
const struct mail_index_record *
const struct mail_index_record *
struct mail_index_map **map_r);
/* Returns TRUE if the given message has already been expunged from index. */
/* Note that returned keyword indexes aren't sorted. */
/* Return keywords from given map. */
/* mail_index_lookup[_keywords]() returns the latest flag changes.
This function instead attempts to return the flags and keywords done by the
last view sync. */
enum mail_flags *flags_r,
/* Returns the UID for given message. May be slightly faster than
mail_index_lookup()->uid. */
/* Convert UID range to sequence range. If no UIDs are found, returns FALSE and
sequences are set to 0. Note that any of the returned sequences may have
been expunged already. */
/* Find first mail with (mail->flags & flags_mask) == flags. Useful mostly for
taking advantage of lowwater-fields in headers. */
/* Append a new record to index. */
/* Assign UIDs for mails with uid=0 or uid<first_uid. All the assigned UIDs
are higher than the highest unassigned UID (i.e. it doesn't try to fill UID
gaps). Assumes that mailbox is locked in a way that UIDs can be safely
assigned. Returns UIDs for all assigned messages, in their sequence order
(so UIDs are not necessary ascending). */
void mail_index_append_finish_uids(struct mail_index_transaction *t,
/* Expunge record from index. Note that this doesn't affect sequence numbers
until transaction is committed and mailbox is synced. */
/* Like mail_index_expunge(), but also write message GUID to transaction log. */
const guid_128_t guid_128);
/* Revert all changes done in this transaction to the given existing mail. */
/* Update flags in index. */
enum modify_type modify_type,
enum mail_flags flags);
void mail_index_update_flags_range(struct mail_index_transaction *t,
enum modify_type modify_type,
enum mail_flags flags);
/* Specified attribute's value was changed. This is just a notification so the
change gets assigned its own modseq and any log readers can find out about
this change. */
void mail_index_attribute_set(struct mail_index_transaction *t,
/* Attribute was deleted. */
void mail_index_attribute_unset(struct mail_index_transaction *t,
/* Update message's modseq to be at least min_modseq. */
/* Update highest modseq to be at least min_modseq. */
void mail_index_update_highest_modseq(struct mail_index_transaction *t,
/* Reset the index before committing this transaction. This is usually done
only when UIDVALIDITY changes. */
void mail_index_reset(struct mail_index_transaction *t);
/* Remove MAIL_INDEX_HDR_FLAG_FSCKD from header if it exists. This must be
called only during syncing so that the mailbox is locked. */
void mail_index_unset_fscked(struct mail_index_transaction *t);
/* Mark index deleted. No further changes will be possible after the
transaction has been committed. */
void mail_index_set_deleted(struct mail_index_transaction *t);
/* Mark a deleted index as undeleted. Afterwards index can be changed again. */
void mail_index_set_undeleted(struct mail_index_transaction *t);
/* Returns TRUE if index has been set deleted. This gets set only after
/* Returns the last time the index was modified. This can be called even if the
index isn't open. If the index doesn't exist, sets mtime to 0. */
/* Lookup a keyword, returns TRUE if found, FALSE if not. */
const char *keyword,
unsigned int *idx_r);
/* Return a pointer to array of NULL-terminated list of keywords. Note that
the array contents (and thus pointers inside it) may change after calling
mail_index_keywords_create() or mail_index_sync_begin(). */
/* Create a keyword list structure. */
struct mail_keywords *
struct mail_keywords *
const ARRAY_TYPE(keyword_indexes)
/* Update keywords for given message. */
enum modify_type modify_type,
struct mail_keywords *keywords);
/* Update field in header. If prepend is TRUE, the header change is visible
before message syncing begins. */
void mail_index_update_header(struct mail_index_transaction *t,
bool prepend);
/* Returns the full error message for last error. This message may
contain paths etc. so it shouldn't be shown to users. */
/* Reset the error message. */
/* Apply changes in MAIL_INDEX_SYNC_TYPE_FLAGS typed sync records to given
flags variable. */
/* Apply changes in MAIL_INDEX_SYNC_TYPE_KEYWORD_* typed sync records to given
keywords array. Returns TRUE If something was changed. */
/* register index extension. name is a unique identifier for the extension.
returns unique identifier for the name. */
/* Change an already registered extension's default sizes. */
/* Returns TRUE and sets ext_id_r if extension with given name is registered. */
/* Resize existing extension data. If size is grown, the new data will be
zero-filled. If size is shrinked, the data is simply dropped. */
/* Resize header, keeping the old record size. */
void mail_index_ext_resize_hdr(struct mail_index_transaction *t,
/* Reset extension. Any updates for this extension which were issued before the
writer had seen this reset are discarded. reset_id is used to figure this
out, so it must be different every time. If clear_data=TRUE, records and
header is zeroed. */
/* Like mail_index_ext_reset(), but increase extension's reset_id atomically
when the transaction is being committed. If prev_reset_id doesn't match the
latest reset_id, the reset_id isn't increased and all extension changes are
ignored. */
/* Discard existing extension updates in this transaction and write new updates
using the given reset_id. The difference to mail_index_ext_reset() is that
this doesn't clear any existing record or header data. */
void mail_index_ext_set_reset_id(struct mail_index_transaction *t,
/* Get the current reset_id for given extension. Returns TRUE if it exists. */
struct mail_index_map *map,
/* Returns extension header. */
/* Returns the wanted extension record for given message. If it doesn't exist,
*data_r is set to NULL. expunged_r is TRUE if the message has already been
expunged from the index. */
bool *expunged_r);
const void **data_r, bool *expunged_r);
/* Get current extension sizes. Returns 1 if ok, 0 if extension doesn't exist
in view. Any of the _r parameters may be NULL. */
/* Update extension header field. */
void mail_index_update_header_ext(struct mail_index_transaction *t,
/* Update extension record. If old_data_r is non-NULL and the record extension
was already updated in this transaction, it's set to contain the data it's
now overwriting. */
ATTR_NULL(5);
diffs for this seq. */
int mail_index_atomic_inc_ext(struct mail_index_transaction *t,
#endif