mail-tree.c revision c7b3f8406f77d95bcc2480deebbde86e165263ae
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (sizeof(struct mail_tree_header) + \
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen INDEX_MIN_RECORDS_COUNT * sizeof(struct mail_tree_node))
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int tree_set_syscall_error(struct mail_tree *tree, const char *function)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen index_set_error(tree->index, "%s failed with binary tree file %s: %m",
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainenint _mail_tree_set_corrupted(struct mail_tree *tree, const char *fmt, ...)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen index_set_error(tree->index, "Corrupted binary tree file %s: %s",
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* make sure we don't get back here */
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen /* make sure we're synced before munmap() */
59e26ff34b05cd971a111f8a42fc60c13d9f688bTimo Sirainen msync(tree->mmap_base, tree->mmap_highwater, MS_SYNC) < 0)
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen return tree_set_syscall_error(tree, "msync()");
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen if (munmap(tree->mmap_base, tree->mmap_full_length) < 0)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen tree->mmap_base = mmap_rw_file(tree->fd, &tree->mmap_full_length);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return tree_set_syscall_error(tree, "mmap()");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen debug_mprotect(tree->mmap_base, tree->mmap_full_length, tree->index);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen unsigned int extra;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen sizeof(struct mail_tree_header) + sizeof(struct mail_tree_node)) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen index_set_error(tree->index, "Too small binary tree file %s",
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen extra = (tree->mmap_full_length - sizeof(struct mail_tree_header)) %
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen sizeof(struct mail_tree_node);
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen /* partial write or corrupted -
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen truncate the file to valid length */
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen if (ftruncate(tree->fd, (off_t)tree->mmap_full_length) < 0)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen if (hdr->used_file_size > tree->mmap_full_length) {
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen "used_file_size larger than real file size "
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen if (hdr->used_file_size < sizeof(struct mail_tree_header) ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen (hdr->used_file_size - sizeof(struct mail_tree_header)) %
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen sizeof(struct mail_tree_node) != 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen "Invalid used_file_size in header (%"PRIuUOFF_T")",
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen ((char *) tree->mmap_base + sizeof(struct mail_tree_header));
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen tree->mmap_highwater = tree->mmap_used_length;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenint _mail_tree_mmap_update(struct mail_tree *tree, int forced)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen debug_mprotect(tree->mmap_base, tree->mmap_full_length,
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen /* make sure file size hasn't changed */
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen tree->mmap_used_length = tree->header->used_file_size;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (tree->mmap_used_length > tree->mmap_full_length) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen "updating sync_id");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return mmap_update(tree) && mmap_verify(tree);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic struct mail_tree *mail_tree_open(struct mail_index *index)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen path = t_strconcat(index->filepath, ".tree", NULL);
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen index_file_set_syscall_error(index, path, "open()");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic struct mail_tree *mail_tree_create_anon(struct mail_index *index)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen tree->filepath = i_strdup("(in-memory tree)");
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen tree = !index->nodiskspace ? mail_tree_open(index) :
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic int mail_tree_open_init(struct mail_tree *tree)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* just created it */
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* broken header */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (tree->header->indexid != tree->index->indexid) {
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen "IndexID mismatch for binary tree file %s",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenint mail_tree_open_or_create(struct mail_index *index)
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen /* lock and check again, just to avoid rebuilding it twice
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if two processes notice the error at the same time */
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (!tree->index->set_lock(tree->index, MAIL_LOCK_EXCLUSIVE)) {
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainenstatic void mail_tree_close(struct mail_tree *tree)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (munmap_anon(tree->mmap_base, tree->mmap_full_length) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen tree_set_syscall_error(tree, "munmap_anon()");
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (munmap(tree->mmap_base, tree->mmap_full_length) < 0)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic int mail_tree_init(struct mail_tree *tree)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* first node is always used, and is the RBNULL node */
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen memset(&hdr, 0, sizeof(struct mail_tree_header));
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen hdr.used_file_size = sizeof(struct mail_tree_header) +
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen sizeof(struct mail_tree_node);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen tree->mmap_base = mmap_anon(tree->mmap_full_length);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen memcpy(tree->mmap_base, &hdr, sizeof(struct mail_tree_header));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return tree_set_syscall_error(tree, "lseek()");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (write_full(tree->fd, &hdr, sizeof(hdr)) < 0) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return tree_set_syscall_error(tree, "write_full()");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (file_set_size(tree->fd, MAIL_TREE_MIN_SIZE) < 0) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return tree_set_syscall_error(tree, "file_set_size()");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (!tree->index->set_lock(tree->index, MAIL_LOCK_EXCLUSIVE))
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen (!tree->anon_mmap && !_mail_tree_mmap_update(tree, TRUE))) {
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen tree->index->header->flags |= MAIL_INDEX_FLAG_REBUILD_TREE;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainenint mail_tree_sync_file(struct mail_tree *tree, int *fsync_fd)
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (msync(tree->mmap_base, tree->mmap_highwater, MS_SYNC) < 0)
989cafb9d84d8c98d6441fc1ab45b4c37762a98aTimo Sirainen return tree_set_syscall_error(tree, "msync()");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen tree->mmap_highwater = tree->mmap_used_length;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen grow_count = tree->index->header->messages_count *
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen base = mremap_anon(tree->mmap_base, tree->mmap_full_length,
46631c1d903c409444b1b1c4a1d41a033c09ee37Timo Sirainen return tree_set_syscall_error(tree, "mremap_anon()");
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen if (file_set_size(tree->fd, (off_t)new_fsize) < 0) {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen return tree_set_syscall_error(tree, "file_set_size()");
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen /* file size changed, let others know about it too by changing
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen sync_id in header. */
71da447014454c84828d9dface77219875554d7dTimo Sirainenvoid _mail_tree_truncate(struct mail_tree *tree)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* pretty much copy&pasted from mail_index_compress() */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen i_assert(tree->index->lock_type == MAIL_LOCK_EXCLUSIVE);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (tree->mmap_full_length <= MAIL_TREE_MIN_SIZE || tree->anon_mmap)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen empty_space = tree->mmap_full_length - tree->mmap_used_length;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen tree->mmap_full_length / 100 * INDEX_TRUNCATE_PERCENTAGE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen tree->mmap_full_length = tree->mmap_used_length +
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (empty_space * INDEX_TRUNCATE_KEEP_PERCENTAGE / 100);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* keep the size record-aligned */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen tree->mmap_full_length -= (tree->mmap_full_length -
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen sizeof(struct mail_tree_header)) %
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen sizeof(struct mail_tree_node);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (tree->mmap_full_length < MAIL_TREE_MIN_SIZE)