]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Allow growing ext record_size after mail_index_update_ext()
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 3 Jun 2016 14:54:36 +0000 (17:54 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 3 Jun 2016 14:54:36 +0000 (17:54 +0300)
The existing records will just get some zero-padding at the end of records.

src/lib-index/mail-index-transaction-update.c
src/lib-index/mail-index-util.c
src/lib-index/mail-index-util.h

index ac1cf62bc5aa83f9a38aacc709042043970a0f19..38f9905b97d568b91972a67463ce9cd203e6c0c7 100644 (file)
@@ -713,6 +713,33 @@ void mail_index_update_header(struct mail_index_transaction *t,
        }
 }
 
+static void
+mail_index_ext_rec_updates_resize(struct mail_index_transaction *t,
+                                 uint32_t ext_id, uint16_t new_record_size)
+{
+       ARRAY_TYPE(seq_array) *array, old_array;
+       unsigned int i;
+
+       if (!array_is_created(&t->ext_rec_updates))
+               return;
+       array = array_idx_modifiable(&t->ext_rec_updates, ext_id);
+       if (!array_is_created(array))
+               return;
+
+       old_array = *array;
+       memset(array, 0, sizeof(*array));
+       mail_index_seq_array_alloc(array, new_record_size);
+
+       /* copy the records' beginnings. leave the end zero-filled. */
+       for (i = 0; i < array_count(&old_array); i++) {
+               const void *old_record = array_idx(&old_array, i);
+
+               memcpy(array_append_space(array), old_record,
+                      old_array.arr.element_size);
+       }
+       array_free(&old_array);
+}
+
 void mail_index_ext_resize(struct mail_index_transaction *t, uint32_t ext_id,
                           uint32_t hdr_size, uint16_t record_size,
                           uint16_t record_align)
@@ -741,12 +768,13 @@ void mail_index_ext_resize(struct mail_index_transaction *t, uint32_t ext_id,
                old_header_size = ext->hdr_size;
        }
 
-       /* allow only header size changes if extension records have already
-          been changed in transaction */
-       i_assert(!array_is_created(&t->ext_rec_updates) ||
-                record_size == (uint16_t)-1 ||
-                (old_record_size == record_size &&
-                 old_record_align == record_align));
+       if (record_size != old_record_size) {
+               /* if record_size grows, we'll just resize the existing
+                  ext_rec_updates array. it's not possible to shrink
+                  record_size without data loss. */
+               i_assert(record_size > old_record_size);
+               mail_index_ext_rec_updates_resize(t, ext_id, record_size);
+       }
 
        t->log_ext_updates = TRUE;
 
index b633539588fab1d414fac101b15658c4f40abe13..659d622764d94ef1fc9e392744b82c9975356c2c 100644 (file)
@@ -116,6 +116,18 @@ bool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array,
                                        mail_index_seq_record_cmp, idx_r);
 }
 
+void mail_index_seq_array_alloc(ARRAY_TYPE(seq_array) *array,
+                               size_t record_size)
+{
+       size_t aligned_record_size = (record_size + 3) & ~3;
+
+       i_assert(!array_is_created(array));
+
+       array_create(array, default_pool,
+                    sizeof(uint32_t) + aligned_record_size,
+                    1024 / (sizeof(uint32_t) + aligned_record_size));
+}
+
 bool mail_index_seq_array_add(ARRAY_TYPE(seq_array) *array, uint32_t seq,
                              const void *record, size_t record_size,
                              void *old_record)
@@ -126,11 +138,8 @@ bool mail_index_seq_array_add(ARRAY_TYPE(seq_array) *array, uint32_t seq,
        /* records need to be 32bit aligned */
        aligned_record_size = (record_size + 3) & ~3;
 
-       if (!array_is_created(array)) {
-               array_create(array, default_pool,
-                            sizeof(seq) + aligned_record_size,
-                            1024 / (sizeof(seq) + aligned_record_size));
-       }
+       if (!array_is_created(array))
+               mail_index_seq_array_alloc(array, record_size);
        i_assert(array->arr.element_size == sizeof(seq) + aligned_record_size);
 
        if (mail_index_seq_array_lookup(array, seq, &idx)) {
index eeb17e949917dfd0979c4e1cdeb79b6078f1672b..b61e16a23aacfe5839b57668123161e8274b482e 100644 (file)
@@ -13,6 +13,8 @@ int mail_index_unpack_num(const uint8_t **p, const uint8_t *end,
 
 bool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array,
                                 uint32_t seq, unsigned int *idx_r);
+void mail_index_seq_array_alloc(ARRAY_TYPE(seq_array) *array,
+                               size_t record_size);
 bool mail_index_seq_array_add(ARRAY_TYPE(seq_array) *array, uint32_t seq,
                              const void *record, size_t record_size,
                              void *old_record) ATTR_NULL(5);