From: Timo Sirainen Date: Tue, 17 Feb 2009 03:44:42 +0000 (-0500) Subject: dbox: Removed dbox-index code. X-Git-Tag: 2.0.alpha1~1038^2~89 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=816278ef6191200da823f1853de137f2c006f1ca;p=thirdparty%2Fdovecot%2Fcore.git dbox: Removed dbox-index code. --HG-- branch : HEAD --- diff --git a/src/lib-storage/index/dbox/dbox-file.h b/src/lib-storage/index/dbox/dbox-file.h index 80acec3e97..5f63b95940 100644 --- a/src/lib-storage/index/dbox/dbox-file.h +++ b/src/lib-storage/index/dbox/dbox-file.h @@ -145,7 +145,7 @@ void dbox_files_free(struct dbox_mailbox *mbox); /* Assign a newly created file (file_id=0) a new id. */ int dbox_file_assign_id(struct dbox_file *file, unsigned int file_id); -/* If file_id is 0, open the file, otherwise create it. Returns 1 if ok, +/* Open the file if file_id is not 0, otherwise create it. Returns 1 if ok, 0 if read_header=TRUE and opened file was broken, -1 if error. If file is deleted, deleted_r=TRUE and 1 is returned. */ int dbox_file_open_or_create(struct dbox_file *file, bool read_header, diff --git a/src/lib-storage/index/dbox/dbox-index.c b/src/lib-storage/index/dbox/dbox-index.c index aedbc342b1..8790ee8dbe 100644 --- a/src/lib-storage/index/dbox/dbox-index.c +++ b/src/lib-storage/index/dbox/dbox-index.c @@ -2,36 +2,12 @@ #include "lib.h" #include "array.h" -#include "hex-dec.h" -#include "str.h" -#include "istream.h" -#include "ostream.h" -#include "write-full.h" -#include "nfs-workarounds.h" -#include "safe-mkstemp.h" -#include "mailbox-uidvalidity.h" #include "dbox-storage.h" #include "dbox-file.h" #include "dbox-index.h" -#include -#include -#include - -#define DBOX_INDEX_LOCK_RETRY_COUNT 10 - struct dbox_index { struct dbox_mailbox *mbox; - - struct istream *input; - char *path; - int fd; - - uint32_t uid_validity, next_uid; - unsigned int next_file_id; - - pool_t record_data_pool; - ARRAY_DEFINE(records, struct dbox_index_record); }; struct dbox_index_append_context { @@ -40,656 +16,47 @@ struct dbox_index_append_context { uoff_t output_offset; unsigned int new_record_idx; - unsigned int first_new_file_id; + uint32_t first_new_file_id; unsigned int locked_header:1; }; -static int dbox_index_recreate(struct dbox_index *index, bool locked); - struct dbox_index *dbox_index_init(struct dbox_mailbox *mbox) { struct dbox_index *index; index = i_new(struct dbox_index, 1); index->mbox = mbox; - index->path = i_strdup_printf("%s/"DBOX_INDEX_NAME, mbox->path); - index->fd = -1; - index->next_uid = 1; - index->next_file_id = 1; - i_array_init(&index->records, 128); - index->record_data_pool = - pool_alloconly_create("dbox index record data", 256); return index; } -static void dbox_index_close(struct dbox_index *index) -{ - if (index->input != NULL) - i_stream_unref(&index->input); - if (index->fd != -1) { - if (close(index->fd) < 0) - i_error("close(%s) failed: %m", index->path); - index->fd = -1; - } -} - void dbox_index_deinit(struct dbox_index **_index) { struct dbox_index *index = *_index; *_index = NULL; - dbox_index_close(index); - array_free(&index->records); - pool_unref(&index->record_data_pool); - i_free(index->path); i_free(index); } -static int dbox_index_parse_maildir(struct dbox_index *index, const char *line, - struct dbox_index_record *rec) -{ - char *p; - unsigned long uid; - - if (*line++ != ' ') - return -1; - - uid = strtoul(line, &p, 10); - if (*p++ != ' ' || *p == '\0' || uid == 0 || uid >= (uint32_t)-1) - return -1; - - if (*p == ':' || strstr(p, " :") != NULL) - rec->data = p_strdup(index->record_data_pool, line); - else { - /* convert to new format */ - rec->data = p_strconcat(index->record_data_pool, - t_strdup_until(line, p), ":", p, NULL); - } - return 0; -} - -static int dbox_index_parse_line(struct dbox_index *index, const char *line, - unsigned int offset) -{ - struct dbox_index_record rec; - - memset(&rec, 0, sizeof(rec)); - rec.file_offset = offset; - - /* [] */ - while (*line >= '0' && *line <= '9') { - rec.file_id = rec.file_id*10 + *line - '0'; - line++; - } - if (*line++ != ' ') - return -1; - - if ((rec.file_id & DBOX_FILE_ID_FLAG_UID) != 0) { - /* UID files shouldn't be listed in dbox.index */ - return -1; - } - - if (line[0] == '\0' || line[1] == '\0' || line[2] == '\0') - return -1; - rec.status = line[0]; - rec.expunges = line[1] != '0'; - rec.dirty = line[2] != '0'; - - line += 3; - if (rec.status == DBOX_INDEX_FILE_STATUS_MAILDIR) { - if (dbox_index_parse_maildir(index, line, &rec) < 0) - return -1; - } - array_append(&index->records, &rec, 1); - return 0; -} - -static int -dbox_index_set_corrupted(struct dbox_index *index, const char *reason) -{ - mail_storage_set_critical(index->mbox->ibox.box.storage, - "dbox index %s corrupted: %s", - index->path, reason); - - if (unlink(index->path) < 0 && errno != ENOENT) - i_error("unlink(%s) failed: %m", index->path); - return -1; -} - -static uint32_t dbox_get_uidvalidity_next(struct mail_storage *storage) -{ - const char *path; - - path = mailbox_list_get_path(storage->list, NULL, - MAILBOX_LIST_PATH_TYPE_CONTROL); - path = t_strconcat(path, "/"DBOX_UIDVALIDITY_FILE_NAME, NULL); - return mailbox_uidvalidity_next(path); -} - -static void dbox_index_header_init(struct dbox_index *index, - struct dbox_index_file_header *hdr) -{ - if (index->uid_validity == 0) { - struct index_mailbox *ibox = &index->mbox->ibox; - const struct mail_index_header *idx_hdr; - - idx_hdr = mail_index_get_header(ibox->view); - index->uid_validity = idx_hdr->uid_validity != 0 ? - idx_hdr->uid_validity : - dbox_get_uidvalidity_next(ibox->box.storage); - } - - memset(hdr, ' ', sizeof(*hdr)); - hdr->version = DBOX_INDEX_VERSION; - dec2hex(hdr->uid_validity_hex, index->uid_validity, - sizeof(hdr->uid_validity_hex)); - dec2hex(hdr->next_uid_hex, index->next_uid, sizeof(hdr->next_uid_hex)); - dec2hex(hdr->next_file_id_hex, index->next_file_id, - sizeof(hdr->next_file_id_hex)); -} - -static int dbox_index_parse_header(struct dbox_index *index, const char *line) -{ - struct dbox_index_file_header hdr; - - if (strlen(line) < sizeof(hdr)) - return dbox_index_set_corrupted(index, "Header too short"); - - memcpy(&hdr, line, sizeof(hdr)); - if (hdr.version != DBOX_INDEX_VERSION) - return dbox_index_set_corrupted(index, "Invalid version"); - - index->uid_validity = - hex2dec(hdr.uid_validity_hex, sizeof(hdr.uid_validity_hex)); - if (index->uid_validity == 0) - return dbox_index_set_corrupted(index, "uid_validity = 0"); - - index->next_uid = hex2dec(hdr.next_uid_hex, sizeof(hdr.next_uid_hex)); - if (index->next_uid == 0) - return dbox_index_set_corrupted(index, "next_uid = 0"); - index->next_file_id = - hex2dec(hdr.next_file_id_hex, sizeof(hdr.next_file_id_hex)); - return 0; -} - -static int dbox_index_read_header(struct dbox_index *index) -{ - const char *line; - - i_stream_sync(index->input); - i_stream_seek(index->input, 0); - - line = i_stream_read_next_line(index->input); - if (line == NULL) - return dbox_index_set_corrupted(index, "Missing header"); - return dbox_index_parse_header(index, line); -} - -static int dbox_index_read(struct dbox_index *index) -{ - struct istream *input; - const char *line; - uoff_t start_offset; - int ret; - - if (index->fd != -1) - dbox_index_close(index); - - index->fd = open(index->path, O_RDWR); - if (index->fd == -1) { - if (errno == ENOENT) - return 0; - mail_storage_set_critical(index->mbox->ibox.box.storage, - "open(%s) failed: %m", index->path); - return -1; - } - - p_clear(index->record_data_pool); - array_clear(&index->records); - input = index->input = i_stream_create_fd(index->fd, 1024, FALSE); - - ret = dbox_index_read_header(index); - start_offset = input->v_offset; - while ((line = i_stream_read_next_line(input)) != NULL) { - if (dbox_index_parse_line(index, line, start_offset) < 0) { - dbox_index_set_corrupted(index, "Corrupted record"); - ret = -1; - break; - } - start_offset = input->v_offset; - } - return ret == 0 ? 1 : - (input->stream_errno == 0 ? 0 : -1); -} - -static int dbox_index_read_or_create(struct dbox_index *index) -{ - unsigned int i; - int ret; - - for (i = 0;; i++) { - if ((ret = dbox_index_read(index)) != 0) - return ret; - - /* doesn't exist / corrupted */ - if (i == DBOX_INDEX_LOCK_RETRY_COUNT) - break; - - if (index->fd != -1) - dbox_index_close(index); - - T_BEGIN { - ret = dbox_index_recreate(index, FALSE); - } T_END; - if (ret < 0) - return -1; - } - - mail_storage_set_critical(index->mbox->ibox.box.storage, - "dbox index recreation keeps failing: %s", index->path); - return -1; -} - -static int dbox_index_refresh(struct dbox_index *index) -{ - struct stat st1, st2; - - if (index->fd == -1) { - if (dbox_index_read_or_create(index) < 0) - return -1; - i_assert(index->fd != -1); - return 1; - } - - if (fstat(index->fd, &st1) < 0) { - mail_storage_set_critical(index->mbox->ibox.box.storage, - "fstat(%s) failed: %m", index->path); - return -1; - } - if (stat(index->path, &st2) < 0) { - mail_storage_set_critical(index->mbox->ibox.box.storage, - "stat(%s) failed: %m", index->path); - return -1; - } - - if (st1.st_ino != st2.st_ino || !CMP_DEV_T(st1.st_dev, st2.st_dev)) { - if (dbox_index_read(index) < 0) - return -1; - return 1; - } - return 0; -} - -static int dbox_index_record_cmp(const void *key, const void *data) -{ - const unsigned int *file_id = key; - const struct dbox_index_record *rec = data; - - return *file_id - rec->file_id; -} - -struct dbox_index_record * -dbox_index_record_lookup(struct dbox_index *index, unsigned int file_id) -{ - struct dbox_index_record *records; - unsigned int count; - - if ((file_id & DBOX_FILE_ID_FLAG_UID) != 0) - return NULL; - - if (index->fd == -1) { - if (dbox_index_refresh(index) < 0) - return NULL; - } - - records = array_get_modifiable(&index->records, &count); - return bsearch(&file_id, records, count, sizeof(*records), - dbox_index_record_cmp); -} - -static int -dbox_index_lock_range(struct dbox_index *index, int cmd, int lock_type, - off_t start, off_t len) -{ - struct flock fl; - const char *errstr; - - fl.l_type = lock_type; - fl.l_whence = SEEK_SET; - fl.l_start = start; - fl.l_len = len; - if (fcntl(index->fd, cmd, &fl) < 0) { - if ((errno == EACCES || errno == EAGAIN || errno == EINTR) && - cmd == F_SETLK) - return 0; - - errstr = errno != EACCES ? strerror(errno) : - "File is locked by another process (EACCES)"; - mail_storage_set_critical(index->mbox->ibox.box.storage, - "fcntl(%s, %s) failed: %s", index->path, - lock_type == F_UNLCK ? "F_UNLCK" : "F_WRLCK", errstr); - return -1; - } - return 1; -} - -static void dbox_index_unlock_range(struct dbox_index *index, - off_t start, off_t len) -{ - (void)dbox_index_lock_range(index, F_SETLK, F_UNLCK, start, len); -} - -static int -dbox_index_try_lock_once(struct dbox_index *index, unsigned int file_id, - enum dbox_index_file_lock_status *lock_status_r) -{ - struct dbox_index_record *rec; - int ret; - - i_assert((file_id & DBOX_FILE_ID_FLAG_UID) == 0); - - rec = dbox_index_record_lookup(index, file_id); - if (rec == NULL || rec->status == DBOX_INDEX_FILE_STATUS_UNLINKED) { - *lock_status_r = DBOX_INDEX_FILE_LOCK_UNLINKED; - return 0; - } - - if (rec->status != DBOX_INDEX_FILE_STATUS_APPENDABLE) { - *lock_status_r = DBOX_INDEX_FILE_LOCK_NOT_NEEDED; - return 1; - } - - /* we'll need to try to lock this record */ - ret = dbox_index_lock_range(index, F_SETLK, F_WRLCK, - rec->file_offset, 1); - if (ret > 0) { - *lock_status_r = DBOX_INDEX_FILE_LOCKED; - rec->locked = TRUE; - } else if (ret == 0) - *lock_status_r = DBOX_INDEX_FILE_LOCK_TRY_AGAIN; - return ret; -} - -int dbox_index_try_lock_file(struct dbox_index *index, unsigned int file_id, - enum dbox_index_file_lock_status *lock_status_r) -{ - int i, ret; - - if ((file_id & DBOX_FILE_ID_FLAG_UID) != 0) { - *lock_status_r = DBOX_INDEX_FILE_LOCK_NOT_NEEDED; - return 1; - } - - if (index->fd == -1) { - if (dbox_index_refresh(index) < 0) - return 1; - } - - for (i = 0; i < DBOX_INDEX_LOCK_RETRY_COUNT; i++) { - ret = dbox_index_try_lock_once(index, file_id, lock_status_r); - if (ret <= 0 || *lock_status_r != DBOX_INDEX_FILE_LOCKED) - return ret; - - /* if file was recreated, reopen it and try again */ - if ((ret = dbox_index_refresh(index)) <= 0) - return ret < 0 ? -1 : 1; - } - - i_warning("dbox index keeps getting recreated: %s", index->path); - return 0; -} - -void dbox_index_unlock_file(struct dbox_index *index, unsigned int file_id) -{ - struct dbox_index_record *rec; - - rec = dbox_index_record_lookup(index, file_id); - if (rec == NULL || !rec->locked) - return; - - dbox_index_unlock_range(index, rec->file_offset, 1); - rec->locked = FALSE; -} - -static int dbox_index_lock_header(struct dbox_index *index) -{ - int i, ret; - - if (index->fd == -1) { - if (dbox_index_refresh(index) < 0) - return 1; - } - - for (i = 0; i < DBOX_INDEX_LOCK_RETRY_COUNT; i++) { - ret = dbox_index_lock_range(index, F_SETLKW, F_WRLCK, 0, - sizeof(struct dbox_index_file_header)); - if (ret <= 0) - return -1; - - /* if file was recreated, reopen it and try again */ - if ((ret = dbox_index_refresh(index)) <= 0) - return ret < 0; - } - - mail_storage_set_critical(index->mbox->ibox.box.storage, - "dbox index keeps getting recreated: %s", index->path); - return -1; -} - -static void dbox_index_unlock_header(struct dbox_index *index) -{ - dbox_index_unlock_range(index, 0, - sizeof(struct dbox_index_file_header)); -} - -static void -dbox_index_append_record(const struct dbox_index_record *rec, string_t *str) -{ - str_printfa(str, "%u %c%c%c", - rec->file_id, rec->status, - rec->expunges ? 'E' : '0', - rec->dirty ? 'D' : '0'); - - switch (rec->status) { - case DBOX_INDEX_FILE_STATUS_APPENDABLE: - str_append(str, " 00000000"); - break; - case DBOX_INDEX_FILE_STATUS_APPENDING: - case DBOX_INDEX_FILE_STATUS_UNLINKED: - i_unreached(); - break; - case DBOX_INDEX_FILE_STATUS_NONAPPENDABLE: - case DBOX_INDEX_FILE_STATUS_SINGLE_MESSAGE: - break; - case DBOX_INDEX_FILE_STATUS_MAILDIR: - str_append_c(str, ' '); - str_append(str, rec->data); - break; - } - str_append_c(str, '\n'); -} - -static int dbox_index_create_fd(struct dbox_mailbox *mbox, string_t *temp_path, - bool locked) -{ - mode_t old_mask; - int fd; - - if (locked) { - str_append(temp_path, ".tmp"); - return dbox_create_fd(mbox, str_c(temp_path)); - } - - str_append_c(temp_path, '.'); - old_mask = umask(0777 & ~mbox->ibox.box.file_create_mode); - fd = safe_mkstemp_hostpid(temp_path, 0777, (uid_t)-1, (gid_t)-1); - umask(old_mask); - - if (fd == -1) { - mail_storage_set_critical(mbox->ibox.box.storage, - "safe_mkstemp_hostpid(%s) failed: %m", - str_c(temp_path)); - } - return fd; -} - -static int dbox_index_recreate(struct dbox_index *index, bool locked) -{ - struct mail_storage *storage = &index->mbox->storage->storage; - struct dbox_index_record *records; - struct ostream *output; - struct dbox_index_file_header hdr; - string_t *temp_path, *str; - unsigned int i, count; - int fd, ret = 0; - - temp_path = t_str_new(256); - str_append(temp_path, index->path); - - fd = dbox_index_create_fd(index->mbox, temp_path, locked); - if (fd == -1) - return -1; - - str = t_str_new(256); - output = o_stream_create_fd_file(fd, 0, FALSE); - o_stream_cork(output); - - dbox_index_header_init(index, &hdr); - o_stream_send(output, &hdr, sizeof(hdr)); - o_stream_send(output, "\n", 1); - - records = array_get_modifiable(&index->records, &count); - for (i = 0; i < count; ) { - if (records[i].status == DBOX_INDEX_FILE_STATUS_UNLINKED) { - array_delete(&index->records, i, 1); - records = array_get_modifiable(&index->records, &count); - } else { - records[i].file_offset = output->offset; - str_truncate(str, 0); - dbox_index_append_record(&records[i], str); - o_stream_send(output, str_data(str), str_len(str)); - i++; - } - } - - if (o_stream_flush(output) < 0) { - mail_storage_set_critical(storage, - "write(%s) failed: %m", str_c(temp_path)); - ret = -1; - } - - o_stream_destroy(&output); - if (ret == 0 && index->mbox->ibox.fsync_disable) { - if (fdatasync(fd) < 0) { - mail_storage_set_critical(storage, - "fdatasync(%s) failed: %m", str_c(temp_path)); - ret = -1; - } - } - if (close(fd) < 0) { - mail_storage_set_critical(storage, - "close(%s) failed: %m", str_c(temp_path)); - ret = -1; - } - if (ret == 0) { - if (locked) { - if (rename(str_c(temp_path), index->path) < 0) { - mail_storage_set_critical(storage, - "rename(%s, %s) failed: %m", - str_c(temp_path), index->path); - ret = -1; - } - } else { - if (nfs_safe_link(str_c(temp_path), index->path, - TRUE) < 0 && - errno != EEXIST) { - mail_storage_set_critical(storage, - "link(%s, %s) failed: %m", - str_c(temp_path), index->path); - ret = -1; - } - } - } - if (ret < 0 || !locked) { - if (unlink(str_c(temp_path)) < 0) - i_error("unlink(%s) failed: %m", str_c(temp_path)); - } - return ret; -} - struct dbox_index_append_context * dbox_index_append_begin(struct dbox_index *index) { struct dbox_index_append_context *ctx; - const void *data; - bool expunged; ctx = i_new(struct dbox_index_append_context, 1); ctx->index = index; - ctx->first_new_file_id = (unsigned int)-1; + ctx->first_new_file_id = (uint32_t)-1; i_array_init(&ctx->files, 64); - - /* refresh the index now if there's a possibility of some appendable - files existing */ - if (mail_index_view_get_messages_count(index->mbox->ibox.view) > 0) { - mail_index_lookup_ext(index->mbox->ibox.view, 1, - index->mbox->dbox_ext_id, - &data, &expunged); - if (data != NULL) - (void)dbox_index_refresh(index); - } return ctx; } -static bool -dbox_index_append_file_record(struct dbox_index_append_context *ctx, - struct dbox_index_record *record, - uoff_t mail_size, struct dbox_file **file_r, - struct ostream **output_r) -{ - struct dbox_file *const *files, *file; - enum dbox_index_file_lock_status lock_status; - unsigned int i, count; - - if (record->status != DBOX_INDEX_FILE_STATUS_APPENDABLE) - return FALSE; - - if (record->expunges) - return FALSE; - - /* if we already have it in our files list, we already checked that - we can't append to it. */ - files = array_get(&ctx->files, &count); - for (i = 0; i < count; i++) { - if (files[i]->file_id == record->file_id) - return FALSE; - } - i_assert(!record->locked); - - if (dbox_index_try_lock_file(ctx->index, record->file_id, - &lock_status) <= 0) - return FALSE; - - /* open the file to see if we can append */ - file = dbox_file_init(ctx->index->mbox, record->file_id); - if (dbox_file_get_append_stream(file, mail_size, output_r) <= 0) { - dbox_index_unlock_file(ctx->index, record->file_id); - dbox_file_unref(&file); - return FALSE; - } - *file_r = file; - return TRUE; -} - int dbox_index_append_next(struct dbox_index_append_context *ctx, uoff_t mail_size, struct dbox_file **file_r, struct ostream **output_r) { struct dbox_file *const *files, *file = NULL; - struct dbox_index_record *records; unsigned int i, count; int ret; @@ -703,13 +70,7 @@ int dbox_index_append_next(struct dbox_index_append_context *ctx, } } - /* try to find an existing appendable file */ - records = array_get_modifiable(&ctx->index->records, &count); - for (i = 0; i < count; i++) { - if (dbox_index_append_file_record(ctx, &records[i], mail_size, - &file, output_r)) - break; - } + /* FIXME: try to find an existing appendable file */ if (file == NULL) { /* create a new file */ @@ -728,157 +89,46 @@ int dbox_index_append_next(struct dbox_index_append_context *ctx, return 0; } -static const char *dbox_file_maildir_get_index_data(struct dbox_file *file) -{ - return t_strdup_printf("%u :%s", file->last_append_uid, - file->fname); -} - static int dbox_index_append_commit_new(struct dbox_index_append_context *ctx, - struct dbox_file *file, string_t *str) + struct dbox_file *file) { - struct mail_storage *storage = &ctx->index->mbox->storage->storage; - struct dbox_index_record rec; - struct stat st; unsigned int file_id; + i_assert(!file->maildir_file); i_assert(file->append_count > 0); - if (file->append_count == 1 && !file->maildir_file && - !dbox_file_can_append(file, 0)) { + if (file->append_count == 1 && !dbox_file_can_append(file, 0)) { /* single UID message file */ i_assert(file->last_append_uid != 0); file_id = file->last_append_uid | DBOX_FILE_ID_FLAG_UID; return dbox_file_assign_id(file, file_id); } - if (!ctx->locked_header) { - if (dbox_index_lock_header(ctx->index) < 0) - return -1; - if (dbox_index_read_header(ctx->index) < 0) { - dbox_index_unlock_header(ctx->index); - return -1; - } - if (fstat(ctx->index->fd, &st) < 0) { - mail_storage_set_critical(storage, - "fstat(%s) failed: %m", ctx->index->path); - dbox_index_unlock_header(ctx->index); - return -1; - } - ctx->output_offset = st.st_size; - ctx->new_record_idx = array_count(&ctx->index->records); - ctx->first_new_file_id = ctx->index->next_file_id; - ctx->locked_header = TRUE; - } - - file_id = ctx->index->next_file_id++; - if (dbox_file_assign_id(file, file_id) < 0) - return -1; - - memset(&rec, 0, sizeof(rec)); - rec.file_id = file_id; - rec.file_offset = ctx->output_offset + str_len(str); - if (file->maildir_file) { - rec.status = DBOX_INDEX_FILE_STATUS_MAILDIR; - rec.data = p_strdup(ctx->index->record_data_pool, - dbox_file_maildir_get_index_data(file)); - - } else { - rec.status = dbox_file_can_append(file, 0) ? - DBOX_INDEX_FILE_STATUS_APPENDABLE : - DBOX_INDEX_FILE_STATUS_NONAPPENDABLE; - } - - array_append(&ctx->index->records, &rec, 1); - dbox_index_append_record(&rec, str); - return 0; -} - -static void -dbox_index_append_rollback_commit(struct dbox_index_append_context *ctx) -{ - struct dbox_file *const *files; - unsigned int i, count; - - files = array_get(&ctx->files, &count); - for (i = 0; i < count; i++) { - if (files[i]->file_id >= ctx->first_new_file_id) { - if (unlink(dbox_file_get_path(files[i])) < 0) { - i_error("unlink(%s) failed: %m", - dbox_file_get_path(files[i])); - } - files[i]->deleted = TRUE; - } else { - /* FIXME: we should delete the appended mails.. */ - } - } - array_delete(&ctx->index->records, ctx->new_record_idx, - array_count(&ctx->index->records) - ctx->new_record_idx); -} - -static int -dbox_index_append_write_records(struct dbox_index_append_context *ctx, - string_t *str) -{ - int ret; - - ret = dbox_index_lock_range(ctx->index, F_SETLKW, F_WRLCK, - ctx->output_offset, str_len(str)); - if (ret <= 0) - return -1; - - if (pwrite_full(ctx->index->fd, str_data(str), str_len(str), - ctx->output_offset) < 0) { - mail_storage_set_critical(&ctx->index->mbox->storage->storage, - "pwrite(%s) failed: %m", ctx->index->path); - if (ftruncate(ctx->index->fd, ctx->output_offset) < 0) - i_error("ftruncate(%s) failed: %m", ctx->index->path); - ret = -1; - } - dbox_index_unlock_range(ctx->index, ctx->output_offset, str_len(str)); - return ret < 0 ? -1 : 0; -} - -static int dbox_index_write_header(struct dbox_index *index) -{ - struct dbox_index_file_header hdr; - - dbox_index_header_init(index, &hdr); - if (pwrite_full(index->fd, &hdr, sizeof(hdr), 0) < 0) { - mail_storage_set_critical(&index->mbox->storage->storage, - "pwrite(%s) failed: %m", index->path); - return -1; - } - return 0; + /* FIXME */ + return -1; } int dbox_index_append_assign_file_ids(struct dbox_index_append_context *ctx) { struct dbox_file *const *files, *file; - string_t *str; unsigned int i, count; int ret = 0; - str = str_new(default_pool, 1024); files = array_get(&ctx->files, &count); for (i = 0; i < count; i++) { file = files[i]; - if (file->file_id == 0) T_BEGIN { - if (dbox_index_append_commit_new(ctx, file, str) < 0) + if (file->file_id == 0) { + if (dbox_index_append_commit_new(ctx, file) < 0) { ret = -1; - } T_END; + break; + } + } } - if (ret == 0 && str_len(str) > 0) { - /* write the new records to index */ - ret = dbox_index_append_write_records(ctx, str); + if (ret < 0) { + /* FIXME: we have to rollback the changes we made */ } - if (ret < 0 && str_len(str) > 0) { - /* we have to rollback changes we made */ - dbox_index_append_rollback_commit(ctx); - } - str_free(&str); return ret; } @@ -887,24 +137,12 @@ int dbox_index_append_commit(struct dbox_index_append_context **_ctx) struct dbox_index_append_context *ctx = *_ctx; struct dbox_file **files; unsigned int i, count; - int ret = 0; *_ctx = NULL; files = array_get_modifiable(&ctx->files, &count); - for (i = 0; i < count; i++) { - if (files[i]->file_id < ctx->first_new_file_id) { - /* FIXME: update status */ - dbox_index_unlock_file(ctx->index, files[i]->file_id); - } + for (i = 0; i < count; i++) dbox_file_unref(&files[i]); - } - - if (ctx->locked_header) { - if (dbox_index_write_header(ctx->index) < 0) - ret = -1; - dbox_index_unlock_header(ctx->index); - } array_free(&ctx->files); i_free(ctx); @@ -923,9 +161,9 @@ void dbox_index_append_rollback(struct dbox_index_append_context **_ctx) for (i = 0; i < count; i++) { file = files[i]; - if (file->file_id != 0) - dbox_index_unlock_file(ctx->index, file->file_id); - else { + if (file->file_id != 0) { + /* FIXME: truncate? */ + } else { if (unlink(dbox_file_get_path(file)) < 0) { i_error("unlink(%s) failed: %m", dbox_file_get_path(file)); diff --git a/src/lib-storage/index/dbox/dbox-index.h b/src/lib-storage/index/dbox/dbox-index.h index 7be931a3d9..721f834f9f 100644 --- a/src/lib-storage/index/dbox/dbox-index.h +++ b/src/lib-storage/index/dbox/dbox-index.h @@ -1,107 +1,12 @@ #ifndef DBOX_INDEX_H #define DBOX_INDEX_H -/* The file begins with a header followed by zero or more records: - - [] - - contains either '0' = no or 'E' = file contains messages marked - as expunged, which should be removed when possible. - - contains either '0' = no or 'D' = file contains messages that don't - have up-to-date metadata. When expunge copies message data to a new file, - the dirty state should be flushed for the copied messages (or the dirty - state should be copied). - - and can be written without locking the record, so syncing - can update them even while messages are being appended to the file. - - If status-specific data isn't specified for the given status, it should be - ignored. Especially 'U' status may contain different kinds of data. -*/ - struct dbox_file; struct dbox_index_append_context; -#define DBOX_INDEX_VERSION '1' - -enum dbox_index_file_status { - /* File can be appended to as long as is zero. It must be - locked when expunging. status-specific data contains a %08x lock - timestamp. */ - DBOX_INDEX_FILE_STATUS_APPENDABLE = '0', - /* File is currently being appended to. If this record can be locked, - the append crashed and this file should be opened for fixing - (truncate non-committed appends from the file). */ - DBOX_INDEX_FILE_STATUS_APPENDING = 'A', - /* File can't be appended to. */ - DBOX_INDEX_FILE_STATUS_NONAPPENDABLE = 'N', - /* File contains only a single message. It can't be appended to - and it can be expunged by unlinking the file. */ - DBOX_INDEX_FILE_STATUS_SINGLE_MESSAGE = '1', - /* The file has already been unlinked, this record should be removed. */ - DBOX_INDEX_FILE_STATUS_UNLINKED = 'U', - - /* File is a maildir file. Status-specific data contains - old: - new: [] : - */ - DBOX_INDEX_FILE_STATUS_MAILDIR = 'M' -}; - -enum dbox_index_file_lock_status { - /* File was locked (ret=1) */ - DBOX_INDEX_FILE_LOCKED, - /* File didn't have appendable status (ret=1) */ - DBOX_INDEX_FILE_LOCK_NOT_NEEDED, - /* File was already locked by someone else (ret=0) */ - DBOX_INDEX_FILE_LOCK_TRY_AGAIN, - /* File is already unlinked (ret=0) */ - DBOX_INDEX_FILE_LOCK_UNLINKED -}; - -struct dbox_index_file_header { - /* DBOX_INDEX_VERSION */ - unsigned char version; - unsigned char space_1; - - /* Current UIDVALIDITY */ - unsigned char uid_validity_hex[8]; - unsigned char space_2; - - /* Next available message UID */ - unsigned char next_uid_hex[8]; - unsigned char space_3; - - /* Next available */ - unsigned char next_file_id_hex[8]; -}; - -struct dbox_index_record { - unsigned int file_id; - unsigned int file_offset; - - enum dbox_index_file_status status; - const char *data; - - unsigned int expunges:1; - unsigned int dirty:1; - unsigned int locked:1; -}; - struct dbox_index *dbox_index_init(struct dbox_mailbox *mbox); void dbox_index_deinit(struct dbox_index **index); -struct dbox_index_record * -dbox_index_record_lookup(struct dbox_index *index, unsigned int file_id); - -/* Try to lock a file record. Only appendable files are actually locked. - Returns 1 if lock acquired or not needed, 0 if we failed to get a lock or - file is unlinked, -1 if error. lock_status_r is set if 0 or 1 is returned. */ -int dbox_index_try_lock_file(struct dbox_index *index, unsigned int file_id, - enum dbox_index_file_lock_status *lock_status_r); -void dbox_index_unlock_file(struct dbox_index *index, unsigned int file_id); - struct dbox_index_append_context * dbox_index_append_begin(struct dbox_index *index); /* Request file for saving a new message with given size. If an existing file diff --git a/src/lib-storage/index/dbox/dbox-storage.h b/src/lib-storage/index/dbox/dbox-storage.h index fe837d95d6..d5d20b57e6 100644 --- a/src/lib-storage/index/dbox/dbox-storage.h +++ b/src/lib-storage/index/dbox/dbox-storage.h @@ -10,7 +10,6 @@ #define DBOX_INDEX_PREFIX "dovecot.index" #define DBOX_MAILDIR_NAME "dbox-Mails" -#define DBOX_INDEX_NAME "dbox.index" #define DBOX_MAIL_FILE_MULTI_PREFIX "m." #define DBOX_MAIL_FILE_UID_PREFIX "u." #define DBOX_MAIL_FILE_MULTI_FORMAT DBOX_MAIL_FILE_MULTI_PREFIX"%u" diff --git a/src/lib-storage/index/dbox/dbox-sync-file.c b/src/lib-storage/index/dbox/dbox-sync-file.c index f1acb68900..4654bd30a2 100644 --- a/src/lib-storage/index/dbox/dbox-sync-file.c +++ b/src/lib-storage/index/dbox/dbox-sync-file.c @@ -6,7 +6,6 @@ #include "ostream.h" #include "str.h" #include "dbox-storage.h" -#include "dbox-index.h" #include "dbox-file.h" #include "dbox-sync.h" @@ -52,6 +51,8 @@ dbox_sync_file_expunge(struct dbox_sync_context *ctx, struct dbox_file *file, bool expunged; int ret; + /* FIXME: lock the file first */ + expunges = array_get(&entry->expunges, &count); if (!dbox_file_lookup(ctx->mbox, ctx->sync_view, expunges[0].seq1, &file_id, &first_offset)) @@ -276,29 +277,11 @@ int dbox_sync_file(struct dbox_sync_context *ctx, const struct dbox_sync_file_entry *entry) { struct dbox_file *file; - struct dbox_index_record *rec; - enum dbox_index_file_status status; - bool locked, deleted; + bool deleted; int ret; - if ((entry->file_id & DBOX_FILE_ID_FLAG_UID) != 0) { - locked = TRUE; - status = DBOX_INDEX_FILE_STATUS_SINGLE_MESSAGE; - } else { - rec = dbox_index_record_lookup(ctx->mbox->dbox_index, - entry->file_id); - if (rec == NULL || - rec->status == DBOX_INDEX_FILE_STATUS_UNLINKED) { - /* file doesn't exist, nothing to do */ - return 1; - } - locked = rec->locked; - status = rec->status; - } - file = dbox_file_init(ctx->mbox, entry->file_id); - if ((status == DBOX_INDEX_FILE_STATUS_SINGLE_MESSAGE || - status == DBOX_INDEX_FILE_STATUS_MAILDIR) && + if ((file->file_id & DBOX_FILE_ID_FLAG_UID) != 0 && array_is_created(&entry->expunges)) { /* fast path to expunging the whole file */ if ((ret = dbox_sync_file_unlink(file)) == 0) { @@ -310,7 +293,7 @@ int dbox_sync_file(struct dbox_sync_context *ctx, ret = dbox_file_open_or_create(file, TRUE, &deleted); if (ret > 0 && !deleted) { dbox_sync_file_move_if_needed(file, entry); - if (array_is_created(&entry->expunges) && locked) + if (array_is_created(&entry->expunges)) ret = dbox_sync_file_expunge(ctx, file, entry); } }