mail-index-transaction.c revision c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3ae
/* 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 "array.h"
#include "seq-range-array.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;
}
static void mail_index_transaction_free(struct mail_index_transaction *t)
{
unsigned i, count;
if (array_is_created(&t->ext_rec_updates)) {
for (i = 0; i < count; i++) {
if (array_is_created(&recs[i]))
array_free(&recs[i]);
}
array_free(&t->ext_rec_updates);
}
if (array_is_created(&t->keyword_updates)) {
struct mail_index_transaction_keyword_update *u;
for (i = 0; i < count; i++) {
if (array_is_created(&u[i].add_seq))
array_free(&u[i].add_seq);
if (array_is_created(&u[i].remove_seq))
array_free(&u[i].remove_seq);
}
array_free(&t->keyword_updates);
}
if (array_is_created(&t->keyword_resets))
array_free(&t->keyword_resets);
if (array_is_created(&t->appends))
array_free(&t->appends);
if (array_is_created(&t->expunges))
array_free(&t->expunges);
if (array_is_created(&t->updates))
array_free(&t->updates);
if (array_is_created(&t->ext_resizes))
array_free(&t->ext_resizes);
if (array_is_created(&t->ext_resets))
array_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 int i, count;
int j;
if (!array_is_created(array))
return;
for (i = 0; i < count; i++) {
if (*seq >= t->first_new_seq) {
} else {
}
}
}
}
static void arrays_convert_to_uids(struct mail_index_transaction *t,
{
unsigned int i, count;
if (!array_is_created(array))
return;
for (i = 0; i < count; i++) {
if (array_is_created(&updates[i])) {
range);
}
}
}
static void keyword_updates_convert_to_uids(struct mail_index_transaction *t)
{
unsigned int i, count;
if (!array_is_created(&t->keyword_updates))
return;
for (i = 0; i < count; i++) {
}
}
}
}
static int
{
if (mail_index_view_lock(t->view) < 0)
return -1;
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 (t->appends_nonsorted) {
struct mail_index_record *recs;
unsigned int count;
}
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 *
{
}
{
struct mail_index_record *rec;
i_assert(!t->no_appends);
t->log_updates = TRUE;
if (!array_is_created(&t->appends)) {
struct mail_index_record, 32);
}
/* 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
if (uid != 0) {
if (!t->appends_nonsorted &&
t->last_new_seq != t->first_new_seq) {
/* if previous record's UID is larger than this one,
we'll have to sort the appends later */
t->appends_nonsorted = TRUE;
}
}
}
void mail_index_append_assign_uids(struct mail_index_transaction *t,
{
struct mail_index_record *recs;
unsigned int i, count;
if (!array_is_created(&t->appends))
return;
/* find the first mail with uid = 0 */
for (i = 0; i < count; i++) {
break;
}
for (; i < count; i++) {
}
*next_uid_r = first_uid;
}
{
t->log_updates = TRUE;
/* expunges is a sorted array of {seq1, seq2, ..}, .. */
}
static void
struct mail_transaction_flag_update u,
{
unsigned int count;
/* find the first update with either overlapping range,
or the update which will come after our insert */
else
break;
}
idx++;
/* insert new update */
tmp_update = u;
move = 0;
} else {
/* split existing update from beginning */
move = 1;
}
}
/* split existing update from end */
}
~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;
unsigned int count;
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;
}
if (!array_is_created(&t->updates)) {
struct mail_transaction_flag_update, 256);
return;
}
if (t->last_update_idx < count) {
/* 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 == count) {
return;
}
/* slow path */
/* added after this */
count);
} else {
/* added before this or on top of this */
}
}
enum modify_type modify_type,
enum mail_flags flags)
{
}
unsigned int *idx_r)
{
if (count == 0) {
*idx_r = 0;
return FALSE;
}
/* we're probably appending it, check */
else {
else {
return TRUE;
}
}
}
return FALSE;
}
void *old_record)
{
ARRAY_SET_TYPE(array, void *);
void *p;
unsigned int idx;
if (!array_is_created(array)) {
sizeof(seq) + record_size,
}
/* already there, update */
if (old_record != NULL) {
}
return TRUE;
} else {
/* insert */
return FALSE;
}
}
void mail_index_update_header(struct mail_index_transaction *t,
int prepend)
{
t->log_updates = TRUE;
if (prepend) {
t->pre_hdr_changed = TRUE;
} else {
t->post_hdr_changed = TRUE;
}
}
{
struct mail_transaction_ext_intro intro;
/* get ext_id from transaction's map if it's there */
/* have to create it */
const struct mail_index_registered_ext *rext;
} else {
const struct mail_index_ext *ext;
}
/* allow only header size changes if extension records have already
been changed in transaction */
(old_record_size == record_size &&
old_record_align == record_align));
t->log_updates = TRUE;
if (!array_is_created(&t->ext_resizes)) {
}
}
{
t->log_updates = TRUE;
if (array_is_created(&t->ext_rec_updates) &&
/* if extension records have been updated, clear them */
if (array_is_created(array))
}
if (!array_is_created(&t->ext_resets)) {
}
}
void mail_index_update_header_ext(struct mail_index_transaction *t,
{
// FIXME
}
{
const struct mail_index_registered_ext *rext;
const struct mail_transaction_ext_intro *intro;
unsigned int count;
seq <= t->last_new_seq));
t->log_updates = TRUE;
if (!array_is_created(&t->ext_resizes)) {
count = 0;
} else {
}
/* resized record */
} else {
}
if (!array_is_created(&t->ext_rec_updates)) {
}
/* @UNSAFE */
old_data_r)) {
if (old_data_r != NULL)
}
}
struct mail_keywords *
mail_index_keywords_create(struct mail_index_transaction *t,
const char *const keywords[])
{
struct mail_keywords *k;
unsigned int i, count;
if (count == 0) {
return k;
}
/* @UNSAFE */
k = i_malloc(sizeof(struct mail_keywords) +
/* look up the keywords from index. they're never removed from there
so we can permanently store indexes to them. */
for (i = 0; i < count; i++) {
}
return k;
}
struct mail_keywords *
const array_t *keyword_indexes)
{
ARRAY_SET_TYPE(keyword_indexes, unsigned int);
struct mail_keywords *k;
unsigned int count;
if (count == 0) {
return k;
}
/* @UNSAFE */
k = i_malloc(sizeof(struct mail_keywords) +
return k;
}
{
}
enum modify_type modify_type,
struct mail_keywords *keywords)
{
struct mail_index_transaction_keyword_update *u;
unsigned int i;
seq <= t->last_new_seq));
max_idx);
}
switch (modify_type) {
case MODIFY_ADD:
u = array_idx_modifyable(&t->keyword_updates,
}
break;
case MODIFY_REMOVE:
u = array_idx_modifyable(&t->keyword_updates,
}
break;
case MODIFY_REPLACE:
u = array_idx_modifyable(&t->keyword_updates,
}
/* If t->keyword_resets is set for a sequence, there's no
need to update remove_seq as it will remove all keywords. */
break;
}
t->log_updates = TRUE;
}