mail-index-transaction.c revision 3127020d0ae64cd75bb428bdee42391376b9dd74
/* Copyright (C) 2003-2004 Timo Sirainen */
/* Inside transaction we keep messages stored in sequences in uid fields.
Before they're written to transaction log the sequences are changed to
UIDs. This is because we're able to compress sequence ranges better. */
#include "lib.h"
#include "buffer.h"
#include "mail-index-view-private.h"
#include "mail-transaction-log.h"
#include "mail-cache-private.h"
#include "mail-index-transaction-private.h"
#include <stddef.h>
#include <stdlib.h>
struct mail_index_transaction *
{
struct mail_index_transaction *t;
/* don't allow syncing view while there's ongoing transactions */
t->refcount = 1;
t->hide_transaction = hide;
/* transaction view cannot work if new records are being added
in two places. make sure it doesn't happen. */
t->no_appends = TRUE;
}
return t;
}
{
struct mail_keyword_transaction **p;
if (*p == kt) {
break;
}
}
if (*p == NULL) {
/* no transactions left, free mail_keywords */
}
}
static void mail_index_transaction_free(struct mail_index_transaction *t)
{
if (t->ext_rec_updates != NULL) {
for (i = 0; i < size; i++) {
buffer_free(recs[i]);
}
}
if (t->keyword_updates != NULL) {
struct mail_keyword_transaction **kt;
for (i = 0; i < size; i++)
}
buffer_free(t->appends);
buffer_free(t->expunges);
buffer_free(t->updates);
if (t->ext_resizes != NULL)
buffer_free(t->ext_resizes);
if (t->ext_resets != NULL)
buffer_free(t->ext_resets);
i_free(t);
}
void mail_index_transaction_ref(struct mail_index_transaction *t)
{
t->refcount++;
}
void mail_index_transaction_unref(struct mail_index_transaction *t)
{
if (--t->refcount == 0)
}
static void
{
const struct mail_index_record *rec;
unsigned char *data;
int j;
return;
/* @UNSAFE */
for (i = 0; i < size; i += record_size) {
if (*seq >= t->first_new_seq) {
} else {
}
}
}
}
static int
{
const struct mail_index_ext *extensions;
if (mail_index_view_lock(t->view) < 0)
return -1;
if (t->ext_rec_updates != NULL) {
for (i = 0; i < size; i++) {
continue;
FALSE);
}
}
if (t->keyword_updates != NULL) {
struct mail_keyword_transaction **kt;
for (i = 0; i < size; i++) {
continue;
}
}
sizeof(struct mail_transaction_expunge), TRUE);
sizeof(struct mail_transaction_flag_update), TRUE);
return 0;
}
int mail_index_transaction_commit(struct mail_index_transaction *t,
{
int ret;
if (mail_index_view_is_inconsistent(t->view)) {
return -1;
}
if (t->cache_trans_ctx != NULL) {
t->cache_trans_ctx = NULL;
}
if (mail_index_transaction_convert_to_uids(t) < 0)
ret = -1;
else {
}
return ret;
}
void mail_index_transaction_rollback(struct mail_index_transaction *t)
{
if (t->cache_trans_ctx != NULL) {
t->cache_trans_ctx = NULL;
}
}
struct mail_index_record *
{
sizeof(struct mail_index_record));
}
{
struct mail_index_record *rec;
i_assert(!t->no_appends);
t->log_updates = TRUE;
/* sequence number is visible only inside given view,
so let it generate it */
if (t->last_new_seq != 0)
*seq_r = ++t->last_new_seq;
else
}
void mail_index_append_assign_uids(struct mail_index_transaction *t,
{
return;
/* find the first mail with uid = 0 */
break;
}
}
*next_uid_r = first_uid;
}
struct seq_range {
};
{
/* quick checks */
/* grow last range */
return;
}
return;
}
/* grow down first range */
return;
}
return;
}
/* somewhere in the middle, array is sorted so find it with
binary search */
/* it's already expunged */
return;
}
} else {
}
}
idx++;
/* idx == size couldn't happen because we already handle it above */
/* merge */
sizeof(*data));
}
/* merge */
sizeof(*data));
}
} else {
}
}
{
t->log_updates = TRUE;
/* expunges is a sorted array of {seq1, seq2, ..}, .. */
return;
}
}
static void
struct mail_transaction_flag_update u,
{
/* find the first update with either overlapping range,
or the update which will come after our insert */
idx = 0;
else
break;
}
idx++;
/* insert new update */
tmp_update = u;
move = 0;
} else {
/* split existing update from beginning */
move = 1;
}
&tmp_update, sizeof(tmp_update));
}
/* split existing update from end */
&tmp_update, sizeof(tmp_update));
size++;
}
~u.remove_flags;
~u.add_flags;
/* break here before idx++ so last_update_idx is set
correctly */
break;
}
}
}
t->last_update_idx = idx;
}
enum modify_type modify_type,
enum mail_flags flags)
{
switch (modify_type) {
case MODIFY_REPLACE:
break;
case MODIFY_ADD:
break;
case MODIFY_REMOVE:
break;
}
}
void mail_index_update_flags_range(struct mail_index_transaction *t,
enum modify_type modify_type,
enum mail_flags flags)
{
struct mail_index_record *rec;
struct mail_transaction_flag_update u, *last_update;
t->log_updates = TRUE;
if (seq2 >= t->first_new_seq) {
/* updates for appended messages, modify them directly */
}
if (seq1 >= t->first_new_seq)
return;
/* range contains also existing messages. update them next. */
}
memset(&u, 0, sizeof(u));
switch (modify_type) {
case MODIFY_REPLACE:
break;
case MODIFY_ADD:
break;
case MODIFY_REMOVE:
u.remove_flags = flags;
break;
}
buffer_append(t->updates, &u, sizeof(u));
return;
}
size /= sizeof(*last_update);
if (t->last_update_idx < size) {
/* fast path - hopefully we're updating the next message,
or a message that is to be appended as last update */
last_update += t->last_update_idx;
/* we can just update the UID range */
return;
}
/* hopefully we can just append it */
t->last_update_idx++;
last_update++;
}
}
if (t->last_update_idx == size) {
buffer_append(t->updates, &u, sizeof(u));
return;
}
/* slow path */
/* added after this */
size);
} else {
/* added before this or on top of this */
mail_index_insert_flag_update(t, u, 0, t->last_update_idx);
}
}
enum modify_type modify_type,
enum mail_flags flags)
{
}
{
void *data;
/* we're probably appending it, check */
if (size == 0)
idx = 0;
else {
else {
return TRUE;
}
}
}
return FALSE;
}
void *old_record)
{
void *p;
return FALSE;
}
/* already there, update */
if (old_record != NULL)
return TRUE;
} else {
/* insert */
return FALSE;
}
}
void mail_index_update_header(struct mail_index_transaction *t,
{
t->hdr_changed = TRUE;
t->log_updates = TRUE;
}
{
struct mail_transaction_ext_intro intro;
const struct mail_index_ext *ext;
} else {
}
/* allow only header size changes if something was already written */
t->log_updates = TRUE;
if (t->ext_resizes == NULL)
}
{
t->log_updates = TRUE;
if (t->ext_rec_updates != NULL &&
buffer_set_used_size(*buf, 0);
}
if (t->ext_resets == NULL) {
}
}
void mail_index_update_header_ext(struct mail_index_transaction *t,
{
// FIXME
}
{
const struct mail_index_ext *ext;
const struct mail_transaction_ext_intro *intro;
seq <= t->last_new_seq));
t->log_updates = TRUE;
if (t->ext_resizes == NULL) {
size = 0;
} else {
}
/* resized record */
} else {
}
if (t->ext_rec_updates == NULL)
sizeof(buffer_t *));
/* @UNSAFE */
old_data_r)) {
if (old_data_r != NULL)
}
}
static struct mail_keyword_transaction *
struct mail_keywords *keywords)
{
struct mail_keyword_transaction *kt;
if (t->keyword_updates == NULL)
kt->transaction = t;
return kt;
}
static struct mail_keywords *
{
struct mail_keywords k;
const char **missing_keywords, *keyword;
unsigned int i, j, bitmask_offset, missing_count = 0;
uint8_t *b;
if (count == 0)
/* @UNSAFE */
t_push();
memset(&k, 0, sizeof(k));
/* keywords are sorted in index. look up the existing ones and add
new ones. build a bitmap pointing to them. keywords are never
removed from index's keyword list. */
bitmask_offset = sizeof(k) - sizeof(k.bitmask);
for (i = 0; i < count; i++) {
break;
}
if (keyword_buf->used == 0) {
/* first one */
k.start = j;
} else if (j < k.start) {
bitmask_offset + k.start - j,
(size_t)-1);
k.start = j;
}
k.end = j;
k.count++;
} else {
/* arrays are sorted, can't match anymore */
}
}
if (missing_count > 0) {
/* add missing keywords. first drop the trailing NULL. */
j = size / sizeof(const char *);
k.end = j;
k.count++;
}
}
t_pop();
return buffer_free_without_data(keyword_buf);
}
struct mail_keywords *
mail_index_keywords_create(struct mail_index_transaction *t,
const char *const keywords[])
{
struct mail_keywords *k;
const char *const null_keywords[] = { NULL };
(void)mail_keyword_transaction_new(t, k);
return k;
}
enum modify_type modify_type,
struct mail_keywords *keywords)
{
struct mail_keyword_transaction *kt;
seq <= t->last_new_seq));
if (kt->transaction == t &&
break;
}
} else {
}
t->log_updates = TRUE;
}