[dovecot-cvs] dovecot/src/lib-index mail-index-transaction.c, 1.73,
1.74
cras at dovecot.org
cras at dovecot.org
Thu Apr 20 17:10:13 EEST 2006
Update of /var/lib/cvs/dovecot/src/lib-index
In directory talvi:/tmp/cvs-serv27413/lib-index
Modified Files:
mail-index-transaction.c
Log Message:
If we sorted appended messages, we weren't sorting extensions and keywords
so they were mapped to wrong messages (dbox-only problem, keywords not yet
fixed by this change).
Index: mail-index-transaction.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-transaction.c,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -d -r1.73 -r1.74
--- mail-index-transaction.c 15 Jan 2006 00:11:36 -0000 1.73
+++ mail-index-transaction.c 20 Apr 2006 14:10:11 -0000 1.74
@@ -102,6 +102,78 @@
mail_index_transaction_free(t);
}
+bool mail_index_seq_array_lookup(const array_t *array, uint32_t seq,
+ unsigned int *idx_r)
+{
+ ARRAY_SET_TYPE(array, uint32_t);
+ unsigned int idx, left_idx, right_idx, count;
+ const uint32_t *seq_p;
+
+ count = array_count(array);
+ if (count == 0) {
+ *idx_r = 0;
+ return FALSE;
+ }
+
+ /* we're probably appending it, check */
+ seq_p = array_idx(array, count-1);
+ if (*seq_p < seq)
+ idx = count;
+ else {
+ idx = 0; left_idx = 0; right_idx = count;
+ while (left_idx < right_idx) {
+ idx = (left_idx + right_idx) / 2;
+
+ seq_p = array_idx(array, idx);
+ if (*seq_p < seq)
+ left_idx = idx+1;
+ else if (*seq_p > seq)
+ right_idx = idx;
+ else {
+ *idx_r = idx;
+ return TRUE;
+ }
+ }
+ }
+
+ *idx_r = idx;
+ return FALSE;
+}
+
+static bool mail_index_seq_array_add(array_t *array, uint32_t seq,
+ const void *record, size_t record_size,
+ void *old_record)
+{
+ ARRAY_SET_TYPE(array, void *);
+ void *p;
+ unsigned int idx;
+
+ if (!array_is_created(array)) {
+ array_create(array, default_pool,
+ sizeof(seq) + record_size,
+ 1024 / (sizeof(seq) + record_size));
+ }
+ i_assert(array->element_size == sizeof(seq) + record_size);
+
+ if (mail_index_seq_array_lookup(array, seq, &idx)) {
+ /* already there, update */
+ p = array_idx_modifyable(array, idx);
+ if (old_record != NULL) {
+ /* save the old record before overwriting it */
+ memcpy(old_record, PTR_OFFSET(p, sizeof(seq)),
+ record_size);
+ }
+ memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
+ return TRUE;
+ } else {
+ /* insert */
+ p = array_insert_space(array, idx);
+ memcpy(p, &seq, sizeof(seq));
+ memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
+ return FALSE;
+ }
+}
+
static void
mail_index_buffer_convert_to_uids(struct mail_index_transaction *t,
array_t *array, bool range)
@@ -198,12 +270,86 @@
return 0;
}
-static int mail_index_append_rec_cmp(const void *p1, const void *p2)
+struct uid_map {
+ uint32_t idx;
+ uint32_t uid;
+};
+
+static int uid_map_cmp(const void *p1, const void *p2)
{
- const struct mail_index_record *rec1 = p1, *rec2 = p2;
+ const struct uid_map *m1 = p1, *m2 = p2;
- return rec1->uid < rec2->uid ? -1 :
- rec1->uid > rec2->uid ? 1 : 0;
+ return m1->uid < m2->uid ? -1 :
+ (m1->uid > m2->uid ? 1 : 0);
+}
+
+static void
+mail_index_transaction_sort_appends(struct mail_index_transaction *t)
+{
+ struct mail_index_record *recs, *sorted_recs;
+ struct uid_map *new_uid_map;
+ array_t *ext_rec_arrays;
+ uint32_t *old_to_new_map;
+ unsigned int i, j, count, ext_rec_array_count;
+
+ /* first make a copy of the UIDs and map them to sequences */
+ recs = array_get_modifyable(&t->appends, &count);
+ new_uid_map = i_new(struct uid_map, count);
+ for (i = 0; i < count; i++) {
+ new_uid_map[i].idx = i;
+ new_uid_map[i].uid = recs[i].uid;
+ }
+
+ /* now sort the UID map */
+ qsort(new_uid_map, count, sizeof(*new_uid_map), uid_map_cmp);
+
+ old_to_new_map = i_new(uint32_t, count);
+ for (i = 0; i < count; i++)
+ old_to_new_map[new_uid_map[i].idx] = i;
+
+ /* sort mail records */
+ sorted_recs = i_new(struct mail_index_record, count);
+ for (i = 0; i < count; i++)
+ sorted_recs[i] = recs[new_uid_map[i].idx];
+ buffer_write(t->appends.buffer, 0, sorted_recs,
+ sizeof(*sorted_recs) * count);
+ i_free(sorted_recs);
+
+ /* fix the order in extensions */
+ ext_rec_arrays = array_get_modifyable(&t->ext_rec_updates,
+ &ext_rec_array_count);
+ for (j = 0; j < ext_rec_array_count; j++) {
+ array_t *old_array = &ext_rec_arrays[j];
+ ARRAY_SET_TYPE(old_array, void *);
+ array_t ARRAY_DEFINE(new_array, void *);
+ unsigned int ext_count;
+ const uint32_t *ext_rec;
+ uint32_t seq;
+
+ if (!array_is_created(old_array))
+ continue;
+
+ ext_count = array_count(old_array);
+ array_create(&new_array, default_pool,
+ old_array->element_size, ext_count);
+ for (i = 0; i < ext_count; i++) {
+ ext_rec = array_idx(old_array, i);
+
+ seq = *ext_rec < t->first_new_seq ? *ext_rec :
+ (t->first_new_seq +
+ old_to_new_map[*ext_rec - t->first_new_seq]);
+ mail_index_seq_array_add(&new_array, seq, ext_rec+1,
+ old_array->element_size -
+ sizeof(*ext_rec), NULL);
+ }
+ array_free(old_array);
+ ext_rec_arrays[j] = new_array;
+ }
+
+ /* FIXME: fix the order in keywords */
+
+ i_free(new_uid_map);
+ i_free(old_to_new_map);
}
int mail_index_transaction_commit(struct mail_index_transaction **_t,
@@ -223,13 +369,8 @@
t->cache_trans_ctx = NULL;
}
- if (t->appends_nonsorted) {
- struct mail_index_record *recs;
- unsigned int count;
-
- recs = array_get_modifyable(&t->appends, &count);
- qsort(recs, count, sizeof(*recs), mail_index_append_rec_cmp);
- }
+ if (t->appends_nonsorted)
+ mail_index_transaction_sort_appends(t);
if (mail_index_transaction_convert_to_uids(t) < 0)
ret = -1;
@@ -544,77 +685,6 @@
mail_index_update_flags_range(t, seq, seq, modify_type, flags);
}
-bool mail_index_seq_array_lookup(const array_t *array, uint32_t seq,
- unsigned int *idx_r)
-{
- ARRAY_SET_TYPE(array, uint32_t);
- unsigned int idx, left_idx, right_idx, count;
- const uint32_t *seq_p;
-
- count = array_count(array);
- if (count == 0) {
- *idx_r = 0;
- return FALSE;
- }
-
- /* we're probably appending it, check */
- seq_p = array_idx(array, count-1);
- if (*seq_p < seq)
- idx = count;
- else {
- idx = 0; left_idx = 0; right_idx = count;
- while (left_idx < right_idx) {
- idx = (left_idx + right_idx) / 2;
-
- seq_p = array_idx(array, idx);
- if (*seq_p < seq)
- left_idx = idx+1;
- else if (*seq_p > seq)
- right_idx = idx;
- else {
- *idx_r = idx;
- return TRUE;
- }
- }
- }
-
- *idx_r = idx;
- return FALSE;
-}
-
-static bool mail_index_seq_array_add(array_t *array, uint32_t seq,
- const void *record, size_t record_size,
- void *old_record)
-{
- ARRAY_SET_TYPE(array, void *);
- void *p;
- unsigned int idx;
-
- if (!array_is_created(array)) {
- array_create(array, default_pool,
- sizeof(seq) + record_size,
- 1024 / (sizeof(seq) + record_size));
- }
- i_assert(array->element_size == sizeof(seq) + record_size);
-
- if (mail_index_seq_array_lookup(array, seq, &idx)) {
- /* already there, update */
- p = array_idx_modifyable(array, idx);
- if (old_record != NULL) {
- memcpy(old_record, PTR_OFFSET(p, sizeof(seq)),
- record_size);
- }
- memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
- return TRUE;
- } else {
- /* insert */
- p = array_insert_space(array, idx);
- memcpy(p, &seq, sizeof(seq));
- memcpy(PTR_OFFSET(p, sizeof(seq)), record, record_size);
- return FALSE;
- }
-}
-
void mail_index_update_header(struct mail_index_transaction *t,
size_t offset, const void *data, size_t size,
bool prepend)
@@ -754,6 +824,7 @@
/* @UNSAFE */
if (!mail_index_seq_array_add(array, seq, data, record_size,
old_data_r)) {
+ /* not found, clear old_data if it was given */
if (old_data_r != NULL)
memset(old_data_r, 0, record_size);
}
@@ -825,8 +896,8 @@
enum modify_type modify_type,
struct mail_keywords *keywords)
{
- struct mail_index_transaction_keyword_update *u;
- unsigned int i;
+ struct mail_index_transaction_keyword_update **ku, *u;
+ unsigned int i, ku_count;
i_assert(seq > 0 &&
(seq <= mail_index_view_get_messages_count(t->view) ||
@@ -842,33 +913,48 @@
max_idx);
}
+ /* Update add_seq and remove_seq arrays which describe the keyword
+ changes. Don't bother updating remove_seq or keyword resets for
+ newly added messages since they default to not having any
+ keywords anyway. */
+ if (array_is_created(&t->keyword_updates))
+ ku = array_get_modifyable(&t->keyword_updates, &ku_count);
+ else {
+ ku = NULL;
+ ku_count = 0;
+ }
switch (modify_type) {
case MODIFY_ADD:
for (i = 0; i < keywords->count; i++) {
- u = array_idx_modifyable(&t->keyword_updates,
- keywords->idx[i]);
+ u = ku[keywords->idx[i]];
seq_range_array_add(&u->add_seq, 16, seq);
- seq_range_array_remove(&u->remove_seq, seq);
+ if (seq < t->first_new_seq)
+ seq_range_array_remove(&u->remove_seq, seq);
}
break;
case MODIFY_REMOVE:
for (i = 0; i < keywords->count; i++) {
- u = array_idx_modifyable(&t->keyword_updates,
- keywords->idx[i]);
+ u = ku[keywords->idx[i]];
seq_range_array_remove(&u->add_seq, seq);
- seq_range_array_add(&u->remove_seq, 16, seq);
+ if (seq < t->first_new_seq)
+ seq_range_array_add(&u->remove_seq, 16, seq);
}
break;
case MODIFY_REPLACE:
+ /* Remove sequence from all add/remove arrays */
+ for (i = 0; i < ku_count; i++) {
+ seq_range_array_remove(&ku[i]->add_seq, seq);
+ if (seq < t->first_new_seq)
+ seq_range_array_remove(&ku[i]->remove_seq, seq);
+ }
+ /* Add the wanted keyword back */
for (i = 0; i < keywords->count; i++) {
- u = array_idx_modifyable(&t->keyword_updates,
- keywords->idx[i]);
+ u = ku[keywords->idx[i]];
seq_range_array_add(&u->add_seq, 16, seq);
}
- /* If t->keyword_resets is set for a sequence, there's no
- need to update remove_seq as it will remove all keywords. */
- seq_range_array_add(&t->keyword_resets, 16, seq);
+ if (seq < t->first_new_seq)
+ seq_range_array_add(&t->keyword_resets, 16, seq);
break;
}
More information about the dovecot-cvs
mailing list