mail-index-modseq.c revision 0ff139bf6c35ff615a2551e7e4f72a897e8a1341
/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "mail-index-private.h"
#include "mail-index-modseq.h"
#include "mail-index-sync-private.h"
#define MAIL_INDEX_MODSEQ_EXT_NAME "modseq"
enum modseq_metadata_idx {
/* must be in the same order as enum mail_flags */
};
struct mail_index_modseq_header {
/* highest used modseq */
/* last tracked log file position */
};
struct metadata_modseqs {
};
struct mail_index_map_modseq {
/* indexes use enum modseq_metadata_idx */
};
struct mail_index_modseq_sync {
struct mail_index_sync_map_ctx *sync_map_ctx;
struct mail_index_view *view;
struct mail_transaction_log_view *log_view;
struct mail_index_map_modseq *mmap;
};
{
sizeof(struct mail_index_modseq_header),
}
{
}
{
struct mail_index_transaction *trans;
struct mail_index_view *view;
struct mail_index_modseq_header hdr;
if (index->modseqs_enabled)
return;
&ext_map_idx)) {
/* modseqs not enabled to the index yet, add them. */
/* commit also refreshes the index, which syncs the modseqs */
(void)mail_index_transaction_commit(&trans,
&log_seq, &log_offset);
/* get the modseq extension to index map */
&ext_map_idx)) {
/* didn't work for some reason */
return;
}
}
}
{
const struct mail_index_modseq_header *modseq_hdr;
const void *data;
if (size == sizeof(*modseq_hdr)) {
modseq_hdr = data;
if (modseq_hdr->highest_modseq != 0)
return modseq_hdr->highest_modseq;
}
/* fallback to returning the log head */
}
static struct mail_index_map_modseq *
{
return mmap;
/* don't start tracking until we've seen modseq extension intro */
&ext_map_idx))
return NULL;
return mmap;
}
{
struct mail_index_map *map;
const struct mail_index_ext *ext;
const struct mail_index_record *rec;
&ext_map_idx)) {
/* not enabled yet */
}
if (*modseqp == 0) {
/* If we're here because we just enabled modseqs, we'll return
the same modseq (initial highestmodseq) for all messages.
The next sync will change these zeros to initial
highestmodseq or higher.
If we're here because a message got appended but modseq
wasn't set (older Dovecot?), we'll again use the current
highest modseq. This isn't exactly correct, but it gets
fixed after the next sync and this situation shouldn't
normally happen anyway. */
return mail_index_modseq_get_highest(view);
}
return *modseqp;
}
static uint64_t
{
const struct metadata_modseqs *metadata;
unsigned int count;
return 0;
}
enum mail_flags flags_mask,
{
unsigned int i;
/* first try to find a specific match */
for (i = 0; i < METADATA_MODSEQ_IDX_KEYWORD_START; i++) {
if ((flags_mask & (1 << i)) != 0) {
if (highest_modseq < modseq)
}
}
}
if (highest_modseq == 0) {
/* no specific matches, fallback to using the highest */
}
return highest_modseq;
}
const struct mail_keywords *keywords,
{
unsigned int i, metadata_idx;
/* first try to find a specific match */
if (highest_modseq < modseq)
}
}
if (highest_modseq == 0) {
/* no specific matches, fallback to using the highest */
}
return highest_modseq;
}
{
return ctx->log_offset |
}
static void
{
const struct mail_index_ext *ext;
const struct mail_index_record *rec;
&ext_map_idx))
return;
}
}
static bool
{
return FALSE;
return TRUE;
}
static void
const struct mail_transaction_header *thdr,
const void *tdata)
{
unsigned int i, count;
case MAIL_TRANSACTION_APPEND: {
for (i = 0; i < count; i++) {
seq1);
}
}
return;
}
case MAIL_TRANSACTION_FLAG_UPDATE: {
sizeof(struct mail_transaction_flag_update));
break;
}
case MAIL_TRANSACTION_KEYWORD_UPDATE: {
unsigned int seqset_offset;
if ((seqset_offset % 4) != 0)
break;
}
sizeof(struct mail_transaction_keyword_reset));
break;
default:
return;
}
/* update modseqs */
for (i = 0; i < count; i++) {
}
}
{
const struct mail_index_ext *ext;
const struct mail_index_modseq_header *hdr;
const struct mail_transaction_header *thdr;
const void *tdata;
bool reset;
int ret;
&ext_map_idx))
i_unreached();
/* get the current highest_modseq. don't change any modseq below it. */
/* Scan logs for updates between ext_hdr.log_* .. view position.
There are two reasons why there could be any:
1) We just enabled modseqs and we're filling the initial values.
2) A non-modseq-aware Dovecot version added new messages and wrote
dovecot.index file. */
&end_seq, &end_offset);
/* modseqs are up to date */
return;
}
if (ret == 0) {
/* missing files - try with only the last file */
&reset);
/* since we don't know if we skipped some changes, set all
modseqs to beginning of the latest file. */
/* should happen only when setting initial modseqs.
we may already have returned highest_modseq as
some messages' modseq value. don't shrink it. */
}
} else {
/* we have all the logs. replace zero modseqs with the current
highest modseq (we may have already returned it for them). */
}
if (ret > 0) {
T_BEGIN {
tdata);
} T_END;
}
}
}
struct mail_index_modseq_sync *
{
struct mail_index_modseq_sync *ctx;
}
return ctx;
}
{
const struct mail_index_ext *ext;
const struct mail_index_modseq_header *old_modseq_hdr;
&ext_map_idx))
return;
&new_modseq_hdr, sizeof(new_modseq_hdr));
}
}
{
}
{
}
}
{
}
{
struct metadata_modseqs *metadata;
unsigned int i, count;
return;
seq1--;
for (i = 0; i < count; i++) {
}
}
static void
{
}
static void
{
struct metadata_modseqs *metadata;
/* we want to keep permanent modseqs updated, but don't bother
updating in-memory per-flag updates */
return;
}
}
enum mail_flags flags_mask,
{
unsigned int i;
return;
for (i = 0; i < METADATA_MODSEQ_IDX_KEYWORD_START; i++) {
if ((flags_mask & (1 << i)) != 0)
}
}
unsigned int keyword_idx,
{
return;
}
{
unsigned int i, count;
return;
for (i = METADATA_MODSEQ_IDX_KEYWORD_START; i < count; i++)
}
{
struct metadata_modseqs *metadata;
unsigned int i, count;
for (i = 0; i < count; i++) {
}
}