Bugs fixed:

- If not in autocommit mode, delete rows one by one so that we can roll back if necessary
- bitmap->used_size was not correctly set, which caused bitmap pages to be overwritten
- Fixed bug in bitmap handling when allocation tail pages
- Ensure we reserve place for directory entry when calculation place for head and tail pages
- Fixed wrong value in bitmap->size[0]
- Fixed wrong assert in flush_log_for_bitmap
- Fixed bug in _ma_bitmap_release_unused() where tail blocks could be wrongly reset
- Mark new pages as changed (Required to get repair() to work)
- Fixed problem with advancing log horizon pointer within one page bounds
- Fixed DBUG_ASSERT() when enable_indexes failes for end_bulk_insert()
- Fixed bug in logging of rows with more than one big blob
- Fixed DBUG_ASSERTS() in pagecache to allow change of WRITE_LOCK to READ_LOCK in unlock() calls
- Flush pagecache when we change from logging to not logging (if not, pagecache code breaks)
- Ensure my_errno is set on return from write/delete/update
- Fixed bug when using FIELD_SKIP_PRESPACE

New features:
- mysql_fix_privilege_tables now first uses binaries and scripts from source distribution, then in installed distribution
- Fix that optimize works for Maria tables
- maria_check --zerofill now also clear freed blob pages
- maria_check -di now prints more information about record page utilization

Optimizations:
- Use pagecache_unlock_by_link() instead of pagecache_write() if possible. (Avoids a memory copy and a find_block)
- Simplify code to abort when we found optimal bit pattern
- Skip also full head page bit patterns when searching for tail
- Increase default repair buffer to 128M for maria_chk and maria_read_log
- Increase default sort buffer for maria_chk to 64M
- Increase size of sortbuffer and pagecache for mysqld to 64M
- VARCHAR/CHAR fields are stored in increasing length order for BLOCK_RECORD tables

Better reporting:
- Fixed test of error condition for flush (for better error code)
- More error messages to mysqld if Maria recovery fails
- Always print warning if rows are deleted in repair
- Added global function _db_force_flush() that is usable when doing debugging in gdb
- Added call to my_debug_put_break_here() in case of some errors (for debugging)
- Remove used testfiles in unittest as these was written in different directories depending on from where the test was started

This should fix the bugs found when importing a big table with many varchars and one/many blobs to Maria


dbug/dbug.c:
  Added global function _db_force_flush() that is usable when doing debugging in gdbine
extra/replace.c:
  Fixed memory leak
include/my_dbug.h:
  Prototype for _db_force_flush()
include/my_global.h:
  Added stdarg.h as my_sys.h now depends on it.
include/my_sys.h:
  Make my_dbug_put_break_here() a NOP if not DBUG build
  Added my_printv_error()
include/myisamchk.h:
  Added entry 'lost' to be able to count space that is lost forever
mysql-test/r/maria.result:
  Updated results
mysql-test/t/maria.test:
  Reset autocommit after test
  New test to check if delete_all_rows is used (verified with --debug)
mysys/my_error.c:
  Added my_printv_error()
scripts/mysql_fix_privilege_tables.sh:
  First use binaries and scripts from source distribution, then in installed distribution
  This ensures that a development branch doesn't pick up wrong scripts)
sql/mysqld.cc:
  Fix that one can break maria recovery with ^C when debugging
sql/sql_class.cc:
  Removed #ifdef that has no effect
  (The preceeding DBUG_ASSERT() ensures that the following code will not be exectued)
storage/maria/ha_maria.cc:
  Increase size of sortbuffer and pagecache to 64M
  Fix that optimize works for Maria tables
  Fixed DBUG_ASSERT() when enable_indexes failes for end_bulk_insert()
  If not in autocommit mode, delete rows one by one so that we can roll back if necessary
  Fixed variable comments
storage/maria/ma_bitmap.c:
  More ASSERTS to detect overwrite of bitmap pages
  bitmap->used_size was not correctly set, which caused bitmap pages to be overwritten
  Ensure we reserve place for directory entry when calculation place for head and tail pages
  bitmap->size[0] should not include space for directory entry
  Simplify code to abort when we found optimal bit pattern
  Skip also full head page bit patterns when searching for tail (should speed up some common cases)
  Fixed bug in allocate_tail() when block->used was not aligned on 6 bytes
  Fixed wrong assert in flush_log_for_bitmap
  Fixed bug in _ma_bitmap_release_unused() where tail blocks could be wrongly reset
storage/maria/ma_blockrec.c:
  Ensure my_errno is set on return
  Fixed not optimal setting of row->min_length if we don't have variable length fields
  Use pagecache_unlock_by_link() instead of pagecache_write() if possible. (Avoids a memory copy and a find_block)
  Added DBUG_ASSERT() if we read or write wrong VARCHAR data
  Added DBUG_ASSERT() to find out if row sizes are calculated wrong
  Fixed bug in logging of rows with more than one big blob
storage/maria/ma_check.c:
  Disable logging while normal repair is done to avoid logging of index changes
  Fixed bug that caused CHECKSUM part of key page to be used
  Fixed that deleted of wrong records also works for BLOCK_RECORD
  Clear unallocated pages:
  - BLOB pages are not automaticly cleared on delete, so we need to use the bitmap to know if page is used or not
  Better error reporting
  More information about record page utilization
  Change printing of file position to printing of pages to make output more readable
  Always print warning if rows are deleted
storage/maria/ma_create.c:
  Calculate share.base_max_pack_length more accurately for BLOCK_RECORD pages (for future)
  Fixed that FIELD_SKIP_PRESPACE is recorded as FIELD_NORMAL; Fixed bug where fields could be used in wrong order
  Store FIELD_SKIP_ZERO fields before CHAR and VARCHAR fields (optimization)
  Store other fields in length order (to get better utilization of head block)
storage/maria/ma_delete.c:
  Ensure my_errno is set on return
storage/maria/ma_dynrec.c:
  Indentation fix
storage/maria/ma_locking.c:
  Set changed if open_count is counted down.
  (To avoid getting error "client is using or hasn't closed the table properly" with transactional tables
storage/maria/ma_loghandler.c:
  Fixed problem with advancing log horizon pointer within one page bounds (Patch from Sanja)
  Added more DBUG
  Indentation fixes
storage/maria/ma_open.c:
  Removed wrong casts
storage/maria/ma_page.c:
  Fixed usage of PAGECACHE_LOCK_WRITE_UNLOCK with _ma_new()
  Mark new pages as changed (Required to get repair() to work)
storage/maria/ma_pagecache.c:
  Fixed test of error condition for flush
  Fixed problem when using PAGECACHE_LOCK_WRITE_TO_READ with unlock()
  Added call to my_debug_put_break_here() in case of errors (for debugging)
storage/maria/ma_pagecrc.c:
  Ensure we get same crc for 32 and 64 bit systems by forcing argument to maria_page_crc to uint32
storage/maria/ma_recovery.c:
  Call my_printv_error() from eprint() to get critical errors to mysqld log
  Removed \n from error strings to eprint() to get nicer output in mysqld
  Added simple test in _ma_reenable_logging_for_table() to not do any work if not needed
storage/maria/ma_update.c:
  Ensure my_errno is set on return
storage/maria/ma_write.c:
  Ensure my_errno is set on return
storage/maria/maria_chk.c:
  Use DEBUGGER_OFF if --debug is not use (to get slightly faster execution for debug binaries)
  Added option --skip-safemalloc
  Don't write exponents for rec/key
storage/maria/maria_def.h:
  Increase default repair buffer to 128M for maria_chk and maria_read_log
  Increase default sort buffer for maria_chk to 64M
storage/maria/unittest/Makefile.am:
  Don't update files automaticly from bitkeeper
storage/maria/unittest/ma_pagecache_consist.c:
  Remove testfile at end
storage/maria/unittest/ma_pagecache_single.c:
  Remove testfile at end
storage/maria/unittest/ma_test_all-t:
  More tests
  Safer checking if test caused error
This commit is contained in:
unknown 2008-01-07 18:54:41 +02:00
parent c719e1fd33
commit b5df1d3446
34 changed files with 656 additions and 414 deletions

View File

@ -2263,6 +2263,16 @@ static void dbug_flush(CODE_STATE *cs)
} /* dbug_flush */ } /* dbug_flush */
/* For debugging */
void _db_force_flush()
{
CODE_STATE *cs;
get_code_state_or_return;
(void) fflush(cs->stack->out_file);
}
void _db_lock_file_() void _db_lock_file_()
{ {
CODE_STATE *cs; CODE_STATE *cs;

View File

@ -136,6 +136,7 @@ int main(int argc, char *argv[])
} }
} }
free_buffer(); free_buffer();
my_free(replace, MYF(0));
my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR); my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
exit(error ? 2 : 0); exit(error ? 2 : 0);
return 0; /* No compiler warning */ return 0; /* No compiler warning */

View File

@ -47,6 +47,7 @@ extern void _db_end_(void);
extern void _db_lock_file_(void); extern void _db_lock_file_(void);
extern void _db_unlock_file_(void); extern void _db_unlock_file_(void);
extern FILE *_db_fp_(void); extern FILE *_db_fp_(void);
extern void _db_force_flush();
#define DBUG_ENTER(a) const char *_db_func_, *_db_file_; uint _db_level_; \ #define DBUG_ENTER(a) const char *_db_func_, *_db_file_; uint _db_level_; \
char **_db_framep_; \ char **_db_framep_; \

View File

@ -410,6 +410,7 @@ C_MODE_END
#ifndef stdin #ifndef stdin
#include <stdio.h> #include <stdio.h>
#endif #endif
#include <stdarg.h>
#ifdef HAVE_STDLIB_H #ifdef HAVE_STDLIB_H
#include <stdlib.h> #include <stdlib.h>
#endif #endif

View File

@ -653,6 +653,8 @@ extern int my_error _VARARGS((int nr,myf MyFlags, ...));
extern int my_printf_error _VARARGS((uint my_err, const char *format, extern int my_printf_error _VARARGS((uint my_err, const char *format,
myf MyFlags, ...)) myf MyFlags, ...))
ATTRIBUTE_FORMAT(printf, 2, 4); ATTRIBUTE_FORMAT(printf, 2, 4);
extern int my_printv_error(uint error, const char *format, myf MyFlags,
va_list ap);
extern int my_error_register(const char **errmsgs, int first, int last); extern int my_error_register(const char **errmsgs, int first, int last);
extern const char **my_error_unregister(int first, int last); extern const char **my_error_unregister(int first, int last);
extern int my_message(uint my_err, const char *str,myf MyFlags); extern int my_message(uint my_err, const char *str,myf MyFlags);
@ -866,7 +868,12 @@ extern int unpackfrm(uchar **, size_t *, const uchar *);
extern ha_checksum my_checksum(ha_checksum crc, const uchar *mem, extern ha_checksum my_checksum(ha_checksum crc, const uchar *mem,
size_t count); size_t count);
#ifndef DBUG_OFF
extern void my_debug_put_break_here(void); extern void my_debug_put_break_here(void);
#else
#define my_debug_put_break_here() {}
#endif
extern void my_sleep(ulong m_seconds); extern void my_sleep(ulong m_seconds);
extern ulong crc32(ulong crc, const uchar *buf, uint len); extern ulong crc32(ulong crc, const uchar *buf, uint len);
extern uint my_set_max_open_files(uint files); extern uint my_set_max_open_files(uint files);

View File

@ -122,7 +122,7 @@ typedef struct st_handler_check_param
my_off_t search_after_block; my_off_t search_after_block;
my_off_t new_file_pos, key_file_blocks; my_off_t new_file_pos, key_file_blocks;
my_off_t keydata, totaldata, key_blocks, start_check_pos; my_off_t keydata, totaldata, key_blocks, start_check_pos;
my_off_t used, empty, splits, del_length, link_used; my_off_t used, empty, splits, del_length, link_used, lost;
ha_rows total_records, total_deleted, records,del_blocks; ha_rows total_records, total_deleted, records,del_blocks;
ha_rows full_page_count, tail_count; ha_rows full_page_count, tail_count;
ha_checksum record_checksum, glob_crc; ha_checksum record_checksum, glob_crc;

View File

@ -569,6 +569,7 @@ a a b
1 1 1 1 1 1
2 2 1 2 2 1
drop table t1,t2; drop table t1,t2;
set autocommit=1;
CREATE TABLE t1 (c1 varchar(250) NOT NULL) ROW_FORMAT=DYNAMIC; CREATE TABLE t1 (c1 varchar(250) NOT NULL) ROW_FORMAT=DYNAMIC;
CREATE TABLE t2 (c1 varchar(250) NOT NULL, PRIMARY KEY (c1)) ROW_FORMAT=DYNAMIC; CREATE TABLE t2 (c1 varchar(250) NOT NULL, PRIMARY KEY (c1)) ROW_FORMAT=DYNAMIC;
INSERT INTO t1 VALUES ('test000001'), ('test000002'), ('test000003'); INSERT INTO t1 VALUES ('test000001'), ('test000002'), ('test000003');
@ -2088,3 +2089,15 @@ drop table if exists t1;
set global maria_log_file_size=4294967296; set global maria_log_file_size=4294967296;
Warnings: Warnings:
Warning 1292 Truncated incorrect log_file_size value: '4294967296' Warning 1292 Truncated incorrect log_file_size value: '4294967296'
create table t1 (a int not null);
lock tables t1 write;
insert into t1 values (1),(2);
delete from t1;
unlock tables;
select * from t1;
a
insert into t1 values (1),(2);
delete from t1;
select * from t1;
a
drop table t1;

View File

@ -546,6 +546,7 @@ disconnect root;
connection default; connection default;
select straight_join * from t1,t2 force index (primary) where t1.a=t2.a; select straight_join * from t1,t2 force index (primary) where t1.a=t2.a;
drop table t1,t2; drop table t1,t2;
set autocommit=1;
# #
# Full key. # Full key.
CREATE TABLE t1 (c1 varchar(250) NOT NULL) ROW_FORMAT=DYNAMIC; CREATE TABLE t1 (c1 varchar(250) NOT NULL) ROW_FORMAT=DYNAMIC;
@ -1336,6 +1337,21 @@ drop table if exists t1;
--enable_warnings --enable_warnings
set global maria_log_file_size=4294967296; set global maria_log_file_size=4294967296;
#
# Test delete of all rows in autocommit and not autocommit
#
create table t1 (a int not null);
lock tables t1 write;
insert into t1 values (1),(2);
delete from t1;
unlock tables;
select * from t1;
insert into t1 values (1),(2);
delete from t1;
select * from t1;
drop table t1;
# End of 5.2 tests # End of 5.2 tests
--disable_result_log --disable_result_log

View File

@ -114,15 +114,39 @@ int my_printf_error(uint error, const char *format, myf MyFlags, ...)
va_list args; va_list args;
char ebuff[ERRMSGSIZE+20]; char ebuff[ERRMSGSIZE+20];
DBUG_ENTER("my_printf_error"); DBUG_ENTER("my_printf_error");
DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d Format: %s", DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d format: %s",
error, MyFlags, errno, format)); error, MyFlags, errno, format));
va_start(args,MyFlags); va_start(args,MyFlags);
(void) my_vsnprintf (ebuff, sizeof(ebuff), format, args); (void) my_vsnprintf(ebuff, sizeof(ebuff), format, args);
va_end(args); va_end(args);
DBUG_RETURN((*error_handler_hook)(error, ebuff, MyFlags)); DBUG_RETURN((*error_handler_hook)(error, ebuff, MyFlags));
} }
/*
Error with va_list
SYNOPSIS
my_printv_error()
error Errno
format Format string
MyFlags Flags
... variable list
*/
int my_printv_error(uint error, const char *format, myf MyFlags, va_list ap)
{
char ebuff[ERRMSGSIZE+20];
DBUG_ENTER("my_printv_error");
DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d format: %s",
error, MyFlags, errno, format));
(void) my_vsnprintf(ebuff, sizeof(ebuff), format, ap);
DBUG_RETURN((*error_handler_hook)(error, ebuff, MyFlags));
}
/* /*
Give message using error_handler_hook Give message using error_handler_hook

View File

@ -94,7 +94,7 @@ parse_arguments() {
# [mysql_install_db], and then merge with the command line arguments # [mysql_install_db], and then merge with the command line arguments
print_defaults=my_print_defaults print_defaults=my_print_defaults
for dir in ./bin @bindir@ @bindir@ extra $print_defaults_bindir/../bin $print_defaults_bindir/../extra for dir in ./extra ./bin @bindir@ @bindir@ $print_defaults_bindir/../bin $print_defaults_bindir/../extra
do do
if test -x $dir/my_print_defaults if test -x $dir/my_print_defaults
then then
@ -117,7 +117,7 @@ dirname=`dirname "$0"`
if test -z "$bindir" if test -z "$bindir"
then then
for i in @bindir@ $basedir/bin "$dirname/../client" for i in "$dirname/../client" $basedir/bin @bindir@
do do
if test -f $i/mysql if test -f $i/mysql
then then
@ -149,8 +149,8 @@ then
fi fi
# Find where first mysql_fix_privilege_tables.sql is located # Find where first mysql_fix_privilege_tables.sql is located
for i in $basedir/support-files $basedir/share $basedir/share/mysql \ for i in "$dirname" $basedir/support-files $basedir/share \
$basedir/scripts $pkgdatadir . "$dirname" $basedir/share/mysql $basedir/scripts $pkgdatadir .
do do
if test -f $i/$file if test -f $i/$file
then then

View File

@ -2314,10 +2314,6 @@ static void init_signals(void)
struct sigaction sa; struct sigaction sa;
DBUG_ENTER("init_signals"); DBUG_ENTER("init_signals");
if (test_flags & TEST_SIGINT)
{
my_sigset(thr_kill_signal, end_thread_signal);
}
my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called! my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
@ -2378,6 +2374,9 @@ static void init_signals(void)
{ {
// May be SIGINT // May be SIGINT
sigdelset(&set, thr_kill_signal); sigdelset(&set, thr_kill_signal);
sigdelset(&set, SIGINT);
my_sigset(thr_kill_signal, end_thread_signal);
my_sigset(SIGINT, end_thread_signal);
} }
sigprocmask(SIG_SETMASK,&set,NULL); sigprocmask(SIG_SETMASK,&set,NULL);
pthread_sigmask(SIG_SETMASK,&set,NULL); pthread_sigmask(SIG_SETMASK,&set,NULL);

View File

@ -394,12 +394,9 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
const char *message_arg) const char *message_arg)
{ {
DBUG_ASSERT(! is_set()); DBUG_ASSERT(! is_set());
#ifdef DBUG_OFF /* Refuse to overwrite an error with an OK packet. */
/* In production, refuse to overwrite an error with an OK packet. */
if (is_error()) if (is_error())
return; return;
#endif
/** Only allowed to report success if has not yet reported an error */
m_server_status= thd->server_status; m_server_status= thd->server_status;
m_total_warn_count= thd->total_warn_count; m_total_warn_count= thd->total_warn_count;
@ -423,11 +420,9 @@ Diagnostics_area::set_eof_status(THD *thd)
/** Only allowed to report eof if has not yet reported an error */ /** Only allowed to report eof if has not yet reported an error */
DBUG_ASSERT(! is_set()); DBUG_ASSERT(! is_set());
#ifdef DBUG_OFF /* Refuse to overwrite an error with an EOF packet. */
/* In production, refuse to overwrite an error with an EOF packet. */
if (is_error()) if (is_error())
return; return;
#endif
m_server_status= thd->server_status; m_server_status= thd->server_status;
/* /*

View File

@ -159,8 +159,8 @@ static MYSQL_SYSVAR_ULONG(pagecache_age_threshold,
static MYSQL_SYSVAR_ULONGLONG(pagecache_buffer_size, pagecache_buffer_size, static MYSQL_SYSVAR_ULONGLONG(pagecache_buffer_size, pagecache_buffer_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The size of the buffer used for index blocks for Maria tables. " "The size of the buffer used for index blocks for Maria tables. "
"Increase this to get better index handling (for all reads and multiple " "Increase this to get better index handling (for all reads and "
"writes) to as much as you can afford.", 0, 0, "multiple writes) to as much as you can afford.", 0, 0,
KEY_CACHE_SIZE, MALLOC_OVERHEAD, ~(ulong) 0, IO_SIZE); KEY_CACHE_SIZE, MALLOC_OVERHEAD, ~(ulong) 0, IO_SIZE);
static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit, static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit,
@ -180,13 +180,13 @@ static MYSQL_THDVAR_ULONG(sort_buffer_size, PLUGIN_VAR_RQCMDARG,
static MYSQL_THDVAR_ENUM(stats_method, PLUGIN_VAR_RQCMDARG, static MYSQL_THDVAR_ENUM(stats_method, PLUGIN_VAR_RQCMDARG,
"Specifies how maria index statistics collection code should threat " "Specifies how maria index statistics collection code should threat "
"NULLs. Possible values of name are \"nulls_unequal\", \"nulls_equal\", " "NULLs. Possible values are \"nulls_unequal\", \"nulls_equal\", "
"and \"nulls_ignored\".", 0, 0, 0, &maria_stats_method_typelib); "and \"nulls_ignored\".", 0, 0, 0, &maria_stats_method_typelib);
static MYSQL_SYSVAR_ENUM(sync_log_dir, sync_log_dir, PLUGIN_VAR_RQCMDARG, static MYSQL_SYSVAR_ENUM(sync_log_dir, sync_log_dir, PLUGIN_VAR_RQCMDARG,
"Controls syncing directory after log file growth and new file " "Controls syncing directory after log file growth and new file "
"creation. Possible values of are \"never\", \"newfile\" and " "creation. Possible values are \"never\", \"newfile\" and "
"\"always\")", NULL, NULL, TRANSLOG_SYNC_DIR_NEWFILE, "\"always\").", NULL, NULL, TRANSLOG_SYNC_DIR_NEWFILE,
&maria_sync_log_dir_typelib); &maria_sync_log_dir_typelib);
/***************************************************************************** /*****************************************************************************
@ -1249,14 +1249,13 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
DBUG_RETURN(HA_ADMIN_FAILED); DBUG_RETURN(HA_ADMIN_FAILED);
} }
/** @todo BUG the if() below is always false for BLOCK_RECORD */
if (!do_optimize || if (!do_optimize ||
((file->state->del || ((file->s->data_file_type == BLOCK_RECORD) ?
((file->s->data_file_type != BLOCK_RECORD) && (share->state.changed & STATE_NOT_OPTIMIZED_ROWS) :
share->state.split != file->state->records)) && (file->state->del || share->state.split != file->state->records)) &&
(!(param.testflag & T_QUICK) || (!(param.testflag & T_QUICK) ||
(share->state.changed & (STATE_NOT_OPTIMIZED_KEYS | (share->state.changed & (STATE_NOT_OPTIMIZED_KEYS |
STATE_NOT_OPTIMIZED_ROWS))))) STATE_NOT_OPTIMIZED_ROWS))))
{ {
ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ? ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
maria_get_mask_all_keys_active(share->base.keys) : maria_get_mask_all_keys_active(share->base.keys) :
@ -1294,13 +1293,7 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
{ {
thd_proc_info(thd, "Repair with keycache"); thd_proc_info(thd, "Repair with keycache");
param.testflag &= ~(T_REP_BY_SORT | T_REP_PARALLEL); param.testflag &= ~(T_REP_BY_SORT | T_REP_PARALLEL);
/*
Disable logging of index changes as the repair redo call will
make it for us
*/
_ma_tmp_disable_logging_for_table(file, 0);
error= maria_repair(&param, file, fixed_name, param.testflag & T_QUICK); error= maria_repair(&param, file, fixed_name, param.testflag & T_QUICK);
_ma_reenable_logging_for_table(file);
/** /**
@todo RECOVERY BUG we do things with the index file @todo RECOVERY BUG we do things with the index file
(maria_sort_index() after the above which already has logged the (maria_sort_index() after the above which already has logged the
@ -1362,6 +1355,9 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
_ma_check_print_warning(&param, "Number of rows changed from %s to %s", _ma_check_print_warning(&param, "Number of rows changed from %s to %s",
llstr(rows, llbuff), llstr(rows, llbuff),
llstr(file->state->records, llbuff2)); llstr(file->state->records, llbuff2));
/* Abort if warning was converted to error */
if (current_thd->is_error())
error= 1;
} }
} }
else else
@ -1594,7 +1590,7 @@ int ha_maria::enable_indexes(uint mode)
maria_chk_init(&param); maria_chk_init(&param);
param.op_name= "recreating_index"; param.op_name= "recreating_index";
param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK | param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
T_CREATE_MISSING_KEYS); T_CREATE_MISSING_KEYS | T_SAFE_REPAIR);
param.myf_rw &= ~MY_WAIT_IF_FULL; param.myf_rw &= ~MY_WAIT_IF_FULL;
param.sort_buffer_length= THDVAR(thd,sort_buffer_size); param.sort_buffer_length= THDVAR(thd,sort_buffer_size);
param.stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method); param.stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method);
@ -2039,6 +2035,16 @@ int ha_maria::extra_opt(enum ha_extra_function operation, ulong cache_size)
int ha_maria::delete_all_rows() int ha_maria::delete_all_rows()
{ {
if (file->s->now_transactional &&
((table->in_use->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) ||
table->in_use->locked_tables))
{
/*
We are not in autocommit mode or user have done LOCK TABLES.
We must do the delete row by row to be able to rollback the command
*/
return HA_ERR_WRONG_COMMAND;
}
return maria_delete_all_rows(file); return maria_delete_all_rows(file);
} }

View File

@ -46,16 +46,16 @@
Dynamic size records: Dynamic size records:
3 bits are used to indicate 3 bits are used to indicate Bytes free in 8K page
0 Empty page 0 Empty page 8176 (head or tail)
1 0-30 % full (at least room for 3 records) 1 0-30 % full (at least room for 3 records) 5724
2 30-60 % full (at least room for 2 records) 2 30-60 % full (at least room for 2 records) 3271
3 60-90 % full (at least room for one record) 3 60-90 % full (at least room for one record) 818
4 100 % full (no more room for records) 4 100 % full (no more room for records) 0
5 Tail page, 0-40 % full 5 Tail page, 0-40 % full 4906
6 Tail page, 40-80 % full 6 Tail page, 40-80 % full 1636
7 Full tail page or full blob page 7 Full tail page or full blob page 0
Assuming 8K pages, this will allow us to map: Assuming 8K pages, this will allow us to map:
8192 (bytes per page) * 8 bits/byte / 3 bits/page * 8192 (page size)= 170.7M 8192 (bytes per page) * 8 bits/byte / 3 bits/page * 8192 (page size)= 170.7M
@ -222,7 +222,7 @@ my_bool _ma_bitmap_init(MARIA_SHARE *share, File file)
/* Update size for bits */ /* Update size for bits */
/* TODO; Make this dependent of the row size */ /* TODO; Make this dependent of the row size */
max_page_size= share->block_size - PAGE_OVERHEAD_SIZE; max_page_size= share->block_size - PAGE_OVERHEAD_SIZE + DIR_ENTRY_SIZE;
bitmap->sizes[0]= max_page_size; /* Empty page */ bitmap->sizes[0]= max_page_size; /* Empty page */
bitmap->sizes[1]= max_page_size - max_page_size * 30 / 100; bitmap->sizes[1]= max_page_size - max_page_size * 30 / 100;
bitmap->sizes[2]= max_page_size - max_page_size * 60 / 100; bitmap->sizes[2]= max_page_size - max_page_size * 60 / 100;
@ -915,6 +915,7 @@ static void fill_block(MARIA_FILE_BITMAP *bitmap,
/* For each 6 bytes we have 6*8/3= 16 patterns */ /* For each 6 bytes we have 6*8/3= 16 patterns */
page= (best_data - bitmap->map) / 6 * 16 + best_pos; page= (best_data - bitmap->map) / 6 * 16 + best_pos;
DBUG_ASSERT(page + 1 < bitmap->pages_covered);
block->page= bitmap->page + 1 + page; block->page= bitmap->page + 1 + page;
block->page_count= TAIL_PAGE_COUNT_MARKER; block->page_count= TAIL_PAGE_COUNT_MARKER;
block->empty_space= pattern_to_size(bitmap, best_bits); block->empty_space= pattern_to_size(bitmap, best_bits);
@ -971,7 +972,7 @@ static my_bool allocate_head(MARIA_FILE_BITMAP *bitmap, uint size,
LINT_INIT(best_pos); LINT_INIT(best_pos);
DBUG_ASSERT(size <= FULL_PAGE_SIZE(bitmap->block_size)); DBUG_ASSERT(size <= FULL_PAGE_SIZE(bitmap->block_size));
for (; data < end; data += 6) for (; data < end; data+= 6)
{ {
ulonglong bits= uint6korr(data); /* 6 bytes = 6*8/3= 16 patterns */ ulonglong bits= uint6korr(data); /* 6 bytes = 6*8/3= 16 patterns */
uint i; uint i;
@ -991,14 +992,6 @@ static my_bool allocate_head(MARIA_FILE_BITMAP *bitmap, uint size,
if (pattern <= min_bits) if (pattern <= min_bits)
{ {
/* There is enough space here */ /* There is enough space here */
if (pattern == min_bits)
{
/* There is exactly enough space here, return this page */
best_bits= min_bits;
best_data= data;
best_pos= i;
goto found;
}
if ((int) pattern > (int) best_bits) if ((int) pattern > (int) best_bits)
{ {
/* /*
@ -1009,16 +1002,19 @@ static my_bool allocate_head(MARIA_FILE_BITMAP *bitmap, uint size,
best_bits= pattern; best_bits= pattern;
best_data= data; best_data= data;
best_pos= i; best_pos= i;
if (pattern == min_bits)
goto found; /* Best possible match */
} }
} }
} }
} }
if (!best_data) /* Found no place */ if (!best_data) /* Found no place */
{ {
if (bitmap->used_size == bitmap->total_size) if (data >= bitmap->map + bitmap->total_size)
DBUG_RETURN(1); /* No space in bitmap */ DBUG_RETURN(1); /* No space in bitmap */
/* Allocate data at end of bitmap */ /* Allocate data at end of bitmap */
bitmap->used_size+= 6; bitmap->used_size+= 6;
set_if_smaller(bitmap->used_size, bitmap->total_size);
best_data= data; best_data= data;
best_pos= best_bits= 0; best_pos= best_bits= 0;
} }
@ -1068,41 +1064,38 @@ static my_bool allocate_tail(MARIA_FILE_BITMAP *bitmap, uint size,
the following patterns: 1-4 (head pages, not suitable for tail) or the following patterns: 1-4 (head pages, not suitable for tail) or
7 (full tail page). See 'Dynamic size records' comment at start of file. 7 (full tail page). See 'Dynamic size records' comment at start of file.
At the moment we only skip full tail pages (ie, all bits are At the moment we only skip full head and tail pages (ie, all bits are
set) as this is easy to detect with one simple test and is a set) as this is easy to detect with one simple test and is a
quite common case if we have blobs. quite common case if we have blobs.
*/ */
if ((!bits && best_data) || bits == LL(0xffffffffffff)) if ((!bits && best_data) || bits == LL(0xffffffffffff) ||
bits == LL(04444444444444444))
continue; continue;
for (i= 0; i < 16; i++, bits >>= 3) for (i= 0; i < 16; i++, bits >>= 3)
{ {
uint pattern= bits & 7; uint pattern= bits & 7;
if (pattern <= min_bits && (!pattern || pattern >= 5)) if (pattern <= min_bits && (!pattern || pattern >= 5))
{ {
if (pattern == min_bits)
{
best_bits= min_bits;
best_data= data;
best_pos= i;
goto found;
}
if ((int) pattern > (int) best_bits) if ((int) pattern > (int) best_bits)
{ {
best_bits= pattern; best_bits= pattern;
best_data= data; best_data= data;
best_pos= i; best_pos= i;
if (pattern == min_bits)
goto found; /* Can't be better */
} }
} }
} }
} }
if (!best_data) if (!best_data)
{ {
if (bitmap->used_size == bitmap->total_size) if (data >= bitmap->map + bitmap->total_size)
DBUG_RETURN(1); DBUG_RETURN(1);
/* Allocate data at end of bitmap */ /* Allocate data at end of bitmap */
best_data= end; best_data= data;
bitmap->used_size+= 6; bitmap->used_size+= 6;
set_if_smaller(bitmap->used_size, bitmap->total_size);
best_pos= best_bits= 0; best_pos= best_bits= 0;
} }
@ -1253,6 +1246,7 @@ static ulong allocate_full_pages(MARIA_FILE_BITMAP *bitmap,
block->sub_blocks= 0; block->sub_blocks= 0;
block->org_bitmap_value= 0; block->org_bitmap_value= 0;
block->used= 0; block->used= 0;
DBUG_ASSERT(page + best_area_size < bitmap->pages_covered);
DBUG_PRINT("info", ("page: %lu page_count: %u", DBUG_PRINT("info", ("page: %lu page_count: %u",
(ulong) block->page, block->page_count)); (ulong) block->page, block->page_count));
@ -1290,7 +1284,10 @@ static ulong allocate_full_pages(MARIA_FILE_BITMAP *bitmap,
best_data++; best_data++;
} }
if (data_end < best_data) if (data_end < best_data)
{
bitmap->used_size= (uint) (best_data - bitmap->map); bitmap->used_size= (uint) (best_data - bitmap->map);
DBUG_ASSERT(bitmap->used_size <= bitmap->total_size);
}
bitmap->changed= 1; bitmap->changed= 1;
DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap);); DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
DBUG_RETURN(block->page_count); DBUG_RETURN(block->page_count);
@ -1326,7 +1323,11 @@ static my_bool find_head(MARIA_HA *info, uint length, uint position)
*/ */
block= dynamic_element(&info->bitmap_blocks, position, MARIA_BITMAP_BLOCK *); block= dynamic_element(&info->bitmap_blocks, position, MARIA_BITMAP_BLOCK *);
while (allocate_head(bitmap, length, block)) /*
We need to have DIRENTRY_SIZE here to take into account that we may
need an extra directory entry for the row
*/
while (allocate_head(bitmap, length + DIR_ENTRY_SIZE, block))
if (move_to_next_bitmap(info, bitmap)) if (move_to_next_bitmap(info, bitmap))
return 1; return 1;
return 0; return 0;
@ -1353,13 +1354,18 @@ static my_bool find_tail(MARIA_HA *info, uint length, uint position)
MARIA_FILE_BITMAP *bitmap= &info->s->bitmap; MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
MARIA_BITMAP_BLOCK *block; MARIA_BITMAP_BLOCK *block;
DBUG_ENTER("find_tail"); DBUG_ENTER("find_tail");
DBUG_ASSERT(length <= info->s->block_size - PAGE_OVERHEAD_SIZE);
/* Needed, as there is no error checking in dynamic_element */ /* Needed, as there is no error checking in dynamic_element */
if (allocate_dynamic(&info->bitmap_blocks, position)) if (allocate_dynamic(&info->bitmap_blocks, position))
DBUG_RETURN(1); DBUG_RETURN(1);
block= dynamic_element(&info->bitmap_blocks, position, MARIA_BITMAP_BLOCK *); block= dynamic_element(&info->bitmap_blocks, position, MARIA_BITMAP_BLOCK *);
while (allocate_tail(bitmap, length, block)) /*
We have to add DIR_ENTRY_SIZE to ensure we have space for the tail and
it's directroy entry on the page
*/
while (allocate_tail(bitmap, length + DIR_ENTRY_SIZE, block))
if (move_to_next_bitmap(info, bitmap)) if (move_to_next_bitmap(info, bitmap))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_RETURN(0); DBUG_RETURN(0);
@ -1539,6 +1545,7 @@ static void use_head(MARIA_HA *info, ulonglong page, uint size,
MARIA_BITMAP_BLOCK *block; MARIA_BITMAP_BLOCK *block;
uchar *data; uchar *data;
uint offset, tmp, offset_page; uint offset, tmp, offset_page;
DBUG_ASSERT(page % bitmap->pages_covered);
block= dynamic_element(&info->bitmap_blocks, block_position, block= dynamic_element(&info->bitmap_blocks, block_position,
MARIA_BITMAP_BLOCK*); MARIA_BITMAP_BLOCK*);
@ -1740,8 +1747,7 @@ my_bool _ma_bitmap_find_place(MARIA_HA *info, MARIA_ROW *row,
extents_length= row->extents_count * ROW_EXTENT_SIZE; extents_length= row->extents_count * ROW_EXTENT_SIZE;
/* /*
The + 3 here is space to be able to store the number of segments The + 3 is reserved for storing the number of segments in the row header.
in the row header.
*/ */
if ((head_length= (row->head_length + extents_length + 3)) <= if ((head_length= (row->head_length + extents_length + 3)) <=
max_page_size) max_page_size)
@ -2329,9 +2335,9 @@ my_bool _ma_bitmap_release_unused(MARIA_HA *info, MARIA_BITMAP_BLOCKS *blocks)
set_page_bits(info, bitmap, block->page, bits)) set_page_bits(info, bitmap, block->page, bits))
goto err; goto err;
} }
if (!(block->used & BLOCKUSED_USED) && else if (!(block->used & BLOCKUSED_USED) &&
_ma_bitmap_reset_full_page_bits(info, bitmap, _ma_bitmap_reset_full_page_bits(info, bitmap,
block->page, page_count)) block->page, page_count))
goto err; goto err;
} }
@ -2586,8 +2592,7 @@ flush_log_for_bitmap(uchar *page __attribute__((unused)),
const MARIA_SHARE *share= (MARIA_SHARE*)data_ptr; const MARIA_SHARE *share= (MARIA_SHARE*)data_ptr;
#endif #endif
DBUG_ENTER("flush_log_for_bitmap"); DBUG_ENTER("flush_log_for_bitmap");
DBUG_ASSERT(share->page_type == PAGECACHE_LSN_PAGE && DBUG_ASSERT(share->now_transactional);
share->now_transactional);
/* /*
WAL imposes that UNDOs reach disk before bitmap is flushed. We don't know WAL imposes that UNDOs reach disk before bitmap is flushed. We don't know
the LSN of the last UNDO about this bitmap page, so we flush whole log. the LSN of the last UNDO about this bitmap page, so we flush whole log.

View File

@ -1269,8 +1269,23 @@ static void calc_record_size(MARIA_HA *info, const uchar *record,
} }
} }
row->field_lengths_length= (uint) (field_length_data - row->field_lengths); row->field_lengths_length= (uint) (field_length_data - row->field_lengths);
/*
- row->base_length is base information we must have on a page in first
extent:
- flag byte (1) + is_nulls_extended (0 | 1) + null_bytes + pack_bytes +
table_checksum (0 | 1)
- row->min_length is minimum amount of data we must store on
a page. bitmap code will ensure we get at list this much +
total number of extents and one extent information
- fixed_not_null_fields_length is length of fixed length fields that can't
be compacted
- head_length is the amount of data for the head page
(ie, all fields except blobs)
*/
row->min_length= (row->base_length + row->min_length= (row->base_length +
size_to_store_key_length(row->field_lengths_length)); (share->base.max_field_lengths ?
size_to_store_key_length(row->field_lengths_length) :
0));
row->head_length= (row->min_length + row->head_length= (row->min_length +
share->base.fixed_not_null_fields_length + share->base.fixed_not_null_fields_length +
row->field_lengths_length + row->field_lengths_length +
@ -1534,11 +1549,11 @@ static my_bool get_head_or_tail_page(MARIA_HA *info,
/* Read old page */ /* Read old page */
page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK; page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
res->buff= pagecache_read(share->pagecache, &info->dfile, res->buff= pagecache_read(share->pagecache, &info->dfile,
block->page, 0, buff, share->page_type, block->page, 0, 0, share->page_type,
lock, &page_link.link); lock, &page_link.link);
page_link.changed= res->buff == 0; page_link.changed= res->buff != 0;
push_dynamic(&info->pinned_pages, (void*) &page_link); push_dynamic(&info->pinned_pages, (void*) &page_link);
if (page_link.changed) if (!page_link.changed)
goto crashed; goto crashed;
DBUG_ASSERT((res->buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == page_type); DBUG_ASSERT((res->buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == page_type);
@ -1620,10 +1635,10 @@ static my_bool get_rowpos_in_head_or_tail_page(MARIA_HA *info,
else else
{ {
page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK; page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
res->buff= pagecache_read(share->pagecache, &info->dfile, buff= pagecache_read(share->pagecache, &info->dfile,
block->page, 0, buff, share->page_type, block->page, 0, 0, share->page_type,
lock, &page_link.link); lock, &page_link.link);
page_link.changed= res->buff != 0; page_link.changed= buff != 0;
push_dynamic(&info->pinned_pages, (void*) &page_link); push_dynamic(&info->pinned_pages, (void*) &page_link);
if (!page_link.changed) /* Read error */ if (!page_link.changed) /* Read error */
goto err; goto err;
@ -1797,27 +1812,32 @@ static my_bool write_tail(MARIA_HA *info,
info->state->data_file_length= position + block_size; info->state->data_file_length= position + block_size;
} }
DBUG_ASSERT(share->pagecache->block_size == block_size); if (block_is_read)
if (!(res= pagecache_write(share->pagecache, {
&info->dfile, block->page, 0, /* Current page link is last element in pinned_pages */
row_pos.buff,share->page_type, MARIA_PINNED_PAGE *page_link;
block_is_read ? PAGECACHE_LOCK_WRITE_TO_READ : page_link= dynamic_element(&info->pinned_pages,
PAGECACHE_LOCK_READ, info->pinned_pages.elements-1,
block_is_read ? PAGECACHE_PIN_LEFT_PINNED : MARIA_PINNED_PAGE*);
PAGECACHE_PIN, pagecache_unlock_by_link(share->pagecache, page_link->link,
PAGECACHE_WRITE_DELAY, &page_link.link, PAGECACHE_LOCK_WRITE_TO_READ,
LSN_IMPOSSIBLE))) PAGECACHE_PIN_LEFT_PINNED, LSN_IMPOSSIBLE,
LSN_IMPOSSIBLE, 1);
DBUG_ASSERT(page_link->changed);
page_link->unlock= PAGECACHE_LOCK_READ_UNLOCK;
res= 0;
}
else if (!(res= pagecache_write(share->pagecache,
&info->dfile, block->page, 0,
row_pos.buff,share->page_type,
PAGECACHE_LOCK_READ,
PAGECACHE_PIN,
PAGECACHE_WRITE_DELAY, &page_link.link,
LSN_IMPOSSIBLE)))
{ {
page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK; page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK;
page_link.changed= 1; page_link.changed= 1;
if (block_is_read) push_dynamic(&info->pinned_pages, (void*) &page_link);
{
/* Change the lock used when we read the page */
set_dynamic(&info->pinned_pages, (void*) &page_link,
info->pinned_pages.elements-1);
}
else
push_dynamic(&info->pinned_pages, (void*) &page_link);
} }
DBUG_RETURN(res); DBUG_RETURN(res);
} }
@ -1909,7 +1929,6 @@ static my_bool write_full_pages(MARIA_HA *info,
bzero(buff + block_size - PAGE_SUFFIX_SIZE - (data_size - copy_length), bzero(buff + block_size - PAGE_SUFFIX_SIZE - (data_size - copy_length),
(data_size - copy_length) + PAGE_SUFFIX_SIZE); (data_size - copy_length) + PAGE_SUFFIX_SIZE);
DBUG_ASSERT(share->pagecache->block_size == block_size);
if (pagecache_write(share->pagecache, if (pagecache_write(share->pagecache,
&info->dfile, page, 0, &info->dfile, page, 0,
buff, share->page_type, buff, share->page_type,
@ -2333,6 +2352,7 @@ static my_bool write_block_record(MARIA_HA *info,
my_bool row_extents_in_use, blob_full_pages_exists; my_bool row_extents_in_use, blob_full_pages_exists;
LSN lsn; LSN lsn;
my_off_t position; my_off_t position;
uint save_my_errno;
DBUG_ENTER("write_block_record"); DBUG_ENTER("write_block_record");
LINT_INIT(row_extents_first_part); LINT_INIT(row_extents_first_part);
@ -2382,6 +2402,9 @@ static my_bool write_block_record(MARIA_HA *info,
memcpy(data, row->empty_bits, share->base.pack_bytes); memcpy(data, row->empty_bits, share->base.pack_bytes);
data+= share->base.pack_bytes; data+= share->base.pack_bytes;
DBUG_ASSERT(row_extents_in_use || undo_lsn != LSN_ERROR ||
(uint) (data - row_pos->data) == row->min_length);
/* /*
Allocate a buffer of rest of data (except blobs) Allocate a buffer of rest of data (except blobs)
@ -2439,6 +2462,11 @@ static my_bool write_block_record(MARIA_HA *info,
memcpy(tmp_data, field_length_data, row->field_lengths_length); memcpy(tmp_data, field_length_data, row->field_lengths_length);
tmp_data+= row->field_lengths_length; tmp_data+= row->field_lengths_length;
DBUG_ASSERT(row_extents_in_use || undo_lsn != LSN_ERROR ||
(uint) (tmp_data - row_pos->data) == row->min_length +
share->base.fixed_not_null_fields_length +
row->field_lengths_length);
/* Copy variable length fields and fields with null/zero */ /* Copy variable length fields and fields with null/zero */
for (end_column= share->columndef + share->base.fields - share->base.blobs; for (end_column= share->columndef + share->base.fields - share->base.blobs;
column < end_column ; column < end_column ;
@ -2479,6 +2507,7 @@ static my_bool write_block_record(MARIA_HA *info,
field_length_data+= 2; field_length_data+= 2;
field_pos+= 2; field_pos+= 2;
} }
DBUG_ASSERT(length <= column->length);
break; break;
default: /* Wrong data */ default: /* Wrong data */
DBUG_ASSERT(0); DBUG_ASSERT(0);
@ -2831,26 +2860,35 @@ static my_bool write_block_record(MARIA_HA *info,
if (info->state->data_file_length <= position) if (info->state->data_file_length <= position)
info->state->data_file_length= position + block_size; info->state->data_file_length= position + block_size;
DBUG_ASSERT(share->pagecache->block_size == block_size);
if (pagecache_write(share->pagecache,
&info->dfile, head_block->page, 0,
page_buff, share->page_type,
head_block_is_read ? PAGECACHE_LOCK_WRITE_TO_READ :
PAGECACHE_LOCK_READ,
head_block_is_read ? PAGECACHE_PIN_LEFT_PINNED :
PAGECACHE_PIN,
PAGECACHE_WRITE_DELAY, &page_link.link,
LSN_IMPOSSIBLE))
goto disk_err;
page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK;
page_link.changed= 1;
if (head_block_is_read) if (head_block_is_read)
{ {
MARIA_PINNED_PAGE *page_link;
/* Head page is always the first pinned page */ /* Head page is always the first pinned page */
set_dynamic(&info->pinned_pages, (void*) &page_link, 0); page_link= dynamic_element(&info->pinned_pages, 0,
MARIA_PINNED_PAGE*);
pagecache_unlock_by_link(share->pagecache, page_link->link,
PAGECACHE_LOCK_WRITE_TO_READ,
PAGECACHE_PIN_LEFT_PINNED, LSN_IMPOSSIBLE,
LSN_IMPOSSIBLE, 1);
page_link->unlock= PAGECACHE_LOCK_READ_UNLOCK;
page_link->changed= 1;
} }
else else
{
if (pagecache_write(share->pagecache,
&info->dfile, head_block->page, 0,
page_buff, share->page_type,
head_block_is_read ? PAGECACHE_LOCK_WRITE_TO_READ :
PAGECACHE_LOCK_READ,
head_block_is_read ? PAGECACHE_PIN_LEFT_PINNED :
PAGECACHE_PIN,
PAGECACHE_WRITE_DELAY, &page_link.link,
LSN_IMPOSSIBLE))
goto disk_err;
page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK;
page_link.changed= 1;
push_dynamic(&info->pinned_pages, (void*) &page_link); push_dynamic(&info->pinned_pages, (void*) &page_link);
}
if (share->now_transactional && (tmp_data_used || blob_full_pages_exists)) if (share->now_transactional && (tmp_data_used || blob_full_pages_exists))
{ {
@ -2918,8 +2956,8 @@ static my_bool write_block_record(MARIA_HA *info,
if (!*tmp_blob_lengths) /* Null or "" */ if (!*tmp_blob_lengths) /* Null or "" */
continue; continue;
length= tmp_column->length - portable_sizeof_char_ptr;
blob_length= *tmp_blob_lengths; blob_length= *tmp_blob_lengths;
length= tmp_column->length - portable_sizeof_char_ptr;
/* /*
If last part of blog was on tail page, change blob_length to If last part of blog was on tail page, change blob_length to
reflect this reflect this
@ -2929,7 +2967,7 @@ static my_bool write_block_record(MARIA_HA *info,
if (blob_length) if (blob_length)
{ {
memcpy_fixed((uchar*) &log_array_pos->str, memcpy_fixed((uchar*) &log_array_pos->str,
record + column->offset + length, record + tmp_column->offset + length,
sizeof(uchar*)); sizeof(uchar*));
log_array_pos->length= blob_length; log_array_pos->length= blob_length;
log_entry_length+= blob_length; log_entry_length+= blob_length;
@ -3136,8 +3174,9 @@ disk_err:
Unpin all pinned pages to not cause problems for disk cache. This is Unpin all pinned pages to not cause problems for disk cache. This is
safe to call even if we already called _ma_unpin_all_pages() above. safe to call even if we already called _ma_unpin_all_pages() above.
*/ */
save_my_errno= my_errno;
_ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE); _ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE);
my_errno= save_my_errno;
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -3163,6 +3202,7 @@ static my_bool allocate_and_write_block_record(MARIA_HA *info,
{ {
struct st_row_pos_info row_pos; struct st_row_pos_info row_pos;
MARIA_BITMAP_BLOCKS *blocks= &row->insert_blocks; MARIA_BITMAP_BLOCKS *blocks= &row->insert_blocks;
int save_my_errno;
DBUG_ENTER("allocate_and_write_block_record"); DBUG_ENTER("allocate_and_write_block_record");
_ma_bitmap_flushable(info, 1); _ma_bitmap_flushable(info, 1);
@ -3201,10 +3241,13 @@ static my_bool allocate_and_write_block_record(MARIA_HA *info,
/* Now let checkpoint happen but don't commit */ /* Now let checkpoint happen but don't commit */
DBUG_EXECUTE_IF("maria_over_alloc_bitmap", sleep(1000);); DBUG_EXECUTE_IF("maria_over_alloc_bitmap", sleep(1000););
DBUG_RETURN(0); DBUG_RETURN(0);
err: err:
save_my_errno= my_errno;
if (info->non_flushable_state) if (info->non_flushable_state)
_ma_bitmap_flushable(info, -1); _ma_bitmap_flushable(info, -1);
_ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE); _ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE);
my_errno= save_my_errno;
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -3362,8 +3405,8 @@ static my_bool _ma_update_block_record2(MARIA_HA *info,
_ma_bitmap_flushable(info, 1); _ma_bitmap_flushable(info, 1);
buff= pagecache_read(share->pagecache, buff= pagecache_read(share->pagecache,
&info->dfile, (pgcache_page_no_t) page, 0, &info->dfile, (pgcache_page_no_t) page, 0, 0,
info->buff, share->page_type, share->page_type,
PAGECACHE_LOCK_WRITE, &page_link.link); PAGECACHE_LOCK_WRITE, &page_link.link);
page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK; page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
page_link.changed= buff != 0; page_link.changed= buff != 0;
@ -3512,8 +3555,8 @@ static my_bool _ma_update_at_original_place(MARIA_HA *info,
_ma_bitmap_flushable(info, 1); _ma_bitmap_flushable(info, 1);
buff= pagecache_read(share->pagecache, buff= pagecache_read(share->pagecache,
&info->dfile, (pgcache_page_no_t) page, 0, &info->dfile, (pgcache_page_no_t) page, 0, 0,
info->buff, share->page_type, share->page_type,
PAGECACHE_LOCK_WRITE, &page_link.link); PAGECACHE_LOCK_WRITE, &page_link.link);
page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK; page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
page_link.changed= buff != 0; page_link.changed= buff != 0;
@ -3746,10 +3789,8 @@ static my_bool delete_head_or_tail(MARIA_HA *info,
(ulong) ma_recordpos(page, record_number), (ulong) ma_recordpos(page, record_number),
(ulong) page, record_number)); (ulong) page, record_number));
DBUG_ASSERT(share->pagecache->block_size == block_size);
buff= pagecache_read(share->pagecache, buff= pagecache_read(share->pagecache,
&info->dfile, page, 0, &info->dfile, page, 0, 0,
0,
share->page_type, share->page_type,
PAGECACHE_LOCK_WRITE, &page_link.link); PAGECACHE_LOCK_WRITE, &page_link.link);
page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK; page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
@ -3794,14 +3835,6 @@ static my_bool delete_head_or_tail(MARIA_HA *info,
log_data, NULL)) log_data, NULL))
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (pagecache_write(share->pagecache,
&info->dfile, page, 0,
buff, share->page_type,
lock_at_write,
PAGECACHE_PIN_LEFT_PINNED,
PAGECACHE_WRITE_DELAY, &page_link.link,
LSN_IMPOSSIBLE))
DBUG_RETURN(1);
} }
else /* page is now empty */ else /* page is now empty */
{ {
@ -3818,19 +3851,13 @@ static my_bool delete_head_or_tail(MARIA_HA *info,
log_data, NULL)) log_data, NULL))
DBUG_RETURN(1); DBUG_RETURN(1);
} }
/* Write the empty page (needed only for REPAIR to work) */
if (pagecache_write(share->pagecache,
&info->dfile, page, 0,
buff, share->page_type,
lock_at_write,
PAGECACHE_PIN_LEFT_PINNED,
PAGECACHE_WRITE_DELAY, &page_link.link,
LSN_IMPOSSIBLE))
DBUG_RETURN(1);
DBUG_ASSERT(empty_space >= share->bitmap.sizes[0]); DBUG_ASSERT(empty_space >= share->bitmap.sizes[0]);
} }
/* The page is pinned with a read lock */
pagecache_unlock_by_link(share->pagecache, page_link.link,
lock_at_write,
PAGECACHE_PIN_LEFT_PINNED, LSN_IMPOSSIBLE,
LSN_IMPOSSIBLE, 1);
page_link.unlock= lock_at_unpin; page_link.unlock= lock_at_unpin;
set_dynamic(&info->pinned_pages, (void*) &page_link, set_dynamic(&info->pinned_pages, (void*) &page_link,
info->pinned_pages.elements-1); info->pinned_pages.elements-1);
@ -4105,7 +4132,6 @@ static uchar *read_next_extent(MARIA_HA *info, MARIA_EXTENT_CURSOR *extent,
if (extent->tail) if (extent->tail)
lock= extent->lock_for_tail_pages; lock= extent->lock_for_tail_pages;
DBUG_ASSERT(share->pagecache->block_size == share->block_size);
buff= pagecache_read(share->pagecache, buff= pagecache_read(share->pagecache,
&info->dfile, extent->page, 0, &info->dfile, extent->page, 0,
info->buff, share->page_type, info->buff, share->page_type,
@ -4439,6 +4465,10 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record,
field_pos+= 2; field_pos+= 2;
field_length_data+= 2; field_length_data+= 2;
} }
#ifdef SANITY_CHECKS
if (length > column->length)
goto err;
#endif
if (read_long_data(info, field_pos, length, &extent, &data, if (read_long_data(info, field_pos, length, &extent, &data,
&end_of_data)) &end_of_data))
DBUG_RETURN(my_errno); DBUG_RETURN(my_errno);
@ -4673,7 +4703,6 @@ int _ma_read_block_record(MARIA_HA *info, uchar *record,
offset= ma_recordpos_to_dir_entry(record_pos); offset= ma_recordpos_to_dir_entry(record_pos);
DBUG_ASSERT(share->pagecache->block_size == block_size);
if (!(buff= pagecache_read(share->pagecache, if (!(buff= pagecache_read(share->pagecache,
&info->dfile, ma_recordpos_to_page(record_pos), 0, &info->dfile, ma_recordpos_to_page(record_pos), 0,
info->buff, share->page_type, info->buff, share->page_type,
@ -6762,13 +6791,15 @@ err:
/** /**
@brief Pagecache callback to get the TRANSLOG_ADDRESS to flush up to, when a @brief Get the TRANSLOG_ADDRESS to flush up to
data (non-bitmap) or index page needs to be flushed. Returns a real LSN.
@param page Page's content @param page Page's content
@param page_no Page's number (<offset>/<page length>) @param page_no Page's number (<offset>/<page length>)
@param data_ptr Callback data pointer (pointer to MARIA_SHARE) @param data_ptr Callback data pointer (pointer to MARIA_SHARE)
@note
Usable for data (non-bitmap) and index pages
@retval LSN to flush up to @retval LSN to flush up to
*/ */

View File

@ -94,7 +94,8 @@ static int _ma_safe_scan_block_record(MARIA_SORT_INFO *sort_info,
static void copy_data_file_state(MARIA_STATE_INFO *to, static void copy_data_file_state(MARIA_STATE_INFO *to,
MARIA_STATE_INFO *from); MARIA_STATE_INFO *from);
static int write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info); static int write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info);
static void report_keypage_fault(HA_CHECK *param, my_off_t position); static void report_keypage_fault(HA_CHECK *param, MARIA_HA *info,
my_off_t position);
static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file); static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file);
@ -496,7 +497,7 @@ int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
PAGECACHE_LOCK_LEFT_UNLOCKED, DFLT_INIT_HITS, PAGECACHE_LOCK_LEFT_UNLOCKED, DFLT_INIT_HITS,
info->buff, 0, 0)) info->buff, 0, 0))
{ {
report_keypage_fault(param, share->state.key_root[key]); report_keypage_fault(param, info, share->state.key_root[key]);
if (!(param->testflag & T_INFO)) if (!(param->testflag & T_INFO))
DBUG_RETURN(-1); DBUG_RETURN(-1);
result= -1; result= -1;
@ -662,7 +663,7 @@ static int chk_index_down(HA_CHECK *param, MARIA_HA *info,
if (!_ma_fetch_keypage(info, keyinfo, page, PAGECACHE_LOCK_LEFT_UNLOCKED, if (!_ma_fetch_keypage(info, keyinfo, page, PAGECACHE_LOCK_LEFT_UNLOCKED,
DFLT_INIT_HITS, buff, 0, 0)) DFLT_INIT_HITS, buff, 0, 0))
{ {
report_keypage_fault(param, page); report_keypage_fault(param, info, page);
goto err; goto err;
} }
param->key_file_blocks+=keyinfo->block_length; param->key_file_blocks+=keyinfo->block_length;
@ -1578,6 +1579,7 @@ static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
uchar *dir_entry; uchar *dir_entry;
uint row; uint row;
char llbuff[22], llbuff2[22]; char llbuff[22], llbuff2[22];
ulonglong page= page_pos / share->block_size;
DBUG_ENTER("check_head_page"); DBUG_ENTER("check_head_page");
dir_entry= page_buff+ share->block_size - PAGE_SUFFIX_SIZE; dir_entry= page_buff+ share->block_size - PAGE_SUFFIX_SIZE;
@ -1593,25 +1595,24 @@ static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
"Page %9s: Row %3u is too short (%d bytes)", "Page %9s: Row %3u is too short (%d bytes)",
llstr(page_pos, llbuff), row, length); llstr(page, llbuff), row, length);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
flag= (uint) (uchar) page_buff[pos]; flag= (uint) (uchar) page_buff[pos];
if (flag & ~(ROW_FLAG_ALL)) if (flag & ~(ROW_FLAG_ALL))
_ma_check_print_error(param, _ma_check_print_error(param,
"Page %9s: Row %3u has wrong flag: %d", "Page %9s: Row %3u has wrong flag: %d",
llstr(page_pos, llbuff), row, flag); llstr(page, llbuff), row, flag);
DBUG_PRINT("info", ("rowid: %s page: %lu row: %u", DBUG_PRINT("info", ("rowid: %s page: %lu row: %u",
llstr(ma_recordpos(page_pos/share->block_size, row), llstr(ma_recordpos(page, row), llbuff),
llbuff), (ulong) page, row));
(ulong) (page_pos / share->block_size), row));
if (_ma_read_block_record2(info, record, page_buff+pos, if (_ma_read_block_record2(info, record, page_buff+pos,
page_buff+pos+length)) page_buff+pos+length))
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
"Page %9s: Row %3d is crashed", "Page %9s: Row %3d is crashed",
llstr(page_pos, llbuff), row); llstr(page, llbuff), row);
if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE)) if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
DBUG_RETURN(1); DBUG_RETURN(1);
continue; continue;
@ -1621,7 +1622,7 @@ static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
ha_checksum checksum= (*share->calc_checksum)(info, record); ha_checksum checksum= (*share->calc_checksum)(info, record);
if (info->cur_row.checksum != (checksum & 255)) if (info->cur_row.checksum != (checksum & 255))
_ma_check_print_error(param, "Page %9s: Row %3d has wrong checksum", _ma_check_print_error(param, "Page %9s: Row %3d has wrong checksum",
llstr(page_pos, llbuff), row); llstr(page, llbuff), row);
param->glob_crc+= checksum; param->glob_crc+= checksum;
} }
if (info->cur_row.extents_count) if (info->cur_row.extents_count)
@ -1631,8 +1632,8 @@ static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
/* Check that bitmap has the right marker for the found extents */ /* Check that bitmap has the right marker for the found extents */
for (i= 0 ; i < info->cur_row.extents_count ; i++) for (i= 0 ; i < info->cur_row.extents_count ; i++)
{ {
uint page, page_count, page_type; uint extent_page, page_count, page_type;
page= uint5korr(extents); extent_page= uint5korr(extents);
page_count= uint2korr(extents+5) & ~START_EXTENT_BIT; page_count= uint2korr(extents+5) & ~START_EXTENT_BIT;
extents+= ROW_EXTENT_SIZE; extents+= ROW_EXTENT_SIZE;
page_type= BLOB_PAGE; page_type= BLOB_PAGE;
@ -1646,19 +1647,17 @@ static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
Check the whole extent with one test and only do the loop if Check the whole extent with one test and only do the loop if
something is wrong (for exact error reporting) something is wrong (for exact error reporting)
*/ */
for ( ; page_count--; page++) for ( ; page_count--; extent_page++)
{ {
uint bitmap_pattern; uint bitmap_pattern;
if (_ma_check_if_right_bitmap_type(info, page_type, page, if (_ma_check_if_right_bitmap_type(info, page_type, extent_page,
&bitmap_pattern)) &bitmap_pattern))
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
"Page %9s: Row: %3d has an extent with wrong information in bitmap: Page %9s Page_type: %d Bitmap: %d", "Page %9s: Row: %3d has an extent with wrong information in bitmap: Page %9s Page_type: %d Bitmap: %d",
llstr(page_pos, llbuff), row, llstr(page, llbuff), row,
llstr(page * share->bitmap.block_size, llstr(extent_page, llbuff2),
llbuff2), page_type, bitmap_pattern);
page_type,
bitmap_pattern);
if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE)) if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -1668,8 +1667,7 @@ static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
param->full_page_count+= info->cur_row.full_page_count; param->full_page_count+= info->cur_row.full_page_count;
param->tail_count+= info->cur_row.tail_count; param->tail_count+= info->cur_row.tail_count;
if (check_keys_in_record(param, info, extend, if (check_keys_in_record(param, info, extend,
ma_recordpos(page_pos/share->block_size, row), ma_recordpos(page, row), record))
record))
DBUG_RETURN(1); DBUG_RETURN(1);
} }
DBUG_RETURN(0); DBUG_RETURN(0);
@ -1685,6 +1683,7 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
{ {
MARIA_SHARE *share= info->s; MARIA_SHARE *share= info->s;
my_off_t pos; my_off_t pos;
ulonglong page;
uchar *page_buff, *bitmap_buff, *data; uchar *page_buff, *bitmap_buff, *data;
char llbuff[22], llbuff2[22]; char llbuff[22], llbuff2[22];
uint block_size= share->block_size; uint block_size= share->block_size;
@ -1705,10 +1704,11 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
full_page_count= tail_count= 0; full_page_count= tail_count= 0;
param->full_page_count= param->tail_count= 0; param->full_page_count= param->tail_count= 0;
param->used= param->link_used= 0; param->used= param->link_used= 0;
param->splits= info->state->data_file_length / block_size;
for (pos= 0; for (pos= 0, page= 0;
pos < info->state->data_file_length; pos < info->state->data_file_length;
pos+= block_size) pos+= block_size, page++)
{ {
uint row_count, real_row_count, empty_space, page_type, bitmap_pattern; uint row_count, real_row_count, empty_space, page_type, bitmap_pattern;
LINT_INIT(row_count); LINT_INIT(row_count);
@ -1719,19 +1719,19 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
_ma_scan_end_block_record(info); _ma_scan_end_block_record(info);
return -1; return -1;
} }
if (((pos / block_size) % share->bitmap.pages_covered) == 0) if ((page % share->bitmap.pages_covered) == 0)
{ {
/* Bitmap page */ /* Bitmap page */
if (pagecache_read(share->pagecache, if (pagecache_read(share->pagecache,
&info->s->bitmap.file, &info->s->bitmap.file,
(pos / block_size), 1, page, 1,
bitmap_buff, bitmap_buff,
PAGECACHE_PLAIN_PAGE, PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_LEFT_UNLOCKED, 0) == 0) PAGECACHE_LOCK_LEFT_UNLOCKED, 0) == 0)
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
"Page %9s: Got error: %d when reading datafile", "Page %9s: Got error: %d when reading datafile",
llstr(pos, llbuff), my_errno); llstr(page, llbuff), my_errno);
goto err; goto err;
} }
param->used+= block_size; param->used+= block_size;
@ -1739,11 +1739,10 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
continue; continue;
} }
/* Skip pages marked as empty in bitmap */ /* Skip pages marked as empty in bitmap */
offset_page= (((pos / block_size) % share->bitmap.pages_covered) -1) * 3; offset_page= ((page % share->bitmap.pages_covered) -1) * 3;
offset= offset_page & 7; offset= offset_page & 7;
data= bitmap_buff + offset_page / 8; data= bitmap_buff + offset_page / 8;
bitmap_pattern= uint2korr(data); bitmap_pattern= uint2korr(data);
param->splits++;
if (!((bitmap_pattern >> offset) & 7)) if (!((bitmap_pattern >> offset) & 7))
{ {
param->empty+= block_size; param->empty+= block_size;
@ -1753,22 +1752,22 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
if (pagecache_read(share->pagecache, if (pagecache_read(share->pagecache,
&info->dfile, &info->dfile,
(pos / block_size), 1, page, 1,
page_buff, page_buff,
share->page_type, share->page_type,
PAGECACHE_LOCK_LEFT_UNLOCKED, 0) == 0) PAGECACHE_LOCK_LEFT_UNLOCKED, 0) == 0)
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
"Page %9s: Got error: %d when reading datafile", "Page %9s: Got error: %d when reading datafile",
llstr(pos, llbuff), my_errno); llstr(page, llbuff), my_errno);
goto err; goto err;
} }
page_type= page_buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK; page_type= page_buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK;
if (page_type == UNALLOCATED_PAGE || page_type >= MAX_PAGE_TYPE) if (page_type == UNALLOCATED_PAGE || page_type >= MAX_PAGE_TYPE)
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
"Page %9s: Found wrong page type %d", "Page: %9s Found wrong page type %d",
llstr(pos, llbuff), page_type); llstr(page, llbuff), page_type);
if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE)) if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
goto err; goto err;
continue; continue;
@ -1782,20 +1781,22 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
case HEAD_PAGE: case HEAD_PAGE:
row_count= ((uchar*) page_buff)[DIR_COUNT_OFFSET]; row_count= ((uchar*) page_buff)[DIR_COUNT_OFFSET];
empty_space= uint2korr(page_buff + EMPTY_SPACE_OFFSET); empty_space= uint2korr(page_buff + EMPTY_SPACE_OFFSET);
param->used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE + param->used+= block_size - empty_space;
row_count * DIR_ENTRY_SIZE);
param->link_used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE + param->link_used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE +
row_count * DIR_ENTRY_SIZE); row_count * DIR_ENTRY_SIZE);
if (empty_space < share->bitmap.sizes[3])
param->lost+= empty_space;
full_dir= row_count == MAX_ROWS_PER_PAGE; full_dir= row_count == MAX_ROWS_PER_PAGE;
break; break;
case TAIL_PAGE: case TAIL_PAGE:
row_count= ((uchar*) page_buff)[DIR_COUNT_OFFSET]; row_count= ((uchar*) page_buff)[DIR_COUNT_OFFSET];
empty_space= uint2korr(page_buff + EMPTY_SPACE_OFFSET); empty_space= uint2korr(page_buff + EMPTY_SPACE_OFFSET);
param->used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE + param->used+= block_size - empty_space;
row_count * DIR_ENTRY_SIZE);
param->link_used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE + param->link_used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE +
row_count * DIR_ENTRY_SIZE); row_count * DIR_ENTRY_SIZE);
full_dir= row_count == MAX_ROWS_PER_PAGE; full_dir= row_count == MAX_ROWS_PER_PAGE;
if (empty_space < share->bitmap.sizes[6])
param->lost+= empty_space;
break; break;
case BLOB_PAGE: case BLOB_PAGE:
full_page_count++; full_page_count++;
@ -1805,19 +1806,19 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
param->used+= block_size; param->used+= block_size;
break; break;
} }
if (_ma_check_bitmap_data(info, page_type, pos / block_size, if (_ma_check_bitmap_data(info, page_type, page,
full_dir ? 0 : empty_space, full_dir ? 0 : empty_space,
&bitmap_pattern)) &bitmap_pattern))
{ {
if (bitmap_pattern == ~(uint) 0) if (bitmap_pattern == ~(uint) 0)
_ma_check_print_error(param, _ma_check_print_error(param,
"Page: %9s: Wrong bitmap for data on page", "Page %9s: Wrong bitmap for data on page",
llstr(pos, llbuff)); llstr(page, llbuff));
else else
_ma_check_print_error(param, _ma_check_print_error(param,
"Page %9s: Wrong data in bitmap. Page_type: %d empty_space: %u Bitmap-bits: %d", "Page %9s: Wrong data in bitmap. Page_type: %d empty_space: %u Bitmap-bits: %d",
llstr(pos, llbuff), page_type, empty_space, llstr(page, llbuff), page_type,
bitmap_pattern); empty_space, bitmap_pattern);
if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE)) if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
goto err; goto err;
} }
@ -1839,11 +1840,11 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
/* Verify that rest of bitmap is zero */ /* Verify that rest of bitmap is zero */
if ((pos / block_size) % share->bitmap.pages_covered) if (page % share->bitmap.pages_covered)
{ {
/* Not at end of bitmap */ /* Not at end of bitmap */
uint bitmap_pattern; uint bitmap_pattern;
offset_page= (((pos / block_size) % share->bitmap.pages_covered) -1) * 3; offset_page= ((page % share->bitmap.pages_covered) -1) * 3;
offset= offset_page & 7; offset= offset_page & 7;
data= bitmap_buff + offset_page / 8; data= bitmap_buff + offset_page / 8;
bitmap_pattern= uint2korr(data); bitmap_pattern= uint2korr(data);
@ -1853,10 +1854,12 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
data - 2))) data - 2)))
{ {
ulonglong bitmap_page; ulonglong bitmap_page;
bitmap_page= pos / block_size / share->bitmap.pages_covered; bitmap_page= page / share->bitmap.pages_covered;
bitmap_page*= share->bitmap.pages_covered; bitmap_page*= share->bitmap.pages_covered;
_ma_check_print_error(param, "Bitmap at %s has pages reserved outside of data file length", _ma_check_print_error(param,
"Bitmap at page %s has pages reserved outside of "
"data file length",
llstr(bitmap_page, llbuff)); llstr(bitmap_page, llbuff));
DBUG_EXECUTE("bitmap", _ma_print_bitmap(&share->bitmap, bitmap_buff, DBUG_EXECUTE("bitmap", _ma_print_bitmap(&share->bitmap, bitmap_buff,
bitmap_page);); bitmap_page););
@ -1874,9 +1877,6 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
llstr(param->tail_count, llbuff), llstr(param->tail_count, llbuff),
llstr(tail_count, llbuff2)); llstr(tail_count, llbuff2));
/* Update splits to avoid warning */
share->state.split= param->splits;
info->state->del= param->del_blocks;
return param->error_printed != 0; return param->error_printed != 0;
err: err:
@ -1910,6 +1910,7 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info,int extend)
} }
param->records= param->del_blocks= 0; param->records= param->del_blocks= 0;
param->used= param->link_used= param->splits= param->del_length= 0; param->used= param->link_used= param->splits= param->del_length= 0;
param->lost= 0;
param->tmp_record_checksum= param->glob_crc= 0; param->tmp_record_checksum= param->glob_crc= 0;
param->err_count= 0; param->err_count= 0;
@ -1953,7 +1954,7 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info,int extend)
param->record_checksum != param->tmp_record_checksum) param->record_checksum != param->tmp_record_checksum)
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
"Key pointers and record positions doesn't match"); "Key pointers and record positions doesn't match");
error=1; error=1;
} }
else if (param->glob_crc != info->state->checksum && else if (param->glob_crc != info->state->checksum &&
@ -1961,7 +1962,7 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info,int extend)
(HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))) (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
{ {
_ma_check_print_warning(param, _ma_check_print_warning(param,
"Record checksum is not the same as checksum stored in the index file"); "Record checksum is not the same as checksum stored in the index file");
error=1; error=1;
} }
else if (!extend) else if (!extend)
@ -1973,7 +1974,7 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info,int extend)
!(share->keyinfo[key].flag & (HA_FULLTEXT | HA_SPATIAL))) !(share->keyinfo[key].flag & (HA_FULLTEXT | HA_SPATIAL)))
{ {
_ma_check_print_error(param,"Checksum for key: %2d doesn't match checksum for records", _ma_check_print_error(param,"Checksum for key: %2d doesn't match checksum for records",
key+1); key+1);
error=1; error=1;
} }
} }
@ -1982,37 +1983,41 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info,int extend)
if (param->del_length != info->state->empty) if (param->del_length != info->state->empty)
{ {
_ma_check_print_warning(param, _ma_check_print_warning(param,
"Found %s deleted space. Should be %s", "Found %s deleted space. Should be %s",
llstr(param->del_length,llbuff2), llstr(param->del_length,llbuff2),
llstr(info->state->empty,llbuff)); llstr(info->state->empty,llbuff));
} }
if (param->used + param->empty + param->del_length != /* Skip following checks for BLOCK RECORD as they don't make any sence */
info->state->data_file_length) if (share->data_file_type != BLOCK_RECORD)
{ {
_ma_check_print_warning(param, if (param->used + param->empty + param->del_length !=
"Found %s record data and %s unused data and %s deleted data", info->state->data_file_length)
llstr(param->used, llbuff), {
llstr(param->empty,llbuff2), _ma_check_print_warning(param,
llstr(param->del_length,llbuff3)); "Found %s record data and %s unused data and %s deleted data",
_ma_check_print_warning(param, llstr(param->used, llbuff),
"Total %s Should be: %s", llstr(param->empty,llbuff2),
llstr((param->used+param->empty+param->del_length), llstr(param->del_length,llbuff3));
llbuff), _ma_check_print_warning(param,
llstr(info->state->data_file_length,llbuff2)); "Total %s Should be: %s",
} llstr((param->used+param->empty +
if (param->del_blocks != info->state->del) param->del_length), llbuff),
{ llstr(info->state->data_file_length,llbuff2));
_ma_check_print_warning(param, }
"Found %10s deleted blocks Should be: %s", if (param->del_blocks != info->state->del)
llstr(param->del_blocks,llbuff), {
llstr(info->state->del,llbuff2)); _ma_check_print_warning(param,
} "Found %10s deleted blocks Should be: %s",
if (param->splits != share->state.split) llstr(param->del_blocks,llbuff),
{ llstr(info->state->del,llbuff2));
_ma_check_print_warning(param, }
"Found %10s parts Should be: %s parts", if (param->splits != share->state.split)
llstr(param->splits, llbuff), {
llstr(share->state.split,llbuff2)); _ma_check_print_warning(param,
"Found %10s parts Should be: %s parts",
llstr(param->splits, llbuff),
llstr(share->state.split,llbuff2));
}
} }
if (param->testflag & T_INFO) if (param->testflag & T_INFO)
{ {
@ -2044,18 +2049,20 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info,int extend)
printf("Records:%18s\n", "0"); printf("Records:%18s\n", "0");
} }
printf("Record blocks:%12s Delete blocks:%10s\n", printf("Record blocks:%12s Delete blocks:%10s\n",
llstr(param->splits - param->del_blocks, llbuff), llstr(param->splits - param->del_blocks, llbuff),
llstr(param->del_blocks, llbuff2)); llstr(param->del_blocks, llbuff2));
printf("Record data: %12s Deleted data: %10s\n", printf("Record data: %12s Deleted data: %10s\n",
llstr(param->used - param->link_used,llbuff), llstr(param->used - param->link_used,llbuff),
llstr(param->del_length, llbuff2)); llstr(param->del_length, llbuff2));
printf("Lost space: %12s Linkdata: %10s\n", printf("Empty space: %12s Linkdata: %10s\n",
llstr(param->empty, llbuff),llstr(param->link_used, llbuff2)); llstr(param->empty, llbuff),llstr(param->link_used, llbuff2));
if (param->lost)
printf("Lost space: %12s", llstr(param->lost, llbuff));
} }
my_free((uchar*) record,MYF(0)); my_free((uchar*) record,MYF(0));
DBUG_RETURN (error); DBUG_RETURN (error);
err: err:
my_free((uchar*) record,MYF(0)); my_free((uchar*) record,MYF(0));
param->testflag|=T_RETRY_WITHOUT_QUICK; param->testflag|=T_RETRY_WITHOUT_QUICK;
DBUG_RETURN(1); DBUG_RETURN(1);
@ -2180,6 +2187,8 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
if (initialize_variables_for_repair(param, &sort_info, &sort_param, info, if (initialize_variables_for_repair(param, &sort_info, &sort_param, info,
rep_quick)) rep_quick))
goto err; goto err;
if (share->now_transactional)
_ma_tmp_disable_logging_for_table(info, 0);
new_header_length= ((param->testflag & T_UNPACK) ? 0L : new_header_length= ((param->testflag & T_UNPACK) ? 0L :
share->pack.header_length); share->pack.header_length);
@ -2423,11 +2432,11 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
{ {
if (start_records != info->state->records) if (start_records != info->state->records)
printf("Data records: %s\n", llstr(info->state->records,llbuff)); printf("Data records: %s\n", llstr(info->state->records,llbuff));
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
} }
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error= 0; got_error= 0;
/* If invoked by external program that uses thr_lock */ /* If invoked by external program that uses thr_lock */
@ -2469,6 +2478,8 @@ err:
*/ */
write_log_record_for_repair(param, info); write_log_record_for_repair(param, info);
} }
_ma_reenable_logging_for_table(info);
my_free(sort_param.rec_buff, MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_param.rec_buff, MYF(MY_ALLOW_ZERO_PTR));
my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
@ -2799,7 +2810,7 @@ static int sort_one_index(HA_CHECK *param, MARIA_HA *info,
if (!_ma_fetch_keypage(info, keyinfo, pagepos,PAGECACHE_LOCK_LEFT_UNLOCKED, if (!_ma_fetch_keypage(info, keyinfo, pagepos,PAGECACHE_LOCK_LEFT_UNLOCKED,
DFLT_INIT_HITS, buff, 0, 0)) DFLT_INIT_HITS, buff, 0, 0))
{ {
report_keypage_fault(param, pagepos); report_keypage_fault(param, info, pagepos);
goto err; goto err;
} }
if ((nod_flag=_ma_test_if_nod(share, buff)) || keyinfo->flag & HA_FULLTEXT) if ((nod_flag=_ma_test_if_nod(share, buff)) || keyinfo->flag & HA_FULLTEXT)
@ -2952,6 +2963,7 @@ static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info,
my_off_t pos; my_off_t pos;
ulonglong page; ulonglong page;
uint block_size= share->block_size; uint block_size= share->block_size;
MARIA_FILE_BITMAP *bitmap= &share->bitmap;
DBUG_ENTER("maria_zerofill_data"); DBUG_ENTER("maria_zerofill_data");
/* This works only with BLOCK_RECORD files */ /* This works only with BLOCK_RECORD files */
@ -2989,7 +3001,13 @@ static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info,
bzero(buff, block_size); bzero(buff, block_size);
break; break;
case BLOB_PAGE: case BLOB_PAGE:
bzero(buff, LSN_SIZE); if (_ma_bitmap_get_page_bits(info, bitmap, page) == 0)
{
/* Unallocated page */
bzero(buff, block_size);
}
else
bzero(buff, LSN_SIZE);
break; break;
case HEAD_PAGE: case HEAD_PAGE:
case TAIL_PAGE: case TAIL_PAGE:
@ -3364,6 +3382,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
(size_t) param->sort_buffer_length)) (size_t) param->sort_buffer_length))
{ {
param->retry_repair=1; param->retry_repair=1;
_ma_check_print_error(param, "Create index by sort failed");
goto err; goto err;
} }
DBUG_EXECUTE_IF("maria_flush_whole_log", DBUG_EXECUTE_IF("maria_flush_whole_log",
@ -3404,7 +3423,10 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
param->read_cache.end_of_file=sort_param.filepos; param->read_cache.end_of_file=sort_param.filepos;
if (maria_write_data_suffix(&sort_info,1) || if (maria_write_data_suffix(&sort_info,1) ||
end_io_cache(&sort_info.new_info->rec_cache)) end_io_cache(&sort_info.new_info->rec_cache))
{
_ma_check_print_error(param, "Got error when flushing row cache");
goto err; goto err;
}
sort_info.new_info->opt_flag&= ~WRITE_CACHE_USED; sort_info.new_info->opt_flag&= ~WRITE_CACHE_USED;
if (param->testflag & T_SAFE_REPAIR) if (param->testflag & T_SAFE_REPAIR)
@ -3412,14 +3434,20 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
/* Don't repair if we loosed more than one row */ /* Don't repair if we loosed more than one row */
if (info->state->records+1 < start_records) if (info->state->records+1 < start_records)
{ {
info->state->records=start_records; _ma_check_print_error(param,
"Rows lost; Aborting because safe repair was "
"requested");
info->state->records=start_records;
goto err; goto err;
} }
} }
/** @todo RECOVERY BUG seems misplaced in some cases */ /** @todo RECOVERY BUG seems misplaced in some cases */
if (_ma_flush_table_files_after_repair(param, info)) if (_ma_flush_table_files_after_repair(param, info))
{
_ma_check_print_error(param, "Got error when flushing caches");
goto err; goto err;
}
sort_info.new_info->state->data_file_length= sort_param.filepos; sort_info.new_info->state->data_file_length= sort_param.filepos;
if (sort_info.new_info != sort_info.info) if (sort_info.new_info != sort_info.info)
@ -3433,6 +3461,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
copy_data_file_state(&share->state, &save_state); copy_data_file_state(&share->state, &save_state);
new_file= -1; new_file= -1;
sort_info.new_info= info; sort_info.new_info= info;
info->rec_cache.file= info->dfile.file;
} }
share->state.version=(ulong) time((time_t*) 0); /* Force reopen */ share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
@ -3451,6 +3480,7 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
sync_dir) || sync_dir) ||
_ma_open_datafile(info, share, -1)) _ma_open_datafile(info, share, -1))
{ {
_ma_check_print_error(param, "Couldn't change to new data file");
goto err; goto err;
} }
if (param->testflag & T_UNPACK) if (param->testflag & T_UNPACK)
@ -3513,11 +3543,11 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
{ {
if (start_records != info->state->records) if (start_records != info->state->records)
printf("Data records: %s\n", llstr(info->state->records,llbuff)); printf("Data records: %s\n", llstr(info->state->records,llbuff));
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
} }
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error=0; got_error=0;
if (&share->state.state != info->state) if (&share->state.state != info->state)
@ -3953,11 +3983,12 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
if (sort_param[0].fix_datafile) if (sort_param[0].fix_datafile)
{ {
/* /*
Append some nuls to the end of a memory mapped file. Destroy the Append some nulls to the end of a memory mapped file. Destroy the
write cache. The master thread did already detach from the share write cache. The master thread did already detach from the share
by remove_io_thread() in sort.c:thr_find_all_keys(). by remove_io_thread() in sort.c:thr_find_all_keys().
*/ */
if (maria_write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache)) if (maria_write_data_suffix(&sort_info,1) ||
end_io_cache(&info->rec_cache))
goto err; goto err;
if (param->testflag & T_SAFE_REPAIR) if (param->testflag & T_SAFE_REPAIR)
{ {
@ -4013,17 +4044,18 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
if (my_chsize(share->kfile.file, info->state->key_file_length, 0, MYF(0))) if (my_chsize(share->kfile.file, info->state->key_file_length, 0, MYF(0)))
_ma_check_print_warning(param, _ma_check_print_warning(param,
"Can't change size of indexfile, error: %d", my_errno); "Can't change size of indexfile, error: %d",
my_errno);
if (!(param->testflag & T_SILENT)) if (!(param->testflag & T_SILENT))
{ {
if (start_records != info->state->records) if (start_records != info->state->records)
printf("Data records: %s\n", llstr(info->state->records,llbuff)); printf("Data records: %s\n", llstr(info->state->records,llbuff));
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
} }
if (sort_info.dupp)
_ma_check_print_warning(param,
"%s records have been removed",
llstr(sort_info.dupp,llbuff));
got_error=0; got_error=0;
if (&share->state.state != info->state) if (&share->state.state != info->state)
@ -5121,7 +5153,7 @@ static int sort_insert_key(MARIA_SORT_PARAM *sort_param,
a_length+=t_length; a_length+=t_length;
_ma_store_page_used(share, anc_buff, a_length); _ma_store_page_used(share, anc_buff, a_length);
key_block->end_pos+=t_length; key_block->end_pos+=t_length;
if (a_length <= keyinfo->block_length) if (a_length <= (uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
{ {
VOID(_ma_move_key(keyinfo, key_block->lastkey, key)); VOID(_ma_move_key(keyinfo, key_block->lastkey, key));
key_block->last_length=a_length-t_length; key_block->last_length=a_length-t_length;
@ -5196,37 +5228,40 @@ static int sort_delete_record(MARIA_SORT_PARAM *sort_param)
old_file= row_info->dfile.file; old_file= row_info->dfile.file;
/* This only affects static and dynamic row formats */ /* This only affects static and dynamic row formats */
row_info->dfile.file= row_info->rec_cache.file; row_info->dfile.file= row_info->rec_cache.file;
if (sort_info->current_key) if (flush_io_cache(&row_info->rec_cache))
{ DBUG_RETURN(1);
key= key_info->lastkey + key_info->s->base.max_key_length;
if ((error=(*row_info->s->read_record)(row_info, sort_param->record, key= key_info->lastkey + key_info->s->base.max_key_length;
key_info->cur_row.lastpos)) && if ((error=(*row_info->s->read_record)(row_info, sort_param->record,
key_info->cur_row.lastpos)) &&
error != HA_ERR_RECORD_DELETED) error != HA_ERR_RECORD_DELETED)
{
_ma_check_print_error(param,"Can't read record to be removed");
row_info->dfile.file= old_file;
DBUG_RETURN(1);
}
row_info->cur_row.lastpos= key_info->cur_row.lastpos;
for (i=0 ; i < sort_info->current_key ; i++)
{
uint key_length= _ma_make_key(key_info, i, key, sort_param->record,
key_info->cur_row.lastpos);
if (_ma_ck_delete(key_info, i, key, key_length))
{ {
_ma_check_print_error(param,"Can't read record to be removed"); _ma_check_print_error(param,
"Can't delete key %d from record to be removed",
i+1);
row_info->dfile.file= old_file; row_info->dfile.file= old_file;
DBUG_RETURN(1); DBUG_RETURN(1);
} }
for (i=0 ; i < sort_info->current_key ; i++)
{
uint key_length= _ma_make_key(key_info, i, key, sort_param->record,
key_info->cur_row.lastpos);
if (_ma_ck_delete(key_info, i, key, key_length))
{
_ma_check_print_error(param,
"Can't delete key %d from record to be removed",
i+1);
row_info->dfile.file= old_file;
DBUG_RETURN(1);
}
}
if (sort_param->calc_checksum)
param->glob_crc-=(*key_info->s->calc_check_checksum)(key_info,
sort_param->record);
} }
error= (flush_io_cache(&row_info->rec_cache) || if (sort_param->calc_checksum)
(*row_info->s->delete_record)(row_info, sort_param->record)); param->glob_crc-=(*key_info->s->calc_check_checksum)(key_info,
sort_param->record);
error= (*row_info->s->delete_record)(row_info, sort_param->record);
if (error)
_ma_check_print_error(param,"Got error %d when deleting record",
my_errno);
row_info->dfile.file= old_file; /* restore actual value */ row_info->dfile.file= old_file; /* restore actual value */
row_info->state->records--; row_info->state->records--;
DBUG_RETURN(error); DBUG_RETURN(error);
@ -6024,7 +6059,7 @@ static int _ma_safe_scan_block_record(MARIA_SORT_INFO *sort_info,
if (info->scan.dir < info->scan.dir_end) if (info->scan.dir < info->scan.dir_end)
{ {
_ma_check_print_info(sort_info->param, _ma_check_print_info(sort_info->param,
"Wrong directory on page: %s", "Wrong directory on page %s",
llstr(page, llbuff)); llstr(page, llbuff));
goto read_next_page; goto read_next_page;
} }
@ -6075,8 +6110,8 @@ read_next_page:
if (my_errno == HA_ERR_WRONG_CRC) if (my_errno == HA_ERR_WRONG_CRC)
{ {
_ma_check_print_info(sort_info->param, _ma_check_print_info(sort_info->param,
"Wrong CRC on page at %s", "Wrong CRC on datapage at %s",
llstr(page * share->block_size, llbuff)); llstr(page, llbuff));
continue; continue;
} }
DBUG_RETURN(my_errno); DBUG_RETURN(my_errno);
@ -6089,15 +6124,14 @@ read_next_page:
(uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET]) != 0) (uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET]) != 0)
break; break;
_ma_check_print_info(sort_info->param, _ma_check_print_info(sort_info->param,
"Wrong head page at %s", "Wrong head page at page %s",
llstr(page * share->block_size, llbuff)); llstr(page, llbuff));
} }
else if (page_type >= MAX_PAGE_TYPE) else if (page_type >= MAX_PAGE_TYPE)
{ {
_ma_check_print_info(sort_info->param, _ma_check_print_info(sort_info->param,
"Found wrong page type: %d at %s", "Found wrong page type: %d at page %s",
page_type, llstr(page * share->block_size, page_type, llstr(page, llbuff));
llbuff));
} }
} }
@ -6199,17 +6233,19 @@ static int write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info)
/* Give error message why reading of key page failed */ /* Give error message why reading of key page failed */
static void report_keypage_fault(HA_CHECK *param, my_off_t position) static void report_keypage_fault(HA_CHECK *param, MARIA_HA *info,
my_off_t position)
{ {
char buff[11]; char buff[11];
uint32 block_size= info->s->block_size;
if (my_errno == HA_ERR_CRASHED) if (my_errno == HA_ERR_CRASHED)
_ma_check_print_error(param, _ma_check_print_error(param,
"Wrong base information on indexpage at filepos: %s", "Wrong base information on indexpage at page: %s",
llstr(position, buff)); llstr(position / block_size, buff));
else else
_ma_check_print_error(param, _ma_check_print_error(param,
"Can't read indexpage from filepos: %s, " "Can't read indexpage from page: %s, "
"error: %d", "error: %d",
llstr(position,buff), my_errno); llstr(position / block_size, buff), my_errno);
} }

View File

@ -150,7 +150,7 @@ int maria_create(const char *name, enum data_file_type datafile_type,
if (datafile_type == BLOCK_RECORD) if (datafile_type == BLOCK_RECORD)
{ {
if (type == FIELD_SKIP_PRESPACE) if (type == FIELD_SKIP_PRESPACE)
type= FIELD_NORMAL; /* SKIP_PRESPACE not supported */ type= column->type= FIELD_NORMAL; /* SKIP_PRESPACE not supported */
if (type == FIELD_NORMAL && if (type == FIELD_NORMAL &&
column->length > FULL_PAGE_SIZE(maria_block_size)) column->length > FULL_PAGE_SIZE(maria_block_size))
{ {
@ -297,15 +297,17 @@ int maria_create(const char *name, enum data_file_type datafile_type,
share.base.max_field_lengths= max_field_lengths; share.base.max_field_lengths= max_field_lengths;
share.base.field_offsets= 0; /* for future */ share.base.field_offsets= 0; /* for future */
if (pack_reclength != INT_MAX32)
pack_reclength+= max_field_lengths + long_varchar_count;
if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM)) if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
{ {
options|= HA_OPTION_CHECKSUM; options|= HA_OPTION_CHECKSUM;
min_pack_length++; min_pack_length++;
pack_reclength++; pack_reclength++;
} }
if (pack_reclength < INT_MAX32)
pack_reclength+= max_field_lengths + long_varchar_count;
else
pack_reclength= INT_MAX32;
if (flags & HA_CREATE_DELAY_KEY_WRITE) if (flags & HA_CREATE_DELAY_KEY_WRITE)
options|= HA_OPTION_DELAY_KEY_WRITE; options|= HA_OPTION_DELAY_KEY_WRITE;
if (flags & HA_CREATE_RELIES_ON_SQL_LAYER) if (flags & HA_CREATE_RELIES_ON_SQL_LAYER)
@ -741,6 +743,13 @@ int maria_create(const char *name, enum data_file_type datafile_type,
/* Add length of packed fields + length */ /* Add length of packed fields + length */
share.base.pack_reclength+= share.base.max_field_lengths+3; share.base.pack_reclength+= share.base.max_field_lengths+3;
/* Adjust max_pack_length, to be used if we have short rows */
if (share.base.max_pack_length < maria_block_size)
{
share.base.max_pack_length+= FLAG_SIZE;
if (ci->transactional)
share.base.max_pack_length+= TRANSID_SIZE * 2;
}
} }
/* max_data_file_length and max_key_file_length are recalculated on open */ /* max_data_file_length and max_key_file_length are recalculated on open */
@ -1208,7 +1217,8 @@ uint maria_get_pointer_length(ulonglong file_length, uint def)
Fixed size, not null columns Fixed size, not null columns
Fixed length, null fields Fixed length, null fields
Variable length fields (CHAR, VARCHAR) Numbers (zero fill fields)
Variable length fields (CHAR, VARCHAR) according to length
Blobs Blobs
For same kind of fields, keep fields in original order For same kind of fields, keep fields in original order
@ -1225,10 +1235,8 @@ static int compare_columns(MARIA_COLUMNDEF **a_ptr, MARIA_COLUMNDEF **b_ptr)
MARIA_COLUMNDEF *a= *a_ptr, *b= *b_ptr; MARIA_COLUMNDEF *a= *a_ptr, *b= *b_ptr;
enum en_fieldtype a_type, b_type; enum en_fieldtype a_type, b_type;
a_type= ((a->type == FIELD_NORMAL || a->type == FIELD_CHECK) ? a_type= (a->type == FIELD_CHECK) ? FIELD_NORMAL : a->type;
FIELD_NORMAL : a->type); b_type= (b->type == FIELD_CHECK) ? FIELD_NORMAL : b->type;
b_type= ((b->type == FIELD_NORMAL || b->type == FIELD_CHECK) ?
FIELD_NORMAL : b->type);
if (a_type == FIELD_NORMAL && !a->null_bit) if (a_type == FIELD_NORMAL && !a->null_bit)
{ {
@ -1244,6 +1252,13 @@ static int compare_columns(MARIA_COLUMNDEF **a_ptr, MARIA_COLUMNDEF **b_ptr)
return -1; return -1;
if (b_type == FIELD_NORMAL) if (b_type == FIELD_NORMAL)
return 1; return 1;
if (a_type == FIELD_SKIP_ZERO)
return -1;
if (b_type == FIELD_SKIP_ZERO)
return 1;
if (a->type != FIELD_BLOB && b->type != FIELD_BLOB)
if (a->length != b->length)
return sign((long) a->length - (long) b->length);
if (a_type == FIELD_BLOB) if (a_type == FIELD_BLOB)
return 1; return 1;
if (b_type == FIELD_BLOB) if (b_type == FIELD_BLOB)

View File

@ -130,7 +130,11 @@ int maria_delete(MARIA_HA *info,const uchar *record)
DBUG_RETURN(0); DBUG_RETURN(0);
err: err:
save_errno=my_errno; save_errno= my_errno;
DBUG_ASSERT(save_errno);
if (!save_errno)
save_errno= HA_ERR_INTERNAL_ERROR; /* Should never happen */
mi_sizestore(lastpos, info->cur_row.lastpos); mi_sizestore(lastpos, info->cur_row.lastpos);
if (save_errno != HA_ERR_RECORD_CHANGED) if (save_errno != HA_ERR_RECORD_CHANGED)
{ {
@ -140,14 +144,12 @@ err:
VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE)); VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
info->update|=HA_STATE_WRITTEN; /* Buffer changed */ info->update|=HA_STATE_WRITTEN; /* Buffer changed */
allow_break(); /* Allow SIGHUP & SIGINT */ allow_break(); /* Allow SIGHUP & SIGINT */
my_errno=save_errno;
if (save_errno == HA_ERR_KEY_NOT_FOUND) if (save_errno == HA_ERR_KEY_NOT_FOUND)
{ {
maria_print_error(share, HA_ERR_CRASHED); maria_print_error(share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED; my_errno=HA_ERR_CRASHED;
} }
DBUG_RETURN(my_errno= save_errno);
DBUG_RETURN(my_errno);
} /* maria_delete */ } /* maria_delete */

View File

@ -1301,7 +1301,8 @@ ulong _ma_calc_total_blob_length(MARIA_HA *info, const uchar *record)
blob != end; blob != end;
blob++) blob++)
{ {
blob->length= _ma_calc_blob_length(blob->pack_length,record + blob->offset); blob->length= _ma_calc_blob_length(blob->pack_length,
record + blob->offset);
length+=blob->length; length+=blob->length;
} }
return length; return length;

View File

@ -589,6 +589,7 @@ int _ma_decrement_open_count(MARIA_HA *info)
if (share->state.open_count > 0) if (share->state.open_count > 0)
{ {
share->state.open_count--; share->state.open_count--;
share->changed= 1; /* We have to update state */
if (!(share->temporary | share->base.born_transactional)) if (!(share->temporary | share->base.born_transactional))
{ {
mi_int2store(buff,share->state.open_count); mi_int2store(buff,share->state.open_count);

View File

@ -287,7 +287,6 @@ enum enum_translog_status translog_status= TRANSLOG_UNINITED;
#define TRANSLOG_CLSN_LEN_BITS 0xC0 /* Mask to get compressed LSN length */ #define TRANSLOG_CLSN_LEN_BITS 0xC0 /* Mask to get compressed LSN length */
#include <my_atomic.h> #include <my_atomic.h>
/* an array that maps id of a MARIA_SHARE to this MARIA_SHARE */ /* an array that maps id of a MARIA_SHARE to this MARIA_SHARE */
static MARIA_SHARE **id_to_share= NULL; static MARIA_SHARE **id_to_share= NULL;
@ -715,10 +714,14 @@ static void translog_check_cursor(struct st_buffer_cursor *cursor
void translog_stop_writing() void translog_stop_writing()
{ {
DBUG_ENTER("translog_stop_writing");
DBUG_PRINT("error", ("errno: %d my_errno: %d", errno, my_errno));
translog_status= (translog_status == TRANSLOG_SHUTDOWN ? translog_status= (translog_status == TRANSLOG_SHUTDOWN ?
TRANSLOG_UNINITED : TRANSLOG_UNINITED :
TRANSLOG_READONLY); TRANSLOG_READONLY);
log_descriptor.open_flags= O_BINARY | O_RDONLY; log_descriptor.open_flags= O_BINARY | O_RDONLY;
DBUG_ASSERT(0);
DBUG_VOID_RETURN;
} }
@ -1165,7 +1168,6 @@ end:
} }
/* /*
@brief remove file mark "in progress" (for multi-group records) @brief remove file mark "in progress" (for multi-group records)
@ -2238,7 +2240,6 @@ static my_bool translog_buffer_flush(struct st_translog_buffer *buffer)
(ulong) buffer->size)); (ulong) buffer->size));
translog_buffer_lock_assert_owner(buffer); translog_buffer_lock_assert_owner(buffer);
translog_wait_for_writers(buffer); translog_wait_for_writers(buffer);
if (buffer->overlay && buffer->overlay->file == buffer->file && if (buffer->overlay && buffer->overlay->file == buffer->file &&
@ -2299,9 +2300,11 @@ static my_bool translog_buffer_flush(struct st_translog_buffer *buffer)
PAGECACHE_PIN_LEFT_UNPINNED, 0, PAGECACHE_PIN_LEFT_UNPINNED, 0,
LSN_IMPOSSIBLE)) LSN_IMPOSSIBLE))
{ {
DBUG_PRINT("error", ("Can't write page (%lu,0x%lx) to pagecache", DBUG_PRINT("error",
(ulong) buffer->file, ("Can't write page (%lu,0x%lx) to pagecache, error: %d",
(ulong) (LSN_OFFSET(buffer->offset)+ i))); (ulong) buffer->file,
(ulong) (LSN_OFFSET(buffer->offset)+ i),
my_errno));
translog_stop_writing(); translog_stop_writing();
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -2489,7 +2492,6 @@ translog_check_sector_protection(uchar *page, TRANSLOG_FILE *file)
@param page_no The page number (<offset>/<page length>) @param page_no The page number (<offset>/<page length>)
@param data_ptr Read callback data pointer (pointer to TRANSLOG_FILE) @param data_ptr Read callback data pointer (pointer to TRANSLOG_FILE)
@todo: add turning loghandler to read-only mode after merging with @todo: add turning loghandler to read-only mode after merging with
that patch. that patch.
@ -4021,7 +4023,6 @@ translog_buffer_increase_writers(struct st_translog_buffer *buffer)
buffer target buffer buffer target buffer
*/ */
static void translog_buffer_decrease_writers(struct st_translog_buffer *buffer) static void translog_buffer_decrease_writers(struct st_translog_buffer *buffer)
{ {
DBUG_ENTER("translog_buffer_decrease_writers"); DBUG_ENTER("translog_buffer_decrease_writers");
@ -4157,7 +4158,7 @@ translog_write_variable_record_chunk3_page(struct st_translog_parts *parts,
1 Error 1 Error
*/ */
static my_bool translog_advance_pointer(uint pages, uint16 last_page_data) static my_bool translog_advance_pointer(int pages, uint16 last_page_data)
{ {
translog_size_t last_page_offset= (log_descriptor.page_overhead + translog_size_t last_page_offset= (log_descriptor.page_overhead +
last_page_data); last_page_data);
@ -4174,6 +4175,21 @@ static my_bool translog_advance_pointer(uint pages, uint16 last_page_data)
(uint) last_page_data)); (uint) last_page_data));
translog_lock_assert_owner(); translog_lock_assert_owner();
if (pages == -1)
{
/*
It is special case when we advance the pointer on the same page.
It can happened when we write last part of multi-group record.
*/
DBUG_ASSERT(last_page_data + log_descriptor.bc.current_page_fill <=
TRANSLOG_PAGE_SIZE);
offset= last_page_data;
last_page_offset= log_descriptor.bc.current_page_fill + last_page_data;
goto end;
}
DBUG_PRINT("info", ("last_page_offset %lu", (ulong) last_page_offset));
DBUG_ASSERT(last_page_offset <= TRANSLOG_PAGE_SIZE);
/* /*
The loop will be executed 1-3 times. Usually we advance the The loop will be executed 1-3 times. Usually we advance the
pointer to fill only the current buffer (if we have more then 1/2 of pointer to fill only the current buffer (if we have more then 1/2 of
@ -4258,14 +4274,15 @@ static my_bool translog_advance_pointer(uint pages, uint16 last_page_data)
DBUG_RETURN(1); DBUG_RETURN(1);
offset-= min_offset; offset-= min_offset;
} }
DBUG_PRINT("info", ("drop write_counter"));
log_descriptor.bc.write_counter= 0;
log_descriptor.bc.previous_offset= 0;
end:
log_descriptor.bc.ptr+= offset; log_descriptor.bc.ptr+= offset;
log_descriptor.bc.buffer->size+= offset; log_descriptor.bc.buffer->size+= offset;
translog_buffer_increase_writers(log_descriptor.bc.buffer); translog_buffer_increase_writers(log_descriptor.bc.buffer);
log_descriptor.horizon+= offset; /* offset increasing */ log_descriptor.horizon+= offset; /* offset increasing */
log_descriptor.bc.current_page_fill= last_page_offset; log_descriptor.bc.current_page_fill= last_page_offset;
DBUG_PRINT("info", ("drop write_counter"));
log_descriptor.bc.write_counter= 0;
log_descriptor.bc.previous_offset= 0;
DBUG_PRINT("info", ("NewP buffer #%u: 0x%lx chaser: %d Size: %lu (%lu) " DBUG_PRINT("info", ("NewP buffer #%u: 0x%lx chaser: %d Size: %lu (%lu) "
"offset: %u last page: %u", "offset: %u last page: %u",
(uint) log_descriptor.bc.buffer->buffer_no, (uint) log_descriptor.bc.buffer->buffer_no,
@ -4285,7 +4302,6 @@ static my_bool translog_advance_pointer(uint pages, uint16 last_page_data)
} }
/* /*
Get page rest Get page rest
@ -4435,7 +4451,7 @@ translog_write_variable_record_1group(LSN *lsn,
(log_descriptor.page_capacity_chunk_2 - 1), (log_descriptor.page_capacity_chunk_2 - 1),
record_rest, parts->record_length)); record_rest, parts->record_length));
/* record_rest + 3 is chunk type 3 overhead + record_rest */ /* record_rest + 3 is chunk type 3 overhead + record_rest */
rc|= translog_advance_pointer(full_pages + additional_chunk3_page, rc|= translog_advance_pointer((int)(full_pages + additional_chunk3_page),
(record_rest ? record_rest + 3 : 0)); (record_rest ? record_rest + 3 : 0));
log_descriptor.bc.buffer->last_lsn= *lsn; log_descriptor.bc.buffer->last_lsn= *lsn;
@ -4460,7 +4476,6 @@ translog_write_variable_record_1group(LSN *lsn,
/* fill the pages */ /* fill the pages */
translog_write_parts_on_page(&horizon, &cursor, first_page, parts); translog_write_parts_on_page(&horizon, &cursor, first_page, parts);
DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx)", DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx)",
LSN_IN_PARTS(log_descriptor.horizon), LSN_IN_PARTS(log_descriptor.horizon),
LSN_IN_PARTS(horizon))); LSN_IN_PARTS(horizon)));
@ -4959,7 +4974,7 @@ translog_write_variable_record_mgroup(LSN *lsn,
(ulong)(parts->record_length - (first_page - 1 + (ulong)(parts->record_length - (first_page - 1 +
buffer_rest) - buffer_rest) -
done))); done)));
rc|= translog_advance_pointer(full_pages, 0); rc|= translog_advance_pointer((int)full_pages, 0);
rc|= translog_unlock(); rc|= translog_unlock();
@ -5104,8 +5119,10 @@ translog_write_variable_record_mgroup(LSN *lsn,
(ulong) full_pages * (ulong) full_pages *
log_descriptor.page_capacity_chunk_2, log_descriptor.page_capacity_chunk_2,
chunk3_pages, (uint) chunk3_size, (uint) record_rest)); chunk3_pages, (uint) chunk3_size, (uint) record_rest));
rc= translog_advance_pointer(full_pages + chunk3_pages + rc= translog_advance_pointer((int)(full_pages + chunk3_pages +
(chunk0_pages - 1), (chunk0_pages - 1)) +
(full_pages + chunk3_pages + chunk0_pages +
chunk2_page == 1? -1 : 0),
record_rest + header_fixed_part + record_rest + header_fixed_part +
(groups.elements - (groups.elements -
((page_capacity - ((page_capacity -
@ -5573,7 +5590,6 @@ my_bool translog_write_record(LSN *lsn,
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (tbl_info) if (tbl_info)
{ {
MARIA_SHARE *share= tbl_info->s; MARIA_SHARE *share= tbl_info->s;
@ -7526,7 +7542,7 @@ my_bool translog_purge_at_flush()
if (unlikely(translog_status == TRANSLOG_READONLY)) if (unlikely(translog_status == TRANSLOG_READONLY))
{ {
DBUG_PRINT("info", ("The log is read onlyu => exit")); DBUG_PRINT("info", ("The log is read only => exit"));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -7639,4 +7655,3 @@ void translog_set_file_size(uint32 size)
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }

View File

@ -685,7 +685,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
disk_pos=_ma_columndef_read(disk_pos,&share->columndef[i]); disk_pos=_ma_columndef_read(disk_pos,&share->columndef[i]);
share->columndef[i].pack_type=0; share->columndef[i].pack_type=0;
share->columndef[i].huff_tree=0; share->columndef[i].huff_tree=0;
if (share->columndef[i].type == (int) FIELD_BLOB) if (share->columndef[i].type == FIELD_BLOB)
{ {
share->blobs[j].pack_length= share->blobs[j].pack_length=
share->columndef[i].length-portable_sizeof_char_ptr;; share->columndef[i].length-portable_sizeof_char_ptr;;
@ -693,7 +693,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
j++; j++;
} }
} }
share->columndef[i].type=(int) FIELD_LAST; /* End marker */ share->columndef[i].type= FIELD_LAST; /* End marker */
disk_pos= _ma_column_nr_read(disk_pos, share->column_nr, disk_pos= _ma_column_nr_read(disk_pos, share->column_nr,
share->base.fields); share->base.fields);

View File

@ -145,7 +145,8 @@ int _ma_write_keypage(register MARIA_HA *info,
lock, lock,
lock == PAGECACHE_LOCK_LEFT_WRITELOCKED ? lock == PAGECACHE_LOCK_LEFT_WRITELOCKED ?
PAGECACHE_PIN_LEFT_PINNED : PAGECACHE_PIN_LEFT_PINNED :
PAGECACHE_PIN, (lock == PAGECACHE_LOCK_WRITE_UNLOCK ?
PAGECACHE_UNPIN : PAGECACHE_PIN),
PAGECACHE_WRITE_DELAY, &page_link.link, PAGECACHE_WRITE_DELAY, &page_link.link,
LSN_IMPOSSIBLE); LSN_IMPOSSIBLE);
@ -157,8 +158,7 @@ int _ma_write_keypage(register MARIA_HA *info,
push_dynamic(&info->pinned_pages, (void*) &page_link); push_dynamic(&info->pinned_pages, (void*) &page_link);
} }
DBUG_RETURN(res); DBUG_RETURN(res);
}
} /* maria_write_keypage */
/* /*
@ -326,7 +326,11 @@ my_off_t _ma_new(register MARIA_HA *info, int level,
(*page_link)->unlock= PAGECACHE_LOCK_WRITE_UNLOCK; (*page_link)->unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
(*page_link)->write_lock= PAGECACHE_LOCK_WRITE; (*page_link)->write_lock= PAGECACHE_LOCK_WRITE;
(*page_link)->changed= 0; /*
We have to mark it changed as _ma_flush_pending_blocks() uses
'changed' to know if we used the page cache or not
*/
(*page_link)->changed= 1;
push_dynamic(&info->pinned_pages, (void*) *page_link); push_dynamic(&info->pinned_pages, (void*) *page_link);
*page_link= dynamic_element(&info->pinned_pages, *page_link= dynamic_element(&info->pinned_pages,
info->pinned_pages.elements-1, info->pinned_pages.elements-1,

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2000-2006 MySQL AB /* Copyright (C) 2000-2008 MySQL AB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -2053,9 +2053,11 @@ restart:
link_to_file_list(pagecache, block, file, link_to_file_list(pagecache, block, file,
(my_bool)(block->hash_link ? 1 : 0)); (my_bool)(block->hash_link ? 1 : 0));
PCBLOCK_INFO(block); PCBLOCK_INFO(block);
block->status= error? PCBLOCK_ERROR : 0; block->status= error ? PCBLOCK_ERROR : 0;
#ifndef DBUG_OFF #ifndef DBUG_OFF
block->type= PAGECACHE_EMPTY_PAGE; block->type= PAGECACHE_EMPTY_PAGE;
if (error)
my_debug_put_break_here();
#endif #endif
block->hash_link= hash_link; block->hash_link= hash_link;
page_status= PAGE_TO_BE_READ; page_status= PAGE_TO_BE_READ;
@ -2239,8 +2241,8 @@ static my_bool get_wrlock(PAGECACHE *pagecache,
file.file != block->hash_link->file.file || file.file != block->hash_link->file.file ||
pageno != block->hash_link->pageno) pageno != block->hash_link->pageno)
{ {
DBUG_PRINT("info", ("the block 0x%lx changed => need retry" DBUG_PRINT("info", ("the block 0x%lx changed => need retry "
"status %x files %d != %d or pages %d !=%d", "status: %x files %d != %d or pages %d != %d",
(ulong)block, block->status, (ulong)block, block->status,
file.file, block->hash_link->file.file, file.file, block->hash_link->file.file,
pageno, block->hash_link->pageno)); pageno, block->hash_link->pageno));
@ -2446,7 +2448,10 @@ static void read_block(PAGECACHE *pagecache,
pagecache->readwrite_flags); pagecache->readwrite_flags);
pagecache_pthread_mutex_lock(&pagecache->cache_lock); pagecache_pthread_mutex_lock(&pagecache->cache_lock);
if (error) if (error)
{
block->status|= PCBLOCK_ERROR; block->status|= PCBLOCK_ERROR;
my_debug_put_break_here();
}
else else
{ {
block->status|= PCBLOCK_READ; block->status|= PCBLOCK_READ;
@ -2457,6 +2462,7 @@ static void read_block(PAGECACHE *pagecache,
{ {
DBUG_PRINT("error", ("read callback problem")); DBUG_PRINT("error", ("read callback problem"));
block->status|= PCBLOCK_ERROR; block->status|= PCBLOCK_ERROR;
my_debug_put_break_here();
} }
} }
DBUG_PRINT("read_block", DBUG_PRINT("read_block",
@ -2608,6 +2614,7 @@ void pagecache_unlock(PAGECACHE *pagecache,
/* if we lock for write we must link the block to changed blocks */ /* if we lock for write we must link the block to changed blocks */
DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0 || DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0 ||
(lock == PAGECACHE_LOCK_WRITE_UNLOCK || (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
lock == PAGECACHE_LOCK_WRITE_TO_READ ||
lock == PAGECACHE_LOCK_LEFT_WRITELOCKED)); lock == PAGECACHE_LOCK_LEFT_WRITELOCKED));
/* /*
if was_changed then status should be PCBLOCK_DIRECT_W or marked if was_changed then status should be PCBLOCK_DIRECT_W or marked
@ -2616,7 +2623,8 @@ void pagecache_unlock(PAGECACHE *pagecache,
DBUG_ASSERT(!was_changed || (block->status & PCBLOCK_DIRECT_W) || DBUG_ASSERT(!was_changed || (block->status & PCBLOCK_DIRECT_W) ||
(block->status & PCBLOCK_CHANGED)); (block->status & PCBLOCK_CHANGED));
if ((block->status & PCBLOCK_DIRECT_W) && if ((block->status & PCBLOCK_DIRECT_W) &&
(lock == PAGECACHE_LOCK_WRITE_UNLOCK)) (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
lock == PAGECACHE_LOCK_WRITE_TO_READ))
{ {
if (!(block->status & PCBLOCK_CHANGED) && was_changed) if (!(block->status & PCBLOCK_CHANGED) && was_changed)
link_to_changed_list(pagecache, block); link_to_changed_list(pagecache, block);
@ -2737,7 +2745,7 @@ void pagecache_unlock_by_link(PAGECACHE *pagecache,
LSN lsn, my_bool was_changed) LSN lsn, my_bool was_changed)
{ {
DBUG_ENTER("pagecache_unlock_by_link"); DBUG_ENTER("pagecache_unlock_by_link");
DBUG_PRINT("enter", ("block: 0x%lx fd: %u page: %lu changed: %d %s %s", DBUG_PRINT("enter", ("block: 0x%lx fd: %u page: %lu changed: %d %s %s",
(ulong) block, (ulong) block,
(uint) block->hash_link->file.file, (uint) block->hash_link->file.file,
(ulong) block->hash_link->pageno, was_changed, (ulong) block->hash_link->pageno, was_changed,
@ -2790,6 +2798,7 @@ void pagecache_unlock_by_link(PAGECACHE *pagecache,
/* if we lock for write we must link the block to changed blocks */ /* if we lock for write we must link the block to changed blocks */
DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0 || DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0 ||
(lock == PAGECACHE_LOCK_WRITE_UNLOCK || (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
lock == PAGECACHE_LOCK_WRITE_TO_READ ||
lock == PAGECACHE_LOCK_LEFT_WRITELOCKED)); lock == PAGECACHE_LOCK_LEFT_WRITELOCKED));
/* /*
If was_changed then status should be PCBLOCK_DIRECT_W or marked If was_changed then status should be PCBLOCK_DIRECT_W or marked
@ -2798,7 +2807,8 @@ void pagecache_unlock_by_link(PAGECACHE *pagecache,
DBUG_ASSERT(!was_changed || (block->status & PCBLOCK_DIRECT_W) || DBUG_ASSERT(!was_changed || (block->status & PCBLOCK_DIRECT_W) ||
(block->status & PCBLOCK_CHANGED)); (block->status & PCBLOCK_CHANGED));
if ((block->status & PCBLOCK_DIRECT_W) && if ((block->status & PCBLOCK_DIRECT_W) &&
(lock == PAGECACHE_LOCK_WRITE_UNLOCK)) (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
lock == PAGECACHE_LOCK_WRITE_TO_READ))
{ {
if (!(block->status & PCBLOCK_CHANGED) && was_changed) if (!(block->status & PCBLOCK_CHANGED) && was_changed)
link_to_changed_list(pagecache, block); link_to_changed_list(pagecache, block);
@ -2844,7 +2854,7 @@ void pagecache_unpin_by_link(PAGECACHE *pagecache,
LSN lsn) LSN lsn)
{ {
DBUG_ENTER("pagecache_unpin_by_link"); DBUG_ENTER("pagecache_unpin_by_link");
DBUG_PRINT("enter", ("block: 0x%lx fd: %u page: %lu", DBUG_PRINT("enter", ("block: 0x%lx fd: %u page: %lu",
(ulong) block, (ulong) block,
(uint) block->hash_link->file.file, (uint) block->hash_link->file.file,
(ulong) block->hash_link->pageno)); (ulong) block->hash_link->pageno));
@ -3177,6 +3187,7 @@ restart:
if (error) if (error)
{ {
block->status|= PCBLOCK_ERROR; block->status|= PCBLOCK_ERROR;
my_debug_put_break_here();
goto err; goto err;
} }
} }
@ -3407,6 +3418,7 @@ restart:
{ {
if (block->status & PCBLOCK_ERROR) if (block->status & PCBLOCK_ERROR)
{ {
my_debug_put_break_here();
DBUG_PRINT("warning", ("Writing on page with error")); DBUG_PRINT("warning", ("Writing on page with error"));
} }
else else
@ -3431,6 +3443,7 @@ restart:
{ {
DBUG_PRINT("error", ("read callback problem")); DBUG_PRINT("error", ("read callback problem"));
block->status|= PCBLOCK_ERROR; block->status|= PCBLOCK_ERROR;
my_debug_put_break_here();
} }
KEYCACHE_DBUG_PRINT("key_cache_insert", KEYCACHE_DBUG_PRINT("key_cache_insert",
("Page injection")); ("Page injection"));
@ -3488,7 +3501,10 @@ restart:
*page_link= block; *page_link= block;
if (block->status & PCBLOCK_ERROR) if (block->status & PCBLOCK_ERROR)
{
error= 1; error= 1;
my_debug_put_break_here();
}
dec_counter_for_resize_op(pagecache); dec_counter_for_resize_op(pagecache);
@ -3692,6 +3708,7 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
if (error) if (error)
{ {
block->status|= PCBLOCK_ERROR; block->status|= PCBLOCK_ERROR;
my_debug_put_break_here();
if (!*first_errno) if (!*first_errno)
*first_errno= my_errno ? my_errno : -1; *first_errno= my_errno ? my_errno : -1;
rc|= PCFLUSH_ERROR; rc|= PCFLUSH_ERROR;
@ -3930,7 +3947,7 @@ restart:
*/ */
if ((rc|= flush_cached_blocks(pagecache, file, cache, if ((rc|= flush_cached_blocks(pagecache, file, cache,
end, type, &error)) & end, type, &error)) &
PCFLUSH_ERROR) (PCFLUSH_ERROR | PCFLUSH_PINNED))
last_errno=error; last_errno=error;
DBUG_PRINT("info", ("restarting...")); DBUG_PRINT("info", ("restarting..."));
/* /*
@ -3965,7 +3982,8 @@ restart:
if (pos != cache) if (pos != cache)
{ {
if ((rc|= flush_cached_blocks(pagecache, file, cache, pos, type, if ((rc|= flush_cached_blocks(pagecache, file, cache, pos, type,
&error)) & PCFLUSH_ERROR) &error)) &
(PCFLUSH_ERROR | PCFLUSH_PINNED))
last_errno= error; last_errno= error;
} }
/* Wait until list of blocks in switch is empty */ /* Wait until list of blocks in switch is empty */

View File

@ -13,7 +13,7 @@
@return crc of the page without special values @return crc of the page without special values
*/ */
static uint32 maria_page_crc(ulong start, uchar *data, uint length) static uint32 maria_page_crc(uint32 start, uchar *data, uint length)
{ {
uint32 crc= crc32(start, data, length); uint32 crc= crc32(start, data, length);
@ -73,7 +73,7 @@ static my_bool maria_page_crc_check(uchar *page,
} }
DBUG_RETURN(0); DBUG_RETURN(0);
} }
new_crc= maria_page_crc(page_no, page, data_length); new_crc= maria_page_crc(page_no & UINT_MAX32, page, data_length);
DBUG_ASSERT(new_crc != no_crc_val); DBUG_ASSERT(new_crc != no_crc_val);
res= test(new_crc != crc); res= test(new_crc != crc);
if (res) if (res)
@ -103,7 +103,7 @@ my_bool maria_page_crc_set_normal(uchar *page,
{ {
MARIA_SHARE *share= (MARIA_SHARE *)data_ptr; MARIA_SHARE *share= (MARIA_SHARE *)data_ptr;
int data_length= share->block_size - CRC_SIZE; int data_length= share->block_size - CRC_SIZE;
uint32 crc= maria_page_crc(page_no, page, data_length); uint32 crc= maria_page_crc(page_no & UINT_MAX32, page, data_length);
DBUG_ENTER("maria_page_crc_set"); DBUG_ENTER("maria_page_crc_set");
DBUG_PRINT("info", ("Page %lu crc: %lu", (ulong) page_no, (ulong)crc)); DBUG_PRINT("info", ("Page %lu crc: %lu", (ulong) page_no, (ulong)crc));
@ -129,9 +129,8 @@ my_bool maria_page_crc_set_index(uchar *page,
{ {
MARIA_SHARE *share= (MARIA_SHARE *)data_ptr; MARIA_SHARE *share= (MARIA_SHARE *)data_ptr;
int data_length= _ma_get_page_used(share, page); int data_length= _ma_get_page_used(share, page);
uint32 crc= maria_page_crc(page_no, page, data_length); uint32 crc= maria_page_crc(page_no & UINT_MAX32, page, data_length);
DBUG_ENTER("maria_page_crc_set"); DBUG_ENTER("maria_page_crc_set");
DBUG_PRINT("info", ("Page %lu crc: %lu", DBUG_PRINT("info", ("Page %lu crc: %lu",
(ulong) page_no, (ulong) crc)); (ulong) page_no, (ulong) crc));
DBUG_ASSERT((uint)data_length <= share->block_size - CRC_SIZE); DBUG_ASSERT((uint)data_length <= share->block_size - CRC_SIZE);
@ -160,7 +159,7 @@ my_bool maria_page_crc_check_data(uchar *page,
uchar *data_ptr) uchar *data_ptr)
{ {
MARIA_SHARE *share= (MARIA_SHARE *)data_ptr; MARIA_SHARE *share= (MARIA_SHARE *)data_ptr;
return (maria_page_crc_check(page, page_no, share, return (maria_page_crc_check(page, page_no & UINT_MAX32, share,
MARIA_NO_CRC_NORMAL_PAGE, MARIA_NO_CRC_NORMAL_PAGE,
share->block_size - CRC_SIZE)); share->block_size - CRC_SIZE));
} }
@ -182,7 +181,7 @@ my_bool maria_page_crc_check_bitmap(uchar *page,
uchar *data_ptr) uchar *data_ptr)
{ {
MARIA_SHARE *share= (MARIA_SHARE *)data_ptr; MARIA_SHARE *share= (MARIA_SHARE *)data_ptr;
return (maria_page_crc_check(page, page_no, share, return (maria_page_crc_check(page, page_no & UINT_MAX32, share,
MARIA_NO_CRC_BITMAP_PAGE, MARIA_NO_CRC_BITMAP_PAGE,
share->block_size - CRC_SIZE)); share->block_size - CRC_SIZE));
} }
@ -210,7 +209,7 @@ my_bool maria_page_crc_check_index(uchar *page,
DBUG_PRINT("error", ("Wrong page length: %u", length)); DBUG_PRINT("error", ("Wrong page length: %u", length));
return (my_errno= HA_ERR_WRONG_CRC); return (my_errno= HA_ERR_WRONG_CRC);
} }
return maria_page_crc_check(page, page_no, share, return maria_page_crc_check(page, page_no & UINT_MAX32, share,
MARIA_NO_CRC_NORMAL_PAGE, MARIA_NO_CRC_NORMAL_PAGE,
length); length);
} }

View File

@ -174,7 +174,7 @@ void tprint(FILE *trace_file __attribute__ ((unused)),
if (procent_printed) if (procent_printed)
{ {
procent_printed= 0; procent_printed= 0;
fputc('\n', trace_file ? trace_file : stderr); fputc('\n', trace_file);
} }
vfprintf(trace_file, format, args); vfprintf(trace_file, format, args);
} }
@ -190,13 +190,22 @@ void eprint(FILE *trace_file __attribute__ ((unused)),
va_list args; va_list args;
va_start(args, format); va_start(args, format);
DBUG_PRINT("error", ("%s", format)); DBUG_PRINT("error", ("%s", format));
if (!trace_file)
trace_file= stderr;
if (procent_printed) if (procent_printed)
{ {
/* In silent mode, print on another line than the 0% 10% 20% line */ /* In silent mode, print on another line than the 0% 10% 20% line */
procent_printed= 0; procent_printed= 0;
fputc('\n', trace_file ? trace_file : stderr); fputc('\n', trace_file);
}
vfprintf(trace_file , format, args);
fputc('\n', trace_file);
if (trace_file != stderr)
{
va_start(args, format);
my_printv_error(HA_ERR_INITIALIZATION, format, MYF(0), args);
} }
vfprintf(trace_file ? trace_file : stderr, format, args);
va_end(args); va_end(args);
} }
@ -411,7 +420,7 @@ int maria_apply_log(LSN from_lsn, enum maria_apply_log_way apply,
else if (uncommitted_trans > 0) else if (uncommitted_trans > 0)
{ {
eprint(tracef, "***WARNING: %u uncommitted transactions; some tables may" eprint(tracef, "***WARNING: %u uncommitted transactions; some tables may"
" be left inconsistent!***\n", uncommitted_trans); " be left inconsistent!***", uncommitted_trans);
recovery_warnings++; recovery_warnings++;
} }
@ -517,7 +526,7 @@ static int display_and_apply_record(const LOG_DESC *log_desc,
return 1; return 1;
} }
if ((error= (*log_desc->record_execute_in_redo_phase)(rec))) if ((error= (*log_desc->record_execute_in_redo_phase)(rec)))
eprint(tracef, "Got error %d when executing record %s\n", eprint(tracef, "Got error %d when executing record %s",
my_errno, log_desc->name); my_errno, log_desc->name);
return error; return error;
} }
@ -548,7 +557,7 @@ prototype_redo_exec_hook(LONG_TRANSACTION_ID)
llstr(long_trid, llbuf); llstr(long_trid, llbuf);
eprint(tracef, "Found an old transaction long_trid %s short_trid %u" eprint(tracef, "Found an old transaction long_trid %s short_trid %u"
" with same short id as this new transaction, and has neither" " with same short id as this new transaction, and has neither"
" committed nor rollback (undo_lsn: (%lu,0x%lx))\n", " committed nor rollback (undo_lsn: (%lu,0x%lx))",
llbuf, sid, LSN_IN_PARTS(ulsn)); llbuf, sid, LSN_IN_PARTS(ulsn));
goto err; goto err;
} }
@ -656,7 +665,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
goto end; goto end;
} }
name= (char *)log_record_buffer.str; name= (char *)log_record_buffer.str;
@ -667,7 +676,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
*/ */
if (close_one_table(name, rec->lsn)) if (close_one_table(name, rec->lsn))
{ {
eprint(tracef, "Table '%s' got error %d on close\n", name, my_errno); eprint(tracef, "Table '%s' got error %d on close", name, my_errno);
ALERT_USER(); ALERT_USER();
goto end; goto end;
} }
@ -679,7 +688,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
/* check that we're not already using it */ /* check that we're not already using it */
if (share->reopen != 1) if (share->reopen != 1)
{ {
eprint(tracef, "Table '%s is already open (reopen=%u)\n", eprint(tracef, "Table '%s is already open (reopen=%u)",
name, share->reopen); name, share->reopen);
ALERT_USER(); ALERT_USER();
goto end; goto end;
@ -708,7 +717,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
} }
if (maria_is_crashed(info)) if (maria_is_crashed(info))
{ {
eprint(tracef, "Table '%s' is crashed, can't recreate it\n", name); eprint(tracef, "Table '%s' is crashed, can't recreate it", name);
ALERT_USER(); ALERT_USER();
goto end; goto end;
} }
@ -743,7 +752,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
/** @todo handle symlinks */ /** @todo handle symlinks */
if (data_file_name[0] || index_file_name[0]) if (data_file_name[0] || index_file_name[0])
{ {
eprint(tracef, "Table '%s' DATA|INDEX DIRECTORY clauses are not handled\n", eprint(tracef, "Table '%s' DATA|INDEX DIRECTORY clauses are not handled",
name); name);
goto end; goto end;
} }
@ -757,14 +766,14 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
if ((kfile= my_create_with_symlink(linkname_ptr, filename, 0, create_mode, if ((kfile= my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
MYF(MY_WME|create_flag))) < 0) MYF(MY_WME|create_flag))) < 0)
{ {
eprint(tracef, "Failed to create index file\n"); eprint(tracef, "Failed to create index file");
goto end; goto end;
} }
if (my_pwrite(kfile, kfile_header, if (my_pwrite(kfile, kfile_header,
kfile_size_before_extension, 0, MYF(MY_NABP|MY_WME)) || kfile_size_before_extension, 0, MYF(MY_NABP|MY_WME)) ||
my_chsize(kfile, keystart, 0, MYF(MY_WME))) my_chsize(kfile, keystart, 0, MYF(MY_WME)))
{ {
eprint(tracef, "Failed to write to index file\n"); eprint(tracef, "Failed to write to index file");
goto end; goto end;
} }
if (!(flags & HA_DONT_TOUCH_DATA)) if (!(flags & HA_DONT_TOUCH_DATA))
@ -778,7 +787,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
MYF(MY_WME | create_flag))) < 0) || MYF(MY_WME | create_flag))) < 0) ||
my_close(dfile, MYF(MY_WME))) my_close(dfile, MYF(MY_WME)))
{ {
eprint(tracef, "Failed to create data file\n"); eprint(tracef, "Failed to create data file");
goto end; goto end;
} }
/* /*
@ -790,7 +799,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
if (((info= maria_open(name, O_RDONLY, 0)) == NULL) || if (((info= maria_open(name, O_RDONLY, 0)) == NULL) ||
_ma_initialize_data_file(info->s, info->dfile.file)) _ma_initialize_data_file(info->s, info->dfile.file))
{ {
eprint(tracef, "Failed to open new table or write to data file\n"); eprint(tracef, "Failed to open new table or write to data file");
goto end; goto end;
} }
} }
@ -820,7 +829,7 @@ prototype_redo_exec_hook(REDO_RENAME_TABLE)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
goto end; goto end;
} }
old_name= (char *)log_record_buffer.str; old_name= (char *)log_record_buffer.str;
@ -957,13 +966,13 @@ prototype_redo_exec_hook(REDO_RENAME_TABLE)
tprint(tracef, ", renaming '%s'", old_name); tprint(tracef, ", renaming '%s'", old_name);
if (maria_rename(old_name, new_name)) if (maria_rename(old_name, new_name))
{ {
eprint(tracef, "Failed to rename table\n"); eprint(tracef, "Failed to rename table");
goto end; goto end;
} }
info= maria_open(new_name, O_RDONLY, 0); info= maria_open(new_name, O_RDONLY, 0);
if (info == NULL) if (info == NULL)
{ {
eprint(tracef, "Failed to open renamed table\n"); eprint(tracef, "Failed to open renamed table");
goto end; goto end;
} }
if (_ma_update_create_rename_lsn(info->s, rec->lsn, TRUE)) if (_ma_update_create_rename_lsn(info->s, rec->lsn, TRUE))
@ -977,7 +986,7 @@ drop:
tprint(tracef, ", only dropping '%s'", old_name); tprint(tracef, ", only dropping '%s'", old_name);
if (maria_delete_table(old_name)) if (maria_delete_table(old_name))
{ {
eprint(tracef, "Failed to drop table\n"); eprint(tracef, "Failed to drop table");
goto end; goto end;
} }
error= 0; error= 0;
@ -1068,7 +1077,7 @@ prototype_redo_exec_hook(REDO_DROP_TABLE)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
name= (char *)log_record_buffer.str; name= (char *)log_record_buffer.str;
@ -1106,7 +1115,7 @@ prototype_redo_exec_hook(REDO_DROP_TABLE)
tprint(tracef, ", dropping '%s'", name); tprint(tracef, ", dropping '%s'", name);
if (maria_delete_table(name)) if (maria_delete_table(name))
{ {
eprint(tracef, "Failed to drop table\n"); eprint(tracef, "Failed to drop table");
goto end; goto end;
} }
} }
@ -1147,7 +1156,7 @@ prototype_redo_exec_hook(FILE_ID)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
goto end; goto end;
} }
sid= fileid_korr(log_record_buffer.str); sid= fileid_korr(log_record_buffer.str);
@ -1158,7 +1167,7 @@ prototype_redo_exec_hook(FILE_ID)
prepare_table_for_close(info, rec->lsn); prepare_table_for_close(info, rec->lsn);
if (maria_close(info)) if (maria_close(info))
{ {
eprint(tracef, "Failed to close table\n"); eprint(tracef, "Failed to close table");
goto end; goto end;
} }
all_tables[sid].info= NULL; all_tables[sid].info= NULL;
@ -1331,14 +1340,14 @@ prototype_redo_exec_hook(REDO_INSERT_ROW_HEAD)
enlarge_buffer(rec); enlarge_buffer(rec);
if (log_record_buffer.str == NULL) if (log_record_buffer.str == NULL)
{ {
eprint(tracef, "Failed to read allocate buffer for record\n"); eprint(tracef, "Failed to read allocate buffer for record");
goto end; goto end;
} }
if (translog_read_record(rec->lsn, 0, rec->record_length, if (translog_read_record(rec->lsn, 0, rec->record_length,
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
goto end; goto end;
} }
buff= log_record_buffer.str; buff= log_record_buffer.str;
@ -1373,7 +1382,7 @@ prototype_redo_exec_hook(REDO_INSERT_ROW_TAIL)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
goto end; goto end;
} }
buff= log_record_buffer.str; buff= log_record_buffer.str;
@ -1409,7 +1418,7 @@ prototype_redo_exec_hook(REDO_INSERT_ROW_BLOBS)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
goto end; goto end;
} }
buff= log_record_buffer.str; buff= log_record_buffer.str;
@ -1469,7 +1478,7 @@ prototype_redo_exec_hook(REDO_FREE_BLOCKS)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
goto end; goto end;
} }
@ -1528,7 +1537,7 @@ prototype_redo_exec_hook(REDO_INDEX)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
goto end; goto end;
} }
@ -1554,7 +1563,7 @@ prototype_redo_exec_hook(REDO_INDEX_NEW_PAGE)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
goto end; goto end;
} }
@ -1618,7 +1627,7 @@ prototype_redo_exec_hook(UNDO_ROW_INSERT)
HA_CHECKSUM_STORE_SIZE, buff, NULL) != HA_CHECKSUM_STORE_SIZE, buff, NULL) !=
HA_CHECKSUM_STORE_SIZE) HA_CHECKSUM_STORE_SIZE)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
share->state.state.checksum+= ha_checksum_korr(buff); share->state.state.checksum+= ha_checksum_korr(buff);
@ -1655,7 +1664,7 @@ prototype_redo_exec_hook(UNDO_ROW_DELETE)
HA_CHECKSUM_STORE_SIZE, buff, NULL) != HA_CHECKSUM_STORE_SIZE, buff, NULL) !=
HA_CHECKSUM_STORE_SIZE) HA_CHECKSUM_STORE_SIZE)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
share->state.state.checksum+= ha_checksum_korr(buff); share->state.state.checksum+= ha_checksum_korr(buff);
@ -1689,7 +1698,7 @@ prototype_redo_exec_hook(UNDO_ROW_UPDATE)
HA_CHECKSUM_STORE_SIZE, buff, NULL) != HA_CHECKSUM_STORE_SIZE, buff, NULL) !=
HA_CHECKSUM_STORE_SIZE) HA_CHECKSUM_STORE_SIZE)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
share->state.state.checksum+= ha_checksum_korr(buff); share->state.state.checksum+= ha_checksum_korr(buff);
@ -1729,7 +1738,7 @@ prototype_redo_exec_hook(UNDO_KEY_INSERT)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
to= log_record_buffer.str + LSN_STORE_SIZE + FILEID_STORE_SIZE + to= log_record_buffer.str + LSN_STORE_SIZE + FILEID_STORE_SIZE +
@ -1851,7 +1860,7 @@ prototype_redo_exec_hook(CLR_END)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
logpos= (log_record_buffer.str + LSN_STORE_SIZE + FILEID_STORE_SIZE + logpos= (log_record_buffer.str + LSN_STORE_SIZE + FILEID_STORE_SIZE +
@ -1939,7 +1948,7 @@ prototype_undo_exec_hook(UNDO_ROW_INSERT)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
record_ptr= log_record_buffer.str; record_ptr= log_record_buffer.str;
@ -1977,7 +1986,7 @@ prototype_undo_exec_hook(UNDO_ROW_DELETE)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
@ -2013,7 +2022,7 @@ prototype_undo_exec_hook(UNDO_ROW_UPDATE)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
@ -2058,7 +2067,7 @@ prototype_undo_exec_hook(UNDO_KEY_INSERT)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
@ -2104,7 +2113,7 @@ prototype_undo_exec_hook(UNDO_KEY_DELETE)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
@ -2150,7 +2159,7 @@ prototype_undo_exec_hook(UNDO_KEY_DELETE_WITH_ROOT)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec->record_length) rec->record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return 1; return 1;
} }
@ -2234,7 +2243,7 @@ static int run_redo_phase(LSN lsn, enum maria_apply_log_way apply)
if (len == RECHEADER_READ_ERROR) if (len == RECHEADER_READ_ERROR)
{ {
eprint(tracef, "Failed to read header of the first record.\n"); eprint(tracef, "Failed to read header of the first record.");
return 1; return 1;
} }
if (translog_scanner_init(lsn, 1, &scanner, 1)) if (translog_scanner_init(lsn, 1, &scanner, 1))
@ -2530,7 +2539,7 @@ static int run_undo_phase(uint uncommitted)
display_record_position(log_desc, &rec, 0); display_record_position(log_desc, &rec, 0);
if (log_desc->record_execute_in_undo_phase(&rec, trn)) if (log_desc->record_execute_in_undo_phase(&rec, trn))
{ {
eprint(tracef, "Got error %d when executing undo %s\n", my_errno, eprint(tracef, "Got error %d when executing undo %s", my_errno,
log_desc->name); log_desc->name);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -2741,7 +2750,7 @@ static LSN parse_checkpoint_record(LSN lsn)
log_record_buffer.str, NULL) != log_record_buffer.str, NULL) !=
rec.record_length) rec.record_length)
{ {
eprint(tracef, "Failed to read record\n"); eprint(tracef, "Failed to read record");
return LSN_ERROR; return LSN_ERROR;
} }
@ -2999,6 +3008,7 @@ void _ma_tmp_disable_logging_for_table(MARIA_HA *info,
TRANSLOG_INTERNAL_PARTS + 1, log_array, TRANSLOG_INTERNAL_PARTS + 1, log_array,
log_data, NULL); log_data, NULL);
} }
/* if we disabled before writing the record, record wouldn't reach log */ /* if we disabled before writing the record, record wouldn't reach log */
share->now_transactional= FALSE; share->now_transactional= FALSE;
/* /*
@ -3025,6 +3035,10 @@ void _ma_tmp_disable_logging_for_table(MARIA_HA *info,
void _ma_reenable_logging_for_table(MARIA_HA *info) void _ma_reenable_logging_for_table(MARIA_HA *info)
{ {
MARIA_SHARE *share= info->s; MARIA_SHARE *share= info->s;
if (share->now_transactional == share->base.born_transactional)
return;
if ((share->now_transactional= share->base.born_transactional)) if ((share->now_transactional= share->base.born_transactional))
{ {
/* /*

View File

@ -196,7 +196,11 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
err: err:
DBUG_PRINT("error",("key: %d errno: %d",i,my_errno)); DBUG_PRINT("error",("key: %d errno: %d",i,my_errno));
save_errno=my_errno; save_errno= my_errno;
DBUG_ASSERT(save_errno);
if (!save_errno)
save_errno= HA_ERR_INTERNAL_ERROR; /* Should never happen */
if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_OUT_OF_MEM || if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_OUT_OF_MEM ||
my_errno == HA_ERR_RECORD_FILE_FULL) my_errno == HA_ERR_RECORD_FILE_FULL)
{ {

View File

@ -317,6 +317,8 @@ err:
err2: err2:
save_errno=my_errno; save_errno=my_errno;
DBUG_ASSERT(save_errno); DBUG_ASSERT(save_errno);
if (!save_errno)
save_errno= HA_ERR_INTERNAL_ERROR; /* Should never happen */
DBUG_PRINT("error", ("got error: %d", save_errno)); DBUG_PRINT("error", ("got error: %d", save_errno));
VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE)); VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
allow_break(); /* Allow SIGHUP & SIGINT */ allow_break(); /* Allow SIGHUP & SIGINT */

View File

@ -41,7 +41,7 @@ static const char *set_collation_name, *opt_tmpdir;
static CHARSET_INFO *set_collation; static CHARSET_INFO *set_collation;
static int stopwords_inited= 0; static int stopwords_inited= 0;
static MY_TMPDIR maria_chk_tmpdir; static MY_TMPDIR maria_chk_tmpdir;
static my_bool opt_transaction_logging; static my_bool opt_transaction_logging, opt_debug;
static const char *type_names[]= static const char *type_names[]=
{ {
@ -179,7 +179,8 @@ enum options_mc {
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE, OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN, OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE, OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD, OPT_TRANSACTION_LOG OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD, OPT_TRANSACTION_LOG,
OPT_SKIP_SAFEMALLOC
}; };
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
@ -289,6 +290,13 @@ static struct my_option my_long_options[] =
{"silent", 's', {"silent", 's',
"Only print errors. One can use two -s to make maria_chk very silent.", "Only print errors. One can use two -s to make maria_chk very silent.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef DBUG_OFF
#ifdef SAFEMALLOC
{"skip-safemalloc", OPT_SKIP_SAFEMALLOC,
"Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG,
0, 0, 0, 0, 0, 0},
#endif
#endif
{"sort-index", 'S', {"sort-index", 'S',
"Sort index blocks. This speeds up 'read-next' in applications.", "Sort index blocks. This speeds up 'read-next' in applications.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@ -713,6 +721,12 @@ get_one_option(int optid,
break; break;
case '#': case '#':
DBUG_SET_INITIAL(argument ? argument : "d:t:o,/tmp/maria_chk.trace"); DBUG_SET_INITIAL(argument ? argument : "d:t:o,/tmp/maria_chk.trace");
opt_debug= 1;
break;
case OPT_SKIP_SAFEMALLOC:
#ifdef SAFEMALLOC
sf_malloc_quick=1;
#endif
break; break;
case 'V': case 'V':
print_version(); print_version();
@ -813,6 +827,10 @@ static void get_options(register int *argc,register char ***argv)
exit(1); exit(1);
} }
if (!opt_debug)
{
DEBUGGER_OFF; /* Speed up things a bit */
}
if (init_tmpdir(&maria_chk_tmpdir, opt_tmpdir)) if (init_tmpdir(&maria_chk_tmpdir, opt_tmpdir))
exit(1); exit(1);
@ -906,7 +924,7 @@ static int maria_chk(HA_CHECK *param, char *filename)
if (param->testflag & T_SORT_RECORDS) if (param->testflag & T_SORT_RECORDS)
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
"Record format used by '%s' is is not yet supported with repair/check", "Record format used by '%s' is is not yet supported with sort-records",
filename); filename);
param->error_printed= 0; param->error_printed= 0;
error= 1; error= 1;
@ -1443,7 +1461,7 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name)
else else
buff[0]=0; buff[0]=0;
if (param->testflag & T_VERBOSE) if (param->testflag & T_VERBOSE)
printf("%11.0g %12s %10d", printf("%11.0f %12s %10d",
share->state.rec_per_key_part[keyseg_nr++], share->state.rec_per_key_part[keyseg_nr++],
buff,keyinfo->block_length); buff,keyinfo->block_length);
VOID(putchar('\n')); VOID(putchar('\n'));
@ -1464,7 +1482,7 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name)
printf(" %-6ld%-3d %-21s", printf(" %-6ld%-3d %-21s",
(long) keyseg->start+1,keyseg->length,buff); (long) keyseg->start+1,keyseg->length,buff);
if (param->testflag & T_VERBOSE) if (param->testflag & T_VERBOSE)
printf("%11.0g", share->state.rec_per_key_part[keyseg_nr++]); printf("%11.0f", share->state.rec_per_key_part[keyseg_nr++]);
VOID(putchar('\n')); VOID(putchar('\n'));
} }
keyseg++; keyseg++;

View File

@ -952,9 +952,9 @@ typedef struct st_maria_block_info
#define UPDATE_AUTO_INC 8 #define UPDATE_AUTO_INC 8
#define UPDATE_OPEN_COUNT 16 #define UPDATE_OPEN_COUNT 16
#define USE_BUFFER_INIT (((1024L*1024L*10-MALLOC_OVERHEAD)/8192)*8192) #define USE_BUFFER_INIT (((1024L*1024L*128-MALLOC_OVERHEAD)/8192)*8192)
#define READ_BUFFER_INIT (1024L*256L-MALLOC_OVERHEAD) #define READ_BUFFER_INIT (1024L*256L-MALLOC_OVERHEAD)
#define SORT_BUFFER_INIT (2048L*1024L-MALLOC_OVERHEAD) #define SORT_BUFFER_INIT (1024L*1024L*64-MALLOC_OVERHEAD)
#define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD) #define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD)
#define fast_ma_writeinfo(INFO) if (!(INFO)->s->tot_locks) (void) _ma_writeinfo((INFO),0) #define fast_ma_writeinfo(INFO) if (!(INFO)->s->tot_locks) (void) _ma_writeinfo((INFO),0)

View File

@ -100,3 +100,5 @@ ma_pagecache_consist_64kWR_t_big_CPPFLAGS = $(ma_pagecache_common_cppflags) -DPA
CLEANFILES = maria_log_control page_cache_test_file_1 \ CLEANFILES = maria_log_control page_cache_test_file_1 \
maria_log.???????? maria_log.????????
# Don't update the files from bitkeeper
%::SCCS/s.%

View File

@ -462,7 +462,7 @@ int main(int argc __attribute__((unused)),
errno); errno);
exit(1); exit(1);
} }
/*my_delete(file1_name, MYF(0));*/ my_delete(file1_name, MYF(0));
my_end(0); my_end(0);
DBUG_PRINT("info", ("file1 (%d) closed", file1.file)); DBUG_PRINT("info", ("file1 (%d) closed", file1.file));

View File

@ -613,7 +613,7 @@ int main(int argc __attribute__((unused)),
if (my_close(file1.file, MYF(MY_WME))) if (my_close(file1.file, MYF(MY_WME)))
exit(1); exit(1);
/*my_delete(file1_name, MYF(0));*/ my_delete(file1_name, MYF(0));
my_end(0); my_end(0);
DBUG_PRINT("info", ("file1 (%d) closed", file1.file)); DBUG_PRINT("info", ("file1 (%d) closed", file1.file));

View File

@ -121,7 +121,9 @@ sub run_check_tests
["--key_multiple -P -S","-sm"] ); ["--key_multiple -P -S","-sm"] );
my @ma_test2_opt= ( ["-L -K -W -P","-sm"], my @ma_test2_opt= ( ["-L -K -W -P","-sm"],
["-L -K -W -P -A","-sm"], ["-L -K -W -P -A","-sm"],
["-L -K -P -R3 -m50 -b1000000","-sm"], ["-L -K -W -P -b32768", "-sm"],
["-L -K -W -P -M -T -c -b32768 -t4 -m300", "-sm"],
["-L -K -P -R3 -m50 -b1000000", "-sm"],
["-L -B","-sm"], ["-L -B","-sm"],
["-D -B -c","-sm"], ["-D -B -c","-sm"],
["-m10000 -e4096 -K","-sm"], ["-m10000 -e4096 -K","-sm"],
@ -200,8 +202,8 @@ sub run_repair_tests()
"$maria_path/maria_chk$suffix -se test2", "$maria_path/maria_chk$suffix -se test2",
"$maria_path/maria_chk$suffix -sr test2", "$maria_path/maria_chk$suffix -sr test2",
"$maria_path/maria_chk$suffix -se test2", "$maria_path/maria_chk$suffix -se test2",
"$maria_path/ma_test2$suffix $silent -c -t4 $row_type", "$maria_path/ma_test2$suffix $silent -c -t4 -b32768 $row_type",
"$maria_path/maria_chk$suffix -sz test1", "$maria_path/maria_chk$suffix -s --zerofill test1",
"$maria_path/maria_chk$suffix -se test1" "$maria_path/maria_chk$suffix -se test1"
); );
@ -294,7 +296,7 @@ sub run_tests_on_warnings_and_errors
# ma_test2$suffix $silent -L -K -R1 -m2000 ; Should give error 135\n # ma_test2$suffix $silent -L -K -R1 -m2000 ; Should give error 135\n
# In the following a failure is a success and success is a failure # In the following a failure is a success and success is a failure
$com= "$maria_path/ma_test2$suffix $silent -L -K -R1 -m2000 "; $com= "$maria_path/ma_test2$suffix $silent -L -K -R1 -m2000 ";
$com.= ">ma_test2_message.txt 2>&1 && false"; $com.= ">ma_test2_message.txt 2>&1";
ok($com, $verbose, 0, 1); ok($com, $verbose, 0, 1);
ok("cat ma_test2_message.txt", $verbose, 0); ok("cat ma_test2_message.txt", $verbose, 0);
ok("grep \"Error: 135\" ma_test2_message.txt > /dev/null", $verbose, 0); ok("grep \"Error: 135\" ma_test2_message.txt > /dev/null", $verbose, 0);
@ -421,18 +423,19 @@ sub ok
print "Running: '$com'\n"; print "Running: '$com'\n";
} }
$output= `$com 2>&1`; $output= `$com 2>&1`;
$err= $? >> 8; $err= $?;
if ($verbose) if ($verbose)
{ {
print "$output\n"; print "$output\n";
} }
if ($err == $expected_error) if ((!$err && !$expected_error) ||
(($err >> 8) == $expected_error && $expected_error))
{ {
print "ok\n"; print "ok\n";
return 1; return 1;
} }
print "not ok\n"; print "not ok\n";
$msg= "\nFailed test '$com' "; $msg= "\nFailed test '$com' with error $err ";
if ($iteration) if ($iteration)
{ {
$msg.= "(loop iteration $iteration.) "; $msg.= "(loop iteration $iteration.) ";
@ -445,6 +448,5 @@ sub ok
$msg.= "Was expecting errcode: $expected_error\n"; $msg.= "Was expecting errcode: $expected_error\n";
} }
warn $msg; warn $msg;
return 0; return 0;
} }