mail-cache-transaction.c revision e0127c3244319fffb07bf65a3ed9e4a5d6e555b7
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen array_t ARRAY_DEFINE(cache_data_seq, uint32_t);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen array_t ARRAY_DEFINE(reservations, struct mail_cache_reservation);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen uint32_t reserved_space_offset, reserved_space;
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainenstatic int mail_cache_link_unlocked(struct mail_cache *cache,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_get_transaction(struct mail_cache_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx = i_new(struct mail_cache_transaction_ctx, 1);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen ARRAY_CREATE(&ctx->reservations, default_pool,
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen view->trans_view = mail_index_transaction_open_updated_view(t);
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenstatic void mail_cache_transaction_reset(struct mail_cache_transaction_ctx *ctx)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen ctx->cache_file_seq = ctx->cache->hdr->file_seq;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void mail_cache_transaction_free(struct mail_cache_transaction_ctx *ctx)
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen ctx->view->trans_seq1 = ctx->view->trans_seq2 = 0;
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainenstatic int mail_cache_transaction_lock(struct mail_cache_transaction_ctx *ctx)
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if (ctx->cache_file_seq != ctx->cache->hdr->file_seq)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic int mail_cache_grow_file(struct mail_cache *cache, size_t size)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* grow the file */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen new_fsize = cache->hdr_copy.used_file_size + size;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen grow_size = new_fsize / 100 * MAIL_CACHE_GROW_PERCENTAGE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (file_set_size(cache->fd, new_fsize) < 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "file_set_size()");
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool mail_cache_unlink_hole(struct mail_cache *cache, size_t size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen while (offset != 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (pread_full(cache->fd, &hole, sizeof(hole), offset) <= 0) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pread_full()");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (hole.magic != MAIL_CACHE_HOLE_HEADER_MAGIC) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "Invalid magic in hole header");
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen if (mail_cache_write(cache, &hole.next_offset,
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainenmail_cache_transaction_add_reservation(struct mail_cache_transaction_ctx *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_reserve_more(struct mail_cache_transaction_ctx *ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct mail_cache_header *hdr = &cache->hdr_copy;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen unsigned int count;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_unlink_hole(cache, block_size, &hole)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* found a large enough hole. */
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen mail_cache_transaction_add_reservation(ctx, hole.next_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* mail_cache_unlink_hole() could have noticed corruption */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if ((uint32_t)-1 - hdr->used_file_size < block_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_index_set_error(cache->index, "Cache file too large: %s",
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (!commit && block_size < MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE) {
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen /* allocate some more space than we need */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen size_t new_block_size = (block_size + ctx->last_grow_size) * 2;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (new_block_size > MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen new_block_size = MAIL_CACHE_MAX_RESERVED_BLOCK_SIZE;
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if ((uint32_t)-1 - hdr->used_file_size >= new_block_size) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_grow_file(ctx->cache, block_size) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (ctx->reserved_space_offset + ctx->reserved_space ==
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we can simply grow it */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* grow reservation. it's probably the last one in the buffer,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen but it's not guarateed because we might have used holes
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen reservations = array_get_modifyable(&ctx->reservations, &count);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen reservations[count].size != hdr->used_file_size);
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen mail_cache_transaction_add_reservation(ctx, hdr->used_file_size,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hdr->used_file_size = ctx->reserved_space_offset + ctx->reserved_space;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_free_space(struct mail_cache *cache, uint32_t offset, uint32_t size)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (offset + size == cache->hdr_copy.used_file_size) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* we can just set used_file_size back */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen } else if (size >= MAIL_CACHE_MIN_HOLE_SIZE) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* set it up as a hole */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen hole.next_offset = cache->hdr_copy.hole_offset;
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen if (mail_cache_write(cache, &hole, sizeof(hole), offset) < 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_free_space(struct mail_cache_transaction_ctx *ctx)
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen /* check again - locking might have reopened the cache file */
0e7a1bd9b7b39e57a22dbd4ba12df9b9603e6391Timo Sirainen i_assert(ctx->cache_file_seq == ctx->cache->hdr->file_seq);
f79a807865222dc8d5afd21667d2ace67f6c831bTimo Sirainen mail_cache_free_space(ctx->cache, ctx->reserved_space_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_get_space(struct mail_cache_transaction_ctx *ctx,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen uint32_t *offset_r, size_t *available_space_r,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* not enough preallocated space in transaction, get more */
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if ((ret = mail_cache_transaction_lock(ctx)) <= 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen ret = mail_cache_transaction_reserve_more(ctx, max_size,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* cache file reopened - need to abort */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* final commit - see if we can free the rest of the
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen reserved space */
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (mail_cache_transaction_free_space(ctx) < 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenmail_cache_transaction_update_index(struct mail_cache_transaction_ctx *ctx,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* write the cache_offsets to index file. records' prev_offset
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen is updated to point to old cache record when index is being
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mail_index_update_ext(ctx->trans, seq[i], cache->ext_id,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* we added records for this message multiple
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen times in this same uncommitted transaction.
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen only the new one will be written to
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen transaction log, we need to do the linking
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ourself here. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (mail_cache_link_unlocked(cache, old_offset,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* if we're combining multiple transactions,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen make sure the one with the smallest offset
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen is written into index. this is required for
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen non-file-mmaped cache to work properly. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct mail_cache_record *rec, *tmp_rec;
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen uint32_t write_offset, write_size, rec_pos, seq_idx, seq_limit;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* committing, remove the last dummy record */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_set_used_size(ctx->cache_data, ctx->prev_pos);
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen if (ctx->cache_file_seq != ctx->cache->hdr->file_seq) {
7496b0969019303b4917eaccd1f4f771584d8a48Timo Sirainen /* cache file reopened - need to abort */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen rec = buffer_get_data(ctx->cache_data, &size);
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen seq = array_get(&ctx->cache_data_seq, &seq_count);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen for (seq_idx = 0, rec_pos = 0; rec_pos < ctx->prev_pos;) {
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen ret = mail_cache_transaction_get_space(ctx, rec->size,
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen /* nothing to write / error / cache file reopened */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* see how much we can really write there */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for (size = 0; size + tmp_rec->size <= max_size; ) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* write it to file */
0e7a1bd9b7b39e57a22dbd4ba12df9b9603e6391Timo Sirainen i_assert(ctx->cache_file_seq == cache->hdr->file_seq);
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen if (mail_cache_write(cache, rec, max_size, write_offset) < 0)
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_transaction_update_index(ctx, rec, seq,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* drop the written data from buffer */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenmail_cache_transaction_switch_seq(struct mail_cache_transaction_ctx *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* fix record size */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen data = buffer_get_modifyable_data(ctx->cache_data, &size);
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen array_append(&ctx->cache_data_seq, &ctx->prev_seq, 1);
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen ARRAY_CREATE(&ctx->cache_data_seq, default_pool, uint32_t, 64);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen buffer_append(ctx->cache_data, &new_rec, sizeof(new_rec));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
531fa12126fc7abf63244a7ed4505896a8694206Timo Sirainen if (!ctx->changes || MAIL_CACHE_IS_UNUSABLE(cache)) {
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen /* Here would be a good place to do fdatasync() to make sure
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen everything is written before offsets are updated to index.
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen However it slows down I/O unneededly and we're pretty good at
2e0019296a16e0ea8c47fd9fe796d92f50f27539Timo Sirainen catching and fixing cache corruption, so we no longer do it. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen const struct mail_cache_reservation *reservations;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen unsigned int count;
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen if ((ctx->reserved_space > 0 || array_count(&ctx->reservations) > 0) &&
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen reservations = array_get(&ctx->reservations, &count);
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen /* free flushed data as well. do it from end to
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen beginning so we have a better chance of
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen updating used_file_size instead of adding
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen while (count > 0) {
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainenstatic int mail_cache_header_add_field(struct mail_cache_transaction_ctx *ctx,
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen unsigned int field)
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen /* re-read header to make sure we don't lose any fields. */
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen if (mail_cache_header_fields_read(cache) < 0) {
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen if (ctx->cache->field_file_map[field] != (uint32_t)-1) {
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen /* it was already added */
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen if (mail_cache_transaction_get_space(ctx, size, size,
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen else if (mail_cache_write(cache, data, size, offset) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else if (mail_cache_header_fields_get_next_offset(cache,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* after it's guaranteed to be in disk, update header offset */
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen if (mail_cache_write(cache, &offset, sizeof(offset),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we'll need to fix mappings. */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenvoid mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int field, const void *data, size_t data_size)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (ctx->cache->fields[field].field.decision ==
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file_field = ctx->cache->field_file_map[field];
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we'll have to add this field to headers */
5ebddd2d812296900bc255b24bcd508878784c37Timo Sirainen if (mail_cache_header_add_field(ctx, field) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen file_field = ctx->cache->field_file_map[field];
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen mail_cache_decision_add(ctx->view, seq, field);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen fixed_size = ctx->cache->fields[field].field.field_size;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen i_assert(fixed_size == (unsigned int)-1 || fixed_size == data_size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* remember roughly what we have modified, so cache lookups can
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen look into transactions to see changes. */
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen if (seq < ctx->view->trans_seq1 || ctx->view->trans_seq1 == 0)
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen buffer_get_size(ctx->cache_data) && ctx->prev_pos > 0) {
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen /* time to flush our buffer. if flushing fails because the
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen cache file had been compressed and was reopened, return
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen without adding the cached data since cache_data buffer
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen doesn't contain the cache_rec anymore. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(ctx->cache_data, &file_field, sizeof(file_field));
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_append(ctx->cache_data, data, data_size);
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen buffer_append_zero(ctx->cache_data, 4 - (data_size & 3));
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainenbool mail_cache_field_want_add(struct mail_cache_transaction_ctx *ctx,
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen decision = mail_cache_field_get_decision(ctx->view->cache, field);
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen if ((decision & ~MAIL_CACHE_DECISION_FORCED) == MAIL_CACHE_DECISION_NO)
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen return mail_cache_field_exists(ctx->view, seq, field) == 0;
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainenbool mail_cache_field_can_add(struct mail_cache_transaction_ctx *ctx,
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen decision = mail_cache_field_get_decision(ctx->view->cache, field);
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen if (decision == (MAIL_CACHE_DECISION_FORCED | MAIL_CACHE_DECISION_NO))
e0127c3244319fffb07bf65a3ed9e4a5d6e555b7Timo Sirainen return mail_cache_field_exists(ctx->view, seq, field) == 0;
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainenstatic int mail_cache_link_unlocked(struct mail_cache *cache,
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen new_offset += offsetof(struct mail_cache_record, prev_offset);
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen return mail_cache_write(cache, &old_offset, sizeof(old_offset),
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint mail_cache_link(struct mail_cache *cache, uint32_t old_offset,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (new_offset + sizeof(struct mail_cache_record) >
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "Cache record offset %u points outside file",
e1f05b193ac1edd3267294e9501e8063aa0f791aTimo Sirainen if (mail_cache_link_unlocked(cache, old_offset, new_offset) < 0)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool find_offset(array_t *array, uint32_t offset)
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen unsigned int i, count;
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen for (i = 0; i < count; i++) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenint mail_cache_delete(struct mail_cache *cache, uint32_t offset)
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen if (mail_cache_get_record(cache, offset, &cache_rec) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we'll only update the deleted_space in header. we can't really
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen do any actual deleting as other processes might still be using
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen the data. also it's actually useful as some index views are still
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen able to ask cached data from messages that have already been
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen ARRAY_CREATE(&tmp_offsets, pool_datastack_create(), uint32_t, 8);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->hdr_copy.deleted_space += cache_rec->size;
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen if (mail_cache_get_record(cache, cache_rec->prev_offset,
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen if (find_offset(&tmp_offsets, cache_rec->prev_offset)) {
874b2d1471ae936c6666432b09bf761b866f7067Timo Sirainen "record list is circular");