mail-tree-redblack.c revision b045ca1be3be3c034584665f64ec3823c28c1229
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen Redblack balanced tree algorithm, http://libredblack.sourceforge.net/
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen Copyright (C) Damian Ivereigh 2000
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen Modified to be suitable for mmap()ing and for IMAP server
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen Copyright (C) Timo Sirainen 2002
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen This program is free software; you can redistribute it and/or modify
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen it under the terms of the GNU Lesser General Public License as published by
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen the Free Software Foundation; either version 2.1 of the License, or
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen (at your option) any later version. See the file COPYING for details.
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen This program is distributed in the hope that it will be useful,
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen GNU General Public License for more details.
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen You should have received a copy of the GNU Lesser General Public License
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen along with this program; if not, write to the Free Software
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen/* NOTE: currently this code doesn't do any bounds checkings. I'm not sure
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen if I should even bother, the code would just get uglier and slower. */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen/* #define DEBUG_TREE */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen/* Dummy (sentinel) node, so that we can make X->left->up = X
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen** We then use this instead of NULL to mean the top or bottom
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen** end of the rb tree. It is a black node.
ebfbf5d78dcf95e8b176429f4b5b0694eb4e17d5Timo Sirainen/* If highest bit in node_count is set, the node is red. */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen#define RED_MASK (1 << (SIZEOF_INT*CHAR_BIT-1))
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen STMT_START { (node).node_count &= ~RED_MASK; } STMT_END
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen STMT_START { (node).node_count |= RED_MASK; } STMT_END
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen STMT_START { (node).node_count += (count); } STMT_END
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen** OK here we go, the balanced tree stuff. The algorithm is the
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen** fairly standard red/black taken from "Introduction to Algorithms"
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen** by Cormen, Leiserson & Rivest. Maybe one of these days I will
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen** fully understand all this stuff.
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen** Basically a red/black balanced tree has the following properties:-
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen** 1) Every node is either red or black (color is RED or BLACK)
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen** 2) A leaf (RBNULL pointer) is considered black
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen** 3) If a node is red then its children are black
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen** 4) Every path from a node to a leaf contains the same no
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen** of black nodes
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen** 3) & 4) above guarantee that the longest path (alternating
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen** red and black nodes) is only twice as long as the shortest
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen** path (all black nodes). Thus the tree remains fairly balanced.
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenstatic unsigned int
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen unsigned int x;
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen if (tree->mmap_used_length == tree->mmap_full_length) {
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen i_assert(tree->header->used_file_size == tree->mmap_used_length);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen i_assert(tree->mmap_used_length + sizeof(MailTreeNode) <=
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen x = (tree->mmap_used_length - sizeof(MailTreeHeader)) /
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen tree->header->used_file_size += sizeof(MailTreeNode);
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen tree->mmap_used_length += sizeof(MailTreeNode);
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen memset(&tree->node_base[x], 0, sizeof(MailTreeNode));
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainenrb_move(MailTree *tree, unsigned int src, unsigned int dest)
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen /* update parent */
fcde781c3ceb470c8dff34a68df19c69f93bcec9Timo Sirainen /* update children */
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen /* update root */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen memcpy(&node[dest], &node[src], sizeof(MailTreeNode));
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen unsigned int last;
fcde781c3ceb470c8dff34a68df19c69f93bcec9Timo Sirainen sizeof(MailTreeHeader) + sizeof(MailTreeNode));
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen /* get index to last used record */
1caf757864e7734345660e7d190f84e42668a6f8Timo Sirainen last = (tree->mmap_used_length - sizeof(MailTreeHeader)) /
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* move it over the one we want free'd */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* mark the moved node unused */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen tree->mmap_used_length -= sizeof(MailTreeNode);
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen tree->header->used_file_size -= sizeof(MailTreeNode);
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen** Rotate our tree thus:-
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen** X rb_left_rotate(X)---> Y
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen** A Y <---rb_right_rotate(Y) X C
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen** N.B. This does not change the ordering.
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen** We assume that neither X or Y is NULL
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen** Node count changes:
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen** X += C+1 X -= C+1
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen** Y -= A+1 Y += A+1
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* Turn Y's left subtree into X's right subtree (move B) */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* If B is not null, set it's parent to be X */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* Set Y's parent to be what X's parent was */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* if X was the root */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* Set X's parent's left or right pointer to be Y */
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen /* Put X on Y's left */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* Set X's parent to be Y */
unsigned int x, y, x_up_up;
x = x_up_up;
x = x_up_up;
b = RBNULL;
b = RBNULL;
if (b != RBNULL) {
while (z != RBNULL) {
#ifdef DEBUG_TREE
if (x == RBNULL)
nleft++;
return nleft;
if (x == RBNULL)
if (x != RBNULL) {
unsigned int root;
unsigned int first_uid,
unsigned int last_uid)
unsigned int x, y, seq;
*seq_r = 0;
seq = 0;
while (x != RBNULL) {
x = RBNULL;
seq--;
while (x != RBNULL) {
return FALSE;
if (x != RBNULL) {
return FALSE;
return FALSE;
if (x == RBNULL)
return TRUE;
return FALSE;
while (x != RBNULL) {
return TRUE;
uid);
return FALSE;
while (x != RBNULL) {