mail-cache-compress.c revision f1700e6d755306a2b137fad88ea5bf8b9fc6ec4f
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2003-2007 Dovecot authors, see the included COPYING file */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenmail_cache_merge_bitmask(struct mail_cache_copy_context *ctx,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen unsigned char *dest;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen unsigned int i, *pos;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen pos = array_idx_modifiable(&ctx->bitmask_pos, field->field_idx);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (*pos == 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* we decided to drop this field */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen dest = buffer_get_space_unsafe(ctx->buffer, *pos, field->size);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen dest[i] |= ((const unsigned char*)field->data)[i];
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenmail_cache_compress_field(struct mail_cache_copy_context *ctx,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen file_field_idx = ctx->field_file_map[field->field_idx];
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen cache_field = &ctx->cache->fields[field->field_idx].field;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen field_seen = buffer_get_space_unsafe(ctx->field_seen,
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen /* duplicate */
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (cache_field->type == MAIL_CACHE_FIELD_BITMASK)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen dec = cache_field->decision & ~MAIL_CACHE_DECISION_FORCED;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen buffer_append(ctx->buffer, &file_field_idx, sizeof(file_field_idx));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (cache_field->field_size == (unsigned int)-1) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen buffer_append(ctx->buffer, &size32, sizeof(size32));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (cache_field->type == MAIL_CACHE_FIELD_BITMASK) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* remember the position in case we need to update it */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen array_idx_set(&ctx->bitmask_pos, field->field_idx, &pos);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen buffer_append(ctx->buffer, field->data, field->size);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen buffer_append_zero(ctx->buffer, 4 - (field->size & 3));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenget_next_file_seq(struct mail_cache *cache, struct mail_index_view *view)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ext = mail_index_view_get_ext(view, cache->ext_id);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen file_seq = ext != NULL ? ext->reset_id + 1 : (uint32_t)ioloop_time;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (cache->hdr != NULL && file_seq <= cache->hdr->file_seq)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenmail_cache_compress_get_fields(struct mail_cache_copy_context *ctx,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen unsigned int i, j, idx;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* Make mail_cache_header_fields_get() return the fields in
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen the same order as we saved them. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen memcpy(cache->field_file_map, ctx->field_file_map,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* reverse mapping */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen cache->file_field_map = used_fields_count == 0 ? NULL :
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen for (i = j = 0; i < cache->fields_count; i++) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* change permanent decisions to temporary decisions.
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if they're still permanent they'll get updated later. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (field->decision == MAIL_CACHE_DECISION_YES)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mail_cache_header_fields_get(cache, ctx->buffer);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenmail_cache_copy(struct mail_cache *cache, struct mail_index_transaction *trans,
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen uint32_t message_count, seq, first_new_seq, ext_offset;
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen unsigned int i, used_fields_count, orig_fields_count;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen view = mail_index_transaction_get_view(trans);
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen /* get sequence of first message which doesn't need its temp fields
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen message_count = mail_index_view_get_messages_count(view);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen cache_view = mail_cache_view_open(cache, view);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen output = o_stream_create_fd_file(fd, 0, FALSE);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen hdr.file_seq = get_next_file_seq(cache, view);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx.buffer = buffer_create_dynamic(default_pool, 4096);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx.field_seen = buffer_create_dynamic(default_pool, 64);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx.field_file_map = t_new(uint32_t, cache->fields_count);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* @UNSAFE: drop unused fields and create a field mapping for
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen used fields */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen idx_hdr->day_stamp - MAIL_CACHE_FIELD_DROP_SECS;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* if some fields' "last used" time is zero, they were probably just
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen added by us. change them to the current time. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* creating the initial cache file. add all fields. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen for (i = 0; i < orig_fields_count; i++)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen for (i = used_fields_count = 0; i < orig_fields_count; i++) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (cache->fields[i].last_used < max_drop_time)
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen ctx.field_file_map[i] = !cache->fields[i].used ?
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (mail_index_transaction_is_expunged(trans, seq)) {
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen memset(buffer_get_modifiable_data(ctx.field_seen, NULL),
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen buffer_append(ctx.buffer, &cache_rec, sizeof(cache_rec));
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen mail_cache_lookup_iter_init(cache_view, seq, &iter);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen while (mail_cache_lookup_iter_next(&iter, &field) > 0)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen cache_rec.size = buffer_get_used_size(ctx.buffer);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* nothing cached */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen o_stream_send(output, ctx.buffer->data, cache_rec.size);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_assert(array_count(ext_offsets) == message_count);
07974f50bd55b06fd6d465f2c0e491794786e2faTimo Sirainen i_assert(orig_fields_count == cache->fields_count);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen hdr.field_header_offset = mail_index_uint32_to_offset(output->offset);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mail_cache_compress_get_fields(&ctx, used_fields_count);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen o_stream_send(output, ctx.buffer->data, ctx.buffer->used);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen mail_cache_set_syscall_error(cache, "o_stream_flush()");
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (hdr.used_file_size < MAIL_CACHE_INITIAL_SIZE) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* grow the file some more. doesn't matter if it fails */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen (void)file_set_size(fd, MAIL_CACHE_INITIAL_SIZE);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
7891195e3975d554df183670dba1fcecfa0a30c3Timo Sirainenstatic int mail_cache_compress_has_file_changed(struct mail_cache *cache)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen unsigned int i;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen for (i = 0;; i++) {
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen fd = nfs_safe_open(cache->filepath, O_RDONLY);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen mail_cache_set_syscall_error(cache, "open()");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* previously it didn't exist */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return hdr.file_seq != cache->need_compress_file_seq;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else if (errno != ESTALE || i >= NFS_ESTALE_RETRY_COUNT) {
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen mail_cache_set_syscall_error(cache, "read()");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int mail_cache_compress_locked(struct mail_cache *cache,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen unsigned int i, count;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* get the latest info on fields */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen fd = file_dotlock_open(&cache->dotlock_settings, cache->filepath,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mail_cache_set_syscall_error(cache, "file_dotlock_open()");
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainen if ((ret = mail_cache_compress_has_file_changed(cache)) != 0) {
59714981ae172b5113be7ca9b8be518b759fc86dTimo Sirainen /* was just compressed, forget this */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen fchown(fd, (uid_t)-1, cache->index->gid) < 0) {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen mail_cache_set_syscall_error(cache, "fchown()");
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (mail_cache_copy(cache, trans, fd, &file_seq, &ext_offsets) < 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen "file_dotlock_replace()");
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen /* once we're sure that the compression was successful,
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen update the offsets */
59714981ae172b5113be7ca9b8be518b759fc86dTimo Sirainen mail_index_ext_reset(trans, cache->ext_id, file_seq);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen for (i = 0; i < count; i++) {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (offsets[i] != 0) {
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen mail_index_update_ext(trans, i + 1, cache->ext_id,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen file_cache_set_fd(cache->file_cache, cache->fd);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenint mail_cache_compress(struct mail_cache *cache,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(cache->index) || cache->index->readonly)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (cache->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* we're using dotlocking, cache file creation itself creates
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen the dotlock file we need. */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return mail_cache_compress_locked(cache, trans, &unlock);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* couldn't lock, either it's broken or doesn't exist.
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen just start creating it. */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return mail_cache_compress_locked(cache, trans, &unlock);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* locking succeeded. */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen ret = mail_cache_compress_locked(cache, trans, &unlock);