mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Add new user variables for tuning memory usage:
query_alloc_block_size, query_prealloc_size, range_alloc_block_size,transaction_alloc_block_size and transaction_prealloc_size Add more checks for "out of memory" detection in range optimization
This commit is contained in:
110
sql/opt_range.cc
110
sql/opt_range.cc
@ -280,6 +280,7 @@ public:
|
||||
|
||||
|
||||
typedef struct st_qsel_param {
|
||||
THD *thd;
|
||||
TABLE *table;
|
||||
KEY_PART *key_parts,*key_parts_end,*key[MAX_KEY];
|
||||
MEM_ROOT *mem_root;
|
||||
@ -382,13 +383,14 @@ SQL_SELECT::~SQL_SELECT()
|
||||
|
||||
#undef index // Fix for Unixware 7
|
||||
|
||||
QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc)
|
||||
QUICK_SELECT::QUICK_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc)
|
||||
:dont_free(0),error(0),index(key_nr),max_used_key_length(0),head(table),
|
||||
it(ranges),range(0)
|
||||
{
|
||||
if (!no_alloc)
|
||||
{
|
||||
init_sql_alloc(&alloc,1024,0); // Allocates everything here
|
||||
// Allocates everything through the internal memroot
|
||||
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
|
||||
my_pthread_setspecific_ptr(THR_MALLOC,&alloc);
|
||||
}
|
||||
else
|
||||
@ -460,17 +462,17 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
|
||||
SEL_ARG *tmp;
|
||||
if (type != KEY_RANGE)
|
||||
{
|
||||
if(!(tmp=new SEL_ARG(type)))
|
||||
return 0; // out of memory
|
||||
if (!(tmp= new SEL_ARG(type)))
|
||||
return 0; // out of memory
|
||||
tmp->prev= *next_arg; // Link into next/prev chain
|
||||
(*next_arg)->next=tmp;
|
||||
(*next_arg)= tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!(tmp=new SEL_ARG(field,part, min_value,max_value,
|
||||
min_flag, max_flag, maybe_flag)))
|
||||
return 0; // out of memory
|
||||
if (!(tmp= new SEL_ARG(field,part, min_value,max_value,
|
||||
min_flag, max_flag, maybe_flag)))
|
||||
return 0; // OOM
|
||||
tmp->parent=new_parent;
|
||||
tmp->next_key_part=next_key_part;
|
||||
if (left != &null_element)
|
||||
@ -481,7 +483,8 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
|
||||
(*next_arg)= tmp;
|
||||
|
||||
if (right != &null_element)
|
||||
tmp->right=right->clone(tmp,next_arg);
|
||||
if (!(tmp->right= right->clone(tmp,next_arg)))
|
||||
return 0; // OOM
|
||||
}
|
||||
increment_use_count(1);
|
||||
return tmp;
|
||||
@ -560,10 +563,11 @@ SEL_ARG *SEL_ARG::clone_tree()
|
||||
{
|
||||
SEL_ARG tmp_link,*next_arg,*root;
|
||||
next_arg= &tmp_link;
|
||||
root=clone((SEL_ARG *) 0, &next_arg);
|
||||
root= clone((SEL_ARG *) 0, &next_arg);
|
||||
next_arg->next=0; // Fix last link
|
||||
tmp_link.next->prev=0; // Fix first link
|
||||
root->use_count=0;
|
||||
if (root) // If not OOM
|
||||
root->use_count= 0;
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -581,7 +585,8 @@ SEL_ARG *SEL_ARG::clone_tree()
|
||||
** quick_rows ; How many rows the key matches
|
||||
*****************************************************************************/
|
||||
|
||||
int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
|
||||
int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
||||
table_map prev_tables,
|
||||
ha_rows limit, bool force_quick_range)
|
||||
{
|
||||
uint basflag;
|
||||
@ -624,6 +629,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
|
||||
PARAM param;
|
||||
|
||||
/* set up parameter that is passed to all functions */
|
||||
param.thd= thd;
|
||||
param.baseflag=basflag;
|
||||
param.prev_tables=prev_tables | const_tables;
|
||||
param.read_tables=read_tables;
|
||||
@ -632,13 +638,13 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
|
||||
param.keys=0;
|
||||
param.mem_root= &alloc;
|
||||
|
||||
current_thd->no_errors=1; // Don't warn about NULL
|
||||
init_sql_alloc(&alloc,2048,0);
|
||||
param.thd->no_errors=1; // Don't warn about NULL
|
||||
init_sql_alloc(&alloc, param.thd->variables.range_alloc_block_size, 0);
|
||||
if (!(param.key_parts = (KEY_PART*) alloc_root(&alloc,
|
||||
sizeof(KEY_PART)*
|
||||
head->key_parts)))
|
||||
{
|
||||
current_thd->no_errors=0;
|
||||
param.thd->no_errors=0;
|
||||
free_root(&alloc,MYF(0)); // Return memory & allocator
|
||||
DBUG_RETURN(0); // Can't use range
|
||||
}
|
||||
@ -737,7 +743,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
|
||||
}
|
||||
free_root(&alloc,MYF(0)); // Return memory & allocator
|
||||
my_pthread_setspecific_ptr(THR_MALLOC,old_root);
|
||||
current_thd->no_errors=0;
|
||||
param.thd->no_errors=0;
|
||||
}
|
||||
DBUG_EXECUTE("info",print_quick(quick,needed_reg););
|
||||
/*
|
||||
@ -765,7 +771,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
||||
while ((item=li++))
|
||||
{
|
||||
SEL_TREE *new_tree=get_mm_tree(param,item);
|
||||
if(current_thd->fatal_error)
|
||||
if (param->thd->fatal_error)
|
||||
DBUG_RETURN(0); // out of memory
|
||||
tree=tree_and(param,tree,new_tree);
|
||||
if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
|
||||
@ -906,7 +912,7 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
|
||||
{
|
||||
SEL_ARG *sel_arg=0;
|
||||
if (!tree && !(tree=new SEL_TREE()))
|
||||
DBUG_RETURN(0); // out of memory
|
||||
DBUG_RETURN(0); // OOM
|
||||
if (!value || !(value->used_tables() & ~param->read_tables))
|
||||
{
|
||||
sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value);
|
||||
@ -918,10 +924,11 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
|
||||
DBUG_RETURN(tree);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
// This key may be used later
|
||||
if(!(sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY)))
|
||||
DBUG_RETURN(0); // out of memory
|
||||
if (!(sel_arg= new SEL_ARG(SEL_ARG::MAYBE_KEY)))
|
||||
DBUG_RETURN(0); // OOM
|
||||
}
|
||||
sel_arg->part=(uchar) key_part->part;
|
||||
tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg);
|
||||
@ -1164,8 +1171,8 @@ static bool like_range(const char *ptr,uint ptr_length,char escape,
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
** Add a new key test to a key when scanning through all keys
|
||||
** This will never be called for same key parts.
|
||||
Add a new key test to a key when scanning through all keys
|
||||
This will never be called for same key parts.
|
||||
*/
|
||||
|
||||
static SEL_ARG *
|
||||
@ -1349,7 +1356,8 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
|
||||
// key1->part < key2->part
|
||||
key1->use_count--;
|
||||
if (key1->use_count > 0)
|
||||
key1=key1->clone_tree();
|
||||
if (!(key1= key1->clone_tree()))
|
||||
return 0; // OOM
|
||||
return and_all_keys(key1,key2,clone_flag);
|
||||
}
|
||||
|
||||
@ -1368,7 +1376,8 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
|
||||
if (key1->use_count > 1)
|
||||
{
|
||||
key1->use_count--;
|
||||
key1=key1->clone_tree();
|
||||
if (!(key1=key1->clone_tree()))
|
||||
return 0; // OOM
|
||||
key1->use_count++;
|
||||
}
|
||||
if (key1->type == SEL_ARG::MAYBE_KEY)
|
||||
@ -1412,6 +1421,8 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
|
||||
if (!next || next->type != SEL_ARG::IMPOSSIBLE)
|
||||
{
|
||||
SEL_ARG *new_arg= e1->clone_and(e2);
|
||||
if (!new_arg)
|
||||
return &null_element; // End of memory
|
||||
new_arg->next_key_part=next;
|
||||
if (!new_tree)
|
||||
{
|
||||
@ -1499,8 +1510,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
|
||||
{
|
||||
swap(SEL_ARG *,key1,key2);
|
||||
}
|
||||
else
|
||||
key1=key1->clone_tree();
|
||||
else if (!(key1=key1->clone_tree()))
|
||||
return 0; // OOM
|
||||
}
|
||||
|
||||
// Add tree at key2 to tree at key1
|
||||
@ -1526,7 +1537,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
|
||||
SEL_ARG *key2_next=key2->next;
|
||||
if (key2_shared)
|
||||
{
|
||||
if(!(key2=new SEL_ARG(*key2)))
|
||||
if (!(key2=new SEL_ARG(*key2)))
|
||||
return 0; // out of memory
|
||||
key2->increment_use_count(key1->use_count+1);
|
||||
key2->next=key2_next; // New copy of key2
|
||||
@ -1568,7 +1579,10 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
|
||||
SEL_ARG *next=key2->next; // Keys are not overlapping
|
||||
if (key2_shared)
|
||||
{
|
||||
key1=key1->insert(new SEL_ARG(*key2)); // Must make copy
|
||||
SEL_ARG *tmp= new SEL_ARG(*key2); // Must make copy
|
||||
if (!tmp)
|
||||
return 0; // OOM
|
||||
key1=key1->insert(tmp);
|
||||
key2->increment_use_count(key1->use_count+1);
|
||||
}
|
||||
else
|
||||
@ -1614,6 +1628,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
|
||||
if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0)
|
||||
{ // tmp.min <= x < key2.min
|
||||
SEL_ARG *new_arg=tmp->clone_first(key2);
|
||||
if (!new_arg)
|
||||
return 0; // OOM
|
||||
if ((new_arg->next_key_part= key1->next_key_part))
|
||||
new_arg->increment_use_count(key1->use_count+1);
|
||||
tmp->copy_min_to_min(key2);
|
||||
@ -1627,6 +1643,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
|
||||
if (tmp->cmp_min_to_min(&key) > 0)
|
||||
{ // key.min <= x < tmp.min
|
||||
SEL_ARG *new_arg=key.clone_first(tmp);
|
||||
if (!new_arg)
|
||||
return 0; // OOM
|
||||
if ((new_arg->next_key_part=key.next_key_part))
|
||||
new_arg->increment_use_count(key1->use_count+1);
|
||||
key1=key1->insert(new_arg);
|
||||
@ -1641,19 +1659,27 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
|
||||
key.copy_max_to_min(tmp);
|
||||
if (!(tmp=tmp->next))
|
||||
{
|
||||
key1=key1->insert(new SEL_ARG(key));
|
||||
SEL_ARG *tmp2= new SEL_ARG(key);
|
||||
if (!tmp2)
|
||||
return 0; // OOM
|
||||
key1=key1->insert(tmp2);
|
||||
key2=key2->next;
|
||||
goto end;
|
||||
}
|
||||
if (tmp->cmp_min_to_max(&key) > 0)
|
||||
{
|
||||
key1=key1->insert(new SEL_ARG(key));
|
||||
SEL_ARG *tmp2= new SEL_ARG(key);
|
||||
if (!tmp2)
|
||||
return 0; // OOM
|
||||
key1=key1->insert(tmp2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SEL_ARG *new_arg=tmp->clone_last(&key); // tmp.min <= x <= key.max
|
||||
if (!new_arg)
|
||||
return 0; // OOM
|
||||
tmp->copy_max_to_min(&key);
|
||||
tmp->increment_use_count(key1->use_count+1);
|
||||
new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part);
|
||||
@ -1670,8 +1696,11 @@ end:
|
||||
SEL_ARG *next=key2->next;
|
||||
if (key2_shared)
|
||||
{
|
||||
SEL_ARG *tmp=new SEL_ARG(*key2); // Must make copy
|
||||
if (!tmp)
|
||||
return 0;
|
||||
key2->increment_use_count(key1->use_count+1);
|
||||
key1=key1->insert(new SEL_ARG(*key2)); // Must make copy
|
||||
key1=key1->insert(tmp);
|
||||
}
|
||||
else
|
||||
key1=key1->insert(key2); // Will destroy key2_root
|
||||
@ -2247,7 +2276,8 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
|
||||
{
|
||||
QUICK_SELECT *quick;
|
||||
DBUG_ENTER("get_quick_select");
|
||||
if ((quick=new QUICK_SELECT(param->table,param->real_keynr[idx])))
|
||||
if ((quick=new QUICK_SELECT(param->thd, param->table,
|
||||
param->real_keynr[idx])))
|
||||
{
|
||||
if (quick->error ||
|
||||
get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0,
|
||||
@ -2351,11 +2381,11 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
|
||||
}
|
||||
|
||||
/* Get range for retrieving rows in QUICK_SELECT::get_next */
|
||||
if(!(range= new QUICK_RANGE(param->min_key,
|
||||
(uint) (tmp_min_key - param->min_key),
|
||||
param->max_key,
|
||||
(uint) (tmp_max_key - param->max_key),
|
||||
flag)))
|
||||
if (!(range= new QUICK_RANGE(param->min_key,
|
||||
(uint) (tmp_min_key - param->min_key),
|
||||
param->max_key,
|
||||
(uint) (tmp_max_key - param->max_key),
|
||||
flag)))
|
||||
return 1; // out of memory
|
||||
|
||||
set_if_bigger(quick->max_used_key_length,range->min_length);
|
||||
@ -2411,10 +2441,10 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
|
||||
** Create a QUICK RANGE based on a key
|
||||
****************************************************************************/
|
||||
|
||||
QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref)
|
||||
QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
|
||||
{
|
||||
table->file->index_end(); // Remove old cursor
|
||||
QUICK_SELECT *quick=new QUICK_SELECT(table, ref->key, 1);
|
||||
QUICK_SELECT *quick=new QUICK_SELECT(thd, table, ref->key, 1);
|
||||
KEY *key_info = &table->key_info[ref->key];
|
||||
KEY_PART *key_part;
|
||||
uint part;
|
||||
@ -2423,7 +2453,7 @@ QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref)
|
||||
return 0; /* no ranges found */
|
||||
if (cp_buffer_from_ref(ref))
|
||||
{
|
||||
if (current_thd->fatal_error)
|
||||
if (thd->fatal_error)
|
||||
return 0; // out of memory
|
||||
return quick; // empty range
|
||||
}
|
||||
|
Reference in New Issue
Block a user