mail-cache-compress.c revision e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainenmail_cache_merge_bitmask(struct mail_cache_copy_context *ctx,
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen unsigned char *dest;
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen unsigned int i, *pos;
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen pos = array_idx_modifiable(&ctx->bitmask_pos, field->field_idx);
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen if (*pos == 0) {
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen /* we decided to drop this field */
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen dest = buffer_get_space_unsafe(ctx->buffer, *pos, field->size);
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen dest[i] |= ((const unsigned char*)field->data)[i];
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenmail_cache_compress_field(struct mail_cache_copy_context *ctx,
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen file_field_idx = ctx->field_file_map[field->field_idx];
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen cache_field = &ctx->cache->fields[field->field_idx].field;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen field_seen = buffer_get_space_unsafe(ctx->field_seen,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* duplicate */
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen if (cache_field->type == MAIL_CACHE_FIELD_BITMASK)
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen dec = cache_field->decision & ~MAIL_CACHE_DECISION_FORCED;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen buffer_append(ctx->buffer, &file_field_idx, sizeof(file_field_idx));
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen if (cache_field->field_size == (unsigned int)-1) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_append(ctx->buffer, &size32, sizeof(size32));
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen if (cache_field->type == MAIL_CACHE_FIELD_BITMASK) {
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen /* remember the position in case we need to update it */
7d75b95c260e58ee5039fa3afd79e9fda3bc8002Timo Sirainen array_idx_set(&ctx->bitmask_pos, field->field_idx, &pos);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen buffer_append(ctx->buffer, field->data, field->size);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen buffer_append_zero(ctx->buffer, 4 - (field->size & 3));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenget_next_file_seq(struct mail_cache *cache, struct mail_index_view *view)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ext = mail_index_view_get_ext(view, cache->ext_id);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen file_seq = ext != NULL ? ext->reset_id + 1 : (uint32_t)ioloop_time;
6237f743bbaf74de5a2d2051672baed87023657bTimo Sirainen if (cache->hdr != NULL && file_seq <= cache->hdr->file_seq)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainenmail_cache_compress_get_fields(struct mail_cache_copy_context *ctx,
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen unsigned int i, j, idx;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen /* Make mail_cache_header_fields_get() return the fields in
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen the same order as we saved them. */
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen memcpy(cache->field_file_map, ctx->field_file_map,
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen /* reverse mapping */
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen cache->file_field_map = used_fields_count == 0 ? NULL :
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen for (i = j = 0; i < cache->fields_count; i++) {
fd44baee6e92f13d42ff711895d6510067f70955Timo Sirainen /* change permanent decisions to temporary decisions.
fd44baee6e92f13d42ff711895d6510067f70955Timo Sirainen if they're still permanent they'll get updated later. */
fd44baee6e92f13d42ff711895d6510067f70955Timo Sirainen if (field->decision == MAIL_CACHE_DECISION_YES)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen mail_cache_header_fields_get(cache, ctx->buffer);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainenmail_cache_copy(struct mail_cache *cache, struct mail_index_transaction *trans,
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen uint32_t message_count, seq, first_new_seq, ext_offset;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen unsigned int i, used_fields_count, orig_fields_count;
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen view = mail_index_transaction_get_view(trans);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen cache_view = mail_cache_view_open(cache, view);
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen output = o_stream_create_fd_file(fd, 0, FALSE);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen hdr.file_seq = get_next_file_seq(cache, view);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen ctx.buffer = buffer_create_dynamic(default_pool, 4096);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen ctx.field_seen = buffer_create_dynamic(default_pool, 64);
b879ed8dd4b5850987e6b89a92f794d87c6be7d7Timo Sirainen ctx.field_file_map = t_new(uint32_t, cache->fields_count + 1);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen /* @UNSAFE: drop unused fields and create a field mapping for
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen used fields */
8d77ab87a57ae98532c62e5d1548bd131dee3074Timo Sirainen idx_hdr->day_stamp - MAIL_CACHE_FIELD_DROP_SECS;
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen /* creating the initial cache file. add all fields. */
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen for (i = 0; i < orig_fields_count; i++)
fe6cf42464c36ab281c0e0740f0255be77453670Timo Sirainen for (i = used_fields_count = 0; i < orig_fields_count; i++) {
cc3ccdab8a510d88fecedf95187465bf84833711Timo Sirainen /* if the decision isn't forced and this field hasn't
cc3ccdab8a510d88fecedf95187465bf84833711Timo Sirainen been accessed for a while, drop it */
cc3ccdab8a510d88fecedf95187465bf84833711Timo Sirainen if ((dec & MAIL_CACHE_DECISION_FORCED) == 0 &&
ddbad7a661c0663fafd2b79393efa85f840d6af6Timo Sirainen /* drop all fields we don't want */
956f7778e413d3184d69e7b96e4a6b3cd5570bcdTimo Sirainen /* get sequence of first message which doesn't need its temp fields
956f7778e413d3184d69e7b96e4a6b3cd5570bcdTimo Sirainen first_new_seq = mail_cache_get_first_new_seq(view);
956f7778e413d3184d69e7b96e4a6b3cd5570bcdTimo Sirainen message_count = mail_index_view_get_messages_count(view);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (mail_index_transaction_is_expunged(trans, seq)) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen memset(buffer_get_modifiable_data(ctx.field_seen, NULL),
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_append(ctx.buffer, &cache_rec, sizeof(cache_rec));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_lookup_iter_init(cache_view, seq, &iter);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen while (mail_cache_lookup_iter_next(&iter, &field) > 0)
aff7542e1d2f48b030560a4f01096a2cc3f671ceTimo Sirainen cache_rec.size = buffer_get_used_size(ctx.buffer);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen /* nothing cached */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, ctx.buffer->data, cache_rec.size);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen i_assert(orig_fields_count == cache->fields_count);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen hdr.field_header_offset = mail_index_uint32_to_offset(output->offset);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen mail_cache_compress_get_fields(&ctx, used_fields_count);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, ctx.buffer->data, ctx.buffer->used);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen mail_cache_set_syscall_error(cache, "write()");
aff7542e1d2f48b030560a4f01096a2cc3f671ceTimo Sirainen if (hdr.used_file_size < MAIL_CACHE_INITIAL_SIZE) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* grow the file some more. doesn't matter if it fails */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen (void)file_set_size(fd, MAIL_CACHE_INITIAL_SIZE);
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (cache->index->fsync_mode == FSYNC_MODE_ALWAYS) {
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainenstatic int mail_cache_compress_has_file_changed(struct mail_cache *cache)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen unsigned int i;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen for (i = 0;; i++) {
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen fd = nfs_safe_open(cache->filepath, O_RDONLY);
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen mail_cache_set_syscall_error(cache, "open()");
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen /* previously it didn't exist */
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen return hdr.file_seq != cache->need_compress_file_seq;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen } else if (errno != ESTALE || i >= NFS_ESTALE_RETRY_COUNT) {
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen mail_cache_set_syscall_error(cache, "read()");
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic int mail_cache_compress_locked(struct mail_cache *cache,
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen unsigned int i, count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* get the latest info on fields */
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen fd = file_dotlock_open(&cache->dotlock_settings, cache->filepath,
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen mail_cache_set_syscall_error(cache, "file_dotlock_open()");
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if ((ret = mail_cache_compress_has_file_changed(cache)) != 0) {
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen /* was just compressed, forget this */
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (mail_cache_copy(cache, trans, fd, &file_seq, &ext_offsets) < 0) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen /* the fields may have been updated in memory already.
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen reverse those changes by re-reading them from file. */
f1700e6d755306a2b137fad88ea5bf8b9fc6ec4fTimo Sirainen mail_cache_set_syscall_error(cache, "fstat()");
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen "file_dotlock_replace()");
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen /* once we're sure that the compression was successful,
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen update the offsets */
6e07b4251bf6a3cf34019c351a32a65c08392e58Timo Sirainen mail_index_ext_reset(trans, cache->ext_id, file_seq, TRUE);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen for (i = 0; i < count; i++) {
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen if (offsets[i] != 0) {
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainen mail_index_update_ext(trans, i + 1, cache->ext_id,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen file_cache_set_fd(cache->file_cache, cache->fd);
7ca9da144f79317f9a0d3b0b5cc1fe21e44a5bf4Timo Sirainenint mail_cache_compress(struct mail_cache *cache,
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen if (MAIL_INDEX_IS_IN_MEMORY(cache->index) || cache->index->readonly)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen if (cache->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
365435901c22df7e5838f574c950b0e32e77f78aTimo Sirainen /* we're using dotlocking, cache file creation itself creates
365435901c22df7e5838f574c950b0e32e77f78aTimo Sirainen the dotlock file we need. */
5724e7103eed12fe36b55a7b5a8653284a2184b9Timo Sirainen /* couldn't lock, either it's broken or doesn't exist.
5724e7103eed12fe36b55a7b5a8653284a2184b9Timo Sirainen just start creating it. */
5724e7103eed12fe36b55a7b5a8653284a2184b9Timo Sirainen /* locking succeeded. */
5724e7103eed12fe36b55a7b5a8653284a2184b9Timo Sirainen ret = mail_cache_compress_locked(cache, trans, &unlock);