1
/* Copyright (C) 2000-2002, 2004 MySQL AB
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.
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.
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
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
/* functions on blocks; Keys and records are saved in blocks */
18
#include "heap_priv.h"
23
Find record according to record-position.
25
The record is located by factoring position number pos into (p_0, p_1, ...)
27
pos = SUM_i(block->level_info[i].records_under_level * p_i)
28
{p_0, p_1, ...} serve as indexes to descend the blocks tree.
31
unsigned char *hp_find_block(HP_BLOCK *block, uint32_t pos)
34
HP_PTRS *ptr; /* block base ptr */
36
for (i= block->levels-1, ptr=block->root ; i > 0 ; i--)
38
ptr=(HP_PTRS*)ptr->blocks[pos/block->level_info[i].records_under_level];
39
pos%=block->level_info[i].records_under_level;
41
return (unsigned char*) ptr+ pos*block->recbuffer;
46
Get one new block-of-records. Alloc ptr to block if needed
50
block HP_BLOCK tree-like block
51
alloc_length OUT Amount of memory allocated from the heap
53
Interrupts are stopped to allow ha_panic in interrupts
59
int hp_get_new_block(HP_BLOCK *block, size_t *alloc_length)
64
for (i=0 ; i < block->levels ; i++)
65
if (block->level_info[i].free_ptrs_in_block)
69
Allocate space for leaf block plus space for upper level blocks up to
70
first level that has a free slot to put the pointer.
71
In some cases we actually allocate more then we need:
72
Consider e.g. a situation where we have one level 1 block and one level 0
73
block, the level 0 block is full and this function is called. We only
74
need a leaf block in this case. Nevertheless, we will get here with i=1
75
and will also allocate sizeof(HP_PTRS) for non-leaf block and will never
77
This doesn't add much overhead - with current values of sizeof(HP_PTRS)
78
and my_default_record_cache_size we get about 1/128 unused memory.
80
*alloc_length=sizeof(HP_PTRS)*i+block->records_in_block* block->recbuffer;
81
if (!(root=(HP_PTRS*) malloc(*alloc_length)))
87
block->root=block->level_info[0].last_blocks=root;
91
if ((uint) i == block->levels)
93
/* Adding a new level on top of the existing ones. */
96
Use first allocated HP_PTRS as a top-level block. Put the current
97
block tree into the first slot of a new top-level block.
99
block->level_info[i].free_ptrs_in_block=HP_PTRS_IN_NOD-1;
100
((HP_PTRS**) root)[0]= block->root;
101
block->root=block->level_info[i].last_blocks= root++;
103
/* Occupy the free slot we've found at level i */
104
block->level_info[i].last_blocks->
105
blocks[HP_PTRS_IN_NOD - block->level_info[i].free_ptrs_in_block--]=
106
(unsigned char*) root;
108
/* Add a block subtree with each node having one left-most child */
109
for (uint32_t j= i-1 ; j >0 ; j--)
111
block->level_info[j].last_blocks= root++;
112
block->level_info[j].last_blocks->blocks[0]=(unsigned char*) root;
113
block->level_info[j].free_ptrs_in_block=HP_PTRS_IN_NOD-1;
117
root now points to last (block->records_in_block* block->recbuffer)
118
allocated bytes. Use it as a leaf block.
120
block->level_info[0].last_blocks= root;
126
/* free all blocks under level */
128
unsigned char *hp_free_level(HP_BLOCK *block, uint32_t level, HP_PTRS *pos, unsigned char *last_pos)
131
unsigned char *next_ptr;
135
next_ptr=(unsigned char*) pos+block->recbuffer;
139
max_pos= (block->level_info[level-1].last_blocks == pos) ?
140
HP_PTRS_IN_NOD - block->level_info[level-1].free_ptrs_in_block :
143
next_ptr=(unsigned char*) (pos+1);
144
for (int i= 0; i < max_pos ; i++)
145
next_ptr=hp_free_level(block,level-1,
146
(HP_PTRS*) pos->blocks[i],next_ptr);
149
if ((unsigned char*) pos != last_pos)
151
free((unsigned char*) pos);
154
return next_ptr; /* next memory position */