Subversion Repositories HelenOS-historic

Rev

Rev 1142 | Rev 1147 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1101 jermar 1
/*
2
 * Copyright (C) 2006 Jakub Jermar
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 
29
/*
30
 * This B-tree has the following properties:
1140 jermar 31
 * - it is a ballanced 2-3-4-5 tree (i.e. BTREE_M = 5)
1101 jermar 32
 * - values (i.e. pointers to values) are stored only in leaves
33
 * - leaves are linked in a list
34
 * - technically, it is a B+-tree (because of the previous properties)
35
 *
1134 jermar 36
 * Be carefull when using these trees. They need to allocate
37
 * and deallocate memory for their index nodes and as such
38
 * can sleep.
1101 jermar 39
 */
40
 
41
#include <adt/btree.h>
42
#include <adt/list.h>
43
#include <mm/slab.h>
44
#include <debug.h>
45
#include <panic.h>
46
#include <typedefs.h>
47
#include <print.h>
48
 
49
static void _btree_insert(btree_t *t, __native key, void *value, btree_node_t *rsubtree, btree_node_t *node);
1142 jermar 50
static void _btree_remove(btree_t *t, __native key, btree_node_t *node);
1101 jermar 51
static void node_initialize(btree_node_t *node);
1144 jermar 52
static void node_insert_key_and_lsubtree(btree_node_t *node, __native key, void *value, btree_node_t *lsubtree);
1142 jermar 53
static void node_insert_key_and_rsubtree(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
1144 jermar 54
static void node_remove_key_and_lsubtree(btree_node_t *node, __native key);
55
static void node_remove_key_and_rsubtree(btree_node_t *node, __native key);
1101 jermar 56
static btree_node_t *node_split(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree, __native *median);
1142 jermar 57
static btree_node_t *node_combine(btree_node_t *node);
1136 jermar 58
static index_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right);
1142 jermar 59
static void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, index_t idx);
60
static void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, index_t idx);
61
static bool try_insert_by_rotation_to_left(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
62
static bool try_insert_by_rotation_to_right(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
63
static bool try_rotation_from_left(btree_node_t *rnode);
64
static bool try_rotation_from_right(btree_node_t *lnode);
1101 jermar 65
 
66
#define ROOT_NODE(n)		(!(n)->parent)
67
#define INDEX_NODE(n)		((n)->subtree[0] != NULL)
68
#define LEAF_NODE(n)		((n)->subtree[0] == NULL)
69
 
1140 jermar 70
#define FILL_FACTOR		((BTREE_M-1)/2)
71
 
1101 jermar 72
#define MEDIAN_LOW_INDEX(n)	(((n)->keys-1)/2)
73
#define MEDIAN_HIGH_INDEX(n)	((n)->keys/2)
74
#define MEDIAN_LOW(n)		((n)->key[MEDIAN_LOW_INDEX((n))]);
75
#define MEDIAN_HIGH(n)		((n)->key[MEDIAN_HIGH_INDEX((n))]);
76
 
77
/** Create empty B-tree.
78
 *
79
 * @param t B-tree.
80
 */
81
void btree_create(btree_t *t)
82
{
83
	list_initialize(&t->leaf_head);
84
	t->root = (btree_node_t *) malloc(sizeof(btree_node_t), 0);
85
	node_initialize(t->root);
86
	list_append(&t->root->leaf_link, &t->leaf_head);
87
}
88
 
89
/** Destroy empty B-tree. */
90
void btree_destroy(btree_t *t)
91
{
92
	ASSERT(!t->root->keys);
93
	free(t->root);
94
}
95
 
96
/** Insert key-value pair into B-tree.
97
 *
98
 * @param t B-tree.
99
 * @param key Key to be inserted.
100
 * @param value Value to be inserted.
101
 * @param leaf_node Leaf node where the insertion should begin.
102
 */ 
103
void btree_insert(btree_t *t, __native key, void *value, btree_node_t *leaf_node)
104
{
105
	btree_node_t *lnode;
106
 
107
	ASSERT(value);
108
 
109
	lnode = leaf_node;
110
	if (!lnode) {
111
		if (btree_search(t, key, &lnode)) {
112
			panic("B-tree %P already contains key %d\n", t, key);
113
		}
114
	}
115
 
116
	_btree_insert(t, key, value, NULL, lnode);
117
}
118
 
119
/** Recursively insert into B-tree.
120
 *
121
 * @param t B-tree.
122
 * @param key Key to be inserted.
123
 * @param value Value to be inserted.
124
 * @param rsubtree Right subtree of the inserted key.
125
 * @param node Start inserting into this node.
126
 */
127
void _btree_insert(btree_t *t, __native key, void *value, btree_node_t *rsubtree, btree_node_t *node)
128
{
129
	if (node->keys < BTREE_MAX_KEYS) {
130
		/*
131
		 * Node conatins enough space, the key can be stored immediately.
132
		 */
1142 jermar 133
		node_insert_key_and_rsubtree(node, key, value, rsubtree);
134
	} else if (try_insert_by_rotation_to_left(node, key, value, rsubtree)) {
1136 jermar 135
		/*
136
		 * The key-value-rsubtree triplet has been inserted because
137
		 * some keys could have been moved to the left sibling.
138
		 */
1142 jermar 139
	} else if (try_insert_by_rotation_to_right(node, key, value, rsubtree)) {
1136 jermar 140
		/*
141
		 * The key-value-rsubtree triplet has been inserted because
142
		 * some keys could have been moved to the right sibling.
143
		 */
1101 jermar 144
	} else {
145
		btree_node_t *rnode;
146
		__native median;
147
 
148
		/*
1136 jermar 149
		 * Node is full and both siblings (if both exist) are full too.
150
		 * Split the node and insert the smallest key from the node containing
151
		 * bigger keys (i.e. the new node) into its parent.
1101 jermar 152
		 */
153
 
154
		rnode = node_split(node, key, value, rsubtree, &median);
155
 
156
		if (LEAF_NODE(node)) {
1144 jermar 157
			list_prepend(&rnode->leaf_link, &node->leaf_link);
1101 jermar 158
		}
159
 
160
		if (ROOT_NODE(node)) {
161
			/*
162
			 * We split the root node. Create new root.
163
			 */
164
			t->root = (btree_node_t *) malloc(sizeof(btree_node_t), 0);
165
			node->parent = t->root;
166
			rnode->parent = t->root;
167
			node_initialize(t->root);
168
 
169
			/*
170
			 * Left-hand side subtree will be the old root (i.e. node).
171
			 * Right-hand side subtree will be rnode.
172
			 */			
173
			t->root->subtree[0] = node;
174
 
175
			t->root->depth = node->depth + 1;
176
		}
177
		_btree_insert(t, median, NULL, rnode, node->parent);
178
	}	
179
 
180
}
181
 
1140 jermar 182
/** Remove B-tree node.
183
 *
184
 * @param B-tree.
185
 * @param key Key to be removed from the B-tree along with its associated value.
186
 * @param leaf_node If not NULL, pointer to the leaf node where the key is found.
187
 */
188
void btree_remove(btree_t *t, __native key, btree_node_t *leaf_node)
1101 jermar 189
{
1140 jermar 190
	btree_node_t *lnode;
191
 
192
	lnode = leaf_node;
193
	if (!lnode) {
194
		if (!btree_search(t, key, &lnode)) {
195
			panic("B-tree %P does not contain key %d\n", t, key);
196
		}
197
	}
198
 
1142 jermar 199
	_btree_remove(t, key, lnode);
200
}
1140 jermar 201
 
1142 jermar 202
/** Recursively remove B-tree node.
203
 *
204
 * @param B-tree.
205
 * @param key Key to be removed from the B-tree along with its associated value.
206
 * @param node Node where the key being removed resides.
207
 */
208
void _btree_remove(btree_t *t, __native key, btree_node_t *node)
209
{
210
	if (ROOT_NODE(node)) {
211
		if (node->keys == 1 && node->subtree[0]) {
212
			/*
213
			 * Free the current root and set new root.
214
			 */
215
			t->root = node->subtree[0];
216
			t->root->parent = NULL;
217
			free(node);
218
		} else {
219
			/*
220
			 * Remove the key from the root node.
221
			 * Note that the right subtree is removed because when
222
			 * combining two nodes, the left-side sibling is preserved
223
			 * and the right-side sibling is freed.
224
			 */
225
			node_remove_key_and_rsubtree(node, key);
226
		}
227
		return;
228
	}
229
 
230
	if (node->keys <= FILL_FACTOR) {
231
		/*
232
		 * If the node is below the fill factor,
233
		 * try to borrow keys from left or right sibling.
234
		 */
235
		if (!try_rotation_from_left(node))
236
			try_rotation_from_right(node);
237
	}
238
 
239
	if (node->keys > FILL_FACTOR) {
240
		int i;
241
 
242
		/*
243
		 * The key can be immediatelly removed.
244
		 *
245
		 * Note that the right subtree is removed because when
246
		 * combining two nodes, the left-side sibling is preserved
247
		 * and the right-side sibling is freed.
248
		 */
249
		node_remove_key_and_rsubtree(node, key);
250
		for (i = 0; i < node->parent->keys; i++) {
251
			if (node->parent->key[i] == key)
252
				node->parent->key[i] = node->key[0];
253
		}
254
 
255
	} else {
256
		index_t idx;
257
		btree_node_t *rnode, *parent;
258
 
259
		/*
260
		 * The node is below the fill factor as well as its left and right sibling.
261
		 * Resort to combining the node with one of its siblings.
262
		 * The node which is on the left is preserved and the node on the right is
263
		 * freed.
264
		 */
265
		parent = node->parent;
266
		node_remove_key_and_rsubtree(node, key);
267
		rnode = node_combine(node);
268
		if (LEAF_NODE(rnode))
269
			list_remove(&rnode->leaf_link);
270
		idx = find_key_by_subtree(parent, rnode, true);
271
		ASSERT((int) idx != -1);
272
		free(rnode);
273
		_btree_remove(t, parent->key[idx], parent);
274
	}
1101 jermar 275
}
276
 
277
/** Search key in a B-tree.
278
 *
279
 * @param t B-tree.
280
 * @param key Key to be searched.
281
 * @param leaf_node Address where to put pointer to visited leaf node.
282
 *
283
 * @return Pointer to value or NULL if there is no such key.
284
 */
285
void *btree_search(btree_t *t, __native key, btree_node_t **leaf_node)
286
{
287
	btree_node_t *cur, *next;
288
 
289
	/*
1134 jermar 290
	 * Iteratively descend to the leaf that can contain the searched key.
1101 jermar 291
	 */
292
	for (cur = t->root; cur; cur = next) {
1134 jermar 293
 
1101 jermar 294
		/* Last iteration will set this with proper leaf node address. */
295
		*leaf_node = cur;
1134 jermar 296
 
297
		/*
298
		 * The key can be in the leftmost subtree.
299
		 * Test it separately.
300
		 */
301
		if (key < cur->key[0]) {
302
			next = cur->subtree[0];
303
			continue;
304
		} else {
305
			void *val;
306
			int i;
307
 
308
			/*
309
			 * Now if the key is smaller than cur->key[i]
310
			 * it can only mean that the value is in cur->subtree[i]
311
			 * or it is not in the tree at all.
312
			 */
313
			for (i = 1; i < cur->keys; i++) {
314
				if (key < cur->key[i]) {
315
					next = cur->subtree[i];
316
					val = cur->value[i - 1];
317
 
318
					if (LEAF_NODE(cur))
319
						return key == cur->key[i - 1] ? val : NULL;
320
 
321
					goto descend;
322
				} 
1101 jermar 323
			}
1134 jermar 324
 
325
			/*
326
			 * Last possibility is that the key is in the rightmost subtree.
327
			 */
328
			next = cur->subtree[i];
329
			val = cur->value[i - 1];
330
			if (LEAF_NODE(cur))
331
				return key == cur->key[i - 1] ? val : NULL;
1101 jermar 332
		}
1134 jermar 333
		descend:
334
			;
1101 jermar 335
	}
336
 
337
	/*
1134 jermar 338
	 * The key was not found in the *leaf_node and is smaller than any of its keys.
1101 jermar 339
	 */
340
	return NULL;
341
}
342
 
343
/** Initialize B-tree node.
344
 *
345
 * @param node B-tree node.
346
 */
347
void node_initialize(btree_node_t *node)
348
{
349
	int i;
350
 
351
	node->keys = 0;
352
 
353
	/* Clean also space for the extra key. */
354
	for (i = 0; i < BTREE_MAX_KEYS + 1; i++) {
355
		node->key[i] = 0;
356
		node->value[i] = NULL;
357
		node->subtree[i] = NULL;
358
	}
359
	node->subtree[i] = NULL;
360
 
361
	node->parent = NULL;
362
 
363
	link_initialize(&node->leaf_link);
364
 
365
	link_initialize(&node->bfs_link);
366
	node->depth = 0;
367
}
368
 
1136 jermar 369
/** Insert key-value-lsubtree triplet into B-tree node.
1101 jermar 370
 *
371
 * It is actually possible to have more keys than BTREE_MAX_KEYS.
1136 jermar 372
 * This feature is used during insert by right rotation.
373
 *
374
 * @param node B-tree node into wich the new key is to be inserted.
375
 * @param key The key to be inserted.
376
 * @param value Pointer to value to be inserted.
377
 * @param lsubtree Pointer to the left subtree.
378
 */ 
1142 jermar 379
void node_insert_key_and_lsubtree(btree_node_t *node, __native key, void *value, btree_node_t *lsubtree)
1136 jermar 380
{
381
	int i;
382
 
383
	for (i = 0; i < node->keys; i++) {
384
		if (key < node->key[i]) {
385
			int j;
386
 
387
			for (j = node->keys; j > i; j--) {
388
				node->key[j] = node->key[j - 1];
389
				node->value[j] = node->value[j - 1];
390
				node->subtree[j + 1] = node->subtree[j];
391
			}
392
			node->subtree[j + 1] = node->subtree[j];
393
			break;	
394
		}
395
	}
396
	node->key[i] = key;
397
	node->value[i] = value;
398
	node->subtree[i] = lsubtree;
399
 
400
	node->keys++;
401
}
402
 
403
/** Insert key-value-rsubtree triplet into B-tree node.
404
 *
405
 * It is actually possible to have more keys than BTREE_MAX_KEYS.
1101 jermar 406
 * This feature is used during splitting the node when the
1136 jermar 407
 * number of keys is BTREE_MAX_KEYS + 1. Insert by left rotation
408
 * also makes use of this feature.
1101 jermar 409
 *
410
 * @param node B-tree node into wich the new key is to be inserted.
411
 * @param key The key to be inserted.
412
 * @param value Pointer to value to be inserted.
413
 * @param rsubtree Pointer to the right subtree.
414
 */ 
1142 jermar 415
void node_insert_key_and_rsubtree(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree)
1101 jermar 416
{
417
	int i;
418
 
419
	for (i = 0; i < node->keys; i++) {
420
		if (key < node->key[i]) {
421
			int j;
422
 
423
			for (j = node->keys; j > i; j--) {
424
				node->key[j] = node->key[j - 1];
425
				node->value[j] = node->value[j - 1];
426
				node->subtree[j + 1] = node->subtree[j];
427
			}
428
			break;	
429
		}
430
	}
431
	node->key[i] = key;
432
	node->value[i] = value;
433
	node->subtree[i + 1] = rsubtree;
434
 
435
	node->keys++;
436
}
437
 
1144 jermar 438
/** Remove key and its left subtree pointer from B-tree node.
439
 *
440
 * Remove the key and eliminate gaps in node->key array.
441
 * Note that the value pointer and the left subtree pointer
442
 * is removed from the node as well.
443
 *
444
 * @param node B-tree node.
445
 * @param key Key to be removed.
446
 */
447
void node_remove_key_and_lsubtree(btree_node_t *node, __native key)
448
{
449
	int i, j;
450
 
451
	for (i = 0; i < node->keys; i++) {
452
		if (key == node->key[i]) {
453
			for (j = i + 1; j < node->keys; j++) {
454
				node->key[j - 1] = node->key[j];
455
				node->value[j - 1] = node->value[j];
456
				node->subtree[j - 1] = node->subtree[j];
457
			}
458
			node->subtree[j - 1] = node->subtree[j];
459
			node->keys--;
460
			return;
461
		}
462
	}
463
	panic("node %P does not contain key %d\n", node, key);
464
}
465
 
466
/** Remove key and its right subtree pointer from B-tree node.
467
 *
468
 * Remove the key and eliminate gaps in node->key array.
469
 * Note that the value pointer and the right subtree pointer
470
 * is removed from the node as well.
471
 *
472
 * @param node B-tree node.
473
 * @param key Key to be removed.
474
 */
475
void node_remove_key_and_rsubtree(btree_node_t *node, __native key)
476
{
477
	int i, j;
478
 
479
	for (i = 0; i < node->keys; i++) {
480
		if (key == node->key[i]) {
481
			for (j = i + 1; j < node->keys; j++) {
482
				node->key[j - 1] = node->key[j];
483
				node->value[j - 1] = node->value[j];
484
				node->subtree[j] = node->subtree[j + 1];
485
			}
486
			node->keys--;
487
			return;
488
		}
489
	}
490
	panic("node %P does not contain key %d\n", node, key);
491
}
492
 
1134 jermar 493
/** Split full B-tree node and insert new key-value-right-subtree triplet.
1101 jermar 494
 *
495
 * This function will split a node and return pointer to a newly created
1134 jermar 496
 * node containing keys greater than or equal to the greater of medians
497
 * (or median) of the old keys and the newly added key. It will also write
498
 * the median key to a memory address supplied by the caller.
1101 jermar 499
 *
1134 jermar 500
 * If the node being split is an index node, the median will not be
501
 * included in the new node. If the node is a leaf node,
502
 * the median will be copied there.
1101 jermar 503
 *
504
 * @param node B-tree node wich is going to be split.
505
 * @param key The key to be inserted.
506
 * @param value Pointer to the value to be inserted.
507
 * @param rsubtree Pointer to the right subtree of the key being added.
508
 * @param median Address in memory, where the median key will be stored.
509
 *
510
 * @return Newly created right sibling of node.
511
 */ 
512
btree_node_t *node_split(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree, __native *median)
513
{
514
	btree_node_t *rnode;
515
	int i, j;
516
 
517
	ASSERT(median);
518
	ASSERT(node->keys == BTREE_MAX_KEYS);
1136 jermar 519
 
1101 jermar 520
	/*
521
	 * Use the extra space to store the extra node.
522
	 */
1142 jermar 523
	node_insert_key_and_rsubtree(node, key, value, rsubtree);
1101 jermar 524
 
525
	/*
526
	 * Compute median of keys.
527
	 */
1134 jermar 528
	*median = MEDIAN_HIGH(node);
1101 jermar 529
 
1134 jermar 530
	/*
531
	 * Allocate and initialize new right sibling.
532
	 */
1101 jermar 533
	rnode = (btree_node_t *) malloc(sizeof(btree_node_t), 0);
534
	node_initialize(rnode);
535
	rnode->parent = node->parent;
536
	rnode->depth = node->depth;
537
 
538
	/*
539
	 * Copy big keys, values and subtree pointers to the new right sibling.
1134 jermar 540
	 * If this is an index node, do not copy the median.
1101 jermar 541
	 */
1134 jermar 542
	i = (int) INDEX_NODE(node);
543
	for (i += MEDIAN_HIGH_INDEX(node), j = 0; i < node->keys; i++, j++) {
1101 jermar 544
		rnode->key[j] = node->key[i];
545
		rnode->value[j] = node->value[i];
546
		rnode->subtree[j] = node->subtree[i];
547
 
548
		/*
549
		 * Fix parent links in subtrees.
550
		 */
551
		if (rnode->subtree[j])
552
			rnode->subtree[j]->parent = rnode;
553
 
554
	}
555
	rnode->subtree[j] = node->subtree[i];
556
	if (rnode->subtree[j])
557
		rnode->subtree[j]->parent = rnode;
1134 jermar 558
 
559
	rnode->keys = j;	/* Set number of keys of the new node. */
560
	node->keys /= 2;	/* Shrink the old node. */
1101 jermar 561
 
562
	return rnode;
563
}
564
 
1142 jermar 565
/** Combine node with any of its siblings.
566
 *
567
 * The siblings are required to be below the fill factor.
568
 *
569
 * @param node Node to combine with one of its siblings.
570
 *
571
 * @return Pointer to the rightmost of the two nodes.
572
 */
573
btree_node_t *node_combine(btree_node_t *node)
574
{
575
	index_t idx;
576
	btree_node_t *rnode;
577
	int i;
578
 
579
	ASSERT(!ROOT_NODE(node));
580
 
581
	idx = find_key_by_subtree(node->parent, node, false);
582
	if (idx == node->parent->keys) {
583
		/*
584
		 * Rightmost subtree of its parent, combine with the left sibling.
585
		 */
586
		idx--;
587
		rnode = node;
588
		node = node->parent->subtree[idx];
589
	} else {
590
		rnode = node->parent->subtree[idx + 1];
591
	}
592
 
593
	/* Index nodes need to insert parent node key in between left and right node. */
594
	if (INDEX_NODE(node))
595
		node->key[node->keys++] = node->parent->key[idx];
596
 
597
	/* Copy the key-value-subtree triplets from the right node. */
598
	for (i = 0; i < rnode->keys; i++) {
599
		node->key[node->keys + i] = rnode->key[i];
600
		node->value[node->keys + i] = rnode->value[i];
601
		if (INDEX_NODE(node)) {
602
			node->subtree[node->keys + i] = rnode->subtree[i];
603
			rnode->subtree[i]->parent = node;
604
		}
605
	}
606
	if (INDEX_NODE(node)) {
607
		node->subtree[node->keys + i] = rnode->subtree[i];
608
		rnode->subtree[i]->parent = node;
609
	}
610
 
611
	node->keys += rnode->keys;
612
 
613
	return rnode;
614
}
615
 
1136 jermar 616
/** Find key by its left or right subtree.
617
 *
618
 * @param node B-tree node.
619
 * @param subtree Left or right subtree of a key found in node.
620
 * @param right If true, subtree is a right subtree. If false, subtree is a left subtree.
621
 *
622
 * @return Index of the key associated with the subtree.
623
 */ 
624
index_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right)
625
{
626
	int i;
627
 
628
	for (i = 0; i < node->keys + 1; i++) {
629
		if (subtree == node->subtree[i])
630
			return i - (int) (right != false);
631
	}
632
	panic("node %P does not contain subtree %P\n", node, subtree);
633
}
634
 
1142 jermar 635
/** Rotate one key-value-rsubtree triplet from the left sibling to the right sibling.
636
 *
637
 * The biggest key and its value and right subtree is rotated from the left node
638
 * to the right. If the node is an index node, than the parent node key belonging to
639
 * the left node takes part in the rotation.
640
 *
641
 * @param lnode Left sibling.
642
 * @param rnode Right sibling.
643
 * @param idx Index of the parent node key that is taking part in the rotation.
644
 */
645
void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, index_t idx)
646
{
647
	__native key;
648
 
649
	key = lnode->key[lnode->keys - 1];
650
 
651
	if (LEAF_NODE(lnode)) {
652
		void *value;
653
 
654
		value = lnode->value[lnode->keys - 1];
655
		node_remove_key_and_rsubtree(lnode, key);
656
		node_insert_key_and_lsubtree(rnode, key, value, NULL);
657
		lnode->parent->key[idx] = key;
658
	} else {
659
		btree_node_t *rsubtree;
660
 
661
		rsubtree = lnode->subtree[lnode->keys];
662
		node_remove_key_and_rsubtree(lnode, key);
663
		node_insert_key_and_lsubtree(rnode, lnode->parent->key[idx], NULL, rsubtree);
664
		lnode->parent->key[idx] = key;
665
 
666
		/* Fix parent link of the reconnected right subtree. */
667
		rsubtree->parent = rnode;
668
	}
669
 
670
}
671
 
672
/** Rotate one key-value-lsubtree triplet from the right sibling to the left sibling.
673
 *
674
 * The smallest key and its value and left subtree is rotated from the right node
675
 * to the left. If the node is an index node, than the parent node key belonging to
676
 * the right node takes part in the rotation.
677
 *
678
 * @param lnode Left sibling.
679
 * @param rnode Right sibling.
680
 * @param idx Index of the parent node key that is taking part in the rotation.
681
 */
682
void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, index_t idx)
683
{
684
	__native key;
685
 
686
	key = rnode->key[0];
687
 
688
	if (LEAF_NODE(rnode)) {
689
		void *value;
690
 
691
		value = rnode->value[0];
692
		node_remove_key_and_lsubtree(rnode, key);
693
		node_insert_key_and_rsubtree(lnode, key, value, NULL);
694
		rnode->parent->key[idx] = rnode->key[0];
695
	} else {
696
		btree_node_t *lsubtree;
697
 
698
		lsubtree = rnode->subtree[0];
699
		node_remove_key_and_lsubtree(rnode, key);
700
		node_insert_key_and_rsubtree(lnode, rnode->parent->key[idx], NULL, lsubtree);
701
		rnode->parent->key[idx] = key;
702
 
703
		/* Fix parent link of the reconnected left subtree. */
704
		lsubtree->parent = lnode;
705
	}
706
 
707
}
708
 
1136 jermar 709
/** Insert key-value-rsubtree triplet and rotate the node to the left, if this operation can be done.
710
 *
711
 * Left sibling of the node (if it exists) is checked for free space.
712
 * If there is free space, the key is inserted and the smallest key of
713
 * the node is moved there. The index node which is the parent of both
714
 * nodes is fixed.
715
 *
716
 * @param node B-tree node.
717
 * @param inskey Key to be inserted.
718
 * @param insvalue Value to be inserted.
719
 * @param rsubtree Right subtree of inskey.
720
 *
721
 * @return True if the rotation was performed, false otherwise.
722
 */
1142 jermar 723
bool try_insert_by_rotation_to_left(btree_node_t *node, __native inskey, void *insvalue, btree_node_t *rsubtree)
1136 jermar 724
{
725
	index_t idx;
726
	btree_node_t *lnode;
727
 
728
	/*
729
	 * If this is root node, the rotation can not be done.
730
	 */
731
	if (ROOT_NODE(node))
732
		return false;
733
 
734
	idx = find_key_by_subtree(node->parent, node, true);
735
	if ((int) idx == -1) {
736
		/*
737
		 * If this node is the leftmost subtree of its parent,
738
		 * the rotation can not be done.
739
		 */
740
		return false;
741
	}
742
 
743
	lnode = node->parent->subtree[idx];
744
	if (lnode->keys < BTREE_MAX_KEYS) {
745
		/*
746
		 * The rotaion can be done. The left sibling has free space.
747
		 */
1142 jermar 748
		node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree);
749
		rotate_from_right(lnode, node, idx);
1136 jermar 750
		return true;
751
	}
752
 
753
	return false;
754
}
755
 
756
/** Insert key-value-rsubtree triplet and rotate the node to the right, if this operation can be done.
757
 *
758
 * Right sibling of the node (if it exists) is checked for free space.
759
 * If there is free space, the key is inserted and the biggest key of
760
 * the node is moved there. The index node which is the parent of both
761
 * nodes is fixed.
762
 *
763
 * @param node B-tree node.
764
 * @param inskey Key to be inserted.
765
 * @param insvalue Value to be inserted.
766
 * @param rsubtree Right subtree of inskey.
767
 *
768
 * @return True if the rotation was performed, false otherwise.
769
 */
1142 jermar 770
bool try_insert_by_rotation_to_right(btree_node_t *node, __native inskey, void *insvalue, btree_node_t *rsubtree)
1136 jermar 771
{
772
	index_t idx;
773
	btree_node_t *rnode;
774
 
775
	/*
776
	 * If this is root node, the rotation can not be done.
777
	 */
778
	if (ROOT_NODE(node))
779
		return false;
780
 
781
	idx = find_key_by_subtree(node->parent, node, false);
782
	if (idx == node->parent->keys) {
783
		/*
784
		 * If this node is the rightmost subtree of its parent,
785
		 * the rotation can not be done.
786
		 */
787
		return false;
788
	}
789
 
790
	rnode = node->parent->subtree[idx + 1];
791
	if (rnode->keys < BTREE_MAX_KEYS) {
792
		/*
793
		 * The rotaion can be done. The right sibling has free space.
794
		 */
1142 jermar 795
		node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree);
796
		rotate_from_left(node, rnode, idx);
797
		return true;
798
	}
1136 jermar 799
 
1142 jermar 800
	return false;
801
}
1136 jermar 802
 
1142 jermar 803
/** Rotate in a key from the left sibling or from the index node, if this operation can be done.
804
 *
805
 * @param rnode Node into which to add key from its left sibling or from the index node.
806
 *
807
 * @return True if the rotation was performed, false otherwise.
808
 */
809
bool try_rotation_from_left(btree_node_t *rnode)
810
{
811
	index_t idx;
812
	btree_node_t *lnode;
1136 jermar 813
 
1142 jermar 814
	/*
815
	 * If this is root node, the rotation can not be done.
816
	 */
817
	if (ROOT_NODE(rnode))
818
		return false;
819
 
820
	idx = find_key_by_subtree(rnode->parent, rnode, true);
821
	if ((int) idx == -1) {
822
		/*
823
		 * If this node is the leftmost subtree of its parent,
824
		 * the rotation can not be done.
825
		 */
826
		return false;
827
	}
828
 
829
	lnode = rnode->parent->subtree[idx];
830
	if (lnode->keys > FILL_FACTOR) {
831
		rotate_from_left(lnode, rnode, idx);
1136 jermar 832
		return true;
833
	}
1142 jermar 834
 
835
	return false;
836
}
1136 jermar 837
 
1142 jermar 838
/** Rotate in a key from the right sibling or from the index node, if this operation can be done.
839
 *
840
 * @param rnode Node into which to add key from its right sibling or from the index node.
841
 *
842
 * @return True if the rotation was performed, false otherwise.
843
 */
844
bool try_rotation_from_right(btree_node_t *lnode)
845
{
846
	index_t idx;
847
	btree_node_t *rnode;
848
 
849
	/*
850
	 * If this is root node, the rotation can not be done.
851
	 */
852
	if (ROOT_NODE(lnode))
853
		return false;
854
 
855
	idx = find_key_by_subtree(lnode->parent, lnode, false);
856
	if (idx == lnode->parent->keys) {
857
		/*
858
		 * If this node is the rightmost subtree of its parent,
859
		 * the rotation can not be done.
860
		 */
861
		return false;
862
	}
863
 
864
	rnode = lnode->parent->subtree[idx + 1];
865
	if (rnode->keys > FILL_FACTOR) {
866
		rotate_from_right(lnode, rnode, idx);
867
		return true;
868
	}	
869
 
1136 jermar 870
	return false;
871
}
872
 
1101 jermar 873
/** Print B-tree.
874
 *
875
 * @param t Print out B-tree.
876
 */
877
void btree_print(btree_t *t)
878
{
879
	int i, depth = t->root->depth;
1144 jermar 880
	link_t head, *cur;
881
 
882
	printf("Printing B-tree:\n");
1101 jermar 883
	list_initialize(&head);
884
	list_append(&t->root->bfs_link, &head);
885
 
886
	/*
887
	 * Use BFS search to print out the tree.
888
	 * Levels are distinguished from one another by node->depth.
889
	 */	
890
	while (!list_empty(&head)) {
891
		link_t *hlp;
892
		btree_node_t *node;
893
 
894
		hlp = head.next;
895
		ASSERT(hlp != &head);
896
		node = list_get_instance(hlp, btree_node_t, bfs_link);
897
		list_remove(hlp);
898
 
899
		ASSERT(node);
900
 
901
		if (node->depth != depth) {
902
			printf("\n");
903
			depth = node->depth;
904
		}
905
 
906
		printf("(");
907
		for (i = 0; i < node->keys; i++) {
1144 jermar 908
			printf("%d%s", node->key[i], i < node->keys - 1 ? "," : "");
1101 jermar 909
			if (node->depth && node->subtree[i]) {
910
				list_append(&node->subtree[i]->bfs_link, &head);
911
			}
912
		}
913
		if (node->depth && node->subtree[i]) {
914
			list_append(&node->subtree[i]->bfs_link, &head);
915
		}
916
		printf(")");
917
	}
918
	printf("\n");
1144 jermar 919
 
920
	printf("Printing list of leaves:\n");
921
	for (cur = t->leaf_head.next; cur != &t->leaf_head; cur = cur->next) {
922
		btree_node_t *node;
923
 
924
		node = list_get_instance(cur, btree_node_t, leaf_link);
925
 
926
		ASSERT(node);
927
 
928
		printf("(");
929
		for (i = 0; i < node->keys; i++)
930
			printf("%d%s", node->key[i], i < node->keys - 1 ? "," : "");
931
		printf(")");
932
	}
933
	printf("\n");
1101 jermar 934
}