~drizzle-trunk/drizzle/development

1410.4.2 by Djellel E. Difallah
removing my
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
1410.4.2 by Djellel E. Difallah
removing my
15
16
/*
17
  Code for handling red-black (balanced) binary trees.
18
  key in tree is allocated accrding to following:
19
20
  1) If size < 0 then tree will not allocate keys and only a pointer to
21
     each key is saved in tree.
22
     compare and search functions uses and returns key-pointer
23
24
  2) If size == 0 then there are two options:
25
       - key_size != 0 to tree_insert: The key will be stored in the tree.
26
       - key_size == 0 to tree_insert:  A pointer to the key is stored.
27
     compare and search functions uses and returns key-pointer.
28
29
  3) if key_size is given to init_tree then each node will continue the
30
     key and calls to insert_key may increase length of key.
31
     if key_size > sizeof(pointer) and key_size is a multiple of 8 (double
32
     allign) then key will be put on a 8 alligned adress. Else
33
     the key will be on adress (element+1). This is transparent for user
34
     compare and search functions uses a pointer to given key-argument.
35
36
  - If you use a free function for tree-elements and you are freeing
37
    the element itself, you should use key_size = 0 to init_tree and
38
    tree_search
39
40
  The actual key in TREE_ELEMENT is saved as a pointer or after the
41
  TREE_ELEMENT struct.
42
  If one uses only pointers in tree one can use tree_set_pointer() to
43
  change address of data.
44
45
  Implemented by monty.
46
*/
47
48
/*
49
  NOTE:
50
  tree->compare function should be ALWAYS called as
51
    (*tree->compare)(custom_arg, ELEMENT_KEY(tree,element), key)
52
  and not other way around, as
53
    (*tree->compare)(custom_arg, key, ELEMENT_KEY(tree,element))
54
*/
55
56
#include "config.h"
57
58
#include "drizzled/tree.h"
59
#include "drizzled/internal/my_sys.h"
60
#include "drizzled/internal/m_string.h"
61
#include "drizzled/memory/root.h"
62
63
#define BLACK		1
64
#define RED		0
65
#define DEFAULT_ALLOC_SIZE 8192
66
#define DEFAULT_ALIGN_SIZE 8192
67
68
#define ELEMENT_KEY(tree,element)\
69
(tree->offset_to_key ? (void*)((unsigned char*) element+tree->offset_to_key) :\
70
			*((void**) (element+1)))
71
#define ELEMENT_CHILD(element, offs) (*(TREE_ELEMENT**)((char*)element + offs))
72
73
namespace drizzled
74
{
75
76
77
static void delete_tree_element(TREE *,TREE_ELEMENT *);
78
static int tree_walk_left_root_right(TREE *,TREE_ELEMENT *,
79
				     tree_walk_action,void *);
80
static int tree_walk_right_root_left(TREE *,TREE_ELEMENT *,
81
				     tree_walk_action,void *);
82
static void left_rotate(TREE_ELEMENT **parent,TREE_ELEMENT *leaf);
83
static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf);
84
static void rb_insert(TREE *tree,TREE_ELEMENT ***parent,
85
		      TREE_ELEMENT *leaf);
86
static void rb_delete_fixup(TREE *tree,TREE_ELEMENT ***parent);
87
88
89
void init_tree(TREE *tree, size_t default_alloc_size, uint32_t memory_limit,
90
               uint32_t size, qsort_cmp2 compare, bool with_delete,
91
	       tree_element_free free_element, void *custom_arg)
92
{
93
  if (default_alloc_size < DEFAULT_ALLOC_SIZE)
94
    default_alloc_size= DEFAULT_ALLOC_SIZE;
95
  default_alloc_size= MY_ALIGN(default_alloc_size, DEFAULT_ALIGN_SIZE);
96
  memset(&tree->null_element, 0, sizeof(tree->null_element));
97
  tree->root= &tree->null_element;
98
  tree->compare= compare;
99
  tree->size_of_element= size > 0 ? (uint32_t) size : 0;
100
  tree->memory_limit= memory_limit;
101
  tree->free= free_element;
102
  tree->allocated= 0;
103
  tree->elements_in_tree= 0;
104
  tree->custom_arg = custom_arg;
105
  tree->null_element.colour= BLACK;
106
  tree->null_element.left=tree->null_element.right= 0;
107
  tree->flag= 0;
108
  if (!free_element &&
109
      (size <= sizeof(void*) || ((uint32_t) size & (sizeof(void*)-1))))
110
  {
111
    /*
112
      We know that the data doesn't have to be aligned (like if the key
113
      contains a double), so we can store the data combined with the
114
      TREE_ELEMENT.
115
    */
116
    tree->offset_to_key= sizeof(TREE_ELEMENT); /* Put key after element */
117
    /* Fix allocation size so that we don't lose any memory */
118
    default_alloc_size/= (sizeof(TREE_ELEMENT)+size);
119
    if (!default_alloc_size)
120
      default_alloc_size= 1;
121
    default_alloc_size*= (sizeof(TREE_ELEMENT)+size);
122
  }
123
  else
124
  {
125
    tree->offset_to_key= 0;		/* use key through pointer */
126
    tree->size_of_element+= sizeof(void*);
127
  }
128
  if (! (tree->with_delete= with_delete))
129
  {
1487 by Brian Aker
More updates for memory::Root
130
    tree->mem_root.init_alloc_root(default_alloc_size);
1410.4.2 by Djellel E. Difallah
removing my
131
    tree->mem_root.min_malloc= (sizeof(TREE_ELEMENT)+tree->size_of_element);
132
  }
133
}
134
135
static void free_tree(TREE *tree, myf free_flags)
136
{
137
  if (tree->root)				/* If initialized */
138
  {
139
    if (tree->with_delete)
140
      delete_tree_element(tree,tree->root);
141
    else
142
    {
143
      if (tree->free)
144
      {
145
        if (tree->memory_limit)
146
          (*tree->free)(NULL, free_init, tree->custom_arg);
147
	delete_tree_element(tree,tree->root);
148
        if (tree->memory_limit)
149
          (*tree->free)(NULL, free_end, tree->custom_arg);
150
      }
1487 by Brian Aker
More updates for memory::Root
151
      tree->mem_root.free_root(free_flags);
1410.4.2 by Djellel E. Difallah
removing my
152
    }
153
  }
154
  tree->root= &tree->null_element;
155
  tree->elements_in_tree= 0;
156
  tree->allocated= 0;
157
}
158
159
void delete_tree(TREE* tree)
160
{
161
  free_tree(tree, MYF(0)); /* free() mem_root if applicable */
162
}
163
164
void reset_tree(TREE* tree)
165
{
166
  /* do not free mem_root, just mark blocks as free */
167
  free_tree(tree, MYF(memory::MARK_BLOCKS_FREE));
168
}
169
170
171
static void delete_tree_element(TREE *tree, TREE_ELEMENT *element)
172
{
173
  if (element != &tree->null_element)
174
  {
175
    delete_tree_element(tree,element->left);
176
    if (tree->free)
177
      (*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg);
178
    delete_tree_element(tree,element->right);
179
    if (tree->with_delete)
180
      free((char*) element);
181
  }
182
}
183
184
185
/*
186
  insert, search and delete of elements
187
188
  The following should be true:
189
    parent[0] = & parent[-1][0]->left ||
190
    parent[0] = & parent[-1][0]->right
191
*/
192
193
TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint32_t key_size,
194
                          void* custom_arg)
195
{
196
  int cmp;
197
  TREE_ELEMENT *element,***parent;
198
199
  parent= tree->parents;
200
  *parent = &tree->root; element= tree->root;
201
  for (;;)
202
  {
203
    if (element == &tree->null_element ||
204
	(cmp = (*tree->compare)(custom_arg, ELEMENT_KEY(tree,element),
205
                                key)) == 0)
206
      break;
207
    if (cmp < 0)
208
    {
209
      *++parent= &element->right; element= element->right;
210
    }
211
    else
212
    {
213
      *++parent = &element->left; element= element->left;
214
    }
215
  }
216
  if (element == &tree->null_element)
217
  {
218
    size_t alloc_size= sizeof(TREE_ELEMENT)+key_size+tree->size_of_element;
219
    tree->allocated+= alloc_size;
220
221
    if (tree->memory_limit && tree->elements_in_tree
222
                           && tree->allocated > tree->memory_limit)
223
    {
224
      reset_tree(tree);
225
      return tree_insert(tree, key, key_size, custom_arg);
226
    }
227
228
    key_size+= tree->size_of_element;
229
    if (tree->with_delete)
230
      element= (TREE_ELEMENT *) malloc(alloc_size);
231
    else
1485 by Brian Aker
Updates to confine memroot
232
      element= (TREE_ELEMENT *) tree->mem_root.alloc_root(alloc_size);
1410.4.2 by Djellel E. Difallah
removing my
233
    if (!element)
234
      return(NULL);
235
    **parent= element;
236
    element->left= element->right= &tree->null_element;
237
    if (!tree->offset_to_key)
238
    {
239
      if (key_size == sizeof(void*))		 /* no length, save pointer */
240
	*((void**) (element+1))= key;
241
      else
242
      {
243
	*((void**) (element+1))= (void*) ((void **) (element+1)+1);
244
	memcpy(*((void **) (element+1)),key, key_size - sizeof(void*));
245
      }
246
    }
247
    else
248
      memcpy((unsigned char*) element + tree->offset_to_key, key, key_size);
249
    element->count= 1;			/* May give warning in purify */
250
    tree->elements_in_tree++;
251
    rb_insert(tree,parent,element);	/* rebalance tree */
252
  }
253
  else
254
  {
255
    if (tree->flag & TREE_NO_DUPS)
256
      return(NULL);
257
    element->count++;
258
    /* Avoid a wrap over of the count. */
259
    if (! element->count)
260
      element->count--;
261
  }
262
263
  return element;
264
}
265
266
int tree_delete(TREE *tree, void *key, uint32_t key_size, void *custom_arg)
267
{
268
  int remove_colour;
269
  TREE_ELEMENT *element,***parent, ***org_parent, *nod;
270
  if (!tree->with_delete)
271
    return 1;					/* not allowed */
272
273
  parent= tree->parents;
274
  *parent= &tree->root; element= tree->root;
275
  for (;;)
276
  {
277
    int cmp;
278
279
    if (element == &tree->null_element)
280
      return 1;				/* Was not in tree */
281
    if ((cmp = (*tree->compare)(custom_arg, ELEMENT_KEY(tree,element),
282
                                key)) == 0)
283
      break;
284
    if (cmp < 0)
285
    {
286
      *++parent= &element->right; element= element->right;
287
    }
288
    else
289
    {
290
      *++parent = &element->left; element= element->left;
291
    }
292
  }
293
  if (element->left == &tree->null_element)
294
  {
295
    (**parent)= element->right;
296
    remove_colour= element->colour;
297
  }
298
  else if (element->right == &tree->null_element)
299
  {
300
    (**parent)= element->left;
301
    remove_colour= element->colour;
302
  }
303
  else
304
  {
305
    org_parent= parent;
306
    *++parent= &element->right; nod= element->right;
307
    while (nod->left != &tree->null_element)
308
    {
309
      *++parent= &nod->left; nod= nod->left;
310
    }
311
    (**parent)= nod->right;		/* unlink nod from tree */
312
    remove_colour= nod->colour;
313
    org_parent[0][0]= nod;		/* put y in place of element */
314
    org_parent[1]= &nod->right;
315
    nod->left= element->left;
316
    nod->right= element->right;
317
    nod->colour= element->colour;
318
  }
319
  if (remove_colour == BLACK)
320
    rb_delete_fixup(tree,parent);
321
  if (tree->free)
322
    (*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg);
323
  tree->allocated-= sizeof(TREE_ELEMENT) + tree->size_of_element + key_size;
324
  free((unsigned char*) element);
325
  tree->elements_in_tree--;
326
327
  return 0;
328
}
329
330
void *tree_search_key(TREE *tree, const void *key,
331
                      TREE_ELEMENT **parents, TREE_ELEMENT ***last_pos,
332
                      enum ha_rkey_function flag, void *custom_arg)
333
{
334
  TREE_ELEMENT *element= tree->root;
335
  TREE_ELEMENT **last_left_step_parent= NULL, **last_right_step_parent= NULL;
336
  TREE_ELEMENT **last_equal_element= NULL;
337
338
/*
339
  TODO: support for HA_READ_KEY_OR_PREV, HA_READ_PREFIX flags if needed.
340
*/
341
342
  *parents = &tree->null_element;
343
  while (element != &tree->null_element)
344
  {
345
    int cmp;
346
347
    *++parents= element;
348
349
    if ((cmp= (*tree->compare)(custom_arg, ELEMENT_KEY(tree, element),
350
			       key)) == 0)
351
    {
352
      switch (flag) {
353
      case HA_READ_KEY_EXACT:
354
      case HA_READ_KEY_OR_NEXT:
355
      case HA_READ_BEFORE_KEY:
356
	last_equal_element= parents;
357
	cmp= 1;
358
	break;
359
      case HA_READ_AFTER_KEY:
360
	cmp= -1;
361
	break;
362
      case HA_READ_PREFIX_LAST:
363
      case HA_READ_PREFIX_LAST_OR_PREV:
364
	last_equal_element= parents;
365
	cmp= -1;
366
	break;
367
      default:
368
	return NULL;
369
      }
370
    }
371
    if (cmp < 0) /* element < key */
372
    {
373
      last_right_step_parent= parents;
374
      element= element->right;
375
    }
376
    else
377
    {
378
      last_left_step_parent= parents;
379
      element= element->left;
380
    }
381
  }
382
  switch (flag) {
383
  case HA_READ_KEY_EXACT:
384
  case HA_READ_PREFIX_LAST:
385
    *last_pos= last_equal_element;
386
    break;
387
  case HA_READ_KEY_OR_NEXT:
388
    *last_pos= last_equal_element ? last_equal_element : last_left_step_parent;
389
    break;
390
  case HA_READ_AFTER_KEY:
391
    *last_pos= last_left_step_parent;
392
    break;
393
  case HA_READ_PREFIX_LAST_OR_PREV:
394
    *last_pos= last_equal_element ? last_equal_element : last_right_step_parent;
395
    break;
396
  case HA_READ_BEFORE_KEY:
397
    *last_pos= last_right_step_parent;
398
    break;
399
  default:
400
    return NULL;
401
  }
402
403
  return *last_pos ? ELEMENT_KEY(tree, **last_pos) : NULL;
404
}
405
406
/*
407
  Search first (the most left) or last (the most right) tree element
408
*/
409
void *tree_search_edge(TREE *tree, TREE_ELEMENT **parents,
410
		       TREE_ELEMENT ***last_pos, int child_offs)
411
{
412
  TREE_ELEMENT *element= tree->root;
413
414
  *parents= &tree->null_element;
415
  while (element != &tree->null_element)
416
  {
417
    *++parents= element;
418
    element= ELEMENT_CHILD(element, child_offs);
419
  }
420
  *last_pos= parents;
421
  return **last_pos != &tree->null_element ?
422
    ELEMENT_KEY(tree, **last_pos) : NULL;
423
}
424
425
void *tree_search_next(TREE *tree, TREE_ELEMENT ***last_pos, int l_offs,
426
                       int r_offs)
427
{
428
  TREE_ELEMENT *x= **last_pos;
429
430
  if (ELEMENT_CHILD(x, r_offs) != &tree->null_element)
431
  {
432
    x= ELEMENT_CHILD(x, r_offs);
433
    *++*last_pos= x;
434
    while (ELEMENT_CHILD(x, l_offs) != &tree->null_element)
435
    {
436
      x= ELEMENT_CHILD(x, l_offs);
437
      *++*last_pos= x;
438
    }
439
    return ELEMENT_KEY(tree, x);
440
  }
441
  else
442
  {
443
    TREE_ELEMENT *y= *--*last_pos;
444
    while (y != &tree->null_element && x == ELEMENT_CHILD(y, r_offs))
445
    {
446
      x= y;
447
      y= *--*last_pos;
448
    }
449
    return y == &tree->null_element ? NULL : ELEMENT_KEY(tree, y);
450
  }
451
}
452
453
/*
454
  Expected that tree is fully balanced
455
  (each path from root to leaf has the same length)
456
*/
457
ha_rows tree_record_pos(TREE *tree, const void *key,
458
			enum ha_rkey_function flag, void *custom_arg)
459
{
460
  TREE_ELEMENT *element= tree->root;
461
  double left= 1;
462
  double right= tree->elements_in_tree;
463
464
  while (element != &tree->null_element)
465
  {
466
    int cmp;
467
468
    if ((cmp= (*tree->compare)(custom_arg, ELEMENT_KEY(tree, element),
469
			       key)) == 0)
470
    {
471
      switch (flag) {
472
      case HA_READ_KEY_EXACT:
473
      case HA_READ_BEFORE_KEY:
474
        cmp= 1;
475
        break;
476
      case HA_READ_AFTER_KEY:
477
        cmp= -1;
478
        break;
479
      default:
480
        return HA_POS_ERROR;
481
      }
482
    }
483
    if (cmp < 0) /* element < key */
484
    {
485
      element= element->right;
486
      left= (left + right) / 2;
487
    }
488
    else
489
    {
490
      element= element->left;
491
      right= (left + right) / 2;
492
    }
493
  }
494
495
  switch (flag) {
496
  case HA_READ_KEY_EXACT:
497
  case HA_READ_BEFORE_KEY:
498
    return (ha_rows) right;
499
  case HA_READ_AFTER_KEY:
500
    return (ha_rows) left;
501
  default:
502
    return HA_POS_ERROR;
503
  }
504
}
505
506
int tree_walk(TREE *tree, tree_walk_action action, void *argument, TREE_WALK visit)
507
{
508
  switch (visit) {
509
  case left_root_right:
510
    return tree_walk_left_root_right(tree,tree->root,action,argument);
511
  case right_root_left:
512
    return tree_walk_right_root_left(tree,tree->root,action,argument);
513
  }
514
515
  return 0;			/* Keep gcc happy */
516
}
517
518
static int tree_walk_left_root_right(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument)
519
{
520
  int error;
521
  if (element->left)				/* Not null_element */
522
  {
523
    if ((error=tree_walk_left_root_right(tree,element->left,action,
524
					  argument)) == 0 &&
525
	(error=(*action)(ELEMENT_KEY(tree,element),
526
			  element->count,
527
			  argument)) == 0)
528
      error=tree_walk_left_root_right(tree,element->right,action,argument);
529
    return error;
530
  }
531
532
  return 0;
533
}
534
535
static int tree_walk_right_root_left(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument)
536
{
537
  int error;
538
  if (element->right)				/* Not null_element */
539
  {
540
    if ((error=tree_walk_right_root_left(tree,element->right,action,
541
					  argument)) == 0 &&
542
	(error=(*action)(ELEMENT_KEY(tree,element),
543
			  element->count,
544
			  argument)) == 0)
545
     error=tree_walk_right_root_left(tree,element->left,action,argument);
546
    return error;
547
  }
548
549
  return 0;
550
}
551
552
553
/* Functions to fix up the tree after insert and delete */
554
555
static void left_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf)
556
{
557
  TREE_ELEMENT *y;
558
559
  y= leaf->right;
560
  leaf->right= y->left;
561
  parent[0]= y;
562
  y->left= leaf;
563
}
564
565
static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf)
566
{
567
  TREE_ELEMENT *x;
568
569
  x= leaf->left;
570
  leaf->left= x->right;
571
  parent[0]= x;
572
  x->right= leaf;
573
}
574
575
static void rb_insert(TREE *tree, TREE_ELEMENT ***parent, TREE_ELEMENT *leaf)
576
{
577
  TREE_ELEMENT *y,*par,*par2;
578
579
  leaf->colour=RED;
580
  while (leaf != tree->root && (par=parent[-1][0])->colour == RED)
581
  {
582
    if (par == (par2=parent[-2][0])->left)
583
    {
584
      y= par2->right;
585
      if (y->colour == RED)
586
      {
587
	par->colour= BLACK;
588
	y->colour= BLACK;
589
	leaf= par2;
590
	parent-= 2;
591
	leaf->colour= RED;		/* And the loop continues */
592
      }
593
      else
594
      {
595
	if (leaf == par->right)
596
	{
597
	  left_rotate(parent[-1],par);
598
	  par= leaf;			/* leaf is now parent to old leaf */
599
	}
600
	par->colour= BLACK;
601
	par2->colour= RED;
602
	right_rotate(parent[-2],par2);
603
	break;
604
      }
605
    }
606
    else
607
    {
608
      y= par2->left;
609
      if (y->colour == RED)
610
      {
611
	par->colour= BLACK;
612
	y->colour= BLACK;
613
	leaf= par2;
614
	parent-= 2;
615
	leaf->colour= RED;		/* And the loop continues */
616
      }
617
      else
618
      {
619
	if (leaf == par->left)
620
	{
621
	  right_rotate(parent[-1],par);
622
	  par= leaf;
623
	}
624
	par->colour= BLACK;
625
	par2->colour= RED;
626
	left_rotate(parent[-2],par2);
627
	break;
628
      }
629
    }
630
  }
631
  tree->root->colour=BLACK;
632
}
633
634
static void rb_delete_fixup(TREE *tree, TREE_ELEMENT ***parent)
635
{
636
  TREE_ELEMENT *x,*w,*par;
637
638
  x= **parent;
639
  while (x != tree->root && x->colour == BLACK)
640
  {
641
    if (x == (par=parent[-1][0])->left)
642
    {
643
      w= par->right;
644
      if (w->colour == RED)
645
      {
646
	w->colour= BLACK;
647
	par->colour= RED;
648
	left_rotate(parent[-1],par);
649
	parent[0]= &w->left;
650
	*++parent= &par->left;
651
	w= par->right;
652
      }
653
      if (w->left->colour == BLACK && w->right->colour == BLACK)
654
      {
655
	w->colour= RED;
656
	x= par;
657
	parent--;
658
      }
659
      else
660
      {
661
	if (w->right->colour == BLACK)
662
	{
663
	  w->left->colour= BLACK;
664
	  w->colour= RED;
665
	  right_rotate(&par->right,w);
666
	  w= par->right;
667
	}
668
	w->colour= par->colour;
669
	par->colour= BLACK;
670
	w->right->colour= BLACK;
671
	left_rotate(parent[-1],par);
672
	x= tree->root;
673
	break;
674
      }
675
    }
676
    else
677
    {
678
      w=par->left;
679
      if (w->colour == RED)
680
      {
681
	w->colour= BLACK;
682
	par->colour= RED;
683
	right_rotate(parent[-1],par);
684
	parent[0]= &w->right;
685
	*++parent= &par->right;
686
	w= par->left;
687
      }
688
      if (w->right->colour == BLACK && w->left->colour == BLACK)
689
      {
690
	w->colour= RED;
691
	x= par;
692
	parent--;
693
      }
694
      else
695
      {
696
	if (w->left->colour == BLACK)
697
	{
698
	  w->right->colour= BLACK;
699
	  w->colour= RED;
700
	  left_rotate(&par->left,w);
701
	  w= par->left;
702
	}
703
	w->colour= par->colour;
704
	par->colour= BLACK;
705
	w->left->colour= BLACK;
706
	right_rotate(parent[-1],par);
707
	x= tree->root;
708
	break;
709
      }
710
    }
711
  }
712
  x->colour= BLACK;
713
}
714
715
} /* namespace drizzled */