Quelle hp_create.c
Sprache: C
/* Copyright (c) 2000, 2018, Oracle and/or its affiliates.
Copyright ( c ) 2010 , 2020 , MariaDB Corporation .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
#include "heapdef.h"
#include "my_compare.h"
#include <my_bit.h>
static int keys_compare(void *heap_rb, const void *key1, const void *key2);
static void init_block(HP_BLOCK *block, size_t reclength, ulong min_records,
ulong max_records);
/*
In how many parts are we going to do allocations of memory and indexes
If we assign 1 M to the heap table memory , we will allocate roughly
( 1 M / 16 ) bytes per allocation
*/
static const int heap_allocation_parts= 16 ;
/* min block allocation */
static const ulong heap_min_allocation_block= 16384 ;
/* Create a heap table */
int heap_create(const char *name, HP_CREATE_INFO *create_info,
HP_SHARE **res, my_bool *created_new_share)
{
uint i, j, key_segs, max_length, length;
HP_SHARE *share= 0 ;
HA_KEYSEG *keyseg;
HP_KEYDEF *keydef= create_info->keydef;
uint reclength= create_info->reclength;
uint keys= create_info->keys;
ulong min_records= create_info->min_records;
ulong max_records= create_info->max_records;
uint visible_offset;
DBUG_ENTER("heap_create" );
if (!create_info->internal_table)
{
mysql_mutex_lock(&THR_LOCK_heap);
share= hp_find_named_heap(name);
if (share && share->open_count == 0 )
{
hp_free(share);
share= 0 ;
}
}
else
{
DBUG_PRINT("info" , ("Creating internal (no named) temporary table" ));
}
*created_new_share= (share == NULL);
if (!share)
{
HP_KEYDEF *keyinfo;
DBUG_PRINT("info" ,("Initializing new table" ));
/*
We have to store sometimes uchar * del_link in records ,
so the visible_offset must be least at sizeof ( uchar * )
*/
visible_offset= MY_MAX(reclength, sizeof (char *));
for (i= key_segs= max_length= 0 , keyinfo= keydef; i < keys; i++, keyinfo++)
{
bzero((char *) &keyinfo->block,sizeof (keyinfo->block));
bzero((char *) &keyinfo->rb_tree ,sizeof (keyinfo->rb_tree));
for (j= length= 0 ; j < keyinfo->keysegs; j++)
{
length+= keyinfo->seg[j].length;
if (keyinfo->seg[j].null_bit)
{
length++;
if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
keyinfo->flag|= HA_NULL_PART_KEY;
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
keyinfo->rb_tree.size_of_element++;
}
switch (keyinfo->seg[j].type) {
case HA_KEYTYPE_SHORT_INT:
case HA_KEYTYPE_LONG_INT:
case HA_KEYTYPE_FLOAT:
case HA_KEYTYPE_DOUBLE:
case HA_KEYTYPE_USHORT_INT:
case HA_KEYTYPE_ULONG_INT:
case HA_KEYTYPE_LONGLONG:
case HA_KEYTYPE_ULONGLONG:
case HA_KEYTYPE_INT24:
case HA_KEYTYPE_UINT24:
case HA_KEYTYPE_INT8:
keyinfo->seg[j].flag|= HA_SWAP_KEY;
break ;
case HA_KEYTYPE_VARBINARY1:
/* Case-insensitiveness is handled in hash_sort */
keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
/* fall through */
case HA_KEYTYPE_VARTEXT1:
keyinfo->flag|= HA_VAR_LENGTH_KEY;
/*
For BTREE algorithm , key length , greater than or equal
to 255 , is packed on 3 bytes .
*/
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
length+= size_to_store_key_length(keyinfo->seg[j].length);
else
length+= 2 ;
/* Save number of bytes used to store length */
keyinfo->seg[j].bit_start= 1 ;
break ;
case HA_KEYTYPE_VARBINARY2:
/* Case-insensitiveness is handled in hash_sort */
/* fall_through */
case HA_KEYTYPE_VARTEXT2:
keyinfo->flag|= HA_VAR_LENGTH_KEY;
/*
For BTREE algorithm , key length , greater than or equal
to 255 , is packed on 3 bytes .
*/
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
length+= size_to_store_key_length(keyinfo->seg[j].length);
else
length+= 2 ;
/* Save number of bytes used to store length */
keyinfo->seg[j].bit_start= 2 ;
/*
Make future comparison simpler by only having to check for
one type
*/
keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
break ;
case HA_KEYTYPE_BIT:
/*
The odd bits which stored separately ( if they are present
( bit_pos , bit_length ) ) are already present in seg [ j ] . length as
additional byte .
See field . h , function key_length ( )
*/
break ;
default :
break ;
}
}
keyinfo->length= length;
length+= keyinfo->rb_tree.size_of_element +
((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof (uchar*) : 0 );
if (length > max_length)
max_length= length;
key_segs+= keyinfo->keysegs;
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
{
key_segs++; /* additional HA_KEYTYPE_END segment */
if (keyinfo->flag & HA_VAR_LENGTH_KEY)
keyinfo->get_key_length= hp_rb_var_key_length;
else if (keyinfo->flag & HA_NULL_PART_KEY)
keyinfo->get_key_length= hp_rb_null_key_length;
else
keyinfo->get_key_length= hp_rb_key_length;
}
}
if (!(share= (HP_SHARE*) my_malloc(hp_key_memory_HP_SHARE,
sizeof (HP_SHARE)+
keys*sizeof (HP_KEYDEF)+
key_segs*sizeof (HA_KEYSEG),
MYF(MY_ZEROFILL |
(create_info->internal_table ?
MY_THREAD_SPECIFIC : 0 )))))
goto err;
share->keydef= (HP_KEYDEF*) (share + 1 );
share->key_stat_version= 1 ;
keyseg= (HA_KEYSEG*) (share->keydef + keys);
init_block(&share->block, hp_memory_needed_per_row(reclength),
min_records, max_records);
/* Fix keys */
memcpy(share->keydef, keydef, (size_t) (sizeof (keydef[0 ]) * keys));
for (i= 0 , keyinfo= share->keydef; i < keys; i++, keyinfo++)
{
keyinfo->seg= keyseg;
memcpy(keyseg, keydef[i].seg,
(size_t) (sizeof (keyseg[0 ]) * keydef[i].keysegs));
keyseg+= keydef[i].keysegs;
if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
{
/* additional HA_KEYTYPE_END keyseg */
keyseg->type= HA_KEYTYPE_END;
keyseg->length= sizeof (uchar*);
keyseg->flag= 0 ;
keyseg->null_bit= 0 ;
keyseg++;
init_tree(&keyinfo->rb_tree, 0 , 0 , sizeof (uchar*),
keys_compare, NULL, NULL,
MYF((create_info->internal_table ? MY_THREAD_SPECIFIC : 0 ) |
MY_TREE_WITH_DELETE));
keyinfo->delete_key= hp_rb_delete_key;
keyinfo->write_key= hp_rb_write_key;
}
else
{
init_block(&keyinfo->block, sizeof (HASH_INFO), min_records,
max_records);
keyinfo->delete_key= hp_delete_key;
keyinfo->write_key= hp_write_key;
keyinfo->hash_buckets= 0 ;
}
if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
share->auto_key= i + 1 ;
}
share->min_records= min_records;
share->max_records= max_records;
share->max_table_size= create_info->max_table_size;
share->data_length= share->index_length= 0 ;
share->reclength= reclength;
share->visible= visible_offset;
share->blength= 1 ;
share->keys= keys;
share->max_key_length= max_length;
share->changed= 0 ;
share->auto_key= create_info->auto_key;
share->auto_key_type= create_info->auto_key_type;
share->auto_increment= create_info->auto_increment;
share->create_time= (long ) time((time_t*) 0 );
share->internal= create_info->internal_table;
/* Must be allocated separately for rename to work */
if (!(share->name= my_strdup(hp_key_memory_HP_SHARE, name, MYF(0 ))))
{
my_free(share);
goto err;
}
if (!create_info->internal_table)
{
thr_lock_init(&share->lock);
share->open_list.data= (void *) share;
heap_share_list= list_add(heap_share_list,&share->open_list);
}
else
share->delete_on_close= 1 ;
}
if (!create_info->internal_table)
{
if (create_info->pin_share)
++share->open_count;
mysql_mutex_unlock(&THR_LOCK_heap);
}
*res= share;
DBUG_RETURN(0 );
err:
if (!create_info->internal_table)
mysql_mutex_unlock(&THR_LOCK_heap);
DBUG_RETURN(1 );
} /* heap_create */
static int keys_compare(void *heap_rb_, const void *key1_,
const void *key2_)
{
heap_rb_param *heap_rb= heap_rb_;
const uchar *key1= key1_;
const uchar *key2= key2_;
uint not_used[2 ];
return ha_key_cmp(heap_rb->keyseg, key1, key2, heap_rb->key_length,
heap_rb->search_flag, not_used);
}
/*
Calculate length needed for storing one row
*/
size_t hp_memory_needed_per_row(size_t reclength)
{
/* Data needed for storing record + pointer to records */
reclength= MY_MAX(reclength, sizeof (char *));
/* The + 1 below is for the delete marker at the end of record*/
reclength= MY_ALIGN(reclength+1 , sizeof (char *));
return reclength;
}
/*
Calculate the number of rows that fits into a given memory size
*/
ha_rows hp_rows_in_memory(size_t reclength, size_t index_size,
size_t memory_limit)
{
reclength= hp_memory_needed_per_row(reclength);
if ((memory_limit < index_size + reclength + sizeof (HP_PTRS)))
return 0 ; /* Wrong arguments */
return (ha_rows) ((memory_limit - sizeof (HP_PTRS)) /
(index_size + reclength));
}
static void init_block(HP_BLOCK *block, size_t reclength, ulong min_records,
ulong max_records)
{
ulong i,records_in_block;
ulong recbuffer= (ulong) MY_ALIGN(reclength, sizeof (uchar*));
ulong extra;
ulonglong memory_needed;
size_t alloc_size;
/*
If not min_records and max_records are given , optimize for 1000 rows
*/
if (!min_records)
min_records= MY_MIN(1000 , max_records / heap_allocation_parts);
if (!max_records)
max_records= MY_MAX(min_records, 1000 );
min_records= MY_MIN(min_records, max_records);
/*
We don ' t want too few records_in_block as otherwise the overhead of
of the HP_PTRS block will be too notable
*/
records_in_block= MY_MAX(min_records, max_records / heap_allocation_parts);
/*
Align allocation sizes to power of 2 to get less memory fragmentation from
system alloc ( ) .
As long as we have less than 128 allocations , all but one of the
allocations will have an extra HP_PTRS size structure at the start
of the block .
We ensure that the block is not smaller than heap_min_allocation_block
as otherwise we get strange results when max_records <
heap_allocation_parts )
*/
extra= sizeof (HP_PTRS) + MALLOC_OVERHEAD;
/* We don't want too few blocks per row either */
if (records_in_block < 10 )
records_in_block= MY_MIN(10 , max_records);
memory_needed= MY_MAX(((ulonglong) records_in_block * recbuffer + extra),
(ulonglong) heap_min_allocation_block);
/* We have to limit memory to INT_MAX32 as my_round_up_to_next_power() is 32 bit */
memory_needed= MY_MIN(memory_needed, (ulonglong) INT_MAX32);
alloc_size= my_round_up_to_next_power((uint32)memory_needed);
records_in_block= (ulong) ((alloc_size - extra)/ recbuffer);
DBUG_PRINT("info" , ("records_in_block: %lu" ,records_in_block));
block->records_in_block= records_in_block;
block->recbuffer= recbuffer;
block->last_allocated= 0 L;
/* All allocations are done with this size, if possible */
block->alloc_size= alloc_size - MALLOC_OVERHEAD;
for (i= 0 ; i <= HP_MAX_LEVELS; i++)
block->level_info[i].records_under_level=
(!i ? 1 : i == 1 ? records_in_block :
HP_PTRS_IN_NOD * block->level_info[i - 1 ].records_under_level);
}
static inline void heap_try_free(HP_SHARE *share)
{
DBUG_ENTER("heap_try_free" );
if (share->open_count == 0 )
hp_free(share);
else
{
DBUG_PRINT("info" , ("Table is still in use. Will be freed on close" ));
share->delete_on_close= 1 ;
}
DBUG_VOID_RETURN;
}
int heap_delete_table(const char *name)
{
int result;
reg1 HP_SHARE *share;
DBUG_ENTER("heap_delete_table" );
mysql_mutex_lock(&THR_LOCK_heap);
if ((share= hp_find_named_heap(name)))
{
heap_try_free(share);
result= 0 ;
}
else
{
result= my_errno=ENOENT;
DBUG_PRINT("error" , ("Could not find table '%s'" , name));
}
mysql_mutex_unlock(&THR_LOCK_heap);
DBUG_RETURN(result);
}
void heap_drop_table(HP_INFO *info)
{
DBUG_ENTER("heap_drop_table" );
mysql_mutex_lock(&THR_LOCK_heap);
heap_try_free(info->s);
mysql_mutex_unlock(&THR_LOCK_heap);
DBUG_VOID_RETURN;
}
void hp_free(HP_SHARE *share)
{
if (!share->internal)
{
heap_share_list= list_delete(heap_share_list, &share->open_list);
thr_lock_delete(&share->lock);
}
hp_clear(share); /* Remove blocks from memory */
my_free(share->name);
my_free(share);
return ;
}
Messung V0.5 in Prozent C=93 H=91 G=91
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland
2026-10-10
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1126438
#Domains=1867298