mariadb/storage/maria/ma_delete.c
unknown 21fd2a5a36 First part of redo/undo for key pages
Added key_nr to st_maria_keydef for faster keyinfo->keynr conversion
For transactional tables, shift record number in keys up with 1 bit to have place to indicate if transid follows
Checksum for MyISAM now ignores NULL and not used part of VARCHAR
Renamed some variables that caused shadow compiler warnings
Moved extra() call when waiting for tables to not be used to after tables are removed from cache.
Fixed crashing bugs when using Maria TEMPORARY tables with TRUNCATE. Removed 'hack' code in sql directory to go around this bug.
pagecache_unlock_by_ulink() now has extra argument to say if page was changed.
Give error message if we fail to open control file
Mark page cache variables as not flushable


include/maria.h:
  Made min page cache larger (needed for pinning key page)
  Added key_nr to st_maria_keydef for faster keyinfo->keynr conversion
  Added write_comp_flag to move some runtime code to maria_open()
include/my_base.h:
  Added new error message to be used when handler initialization failed
include/my_global.h:
  Renamed dummy to swap_dummy to avoid conflicts with local 'dummy' variables
include/my_handler.h:
  Added const to some parameters
mysys/array.c:
  More DBUG
mysys/my_error.c:
  Fixed indentation
mysys/my_handler.c:
  Added const to some parameters
  Added missing error messages
sql/field.h:
  Renamed variables to avoid variable shadowing
sql/handler.h:
  Renamed parameter to avoid variable name conflict
sql/item.h:
  Renamed variables to avoid variable shadowing
sql/log_event_old.h:
  Renamed variables to avoid variable shadowing
sql/set_var.h:
  Renamed variables to avoid variable shadowing
sql/sql_delete.cc:
  Removed maria hack for temporary tables
  Fixed indentation
sql/sql_table.cc:
  Moved extra() call when waiting for tables to not be used to after tables are removed from cache.
  This was needed to ensure we don't do a PREPARE_FOR_DROP or similar call while the table is still in use.
sql/table.cc:
  Copy page_checksum from share
  Removed Maria hack
storage/maria/Makefile.am:
  Added new files
storage/maria/ha_maria.cc:
  Renamed records -> record_count and info -> create_info to avoid variable name conflicts
  Mark page cache variables as not flushable
storage/maria/ma_blockrec.c:
  Moved _ma_unpin_all_pages() to ma_key_recover.c
  Moved init of info->pinned_pages to ma_open.c
  Moved _ma_finalize_row() to maria_key_recover.h
  Renamed some variables to avoid variable name conflicts
  Mark page_link.changed for blocks we change directly
  Simplify handling of undo link when writing LOGREC_UNDO_ROW_INSERT (old code crashed when having redo for index)
storage/maria/ma_blockrec.h:
  Removed extra empty line
storage/maria/ma_checkpoint.c:
  Remove not needed trnman.h
storage/maria/ma_close.c:
  Free pinned pages (which are now always allocated)
storage/maria/ma_control_file.c:
  Give error message if we fail to open control file
storage/maria/ma_delete.c:
  Changes for redo logging (first part, logging of underflow not yet done)
  - Log undo-key-delete
  - Log delete of key
  - Updated arguments to _ma_fetch_keypage(), _ma_dispose(), _ma_write_keypage(), _ma_insert()
  - Added new arguments to some functions to be able to write redo information
  - Mark key pages as changed when we write with PAGECACHE_LOCK_LEFT_WRITELOCKED
  
  Remove one not needed _ma_write_keypage() in d_search() when upper level will do the write anyway
  Changed 2 bmove_upp() to bmove() as this made code easer to understand
  More function comments
  Indentation fixes
storage/maria/ma_ft_update.c:
  New arguments to _ma_write_keypage()
storage/maria/ma_loghandler.c:
  Fixed some DBUG_PRINT messages
  Simplify code
  Added new log entrys for key page redo
  Renamed some variables to avoid variable name shadowing
storage/maria/ma_loghandler.h:
  Moved some defines here
  Added define for storing key number on key pages
  Added new translog record types
  Added enum for type of operations in LOGREC_REDO_INDEX
storage/maria/ma_open.c:
  Always allocate info.pinned_pages (we need now also for normal key page usage)
  Update keyinfo->key_nr
  Added virtual functions to convert record position o number to be stored on key pages
  Update keyinfo->write_comp_flag to value of search flag to be used when writing key
storage/maria/ma_page.c:
  Added redo for key pages
  - Extended _ma_fetch_keypage() with type of lock to put on page and address to used MARIA_PINNED_PAGE
  - _ma_fetch_keypage() now pin's pages if needed
  - Extended _ma_write_keypage() with type of locks to be used
  - ma_dispose() now locks info->s->state.key_del from other threads
  - ma_dispose() writes redo log record
  - ma_new() locks info->s->state.key_del from other threads if it was used
  - ma_new() now pins read page
  
  Other things:
  - Removed some not needed arguments from _ma_new() and _ma_dispose)
  - Added some new variables to simplify code
  - If EXTRA_DEBUG is used, do crc on full page to catch not unitialized bytes
storage/maria/ma_pagecache.h:
  Applied patch from Sanja to add extra argument to pagecache_unlock_by_ulink() to mark if page was changed
  Added some defines for pagecache priority levels that one can use
storage/maria/ma_range.c:
  Added new arguments for call to _ma_fetch_keypage()
storage/maria/ma_recovery.c:
  - Added hooks for new translog types:
    REDO_INDEX, REDO_INDEX_NEW_PAGE, REDO_INDEX_FREE_PAGE, UNDO_KEY_INSERT, UNDO_KEY_DELETE and
    UNDO_KEY_DELETE_WITH_ROOT.
  - Moved variable declarations to start of function (portability fixes)
  - Removed some not needed initializations
  - Set only relevant state changes for each redo/undo entry
storage/maria/lockman.c:
  Removed end space
storage/maria/ma_check.c:
  Removed end space
storage/maria/ma_create.c:
  Removed end space
storage/maria/ma_locking.c:
  Removed end space
storage/maria/ma_packrec.c:
  Removed end space
storage/maria/ma_pagecache.c:
  Removed end space
storage/maria/ma_panic.c:
  Removed end space
storage/maria/ma_rt_index.c:
  Added new arguments for call to _ma_fetch_keypage(), _ma_write_keypage(), _ma_dispose() and _ma_new()
  Fixed indentation
storage/maria/ma_rt_key.c:
  Added new arguments for call to _ma_fetch_keypage()
storage/maria/ma_rt_split.c:
  Added new arguments for call to _ma_new()
  Use new keypage header
  Added new arguments for call to _ma_write_keypage()
storage/maria/ma_search.c:
  Updated comments & indentation
  Added new arguments for call to _ma_fetch_keypage()
  Made some variables and arguments const
  Added virtual functions for converting row position to number to be stored in key
  use MARIA_RECORD_POS of record position instead of my_off_t
  Record in MARIA_KEY_PARAM how page was changed one key insert (needed for REDO)
storage/maria/ma_sort.c:
  Removed end space
storage/maria/ma_statrec.c:
  Updated arguments for call to _ma_rec_pos()
storage/maria/ma_test1.c:
  Fixed too small buffer to init_pagecache()
  Fixed bug when using insert_count and test_flag
storage/maria/ma_test2.c:
  Use more resonable pagecache size
  Remove not used code
  Reset blob_length to fix wrong output message
storage/maria/ma_test_all.sh:
  Fixed wrong test
storage/maria/ma_write.c:
  Lots of new code to handle REDO of key pages
  No logic changes because of REDO code, mostly adding new arguments and adding new code for logging 
  
  Added new arguments for calls to _ma_fetch_keypage(), _ma_write_keypage() and similar functions
  Move setting of comp_flag in ma_ck_wrte_btree() from runtime to maria_open()
  Zerofill new used pages for:
  - To remove possible sensitive data left in buffer
  - To get idenitical data on pages after running redo
  - Better compression of pages if archived
storage/maria/maria_chk.c:
  Added information if table is crash safe
storage/maria/maria_def.h:
  New virtual function to convert between record position on key and normal record position
  Aded mutex and extra variables to handle locking of share->state.key_del
  Moved some structure variables to get things more aligned
  Added extra arguments to MARIA_KEY_PARAM to be able to remember what was changed on key page on key insert
  Added argument to MARIA_PINNED_PAGE to indicate if page was changed
  Updated prototypes for functions
  Added some structures for signaling changes in REDO handling
storage/maria/unittest/ma_pagecache_single.c:
  Updated arguments for changed function calls
storage/myisam/mi_check.c:
  Made calc_check_checksum virtual
storage/myisam/mi_checksum.c:
  Update checksums to ignore null columns
storage/myisam/mi_create.c:
  Mark if table has null column (to know when we have to use mi_checksum())
storage/myisam/mi_open.c:
  Added virtual function for calculating checksum to be able to easily ignore NULL fields
storage/myisam/mi_test2.c:
  Fixed bug
storage/myisam/myisamdef.h:
  Added virtual function for calculating checksum during check table
  Removed ha_key_cmp() as this is in handler.h
storage/maria/ma_key_recover.c:
  New BitKeeper file ``storage/maria/ma_key_recover.c''
storage/maria/ma_key_recover.h:
  New BitKeeper file ``storage/maria/ma_key_recover.h''
storage/maria/ma_key_redo.c:
  New BitKeeper file ``storage/maria/ma_key_redo.c''
2007-11-14 19:08:06 +02:00

1117 lines
38 KiB
C

/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Remove a row from a MARIA table */
#include "ma_fulltext.h"
#include "ma_rt_index.h"
#include "trnman.h"
#include "ma_key_recover.h"
static int d_search(MARIA_HA *info,MARIA_KEYDEF *keyinfo,uint comp_flag,
uchar *key, uint key_length,
my_off_t page, uchar *anc_buff,
MARIA_PINNED_PAGE *anc_page_link);
static int del(MARIA_HA *info,MARIA_KEYDEF *keyinfo, uchar *key,
uchar *anc_buff, my_off_t leaf_page, uchar *leaf_buff,
MARIA_PINNED_PAGE *leaf_page_link, uchar *keypos,
my_off_t next_block, uchar *ret_key);
static int underflow(MARIA_HA *info,MARIA_KEYDEF *keyinfo,uchar *anc_buff,
my_off_t leaf_page,uchar *leaf_buff,
MARIA_PINNED_PAGE *leaf_page_link, uchar *keypos);
static uint remove_key(MARIA_KEYDEF *keyinfo,uint nod_flag,uchar *keypos,
uchar *lastkey,uchar *page_end,
my_off_t *next_block, MARIA_KEY_PARAM *s_temp);
static my_bool _ma_log_delete(MARIA_HA *info, my_off_t page, uchar *buff,
uchar *key_pos, uint move_length,
uint change_length);
int maria_delete(MARIA_HA *info,const uchar *record)
{
uint i;
uchar *old_key;
int save_errno;
char lastpos[8];
MARIA_SHARE *share=info->s;
DBUG_ENTER("maria_delete");
/* Test if record is in datafile */
DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_usage",
maria_print_error(share, HA_ERR_CRASHED);
DBUG_RETURN(my_errno= HA_ERR_CRASHED););
DBUG_EXECUTE_IF("my_error_test_undefined_error",
maria_print_error(share, INT_MAX);
DBUG_RETURN(my_errno= INT_MAX););
if (!(info->update & HA_STATE_AKTIV))
{
DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); /* No database read */
}
if (share->options & HA_OPTION_READ_ONLY_DATA)
{
DBUG_RETURN(my_errno=EACCES);
}
if (_ma_readinfo(info,F_WRLCK,1))
DBUG_RETURN(my_errno);
if ((*share->compare_record)(info,record))
goto err; /* Error on read-check */
if (_ma_mark_file_changed(info))
goto err;
/* Remove all keys from the index file */
old_key= info->lastkey2;
for (i=0 ; i < share->base.keys ; i++ )
{
if (maria_is_key_active(share->state.key_map, i))
{
share->keyinfo[i].version++;
if (share->keyinfo[i].flag & HA_FULLTEXT )
{
if (_ma_ft_del(info, i, old_key, record, info->cur_row.lastpos))
goto err;
}
else
{
if (share->keyinfo[i].ck_delete(info,i,old_key,
_ma_make_key(info, i, old_key,
record,
info->cur_row.lastpos)))
goto err;
}
/* The above changed info->lastkey2. Inform maria_rnext_same(). */
info->update&= ~HA_STATE_RNEXT_SAME;
}
}
if (share->calc_checksum)
{
/*
We can't use the row based checksum as this doesn't have enough
precision.
*/
info->cur_row.checksum= (*share->calc_checksum)(info, record);
}
if ((*share->delete_record)(info, record))
goto err; /* Remove record from database */
info->state->checksum+= - !share->now_transactional *
info->cur_row.checksum;
info->update= HA_STATE_CHANGED+HA_STATE_DELETED+HA_STATE_ROW_CHANGED;
info->state->records-= !share->now_transactional;
share->state.changed|= STATE_NOT_OPTIMIZED_ROWS;
mi_sizestore(lastpos, info->cur_row.lastpos);
VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
allow_break(); /* Allow SIGHUP & SIGINT */
if (info->invalidator != 0)
{
DBUG_PRINT("info", ("invalidator... '%s' (delete)", share->open_file_name));
(*info->invalidator)(share->open_file_name);
info->invalidator=0;
}
DBUG_RETURN(0);
err:
save_errno=my_errno;
mi_sizestore(lastpos, info->cur_row.lastpos);
if (save_errno != HA_ERR_RECORD_CHANGED)
{
maria_print_error(share, HA_ERR_CRASHED);
maria_mark_crashed(info); /* mark table crashed */
}
VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
info->update|=HA_STATE_WRITTEN; /* Buffer changed */
allow_break(); /* Allow SIGHUP & SIGINT */
my_errno=save_errno;
if (save_errno == HA_ERR_KEY_NOT_FOUND)
{
maria_print_error(share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
}
DBUG_RETURN(my_errno);
} /* maria_delete */
/* Remove a key from the btree index */
int _ma_ck_delete(register MARIA_HA *info, uint keynr, uchar *key,
uint key_length)
{
int res;
LSN lsn= LSN_IMPOSSIBLE;
my_off_t new_root= info->s->state.key_root[keynr];
DBUG_ENTER("_ma_ck_delete");
res= _ma_ck_real_delete(info, info->s->keyinfo+keynr, key, key_length,
&new_root);
if (!res && info->s->now_transactional)
{
uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE +
KEY_NR_STORE_SIZE + PAGE_STORE_SIZE], *log_pos;
LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
struct st_msg_to_write_hook_for_undo_key msg;
enum translog_record_type log_type= LOGREC_UNDO_KEY_DELETE;
lsn_store(log_data, info->trn->undo_lsn);
key_nr_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE, keynr);
log_pos= log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE;
if (new_root != info->s->state.key_root[keynr])
{
my_off_t page;
page= ((new_root == HA_OFFSET_ERROR) ? IMPOSSIBLE_PAGE_NO :
new_root / info->s->block_size);
page_store(log_pos, page);
log_pos+= PAGE_STORE_SIZE;
log_type= LOGREC_UNDO_KEY_DELETE_WITH_ROOT;
}
log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data;
log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos - log_data);
log_array[TRANSLOG_INTERNAL_PARTS + 1].str= (char*) key;
log_array[TRANSLOG_INTERNAL_PARTS + 1].length= key_length;
msg.root= &info->s->state.key_root[keynr];
msg.value= new_root;
if (translog_write_record(&lsn, log_type,
info->trn, info,
log_array[TRANSLOG_INTERNAL_PARTS + 0].length +
key_length,
TRANSLOG_INTERNAL_PARTS + 2, log_array,
log_data + LSN_STORE_SIZE, &msg))
res= -1;
}
else
{
info->s->state.key_root[keynr]= new_root;
_ma_fast_unlock_key_del(info);
}
_ma_unpin_all_pages_and_finalize_row(info, lsn);
DBUG_RETURN(res);
} /* _ma_ck_delete */
int _ma_ck_real_delete(register MARIA_HA *info, MARIA_KEYDEF *keyinfo,
uchar *key, uint key_length, my_off_t *root)
{
int error;
uint nod_flag;
my_off_t old_root;
uchar *root_buff;
MARIA_PINNED_PAGE *page_link;
DBUG_ENTER("_ma_ck_real_delete");
if ((old_root=*root) == HA_OFFSET_ERROR)
{
maria_print_error(info->s, HA_ERR_CRASHED);
DBUG_RETURN(my_errno=HA_ERR_CRASHED);
}
if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
HA_MAX_KEY_BUFF*2)))
{
DBUG_PRINT("error",("Couldn't allocate memory"));
DBUG_RETURN(my_errno=ENOMEM);
}
DBUG_PRINT("info",("root_page: %ld", (long) old_root));
if (!_ma_fetch_keypage(info, keyinfo, old_root,
PAGECACHE_LOCK_WRITE, DFLT_INIT_HITS, root_buff, 0,
&page_link))
{
error= -1;
goto err;
}
if ((error=d_search(info,keyinfo,
(keyinfo->flag & HA_FULLTEXT ?
SEARCH_FIND | SEARCH_UPDATE : SEARCH_SAME),
key, key_length, old_root, root_buff, page_link)) >0)
{
if (error == 2)
{
DBUG_PRINT("test",("Enlarging of root when deleting"));
error= _ma_enlarge_root(info,keyinfo,key,root);
}
else /* error == 1 */
{
uint used_length;
_ma_get_used_and_nod(info, root_buff, used_length, nod_flag);
page_link->changed= 1;
if (used_length <= nod_flag + info->s->keypage_header + 1)
{
error=0;
if (nod_flag)
*root= _ma_kpos(nod_flag, root_buff +info->s->keypage_header +
nod_flag);
else
*root=HA_OFFSET_ERROR;
if (_ma_dispose(info, old_root, 0))
error= -1;
}
else
error= _ma_write_keypage(info,keyinfo, old_root,
PAGECACHE_LOCK_LEFT_WRITELOCKED,
DFLT_INIT_HITS, root_buff);
}
}
err:
my_afree((uchar*) root_buff);
DBUG_PRINT("exit",("Return: %d",error));
DBUG_RETURN(error);
} /* _ma_ck_real_delete */
/*
@brief Remove key below key root
@param key Key to delete. Will contain new key if block was enlarged
@return
@retval 0 ok (anc_page is not changed)
@retval 1 If data on page is too small; In this case anc_buff is not saved
@retval 2 If data on page is too big
@retval -1 On errors
*/
static int d_search(register MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
uint comp_flag, uchar *key, uint key_length,
my_off_t anc_page, uchar *anc_buff,
MARIA_PINNED_PAGE *anc_page_link)
{
int flag,ret_value,save_flag;
uint length,nod_flag,search_key_length;
my_bool last_key;
uchar *leaf_buff,*keypos;
my_off_t leaf_page,next_block;
uchar lastkey[HA_MAX_KEY_BUFF];
MARIA_PINNED_PAGE *leaf_page_link;
MARIA_KEY_PARAM s_temp;
DBUG_ENTER("d_search");
DBUG_DUMP("page",anc_buff,_ma_get_page_used(info, anc_buff));
search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY;
flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key, search_key_length,
comp_flag, &keypos, lastkey, &last_key);
if (flag == MARIA_FOUND_WRONG_KEY)
{
DBUG_PRINT("error",("Found wrong key"));
DBUG_RETURN(-1);
}
nod_flag=_ma_test_if_nod(info, anc_buff);
if (!flag && keyinfo->flag & HA_FULLTEXT)
{
uint off;
int subkeys;
get_key_full_length_rdonly(off, lastkey);
subkeys=ft_sintXkorr(lastkey+off);
DBUG_ASSERT(info->ft1_to_ft2==0 || subkeys >=0);
comp_flag=SEARCH_SAME;
if (subkeys >= 0)
{
/* normal word, one-level tree structure */
if (info->ft1_to_ft2)
{
/* we're in ft1->ft2 conversion mode. Saving key data */
insert_dynamic(info->ft1_to_ft2, (lastkey+off));
}
else
{
/* we need exact match only if not in ft1->ft2 conversion mode */
flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,USE_WHOLE_KEY,
comp_flag, &keypos, lastkey, &last_key);
}
/* fall through to normal delete */
}
else
{
/* popular word. two-level tree. going down */
uint tmp_key_length;
my_off_t root;
uchar *kpos=keypos;
if (!(tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&kpos,
lastkey)))
{
maria_print_error(info->s, HA_ERR_CRASHED);
my_errno= HA_ERR_CRASHED;
DBUG_RETURN(-1);
}
root= _ma_dpos(info,nod_flag,kpos);
if (subkeys == -1)
{
/* the last entry in sub-tree */
if (_ma_dispose(info, root, 1))
DBUG_RETURN(-1);
/* fall through to normal delete */
}
else
{
keyinfo=&info->s->ft2_keyinfo;
/* we'll modify key entry 'in vivo' */
kpos-=keyinfo->keylength+nod_flag;
get_key_full_length_rdonly(off, key);
key+=off;
ret_value= _ma_ck_real_delete(info, &info->s->ft2_keyinfo,
key, HA_FT_WLEN, &root);
_ma_dpointer(info, kpos+HA_FT_WLEN, root);
subkeys++;
ft_intXstore(kpos, subkeys);
if (!ret_value)
{
anc_page_link->changed= 1;
ret_value= _ma_write_keypage(info, keyinfo, anc_page,
PAGECACHE_LOCK_LEFT_WRITELOCKED,
DFLT_INIT_HITS, anc_buff);
}
DBUG_PRINT("exit",("Return: %d",ret_value));
DBUG_RETURN(ret_value);
}
}
}
leaf_buff=0;
LINT_INIT(leaf_page);
if (nod_flag)
{
leaf_page= _ma_kpos(nod_flag,keypos);
if (!(leaf_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
HA_MAX_KEY_BUFF*2)))
{
DBUG_PRINT("error", ("Couldn't allocate memory"));
my_errno=ENOMEM;
DBUG_RETURN(-1);
}
if (!_ma_fetch_keypage(info,keyinfo,leaf_page,
PAGECACHE_LOCK_WRITE, DFLT_INIT_HITS, leaf_buff,
0, &leaf_page_link))
goto err;
}
if (flag != 0)
{
if (!nod_flag)
{
DBUG_PRINT("error",("Didn't find key"));
maria_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED; /* This should newer happend */
goto err;
}
save_flag=0;
ret_value=d_search(info, keyinfo, comp_flag, key, key_length,
leaf_page, leaf_buff, leaf_page_link);
}
else
{ /* Found key */
uint tmp;
length= _ma_get_page_used(info, anc_buff);
if (!(tmp= remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length,
&next_block, &s_temp)))
goto err;
anc_page_link->changed= 1;
length-= tmp;
_ma_store_page_used(info, anc_buff, length, nod_flag);
/*
Log initial changes on pages
If there is an underflow, there will be more changes logged to the
page
*/
if (info->s->now_transactional &&
_ma_log_delete(info, anc_page, anc_buff, s_temp.key_pos,
s_temp.move_length, s_temp.changed_length))
DBUG_RETURN(-1);
if (!nod_flag)
{ /* On leaf page */
if (test(length <= (info->quick_mode ?
MARIA_MIN_KEYBLOCK_LENGTH :
(uint) keyinfo->underflow_block_length)))
{
/* Page will be written by caller if we return 1 */
DBUG_RETURN(1);
}
if (_ma_write_keypage(info, keyinfo, anc_page,
PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
anc_buff))
DBUG_RETURN(-1);
DBUG_RETURN(0);
}
save_flag=1; /* Mark that anc_buff is changed */
ret_value= del(info, keyinfo, key, anc_buff, leaf_page, leaf_buff,
leaf_page_link, keypos, next_block, lastkey);
}
if (ret_value >0)
{
save_flag=1;
if (ret_value == 1)
ret_value= underflow(info, keyinfo, anc_buff, leaf_page, leaf_buff,
leaf_page_link, keypos);
else
{ /* This happens only with packed keys */
DBUG_PRINT("test",("Enlarging of key when deleting"));
if (!_ma_get_last_key(info,keyinfo,anc_buff,lastkey,keypos,&length))
goto err;
ret_value= _ma_insert(info, keyinfo, key, anc_buff, keypos, anc_page,
lastkey, (my_off_t) 0, (uchar*) 0,
(MARIA_PINNED_PAGE*) 0, (uchar*) 0, (my_bool) 0);
}
}
if (ret_value == 0 && _ma_get_page_used(info, anc_buff) >
(uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
{
save_flag=1;
ret_value= _ma_split_page(info,keyinfo,key,anc_buff,lastkey,0) | 2;
}
if (save_flag && ret_value != 1)
{
anc_page_link->changed= 1;
ret_value|= _ma_write_keypage(info, keyinfo, anc_page,
PAGECACHE_LOCK_LEFT_WRITELOCKED,
DFLT_INIT_HITS, anc_buff);
}
else
{
DBUG_DUMP("page", anc_buff, _ma_get_page_used(info, anc_buff));
}
my_afree(leaf_buff);
DBUG_PRINT("exit",("Return: %d",ret_value));
DBUG_RETURN(ret_value);
err:
my_afree(leaf_buff);
DBUG_PRINT("exit",("Error: %d",my_errno));
DBUG_RETURN (-1);
} /* d_search */
/* Remove a key that has a page-reference */
static int del(register MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
uchar *key, uchar *anc_buff, my_off_t leaf_page,
uchar *leaf_buff, MARIA_PINNED_PAGE *leaf_page_link,
uchar *keypos, /* Pos to where deleted key was */
my_off_t next_block,
uchar *ret_key) /* key before keypos in anc_buff */
{
int ret_value,length;
uint a_length, nod_flag, used_length, tmp;
my_off_t next_page;
uchar keybuff[HA_MAX_KEY_BUFF],*endpos,*next_buff,*key_start, *prev_key;
MARIA_SHARE *share=info->s;
MARIA_KEY_PARAM s_temp;
MARIA_PINNED_PAGE *next_page_link;
DBUG_ENTER("del");
DBUG_PRINT("enter",("leaf_page: %ld keypos: 0x%lx", (long) leaf_page,
(ulong) keypos));
_ma_get_used_and_nod(info, leaf_buff, used_length, nod_flag);
DBUG_DUMP("leaf_buff", leaf_buff, used_length);
endpos= leaf_buff + used_length;
if (!(key_start= _ma_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos,
&tmp)))
DBUG_RETURN(-1);
if (nod_flag)
{
next_page= _ma_kpos(nod_flag,endpos);
if (!(next_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
HA_MAX_KEY_BUFF*2)))
DBUG_RETURN(-1);
if (!_ma_fetch_keypage(info, keyinfo, next_page, PAGECACHE_LOCK_WRITE,
DFLT_INIT_HITS, next_buff, 0, &next_page_link))
ret_value= -1;
else
{
DBUG_DUMP("next_page", next_buff, _ma_get_page_used(info, next_buff));
if ((ret_value= del(info,keyinfo,key,anc_buff, next_page, next_buff,
next_page_link, keypos, next_block, ret_key)) >0)
{
/* Get new length after key was deleted */
endpos=leaf_buff+_ma_get_page_used(info, leaf_buff);
if (ret_value == 1)
{
ret_value= underflow(info, keyinfo, leaf_buff, next_page,
next_buff, next_page_link, endpos);
if (ret_value == 0 &&
_ma_get_page_used(info, leaf_buff) >
(uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
{
ret_value= (_ma_split_page(info,keyinfo,key,leaf_buff,ret_key,0) |
2);
}
}
else
{
DBUG_PRINT("test",("Inserting of key when deleting"));
if (!_ma_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos,
&tmp))
goto err;
ret_value= _ma_insert(info, keyinfo, key, leaf_buff, endpos,
leaf_page, keybuff, (my_off_t) 0, (uchar*) 0,
(MARIA_PINNED_PAGE *) 0, (uchar*) 0, 0);
}
}
leaf_page_link->changed= 1;
if (_ma_write_keypage(info, keyinfo, leaf_page,
PAGECACHE_LOCK_LEFT_WRITELOCKED,
DFLT_INIT_HITS, leaf_buff))
goto err;
}
my_afree(next_buff);
DBUG_RETURN(ret_value);
}
/* Remove last key from leaf page */
leaf_page_link->changed= 1;
_ma_store_page_used(info, leaf_buff, key_start-leaf_buff, nod_flag);
if (_ma_write_keypage(info, keyinfo, leaf_page,
PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
leaf_buff))
goto err;
/* Place last key in ancestor page on deleted key position */
a_length= _ma_get_page_used(info, anc_buff);
endpos=anc_buff+a_length;
if (keypos != anc_buff+info->s->keypage_header + share->base.key_reflength &&
!_ma_get_last_key(info,keyinfo,anc_buff,ret_key,keypos,&tmp))
goto err;
prev_key= (keypos == anc_buff + info->s->keypage_header +
share->base.key_reflength ? 0 : ret_key);
length=(*keyinfo->pack_key)(keyinfo,share->base.key_reflength,
keypos == endpos ? (uchar*) 0 : keypos,
prev_key, prev_key,
keybuff,&s_temp);
if (length > 0)
bmove_upp(endpos+length,endpos,(uint) (endpos-keypos));
else
bmove(keypos,keypos-length, (int) (endpos-keypos)+length);
(*keyinfo->store_key)(keyinfo,keypos,&s_temp);
/* Save pointer to next leaf */
if (!(*keyinfo->get_key)(keyinfo,share->base.key_reflength,&keypos,ret_key))
goto err;
_ma_kpointer(info,keypos - share->base.key_reflength,next_block);
_ma_store_page_used(info, anc_buff, a_length + length,
share->base.key_reflength);
DBUG_RETURN(_ma_get_page_used(info, leaf_buff) <=
(info->quick_mode ? MARIA_MIN_KEYBLOCK_LENGTH :
(uint) keyinfo->underflow_block_length));
err:
DBUG_RETURN(-1);
} /* del */
/* Balances adjacent pages if underflow occours */
static int underflow(register MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
uchar *anc_buff,
my_off_t leaf_page,/* Ancestor page and underflow page */
uchar *leaf_buff,
MARIA_PINNED_PAGE *leaf_page_link,
uchar *keypos) /* Position to pos after key */
{
int t_length;
uint length,anc_length,buff_length,leaf_length,p_length,s_length,nod_flag,
key_reflength,key_length;
my_off_t next_page;
uchar anc_key[HA_MAX_KEY_BUFF],leaf_key[HA_MAX_KEY_BUFF];
uchar *buff,*endpos,*next_keypos,*anc_pos,*half_pos,*temp_pos,*prev_key;
uchar *after_key;
MARIA_KEY_PARAM s_temp;
MARIA_SHARE *share=info->s;
MARIA_PINNED_PAGE *next_page_link;
DBUG_ENTER("underflow");
DBUG_PRINT("enter",("leaf_page: %ld keypos: 0x%lx",(long) leaf_page,
(ulong) keypos));
DBUG_DUMP("anc_buff", anc_buff, _ma_get_page_used(info, anc_buff));
DBUG_DUMP("leaf_buff", leaf_buff, _ma_get_page_used(info, leaf_buff));
buff=info->buff;
info->keyread_buff_used=1;
next_keypos=keypos;
nod_flag= _ma_test_if_nod(info, leaf_buff);
p_length= nod_flag+info->s->keypage_header;
anc_length= _ma_get_page_used(info, anc_buff);
leaf_length= _ma_get_page_used(info, leaf_buff);
key_reflength=share->base.key_reflength;
if (info->s->keyinfo+info->lastinx == keyinfo)
info->page_changed=1;
if ((keypos < anc_buff + anc_length && (info->state->records & 1)) ||
keypos == anc_buff + info->s->keypage_header + key_reflength)
{ /* Use page right of anc-page */
DBUG_PRINT("test",("use right page"));
if (keyinfo->flag & HA_BINARY_PACK_KEY)
{
if (!(next_keypos= _ma_get_key(info, keyinfo,
anc_buff, buff, keypos, &length)))
goto err;
}
else
{
/* Got to end of found key */
buff[0]=buff[1]=0; /* Avoid length error check if packed key */
if (!(*keyinfo->get_key)(keyinfo,key_reflength,&next_keypos,
buff))
goto err;
}
next_page= _ma_kpos(key_reflength,next_keypos);
if (!_ma_fetch_keypage(info,keyinfo, next_page, PAGECACHE_LOCK_WRITE,
DFLT_INIT_HITS, buff, 0, &next_page_link))
goto err;
buff_length= _ma_get_page_used(info, buff);
DBUG_DUMP("next",buff,buff_length);
/* find keys to make a big key-page */
bmove(next_keypos-key_reflength, buff + info->s->keypage_header,
key_reflength);
if (!_ma_get_last_key(info,keyinfo,anc_buff,anc_key,next_keypos,&length) ||
!_ma_get_last_key(info,keyinfo,leaf_buff,leaf_key,
leaf_buff+leaf_length,&length))
goto err;
/* merge pages and put parting key from anc_buff between */
prev_key=(leaf_length == p_length ? (uchar*) 0 : leaf_key);
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,buff+p_length,
prev_key, prev_key,
anc_key, &s_temp);
length=buff_length-p_length;
endpos=buff+length+leaf_length+t_length;
/* buff will always be larger than before !*/
bmove_upp(endpos, buff+buff_length,length);
memcpy(buff, leaf_buff,(size_t) leaf_length);
(*keyinfo->store_key)(keyinfo,buff+leaf_length,&s_temp);
buff_length=(uint) (endpos-buff);
_ma_store_page_used(info, buff, buff_length, nod_flag);
/* remove key from anc_buff */
if (!(s_length=remove_key(keyinfo,key_reflength,keypos,anc_key,
anc_buff+anc_length,(my_off_t *) 0, &s_temp)))
goto err;
anc_length-=s_length;
_ma_store_page_used(info, anc_buff, anc_length, key_reflength);
if (buff_length <= (uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
{ /* Keys in one page */
memcpy(leaf_buff,buff,(size_t) buff_length);
next_page_link->changed= 1;
if (_ma_dispose(info, next_page, 0))
goto err;
}
else
{ /* Page is full */
endpos=anc_buff+anc_length;
DBUG_PRINT("test",("anc_buff: 0x%lx endpos: 0x%lx",
(long) anc_buff, (long) endpos));
if (keypos != anc_buff + info->s->keypage_header + key_reflength &&
!_ma_get_last_key(info,keyinfo,anc_buff,anc_key,keypos,&length))
goto err;
if (!(half_pos= _ma_find_half_pos(info, nod_flag, keyinfo, buff,
leaf_key, &key_length, &after_key)))
goto err;
length=(uint) (half_pos-buff);
memcpy(leaf_buff,buff,(size_t) length);
_ma_store_page_used(info, leaf_buff, length, nod_flag);
/* Correct new keypointer to leaf_page */
half_pos=after_key;
_ma_kpointer(info,leaf_key+key_length,next_page);
/* Save key in anc_buff */
prev_key=(keypos == anc_buff + info->s->keypage_header + key_reflength ?
(uchar*) 0 : anc_key),
t_length=(*keyinfo->pack_key)(keyinfo,key_reflength,
(keypos == endpos ? (uchar*) 0 :
keypos),
prev_key, prev_key,
leaf_key, &s_temp);
if (t_length >= 0)
bmove_upp(endpos+t_length, endpos, (uint) (endpos-keypos));
else
bmove(keypos,keypos-t_length,(uint) (endpos-keypos)+t_length);
(*keyinfo->store_key)(keyinfo,keypos,&s_temp);
anc_length+= t_length;
_ma_store_page_used(info, anc_buff, anc_length, key_reflength);
/* Store key first in new page */
if (nod_flag)
bmove(buff+info->s->keypage_header, half_pos-nod_flag,
(size_t) nod_flag);
if (!(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key))
goto err;
t_length=(int) (*keyinfo->pack_key)(keyinfo, nod_flag, (uchar*) 0,
(uchar*) 0, (uchar*) 0,
leaf_key, &s_temp);
/* t_length will always be > 0 for a new page !*/
length=(uint) ((buff+_ma_get_page_used(info, buff))-half_pos);
bmove(buff+p_length+t_length, half_pos, (size_t) length);
(*keyinfo->store_key)(keyinfo,buff+p_length,&s_temp);
_ma_store_page_used(info, buff, length + t_length + p_length, nod_flag);
next_page_link->changed= 1;
if (_ma_write_keypage(info, keyinfo, next_page,
PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
buff))
goto err;
}
leaf_page_link->changed= 1;
if (_ma_write_keypage(info, keyinfo, leaf_page,
PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
leaf_buff))
goto err;
DBUG_RETURN(anc_length <= ((info->quick_mode ? MARIA_MIN_BLOCK_LENGTH :
(uint) keyinfo->underflow_block_length)));
}
DBUG_PRINT("test",("use left page"));
keypos= _ma_get_last_key(info,keyinfo,anc_buff,anc_key,keypos,&length);
if (!keypos)
goto err;
next_page= _ma_kpos(key_reflength,keypos);
if (!_ma_fetch_keypage(info, keyinfo, next_page, PAGECACHE_LOCK_WRITE,
DFLT_INIT_HITS, buff, 0, &next_page_link))
goto err;
buff_length= _ma_get_page_used(info, buff);
endpos=buff+buff_length;
DBUG_DUMP("prev",buff,buff_length);
/* find keys to make a big key-page */
bmove(next_keypos - key_reflength, leaf_buff + info->s->keypage_header,
key_reflength);
next_keypos=keypos;
if (!(*keyinfo->get_key)(keyinfo,key_reflength,&next_keypos,
anc_key))
goto err;
if (!_ma_get_last_key(info,keyinfo,buff,leaf_key,endpos,&length))
goto err;
/* merge pages and put parting key from anc_buff between */
prev_key=(leaf_length == p_length ? (uchar*) 0 : leaf_key);
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
(leaf_length == p_length ?
(uchar*) 0 : leaf_buff+p_length),
prev_key, prev_key,
anc_key, &s_temp);
if (t_length >= 0)
bmove(endpos+t_length, leaf_buff+p_length,
(size_t) (leaf_length-p_length));
else /* We gained space */
bmove(endpos,leaf_buff+((int) p_length-t_length),
(size_t) (leaf_length-p_length+t_length));
(*keyinfo->store_key)(keyinfo,endpos,&s_temp);
buff_length=buff_length+leaf_length-p_length+t_length;
_ma_store_page_used(info, buff, buff_length, nod_flag);
/* remove key from anc_buff */
if (!(s_length= remove_key(keyinfo,key_reflength,keypos,anc_key,
anc_buff+anc_length,(my_off_t *) 0, &s_temp)))
goto err;
anc_length-=s_length;
_ma_store_page_used(info, anc_buff, anc_length, key_reflength);
if (buff_length <= (uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
{ /* Keys in one page */
leaf_page_link->changed= 1;
if (_ma_dispose(info, leaf_page, 0))
goto err;
}
else
{ /* Page is full */
if (keypos == anc_buff+ info->s->keypage_header + key_reflength)
anc_pos=0; /* First key */
else if (!_ma_get_last_key(info,keyinfo,anc_buff,anc_pos=anc_key,keypos,
&length))
goto err;
endpos= _ma_find_half_pos(info, nod_flag, keyinfo, buff, leaf_key,
&key_length, &half_pos);
if (!endpos)
goto err;
_ma_kpointer(info,leaf_key+key_length,leaf_page);
/* Save key in anc_buff */
DBUG_DUMP("anc_buff",anc_buff,anc_length);
DBUG_DUMP("key_to_anc",leaf_key,key_length);
temp_pos=anc_buff+anc_length;
t_length=(*keyinfo->pack_key)(keyinfo,key_reflength,
keypos == temp_pos ? (uchar*) 0
: keypos,
anc_pos, anc_pos,
leaf_key,&s_temp);
if (t_length > 0)
bmove_upp(temp_pos+t_length, temp_pos, (uint) (temp_pos-keypos));
else
bmove(keypos,keypos-t_length,(uint) (temp_pos-keypos)+t_length);
(*keyinfo->store_key)(keyinfo,keypos,&s_temp);
anc_length+= t_length;
_ma_store_page_used(info, anc_buff, anc_length, key_reflength);
/* Store first key on new page */
if (nod_flag)
bmove(leaf_buff + info->s->keypage_header, half_pos-nod_flag,
(size_t) nod_flag);
if (!(length=(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key)))
goto err;
DBUG_DUMP("key_to_leaf",leaf_key,length);
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag, (uchar*) 0,
(uchar*) 0, (uchar*) 0, leaf_key, &s_temp);
length=(uint) ((buff+buff_length)-half_pos);
DBUG_PRINT("info",("t_length: %d length: %d",t_length,(int) length));
bmove(leaf_buff+p_length+t_length,half_pos,
(size_t) length);
(*keyinfo->store_key)(keyinfo,leaf_buff+p_length,&s_temp);
_ma_store_page_used(info, leaf_buff, length + t_length + p_length,
nod_flag);
leaf_page_link->changed= 1;
if (_ma_write_keypage(info, keyinfo, leaf_page,
PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
leaf_buff))
goto err;
_ma_store_page_used(info, buff, (uint) (endpos - buff),nod_flag);
}
next_page_link->changed= 1;
if (_ma_write_keypage(info, keyinfo, next_page,
PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS, buff))
goto err;
DBUG_RETURN(anc_length <= (uint)
(keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE)/2);
err:
DBUG_RETURN(-1);
} /* underflow */
/*
@brief Remove a key from page
@fn remove_key()
keyinfo Key handle
keypos Where on page key starts
lastkey Unpacked version of key to be removed
page_end Pointer to end of page
next_block If <> 0 and node-page, this is set to address of
next page
s_temp Information about what changes was done one the page:
s_temp.key_pos Start of key
s_temp.move_length Number of bytes removed at keypos
s_temp.changed_length Number of bytes changed at keypos
@todo
The current code doesn't handle the case that the next key may be
packed better against the previous key if there is a case difference
@return
@retval 0 error
@retval # How many chars was removed
*/
static uint remove_key(MARIA_KEYDEF *keyinfo, uint nod_flag,
uchar *keypos, uchar *lastkey,
uchar *page_end, my_off_t *next_block,
MARIA_KEY_PARAM *s_temp)
{
int s_length;
uchar *start;
DBUG_ENTER("remove_key");
DBUG_PRINT("enter", ("keypos: 0x%lx page_end: 0x%lx",
(long) keypos, (long) page_end));
start= s_temp->key_pos= keypos;
s_temp->changed_length= 0;
if (!(keyinfo->flag &
(HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
HA_BINARY_PACK_KEY)))
{
s_length=(int) (keyinfo->keylength+nod_flag);
if (next_block && nod_flag)
*next_block= _ma_kpos(nod_flag,keypos+s_length);
}
else
{ /* Let keypos point at next key */
/* Calculate length of key */
if (!(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
DBUG_RETURN(0); /* Error */
if (next_block && nod_flag)
*next_block= _ma_kpos(nod_flag,keypos);
s_length=(int) (keypos-start);
if (keypos != page_end)
{
if (keyinfo->flag & HA_BINARY_PACK_KEY)
{
uchar *old_key= start;
uint next_length,prev_length,prev_pack_length;
/* keypos points here on start of next key */
get_key_length(next_length,keypos);
get_key_pack_length(prev_length,prev_pack_length,old_key);
if (next_length > prev_length)
{
uint diff= (next_length-prev_length);
/* We have to copy data from the current key to the next key */
keypos-= diff + prev_pack_length;
store_key_length(keypos, prev_length);
bmove(keypos + prev_pack_length, lastkey + prev_length, diff);
s_length=(int) (keypos-start);
s_temp->changed_length= diff + prev_pack_length;
}
}
else
{
/* Check if a variable length first key part */
if ((keyinfo->seg->flag & HA_PACK_KEY) && *keypos & 128)
{
/* Next key is packed against the current one */
uint next_length,prev_length,prev_pack_length,lastkey_length,
rest_length;
if (keyinfo->seg[0].length >= 127)
{
if (!(prev_length=mi_uint2korr(start) & 32767))
goto end;
next_length=mi_uint2korr(keypos) & 32767;
keypos+=2;
prev_pack_length=2;
}
else
{
if (!(prev_length= *start & 127))
goto end; /* Same key as previous*/
next_length= *keypos & 127;
keypos++;
prev_pack_length=1;
}
if (!(*start & 128))
prev_length=0; /* prev key not packed */
if (keyinfo->seg[0].flag & HA_NULL_PART)
lastkey++; /* Skip null marker */
get_key_length(lastkey_length,lastkey);
if (!next_length) /* Same key after */
{
next_length=lastkey_length;
rest_length=0;
}
else
get_key_length(rest_length,keypos);
if (next_length >= prev_length)
{
/* Next key is based on deleted key */
uint pack_length;
uint diff= (next_length-prev_length);
bmove(keypos - diff, lastkey + prev_length, diff);
rest_length+= diff;
pack_length= prev_length ? get_pack_length(rest_length): 0;
keypos-= diff + pack_length + prev_pack_length;
s_length=(int) (keypos-start);
if (prev_length) /* Pack against prev key */
{
*keypos++= start[0];
if (prev_pack_length == 2)
*keypos++= start[1];
store_key_length(keypos,rest_length);
}
else
{
/* Next key is not packed anymore */
if (keyinfo->seg[0].flag & HA_NULL_PART)
{
rest_length++; /* Mark not null */
}
if (prev_pack_length == 2)
{
mi_int2store(keypos,rest_length);
}
else
*keypos= rest_length;
}
s_temp->changed_length= diff + pack_length + prev_pack_length;
}
}
}
}
}
end:
bmove(start, start+s_length, (uint) (page_end-start-s_length));
s_temp->move_length= s_length;
DBUG_RETURN((uint) s_length);
} /* remove_key */
/****************************************************************************
Logging of redos
****************************************************************************/
/*
@brief log entry where some parts are deleted and some things are changed
*/
static my_bool _ma_log_delete(MARIA_HA *info, my_off_t page, uchar *buff,
uchar *key_pos, uint move_length,
uint change_length)
{
LSN lsn;
uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 9], *log_pos;
LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
uint translog_parts;
uint offset= (uint) (key_pos - buff);
DBUG_ENTER("_ma_log_delete");
DBUG_ASSERT(info->s->now_transactional && move_length);
/* Store address of new root page */
page/= info->s->block_size;
page_store(log_data + FILEID_STORE_SIZE, page);
log_pos= log_data+ FILEID_STORE_SIZE + PAGE_STORE_SIZE;
log_pos[0]= KEY_OP_OFFSET;
int2store(log_pos+1, offset);
log_pos[3]= KEY_OP_SHIFT;
int2store(log_pos+4, -(int) move_length);
log_pos+= 6;
translog_parts= 1;
if (change_length)
{
log_pos[0]= KEY_OP_CHANGE;
int2store(log_pos+1, change_length);
log_pos+= 3;
translog_parts= 2;
log_array[TRANSLOG_INTERNAL_PARTS + 1].str= buff + offset;
log_array[TRANSLOG_INTERNAL_PARTS + 1].length= change_length;
}
log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data;
log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos - log_data);
if (translog_write_record(&lsn, LOGREC_REDO_INDEX,
info->trn, info,
log_array[TRANSLOG_INTERNAL_PARTS + 0].length +
change_length,
TRANSLOG_INTERNAL_PARTS + translog_parts,
log_array, log_data, NULL))
DBUG_RETURN(1);
DBUG_RETURN(0);
}