Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/index/dbox/dbox-keywords.c @ 6335:a1c587d3d633 HEAD
Removed autocreate parameter from mail_index_keyword_lookup(). Added a new
mail_index_keyword_lookup_or_create().
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 31 Aug 2007 22:58:25 +0300 |
parents | 78eaf595359c |
children |
line wrap: on
line source
/* Copyright (C) 2006 Timo Sirainen */ #include "lib.h" #include "array.h" #include "str.h" #include "istream.h" #include "write-full.h" #include "seq-range-array.h" #include "bsearch-insert-pos.h" #include "dbox-file.h" #include "dbox-storage.h" #include "dbox-keywords.h" #include <stdlib.h> static int dbox_keyword_map_compare(const void *p1, const void *p2) { const struct keyword_map *map1 = p1, *map2 = p2; return map1->index_idx < map2->index_idx ? -1 : map1->index_idx > map2->index_idx ? 1 : 0; } int dbox_file_read_keywords(struct dbox_mailbox *mbox, struct dbox_file *file) { struct keyword_map *map, kw; const char *line; unsigned int idx, count, insert_idx; uoff_t last_offset; if (array_is_created(&file->idx_file_keywords)) { array_clear(&file->idx_file_keywords); array_clear(&file->file_idx_keywords); } else { i_array_init(&file->idx_file_keywords, file->keyword_count); i_array_init(&file->file_idx_keywords, file->keyword_count); } /* currently we assume that all extra space at the end of header belongs to keyword list. */ file->keyword_list_size_alloc = file->header_size - file->keyword_list_offset; i_stream_seek(file->input, file->keyword_list_offset); idx = 0; last_offset = file->input->v_offset; while ((line = i_stream_read_next_line(file->input)) != NULL) { if (*line == '\0') { /* end of list */ break; } last_offset = file->input->v_offset; /* set up map record for the keyword */ mail_index_keyword_lookup_or_create(mbox->ibox.index, line, &kw.index_idx); kw.file_idx = idx; /* look up the position where to insert it */ map = array_get_modifiable(&file->idx_file_keywords, &count); if (idx == 0) insert_idx = 0; else { bsearch_insert_pos(&kw, map, count, sizeof(*map), dbox_keyword_map_compare, &insert_idx); } array_insert(&file->idx_file_keywords, insert_idx, &kw, 1); array_append(&file->file_idx_keywords, &kw.index_idx, 1); if (++idx == file->keyword_count) break; } if (line == NULL || file->input->v_offset > file->header_size) { /* unexpected end of list, or list continues outside its allocated area */ mail_storage_set_critical(&mbox->storage->storage, "Corrupted keyword list offset in dbox file %s", file->path); array_clear(&file->idx_file_keywords); return 0; } file->keyword_list_size_used = last_offset - file->keyword_list_offset; return 1; } static int keyword_lookup_cmp(const void *key, const void *obj) { const unsigned int *index_idx = key; const struct keyword_map *map = obj; return *index_idx < map->index_idx ? -1 : *index_idx > map->index_idx ? 1 : 0; } bool dbox_file_lookup_keyword(struct dbox_mailbox *mbox, struct dbox_file *file, unsigned int index_idx, unsigned int *idx_r) { const struct keyword_map *map, *pos; unsigned int count; if (!array_is_created(&file->idx_file_keywords)) { /* Read the keywords, if there are any */ if (dbox_file_read_keywords(mbox, file) <= 0) return FALSE; } map = array_get(&file->idx_file_keywords, &count); pos = bsearch(&index_idx, map, count, sizeof(*map), keyword_lookup_cmp); if (pos != NULL && idx_r != NULL) *idx_r = pos->file_idx; return pos != NULL; } int dbox_file_append_keywords(struct dbox_mailbox *mbox, struct dbox_file *file, const struct seq_range *idx_range, unsigned int count) { const ARRAY_TYPE(keywords) *idx_keywords; string_t *keyword_str; const char *const *idx_keyword_names; unsigned int i, idx_keyword_count, new_pos; int ret; t_push(); keyword_str = t_str_new(2048); idx_keywords = mail_index_get_keywords(mbox->ibox.index); idx_keyword_names = array_get(idx_keywords, &idx_keyword_count); /* make sure we've read the existing keywords */ if (!array_is_created(&file->idx_file_keywords)) { ret = dbox_file_read_keywords(mbox, file); if (ret < 0) return -1; if (ret == 0) { /* broken keywords list. */ file->keyword_list_size_used = 0; } } /* append existing keywords */ if (array_count(&file->idx_file_keywords) > 0) { const unsigned int *file_idx; unsigned int file_count; file_idx = array_get(&file->file_idx_keywords, &file_count); for (i = 0; i < file_count; i++) { i_assert(file_idx[i] < idx_keyword_count); str_append(keyword_str, idx_keyword_names[file_idx[i]]); str_append_c(keyword_str, '\n'); } } /* append new keywords */ if (file->keyword_list_size_used == 0) new_pos = 0; else { new_pos = str_len(keyword_str); i_assert(new_pos == file->keyword_list_size_used); } for (i = 0; i < count; i++) { unsigned int idx; for (idx = idx_range[i].seq1; idx <= idx_range[i].seq2; idx++) { size_t prev_len; i_assert(idx < idx_keyword_count); i_assert(!dbox_file_lookup_keyword(mbox, file, idx, NULL)); prev_len = str_len(keyword_str); str_append(keyword_str, idx_keyword_names[idx]); str_append_c(keyword_str, '\n'); if (str_len(keyword_str) >= file->keyword_list_size_alloc) { /* FIXME: keyword list doesn't fit to the space allocated for it. create a new file where there's more space for keywords and move the mails there. for now we'll just ignore the problem. */ str_truncate(keyword_str, prev_len); break; } } } str_append_c(keyword_str, '\n'); i_assert(str_len(keyword_str) <= file->keyword_list_size_alloc); i_assert(new_pos < str_len(keyword_str)); /* we can reuse the existing keyword list position */ if (pwrite_full(file->fd, str_data(keyword_str) + new_pos, str_len(keyword_str) - new_pos, file->keyword_list_offset + new_pos) < 0) { mail_storage_set_critical(&mbox->storage->storage, "pwrite_full(%s) failed: %m", file->path); } /* FIXME: we could do this faster than by reading them.. */ ret = 0; if (dbox_file_read_keywords(mbox, file) <= 0) ret = -1; t_pop(); return ret; }