[dovecot-cvs] dovecot/src/lib-storage/index/dbox Makefile.am, 1.2,
1.3 dbox-file.c, 1.4, 1.5 dbox-file.h, 1.1,
1.2 dbox-keywords.c, NONE, 1.1 dbox-keywords.h, NONE,
1.1 dbox-mail.c, 1.4, 1.5 dbox-storage.h, 1.5,
1.6 dbox-sync-full.c, 1.2, 1.3 dbox-sync.c, 1.5,
1.6 dbox-uidlist.c, 1.13, 1.14
cras at dovecot.org
cras at dovecot.org
Sun Jan 29 00:05:51 EET 2006
- Previous message: [dovecot-cvs] dovecot/src/imap-login client-authenticate.c, 1.38,
1.39 client.c, 1.48, 1.49
- Next message: [dovecot-cvs] dovecot/src/lib-storage/index/dbox dbox-save.c, 1.3,
1.4 dbox-transaction.c, 1.1, 1.2 dbox-uidlist.c, 1.14,
1.15 dbox-uidlist.h, 1.3, 1.4
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /var/lib/cvs/dovecot/src/lib-storage/index/dbox
In directory talvi:/tmp/cvs-serv12050
Modified Files:
Makefile.am dbox-file.c dbox-file.h dbox-mail.c dbox-storage.h
dbox-sync-full.c dbox-sync.c dbox-uidlist.c
Added Files:
dbox-keywords.c dbox-keywords.h
Log Message:
Support storing keywords in dbox files. Doesn't yet work while saving.
Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/dbox/Makefile.am,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- Makefile.am 21 Dec 2005 18:43:16 -0000 1.2
+++ Makefile.am 28 Jan 2006 22:05:48 -0000 1.3
@@ -10,6 +10,7 @@
libstorage_dbox_a_SOURCES = \
dbox-file.c \
+ dbox-keywords.c \
dbox-list.c \
dbox-mail.c \
dbox-save.c \
@@ -22,6 +23,7 @@
noinst_HEADERS = \
dbox-file.h \
+ dbox-keywords.h \
dbox-storage.h \
dbox-sync.h \
dbox-uidlist.h
Index: dbox-file.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/dbox/dbox-file.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbox-file.c 14 Jan 2006 18:47:46 -0000 1.4
+++ dbox-file.c 28 Jan 2006 22:05:48 -0000 1.5
@@ -1,6 +1,8 @@
-/* Copyright (C) 2005 Timo Sirainen */
+/* Copyright (C) 2005-2006 Timo Sirainen */
#include "lib.h"
+#include "array.h"
+#include "bsearch-insert-pos.h"
#include "hex-dec.h"
#include "istream.h"
#include "ostream.h"
@@ -38,12 +40,18 @@
void dbox_file_close(struct dbox_file *file)
{
+ if (array_is_created(&file->file_idx_keywords)) {
+ array_free(&file->idx_file_keywords);
+ array_free(&file->file_idx_keywords);
+ }
+
if (file->input != NULL)
i_stream_unref(&file->input);
if (file->fd != -1) {
if (close(file->fd) < 0)
i_error("close(dbox) failed: %m");
}
+ i_free(file->seeked_keywords);
i_free(file->path);
i_free(file);
}
@@ -56,6 +64,7 @@
const unsigned char *data;
size_t size;
+ /* read the header */
i_stream_seek(file->input, offset);
(void)i_stream_read_data(file->input, &data, &size,
file->mail_header_size-1);
@@ -68,10 +77,15 @@
"read(%s) failed: %m", file->path);
return -1;
}
+
memcpy(&file->seeked_mail_header, data,
sizeof(file->seeked_mail_header));
+ /* @UNSAFE */
+ memcpy(file->seeked_keywords, data + sizeof(file->seeked_mail_header),
+ file->keyword_count);
file->seeked_offset = offset;
+ /* parse the header */
hdr = &file->seeked_mail_header;
file->seeked_mail_size =
hex2dec(hdr->mail_size_hex, sizeof(hdr->mail_size_hex));
@@ -83,15 +97,13 @@
"Corrupted mail header in dbox file %s", file->path);
return -1;
}
- if (file->seeked_mail_size == 0 || file->seeked_uid == 0) {
- /* could be legitimately just not written yet. we're at EOF. */
- return 0;
- }
return 1;
}
int dbox_file_seek(struct dbox_mailbox *mbox, uint32_t file_seq, uoff_t offset)
{
+ int ret;
+
if (mbox->file != NULL && mbox->file->file_seq != file_seq) {
dbox_file_close(mbox->file);
mbox->file = NULL;
@@ -129,39 +141,99 @@
if (offset == 0)
offset = mbox->file->header_size;
- return dbox_file_read_mail_header(mbox, mbox->file, offset);
+ if ((ret = dbox_file_read_mail_header(mbox, mbox->file, offset)) <= 0)
+ return ret;
+
+ if (mbox->file->seeked_mail_size == 0 || mbox->file->seeked_uid == 0) {
+ /* could be legitimately just not written yet. we're at EOF. */
+ return 0;
+ }
+ return 1;
}
int dbox_file_seek_next_nonexpunged(struct dbox_mailbox *mbox)
{
+ const struct dbox_mail_header *hdr;
uoff_t offset;
int ret;
- offset = mbox->file->seeked_offset +
- mbox->file->mail_header_size + mbox->file->seeked_mail_size;
+ for (;;) {
+ offset = mbox->file->seeked_offset +
+ mbox->file->mail_header_size +
+ mbox->file->seeked_mail_size;
- while ((ret = dbox_file_seek(mbox, mbox->file->file_seq, offset)) > 0) {
- if (mbox->file->seeked_mail_header.expunged != '1')
- break;
+ ret = dbox_file_seek(mbox, mbox->file->file_seq, offset);
+ if (ret <= 0)
+ return ret;
- /* marked expunged, get to next mail. */
+ hdr = &mbox->file->seeked_mail_header;
+ if (hdr->expunged != '1') {
+ /* non-expunged mail found */
+ break;
+ }
}
- return ret;
+
+ return 1;
}
void dbox_file_header_init(struct dbox_file_header *hdr)
{
- uint16_t header_size = sizeof(*hdr);
+ uint16_t base_header_size = sizeof(*hdr);
+ uint32_t header_size =
+ base_header_size + DBOX_KEYWORD_NAMES_RESERVED_SPACE;
uint32_t append_offset = header_size;
- uint16_t mail_header_size = sizeof(struct dbox_mail_header);
+ uint16_t keyword_count = DBOX_KEYWORD_COUNT;
+ uint16_t mail_header_size =
+ sizeof(struct dbox_mail_header) + keyword_count;
uint32_t create_time = ioloop_time;
memset(hdr, '0', sizeof(*hdr));
+ DEC2HEX(hdr->base_header_size_hex, base_header_size);
DEC2HEX(hdr->header_size_hex, header_size);
DEC2HEX(hdr->append_offset_hex, append_offset);
DEC2HEX(hdr->create_time_hex, create_time);
DEC2HEX(hdr->mail_header_size_hex, mail_header_size);
- // FIXME: set keyword_count
+ DEC2HEX(hdr->keyword_list_offset_hex, base_header_size);
+ DEC2HEX(hdr->keyword_count_hex, keyword_count);
+}
+
+int dbox_file_header_parse(struct dbox_mailbox *mbox, struct dbox_file *file,
+ const struct dbox_file_header *hdr)
+{
+ file->base_header_size = hex2dec(hdr->base_header_size_hex,
+ sizeof(hdr->base_header_size_hex));
+ file->header_size = hex2dec(hdr->header_size_hex,
+ sizeof(hdr->header_size_hex));
+ file->append_offset = hex2dec(hdr->append_offset_hex,
+ sizeof(hdr->append_offset_hex));
+ file->create_time = hex2dec(hdr->create_time_hex,
+ sizeof(hdr->create_time_hex));
+ file->mail_header_size = hex2dec(hdr->mail_header_size_hex,
+ sizeof(hdr->mail_header_size_hex));
+ file->mail_header_align =
+ hex2dec(hdr->mail_header_align_hex,
+ sizeof(hdr->mail_header_align_hex));
+ file->keyword_count = hex2dec(hdr->keyword_count_hex,
+ sizeof(hdr->keyword_count_hex));
+ file->keyword_list_offset =
+ hex2dec(hdr->keyword_list_offset_hex,
+ sizeof(hdr->keyword_list_offset_hex));
+
+ if (file->base_header_size == 0 ||
+ file->header_size < file->base_header_size ||
+ file->append_offset < file->header_size ||
+ file->keyword_list_offset < file->base_header_size ||
+ file->mail_header_size < sizeof(struct dbox_mail_header) ||
+ file->keyword_count > file->mail_header_size -
+ sizeof(struct dbox_mail_header)) {
+ mail_storage_set_critical(STORAGE(mbox->storage),
+ "dbox %s: broken file header", file->path);
+ return -1;
+ }
+
+ i_free(file->seeked_keywords);
+ file->seeked_keywords = i_malloc(file->keyword_count);
+ return 0;
}
int dbox_file_read_header(struct dbox_mailbox *mbox, struct dbox_file *file)
@@ -170,6 +242,7 @@
const unsigned char *data;
size_t size;
+ /* read the file header */
i_stream_seek(file->input, 0);
(void)i_stream_read_data(file->input, &data, &size, sizeof(hdr)-1);
if (size < sizeof(hdr)) {
@@ -187,25 +260,46 @@
memcpy(&hdr, data, sizeof(hdr));
/* parse the header */
- file->header_size = hex2dec(hdr.header_size_hex,
- sizeof(hdr.header_size_hex));
- file->append_offset = hex2dec(hdr.append_offset_hex,
- sizeof(hdr.append_offset_hex));
- file->create_time = hex2dec(hdr.create_time_hex,
- sizeof(hdr.create_time_hex));
- file->mail_header_size = hex2dec(hdr.mail_header_size_hex,
- sizeof(hdr.mail_header_size_hex));
- file->mail_header_padding =
- hex2dec(hdr.mail_header_padding_hex,
- sizeof(hdr.mail_header_padding_hex));
- file->keyword_count = hex2dec(hdr.keyword_count_hex,
- sizeof(hdr.keyword_count_hex));
+ if (dbox_file_header_parse(mbox, file, &hdr) < 0)
+ return -1;
- if (file->header_size == 0 || file->append_offset < sizeof(hdr) ||
- file->mail_header_size < sizeof(struct dbox_mail_header)) {
+ /* keywords may not be up to date anymore */
+ if (array_is_created(&file->idx_file_keywords)) {
+ array_free(&file->idx_file_keywords);
+ array_free(&file->file_idx_keywords);
+ }
+ return 0;
+}
+
+int dbox_file_write_header(struct dbox_mailbox *mbox, struct dbox_file *file)
+{
+ struct dbox_file_header hdr;
+ char buf[1024];
+ int ret;
+
+ dbox_file_header_init(&hdr);
+ ret = dbox_file_header_parse(mbox, file, &hdr);
+ i_assert(ret == 0);
+
+ /* write header + LF to mark end-of-keywords list */
+ if (o_stream_send(file->output, &hdr, sizeof(hdr)) < 0 ||
+ o_stream_send_str(file->output, "\n") < 0) {
mail_storage_set_critical(STORAGE(mbox->storage),
- "dbox %s: broken file header", file->path);
+ "write(%s) failed: %m", file->path);
return -1;
}
+
+ /* fill the rest of the header with spaces */
+ memset(buf, ' ', sizeof(buf));
+ while (file->output->offset < file->header_size) {
+ unsigned int size = I_MIN(sizeof(buf), file->header_size -
+ file->output->offset);
+
+ if (o_stream_send(file->output, buf, size) < 0) {
+ mail_storage_set_critical(STORAGE(mbox->storage),
+ "write(%s) failed: %m", file->path);
+ return -1;
+ }
+ }
return 0;
}
Index: dbox-file.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/dbox/dbox-file.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- dbox-file.h 27 Nov 2005 23:05:29 -0000 1.1
+++ dbox-file.h 28 Jan 2006 22:05:48 -0000 1.2
@@ -13,10 +13,14 @@
void dbox_file_close(struct dbox_file *file);
/* Returns -1 = error, 0 = EOF (mail was just moved / file broken), 1 = ok */
-int dbox_file_seek(struct dbox_mailbox *mbox, uint32_t file_seq, uoff_t offset);
+int dbox_file_seek(struct dbox_mailbox *mbox,
+ uint32_t file_seq, uoff_t offset);
int dbox_file_seek_next_nonexpunged(struct dbox_mailbox *mbox);
void dbox_file_header_init(struct dbox_file_header *hdr);
+int dbox_file_header_parse(struct dbox_mailbox *mbox, struct dbox_file *file,
+ const struct dbox_file_header *hdr);
int dbox_file_read_header(struct dbox_mailbox *mbox, struct dbox_file *file);
+int dbox_file_write_header(struct dbox_mailbox *mbox, struct dbox_file *file);
#endif
--- NEW FILE: dbox-keywords.c ---
/* 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, *pos, kw;
const char *line;
unsigned int idx, count;
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 {
ARRAY_CREATE(&file->idx_file_keywords, default_pool,
struct keyword_map, file->keyword_count);
ARRAY_CREATE(&file->file_idx_keywords, default_pool,
unsigned int, 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 */
(void)mail_index_keyword_lookup(mbox->ibox.index, line, TRUE,
&kw.index_idx);
kw.file_idx = idx;
/* look up the position where to insert it */
map = array_get_modifyable(&file->idx_file_keywords, &count);
pos = idx == 0 ? map :
bsearch_insert_pos(line, map, count, sizeof(*map),
dbox_keyword_map_compare);
array_insert(&file->idx_file_keywords, pos - map, &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(STORAGE(mbox->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_t *idx_keywords;
ARRAY_SET_TYPE(idx_keywords, const char *);
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);
/* 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(STORAGE(mbox->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;
}
--- NEW FILE: dbox-keywords.h ---
#ifndef __DBOX_KEYWORDS_H
#define __DBOX_KEYWORDS_H
struct seq_range;
/* Read keywords from file into memory. Returns 1 if ok, 0 if the list is
broken or -1 if I/O error. */
int dbox_file_read_keywords(struct dbox_mailbox *mbox, struct dbox_file *file);
/* Index file -> dbox file keyword index lookup. Returns TRUE if found. */
bool dbox_file_lookup_keyword(struct dbox_mailbox *mbox, struct dbox_file *file,
unsigned int index_idx, unsigned int *idx_r);
/* Save keywords to dbox file. Returns -1 if error, 0 if ok. */
int dbox_file_append_keywords(struct dbox_mailbox *mbox, struct dbox_file *file,
const struct seq_range *idx_range,
unsigned int count);
#endif
Index: dbox-mail.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/dbox/dbox-mail.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbox-mail.c 13 Jan 2006 20:26:29 -0000 1.4
+++ dbox-mail.c 28 Jan 2006 22:05:48 -0000 1.5
@@ -21,9 +21,7 @@
const struct dbox_mail_header *hdr = &file->seeked_mail_header;
uint32_t hdr_uid = hex2dec(hdr->uid_hex, sizeof(hdr->uid_hex));
- if (hdr_uid != mail->mail.mail.uid ||
- memcmp(hdr->magic, DBOX_MAIL_HEADER_MAGIC,
- sizeof(hdr->magic)) != 0) {
+ if (hdr_uid != mail->mail.mail.uid) {
mail_storage_set_critical(STORAGE(mbox->storage),
"dbox %s: Cached file offset broken",
mbox->file->path);
@@ -144,9 +142,8 @@
data->received_date = 0;
}
- mail_cache_add(mail->trans->cache_trans, mail->data.seq,
- MAIL_CACHE_RECEIVED_DATE,
- &data->received_date, sizeof(data->received_date));
+ index_mail_cache_add(mail, MAIL_CACHE_RECEIVED_DATE,
+ &data->received_date, sizeof(data->received_date));
return data->received_date;
}
@@ -163,9 +160,8 @@
if (dbox_mail_open(mail, &offset) <= 0)
return (uoff_t)-1;
- mail_cache_add(mail->trans->cache_trans, mail->data.seq,
- MAIL_CACHE_PHYSICAL_FULL_SIZE,
- &data->physical_size, sizeof(data->physical_size));
+ index_mail_cache_add(mail, MAIL_CACHE_PHYSICAL_FULL_SIZE,
+ &data->physical_size, sizeof(data->physical_size));
return data->physical_size;
}
Index: dbox-storage.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/dbox/dbox-storage.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- dbox-storage.h 13 Jan 2006 20:26:29 -0000 1.5
+++ dbox-storage.h 28 Jan 2006 22:05:48 -0000 1.6
@@ -6,6 +6,9 @@
#define DBOX_MAILDIR_NAME "Mails"
#define DBOX_MAIL_FILE_PREFIX "msg."
+#define DBOX_KEYWORD_COUNT 64
+#define DBOX_KEYWORD_NAMES_RESERVED_SPACE (2048-sizeof(struct dbox_file_header))
+
#include "index-storage.h"
#define STORAGE(mbox_storage) \
@@ -21,17 +24,37 @@
struct dbox_uidlist;
struct dbox_file_header {
+ /* Size of the base header. sizeof(struct dbox_file_header) */
+ unsigned char base_header_size_hex[4];
+ /* Size of the full header, including keywords list and padding */
unsigned char header_size_hex[8];
+ /* Offset where to store the next mail. note that a mail may already
+ have been fully written here and added to uidlist, but this offset
+ just wasn't updated. In that case the append_offset should be
+ updated instead of overwriting the mail. */
unsigned char append_offset_hex[16];
+ /* Initial file creation time as UNIX timestamp. */
unsigned char create_time_hex[8];
+ /* Size of each message's header. */
unsigned char mail_header_size_hex[4];
- unsigned char mail_header_padding_hex[4];
+ /* If set, mail headers start always at given alignmentation.
+ Currently not supported. */
+ unsigned char mail_header_align_hex[4];
+ /* Number of keywords allocated for each mail (not necessarily used) */
unsigned char keyword_count_hex[4];
- /* possible padding to fill header_size */
+ /* Offset for the keyword list inside the file header. */
+ unsigned char keyword_list_offset_hex[8];
+
+ /* space reserved for keyword list and possible other future
+ extensions. */
+ /* unsigned char [header_size - header_base_size]; */
};
#define DBOX_MAIL_HEADER_MAGIC "\001\003"
struct dbox_mail_header {
+ /* This field acts as kind of a verification marker to make sure that
+ seeked offset is valid. So the magic value should be something that
+ normally doesn't occur in mails. */
unsigned char magic[2];
unsigned char uid_hex[8];
unsigned char mail_size_hex[16];
@@ -42,13 +65,18 @@
unsigned char seen;
unsigned char draft;
unsigned char expunged;
- /* unsigned char keywords[]; */
+ /* unsigned char keywords[keywords_count]; */
};
struct dbox_storage {
struct index_storage storage;
};
+struct keyword_map {
+ unsigned int index_idx;
+ unsigned int file_idx;
+};
+
struct dbox_file {
uint32_t file_seq;
char *path;
@@ -57,17 +85,27 @@
struct istream *input;
struct ostream *output; /* while appending mails */
+ uint16_t base_header_size;
uint32_t header_size;
time_t create_time;
uint64_t append_offset;
uint16_t mail_header_size;
- uint16_t mail_header_padding;
+ uint16_t mail_header_align;
uint16_t keyword_count;
+ uint64_t keyword_list_offset;
+ uint32_t keyword_list_size_alloc;
+ uint32_t keyword_list_size_used;
uoff_t seeked_offset;
uoff_t seeked_mail_size;
uint32_t seeked_uid;
- struct dbox_mail_header seeked_mail_header;
+ struct dbox_mail_header seeked_mail_header;
+ unsigned char *seeked_keywords;
+
+ /* Keywords list, sorted by index_idx. */
+ array_t ARRAY_DEFINE(idx_file_keywords, struct keyword_map);
+ /* idx -> index_idx array */
+ array_t ARRAY_DEFINE(file_idx_keywords, unsigned int);
};
struct dbox_mailbox {
Index: dbox-sync-full.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/dbox/dbox-sync-full.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- dbox-sync-full.c 5 Jan 2006 01:27:51 -0000 1.2
+++ dbox-sync-full.c 28 Jan 2006 22:05:48 -0000 1.3
@@ -6,6 +6,7 @@
#include "dbox-storage.h"
#include "dbox-uidlist.h"
#include "dbox-file.h"
+#include "dbox-keywords.h"
#include "dbox-sync.h"
#include <stdlib.h>
@@ -13,11 +14,36 @@
#include <fcntl.h>
#include <dirent.h>
+static int
+dbox_mail_get_keywords(struct dbox_mailbox *mbox, struct dbox_file *file,
+ array_t *keywords)
+{
+ const unsigned int *map;
+ unsigned int i, count;
+
+ ARRAY_SET_TYPE(keywords, unsigned int);
+
+ if (!array_is_created(&file->file_idx_keywords)) {
+ if (dbox_file_read_keywords(mbox, file) < 0)
+ return -1;
+ }
+
+ map = array_get(&file->file_idx_keywords, &count);
+ for (i = 0; i < count; i++) {
+ if (file->seeked_keywords[i] != '0')
+ array_append(keywords, &map[i], 1);
+ }
+
+ return 0;
+}
+
static int dbox_sync_full_mail(struct dbox_sync_context *ctx, uint32_t *seq_r)
{
struct dbox_mailbox *mbox = ctx->mbox;
const struct dbox_mail_header *hdr = &mbox->file->seeked_mail_header;
enum mail_flags flags;
+ struct mail_keywords *keywords;
+ array_t ARRAY_DEFINE(keywords_arr, unsigned int);
uint32_t seq;
uint64_t hdr_offset = mbox->file->seeked_offset;
@@ -60,7 +86,20 @@
if (hdr->draft == '1')
flags |= MAIL_DRAFT;
mail_index_update_flags(ctx->trans, seq, MODIFY_REPLACE, flags);
- // FIXME: keywords
+
+ t_push();
+ ARRAY_CREATE(&keywords_arr, pool_datastack_create(),
+ unsigned int, mbox->file->keyword_count);
+ if (dbox_mail_get_keywords(mbox, mbox->file, &keywords_arr) < 0) {
+ t_pop();
+ return -1;
+ }
+ keywords = mail_index_keywords_create_from_indexes(ctx->trans,
+ &keywords_arr);
+ mail_index_update_keywords(ctx->trans, seq, MODIFY_REPLACE, keywords);
+ mail_index_keywords_free(&keywords);
+ t_pop();
+
mail_index_update_ext(ctx->trans, seq, mbox->dbox_file_ext_idx,
&mbox->file->file_seq, NULL);
mail_index_update_ext(ctx->trans, seq, mbox->dbox_offset_ext_idx,
Index: dbox-sync.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/dbox/dbox-sync.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- dbox-sync.c 14 Jan 2006 18:47:46 -0000 1.5
+++ dbox-sync.c 28 Jan 2006 22:05:48 -0000 1.6
@@ -4,8 +4,10 @@
#include "ioloop.h"
#include "array.h"
#include "hash.h"
+#include "seq-range-array.h"
#include "write-full.h"
#include "dbox-file.h"
+#include "dbox-keywords.h"
#include "dbox-sync.h"
#include "dbox-uidlist.h"
#include "dbox-storage.h"
@@ -120,45 +122,18 @@
return 0;
}
-int dbox_sync_update_flags(struct dbox_sync_context *ctx,
- const struct dbox_sync_rec *sync_rec)
+static int
+dbox_sync_write_mask(struct dbox_sync_context *ctx,
+ const struct dbox_sync_rec *sync_rec,
+ unsigned int first_flag_offset, unsigned int flag_count,
+ const unsigned char *array, const unsigned char *mask)
{
- static enum mail_flags dbox_flag_list[] = {
- MAIL_ANSWERED,
- MAIL_FLAGGED,
- MAIL_DELETED,
- MAIL_SEEN,
- MAIL_DRAFT,
- 0 /* expunged */
- };
-#define DBOX_FLAG_COUNT (sizeof(dbox_flag_list)/sizeof(dbox_flag_list[0]))
struct dbox_mailbox *mbox = ctx->mbox;
- unsigned char dbox_flag_array[DBOX_FLAG_COUNT];
- unsigned char dbox_flag_mask[DBOX_FLAG_COUNT];
uint32_t file_seq, uid2;
uoff_t offset;
- unsigned int i, start, first_flag_offset;
+ unsigned int i, start;
int ret;
- /* first build flag array and mask */
- if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE) {
- memset(dbox_flag_array, '0', sizeof(dbox_flag_array));
- memset(dbox_flag_mask, 0, sizeof(dbox_flag_mask));
- dbox_flag_mask[5] = 1;
- dbox_flag_array[5] = '1';
- } else {
- i_assert(sync_rec->type == MAIL_INDEX_SYNC_TYPE_FLAGS);
- for (i = 0; i < DBOX_FLAG_COUNT; i++) {
- dbox_flag_array[i] =
- (sync_rec->value.flags.add &
- dbox_flag_list[i]) != 0 ? '1' : '0';
- dbox_flag_mask[i] = dbox_flag_array[i] ||
- (sync_rec->value.flags.remove &
- dbox_flag_list[i]) != 0;
- }
- }
- first_flag_offset = offsetof(struct dbox_mail_header, answered);
-
if (dbox_sync_get_file_offset(ctx, sync_rec->seq1,
&file_seq, &offset) < 0)
return -1;
@@ -172,18 +147,18 @@
return ret;
while (mbox->file->seeked_uid <= uid2) {
- for (i = 0; i < DBOX_FLAG_COUNT; ) {
- if (!dbox_flag_mask[i])
+ for (i = 0; i < flag_count; ) {
+ if (!mask[i])
continue;
start = i;
- while (i < DBOX_FLAG_COUNT) {
- if (!dbox_flag_mask[i])
+ while (i < flag_count) {
+ if (!mask[i])
break;
i++;
}
ret = pwrite_full(ctx->mbox->file->fd,
- dbox_flag_array+start, i - start,
+ array + start, i - start,
offset + first_flag_offset + start);
if (ret < 0) {
mail_storage_set_critical(
@@ -205,11 +180,143 @@
return 0;
}
+int dbox_sync_update_flags(struct dbox_sync_context *ctx,
+ const struct dbox_sync_rec *sync_rec)
+{
+ static enum mail_flags dbox_flag_list[] = {
+ MAIL_ANSWERED,
+ MAIL_FLAGGED,
+ MAIL_DELETED,
+ MAIL_SEEN,
+ MAIL_DRAFT,
+ 0 /* expunged */
+ };
+#define DBOX_FLAG_COUNT (sizeof(dbox_flag_list)/sizeof(dbox_flag_list[0]))
+ unsigned char dbox_flag_array[DBOX_FLAG_COUNT];
+ unsigned char dbox_flag_mask[DBOX_FLAG_COUNT];
+ unsigned int i, first_flag_offset;
+
+ /* first build flag array and mask */
+ if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE) {
+ memset(dbox_flag_array, '0', sizeof(dbox_flag_array));
+ memset(dbox_flag_mask, 0, sizeof(dbox_flag_mask));
+ dbox_flag_mask[5] = 1;
+ dbox_flag_array[5] = '1';
+ } else {
+ i_assert(sync_rec->type == MAIL_INDEX_SYNC_TYPE_FLAGS);
+ for (i = 0; i < DBOX_FLAG_COUNT; i++) {
+ dbox_flag_array[i] =
+ (sync_rec->value.flags.add &
+ dbox_flag_list[i]) != 0 ? '1' : '0';
+ dbox_flag_mask[i] = dbox_flag_array[i] ||
+ (sync_rec->value.flags.remove &
+ dbox_flag_list[i]) != 0;
+ }
+ }
+ first_flag_offset = offsetof(struct dbox_mail_header, answered);
+
+ return dbox_sync_write_mask(ctx, sync_rec,
+ first_flag_offset, DBOX_FLAG_COUNT,
+ dbox_flag_array, dbox_flag_mask);
+}
+
+static int
+dbox_sync_update_keyword(struct dbox_sync_context *ctx,
+ const struct dbox_sync_rec *sync_rec, bool set)
+{
+ unsigned char keyword_array, keyword_mask = 1;
+ unsigned int file_idx, first_flag_offset;
+
+ keyword_array = set ? '1' : '0';
+
+ if (!dbox_file_lookup_keyword(ctx->mbox, ctx->mbox->file,
+ sync_rec->value.keyword_idx, &file_idx)) {
+ /* not found. if removing, just ignore.
+
+ if adding, it currently happens only if the maximum keyword
+ count was reached. once we support moving mails to new file
+ to grow keywords count, this should never happen.
+ for now, just ignore this. */
+ return 0;
+ }
+
+ first_flag_offset = sizeof(struct dbox_mail_header) + file_idx;
+ return dbox_sync_write_mask(ctx, sync_rec, first_flag_offset, 1,
+ &keyword_array, &keyword_mask);
+}
+
+static int
+dbox_sync_reset_keyword(struct dbox_sync_context *ctx,
+ const struct dbox_sync_rec *sync_rec)
+{
+ unsigned char *keyword_array, *keyword_mask;
+ unsigned int first_flag_offset;
+ int ret;
+
+ t_push();
+ keyword_array = t_malloc(ctx->mbox->file->keyword_count);
+ keyword_mask = t_malloc(ctx->mbox->file->keyword_count);
+ memset(keyword_array, '0', ctx->mbox->file->keyword_count);
+ memset(keyword_mask, 1, ctx->mbox->file->keyword_count);
+
+ first_flag_offset = sizeof(struct dbox_mail_header);
+ ret = dbox_sync_write_mask(ctx, sync_rec, first_flag_offset,
+ ctx->mbox->file->keyword_count,
+ keyword_array, keyword_mask);
+ t_pop();
+ return ret;
+}
+
+static int
+dbox_sync_file_add_keywords(struct dbox_sync_context *ctx,
+ const struct dbox_sync_file_entry *entry,
+ unsigned int i)
+{
+ array_t ARRAY_DEFINE(keywords, struct seq_range);
+ const struct dbox_sync_rec *sync_recs;
+ const struct seq_range *range;
+ unsigned int count, file_idx, keyword_idx;
+ int ret = 0;
+
+ if (dbox_file_seek(ctx->mbox, entry->file_seq, 0) <= 0)
+ return -1;
+
+ /* Get a list of all new keywords. Using seq_range is the easiest
+ way to do this and should be pretty fast too. */
+ t_push();
+ ARRAY_CREATE(&keywords, pool_datastack_create(), struct seq_range, 16);
+ sync_recs = array_get(&entry->sync_recs, &count);
+ for (; i < count; i++) {
+ if (sync_recs[i].type != MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD)
+ continue;
+
+ /* check if it's already in the file */
+ keyword_idx = sync_recs[i].value.keyword_idx;
+ if (dbox_file_lookup_keyword(ctx->mbox, ctx->mbox->file,
+ keyword_idx, &file_idx))
+ continue;
+
+ /* add it. if it already exists, it's handled internally. */
+ seq_range_array_add(&keywords, 0, keyword_idx);
+ }
+
+ /* now, write them to file */
+ range = array_get(&keywords, &count);
+ if (count > 0) {
+ ret = dbox_file_append_keywords(ctx->mbox, ctx->mbox->file,
+ range, count);
+ }
+
+ t_pop();
+ return ret;
+}
+
static int dbox_sync_file(struct dbox_sync_context *ctx,
const struct dbox_sync_file_entry *entry)
{
const struct dbox_sync_rec *sync_recs;
unsigned int i, count;
+ bool first_keyword = TRUE;
int ret;
sync_recs = array_get(&entry->sync_recs, &count);
@@ -232,9 +339,25 @@
return -1;
break;
case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
+ if (first_keyword) {
+ /* add all new keywords in one go */
+ first_keyword = FALSE;
+ if (dbox_sync_file_add_keywords(ctx, entry,
+ i) < 0)
+ return -1;
+ }
+ if (dbox_sync_update_keyword(ctx, &sync_recs[i],
+ TRUE) < 0)
+ return -1;
+ break;
case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
+ if (dbox_sync_update_keyword(ctx, &sync_recs[i],
+ FALSE) < 0)
+ return -1;
+ break;
case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
- /* FIXME */
+ if (dbox_sync_reset_keyword(ctx, &sync_recs[i]) < 0)
+ return -1;
break;
case MAIL_INDEX_SYNC_TYPE_APPEND:
i_unreached();
Index: dbox-uidlist.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/dbox/dbox-uidlist.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- dbox-uidlist.c 14 Jan 2006 18:47:46 -0000 1.13
+++ dbox-uidlist.c 28 Jan 2006 22:05:48 -0000 1.14
@@ -794,26 +794,6 @@
return 0;
}
-static int dbox_file_write_header(struct dbox_mailbox *mbox,
- struct dbox_file *file)
-{
- struct dbox_file_header hdr;
-
- // FIXME: code duplication
- file->header_size = sizeof(hdr);
- file->append_offset = file->header_size;
- file->create_time = ioloop_time;
- file->mail_header_size = sizeof(struct dbox_mail_header);
-
- dbox_file_header_init(&hdr);
- if (o_stream_send(file->output, &hdr, sizeof(hdr)) < 0) {
- mail_storage_set_critical(STORAGE(mbox->storage),
- "write(%s) failed: %m", file->path);
- return -1;
- }
- return 0;
-}
-
static int dbox_uidlist_files_lookup(struct dbox_uidlist_append_ctx *ctx,
uint32_t file_seq)
{
@@ -951,12 +931,7 @@
file->input = i_stream_create_file(file->fd, default_pool,
65536, FALSE);
-
- /* we'll be using CRLF linefeeds always */
- output = o_stream_create_file(file->fd, default_pool, 0, FALSE);
- file->output = o_stream_create_crlf(default_pool, output);
- o_stream_unref(&output);
-
+ file->output = o_stream_create_file(file->fd, default_pool, 0, FALSE);
if ((uoff_t)st.st_size < sizeof(struct dbox_file_header)) {
if (dbox_file_write_header(mbox, file) < 0) {
dbox_file_close(file);
@@ -967,9 +942,16 @@
dbox_file_close(file);
return -1;
}
- o_stream_seek(file->output, file->append_offset);
}
+ /* we'll always use CRLF linefeeds for mails (but not the header,
+ so don't do this before dbox_file_write_header()) */
+ output = o_stream_create_crlf(default_pool, file->output);
+ o_stream_unref(&file->output);
+ file->output = output;
+
+ o_stream_seek(file->output, file->append_offset);
+
save_file->dev = st.st_dev;
save_file->ino = st.st_ino;
ARRAY_CREATE(&save_file->seqs, ctx->pool, unsigned int, 8);
- Previous message: [dovecot-cvs] dovecot/src/imap-login client-authenticate.c, 1.38,
1.39 client.c, 1.48, 1.49
- Next message: [dovecot-cvs] dovecot/src/lib-storage/index/dbox dbox-save.c, 1.3,
1.4 dbox-transaction.c, 1.1, 1.2 dbox-uidlist.c, 1.14,
1.15 dbox-uidlist.h, 1.3, 1.4
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the dovecot-cvs
mailing list