mail-cache-compress.c revision 369a1084c500a9df7448ffa9409ce32e42060bc2
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainenstatic void mail_cache_merge_bitmask(struct mail_cache *cache, buffer_t *buffer,
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen unsigned int i, buf_data_size;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen buf_data = buffer_get_modifiable_data(buffer, &buf_size);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen for (pos = sizeof(struct mail_cache_record); pos < buf_size; ) {
72e9e7ad158101d46860b42c4080e894485c78c3Timo Sirainen buf_field = *((uint32_t *)PTR_OFFSET(buf_data, pos));
afa6ac39d1d6df246d4e7352288c2a0388276a24Timo Sirainen buf_data_size = cache->fields[buf_field].field.field_size;
4823da41d112ff9f5e8f088b0e60d1636e01ff92Timo Sirainen /* @UNSAFE: found it, do the merging */
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen unsigned char *dest = PTR_OFFSET(buf_data, pos);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen for (i = 0; i < buf_data_size; i++)
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainenmail_cache_compress_callback(struct mail_cache_view *view, uint32_t field,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen const void *data, size_t data_size, void *context)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_cache_copy_context *ctx = context;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen cache_field = &view->cache->fields[field].field;
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen field_seen = buffer_get_space_unsafe(ctx->field_seen, field, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* duplicate */
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen if (cache_field->type == MAIL_CACHE_FIELD_BITMASK) {
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen mail_cache_merge_bitmask(view->cache, ctx->buffer,
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen dec = cache_field->decision & ~MAIL_CACHE_DECISION_FORCED;
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen buffer_append(ctx->buffer, &field, sizeof(field));
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen if (cache_field->field_size == (unsigned int)-1) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_append(ctx->buffer, &size32, sizeof(size32));
d5ac54ef50db16b50689b5c8b7bb64d344190832Timo Sirainen buffer_append_zero(ctx->buffer, 4 - (data_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;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainenmail_cache_copy(struct mail_cache *cache, struct mail_index_view *view, int fd)
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen uint32_t i, message_count, seq, first_new_seq, old_offset;
325d4ad220bd13f6d176391d962a0e33c856a7f6Timo Sirainen /* get sequence of first message which doesn't need its temp fields
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen message_count = mail_index_view_get_messages_count(view);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (mail_index_lookup_uid_range(view, idx_hdr->day_first_uid[7],
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen cache_view = mail_cache_view_open(cache, view);
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen t = mail_index_transaction_begin(view, FALSE, TRUE);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen output = o_stream_create_file(fd, default_pool, 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);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_ext_reset(t, cache->ext_id, hdr.file_seq);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen memset(buffer_get_modifiable_data(ctx.field_seen, NULL),
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen buffer_append(ctx.buffer, &cache_rec, sizeof(cache_rec));
aff7542e1d2f48b030560a4f01096a2cc3f671ceTimo Sirainen cache_rec.size = buffer_get_used_size(ctx.buffer);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_update_ext(t, seq, cache->ext_id, &output->offset,
aff7542e1d2f48b030560a4f01096a2cc3f671ceTimo Sirainen buffer_write(ctx.buffer, 0, &cache_rec, sizeof(cache_rec));
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen o_stream_send(output, ctx.buffer->data, cache_rec.size);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* we wrote everything using our internal field ids. so we want
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen mail_cache_header_fields_get() to use them and ignore any
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen existing id mappings in the old cache file. */
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buffer = buffer_create_dynamic(pool_datastack_create(), 256);
4edf90751f075cc6ab3d6f53fc78b656efa80922Timo Sirainen o_stream_send(output, buffer_get_data(buffer, NULL),
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen mail_cache_set_syscall_error(cache, "o_stream_flush()");
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);
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen mail_cache_set_syscall_error(cache, "fdatasync()");
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return mail_index_transaction_commit(&t, &seq, &offset);
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 if (cache->need_compress_file_seq == (uint32_t)-1) {
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,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* get the latest info on fields */
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen fd = file_dotlock_open(&cache->dotlock_settings, cache->filepath,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo 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 */
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen cache->filepath, cache->need_compress_file_seq);
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen fchown(fd, (uid_t)-1, cache->index->gid) < 0) {
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen mail_cache_set_syscall_error(cache, "fchown()");
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen "file_dotlock_replace()");
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen file_cache_set_fd(cache->file_cache, cache->fd);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenint mail_cache_compress(struct mail_cache *cache, struct mail_index_view *view)
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. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return mail_cache_compress_locked(cache, view, &unlock);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen /* couldn't lock, either it's broken or doesn't exist.
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen just start creating it. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return mail_cache_compress_locked(cache, view, &unlock);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen /* locking succeeded. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen ret = mail_cache_compress_locked(cache, view, &unlock);