summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xBUILD/SETUP.sh1
-rwxr-xr-xBUILD/compile-amd64-gprof-no-ndb7
-rw-r--r--sql/opt_range.cc3
-rw-r--r--sql/sql_insert.cc18
-rw-r--r--storage/maria/Makefile.am2
-rw-r--r--storage/maria/ha_maria.cc3
-rw-r--r--storage/maria/ma_blockrec.c541
-rw-r--r--storage/maria/ma_blockrec.h25
-rw-r--r--storage/maria/ma_check.c10
-rw-r--r--storage/maria/ma_check_standalone.h106
-rw-r--r--storage/maria/ma_checkpoint.c6
-rw-r--r--storage/maria/ma_commit.c2
-rw-r--r--storage/maria/ma_create.c2
-rw-r--r--storage/maria/ma_delete.c41
-rw-r--r--storage/maria/ma_delete_all.c9
-rw-r--r--storage/maria/ma_delete_table.c2
-rw-r--r--storage/maria/ma_loghandler.c667
-rw-r--r--storage/maria/ma_loghandler.h24
-rw-r--r--storage/maria/ma_open.c6
-rwxr-xr-xstorage/maria/ma_pagecache.c149
-rw-r--r--storage/maria/ma_pagecache.h44
-rw-r--r--storage/maria/ma_recovery.c277
-rw-r--r--storage/maria/ma_rename.c2
-rw-r--r--storage/maria/ma_test_recovery.expected176
-rw-r--r--storage/maria/ma_update.c51
-rw-r--r--storage/maria/ma_write.c7
-rw-r--r--storage/maria/maria_chk.c86
-rw-r--r--storage/maria/maria_def.h11
-rw-r--r--storage/maria/maria_read_log.c62
-rw-r--r--storage/maria/unittest/ma_control_file-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler-t.c23
-rw-r--r--storage/maria/unittest/ma_test_loghandler_first_lsn-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_max_lsn-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_multigroup-t.c26
-rw-r--r--storage/maria/unittest/ma_test_loghandler_multithread-t.c8
-rw-r--r--storage/maria/unittest/ma_test_loghandler_noflush-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_pagecache-t.c2
-rw-r--r--storage/maria/unittest/ma_test_loghandler_purge-t.c8
38 files changed, 1374 insertions, 1041 deletions
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index e093f43a252..34bdfecf995 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -145,6 +145,7 @@ base_configs="--prefix=$prefix --enable-assembler "
base_configs="$base_configs --with-extra-charsets=complex "
base_configs="$base_configs --enable-thread-safe-client "
base_configs="$base_configs --with-big-tables"
+base_configs="$base_configs --with-plugin-maria"
if test -d "$path/../cmd-line-utils/readline"
then
diff --git a/BUILD/compile-amd64-gprof-no-ndb b/BUILD/compile-amd64-gprof-no-ndb
new file mode 100755
index 00000000000..9fd4c67155c
--- /dev/null
+++ b/BUILD/compile-amd64-gprof-no-ndb
@@ -0,0 +1,7 @@
+#! /bin/sh
+path=`dirname $0`
+. "$path/SETUP.sh"
+extra_flags="$amd64_cflags -pg -g"
+extra_configs="$amd64_configs $max_no_ndb_configs --disable-shared $static_link"
+
+. "$path/FINISH.sh"
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index be38f0406da..97d0bcc8707 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2139,9 +2139,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
quick=0;
needed_reg.clear_all();
quick_keys.clear_all();
- if ((specialflag & SPECIAL_SAFE_MODE) && ! force_quick_range ||
- !limit)
- DBUG_RETURN(0); /* purecov: inspected */
if (keys_to_use.is_clear_all())
DBUG_RETURN(0);
records= head->file->stats.records;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index f7f68ba9509..0774b5ae42e 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -3488,10 +3488,12 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
/*
If error during the CREATE SELECT we drop the table, so no need for
- engines to do logging of insertions (optimization).
+ engines to do logging of insertions (optimization). We don't do it for
+ temporary tables (yet) as re-enabling causes an undesirable commit.
*/
- if (ha_enable_transaction(thd, FALSE))
- DBUG_RETURN(-1);
+ if (((thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) == 0) &&
+ ha_enable_transaction(thd, FALSE))
+ DBUG_RETURN(-1);
if (!(table= create_table_from_items(thd, create_info, create_table,
alter_info, &values,
@@ -3632,11 +3634,12 @@ bool select_create::send_eof()
nevertheless.
*/
if (!table->s->tmp_table)
+ {
+ ha_enable_transaction(thd, TRUE);
ha_commit(thd); // Can fail, but we proceed anyway
-
+ }
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
- ha_enable_transaction(thd, TRUE);
if (thd->extra_lock)
{
mysql_unlock_tables(thd, thd->extra_lock);
@@ -3659,6 +3662,9 @@ void select_create::abort()
select_insert::abort();
reenable_binlog(thd);
+ if (table && !table->s->tmp_table)
+ ha_enable_transaction(thd, TRUE);
+
/*
We roll back the statement, including truncating the transaction
cache of the binary log, if the statement failed.
@@ -3675,8 +3681,6 @@ void select_create::abort()
if (thd->current_stmt_binlog_row_based)
ha_rollback_stmt(thd);
- ha_enable_transaction(thd, TRUE);
-
if (thd->extra_lock)
{
mysql_unlock_tables(thd, thd->extra_lock);
diff --git a/storage/maria/Makefile.am b/storage/maria/Makefile.am
index 2bd9b7db922..795784f31aa 100644
--- a/storage/maria/Makefile.am
+++ b/storage/maria/Makefile.am
@@ -62,7 +62,7 @@ noinst_HEADERS = maria_def.h ma_rt_index.h ma_rt_key.h ma_rt_mbr.h \
ma_control_file.h ha_maria.h ma_blockrec.h \
ma_loghandler.h ma_loghandler_lsn.h ma_pagecache.h \
ma_checkpoint.h ma_recovery.h ma_commit.h \
- trnman_public.h
+ trnman_public.h ma_check_standalone.h
ma_test1_DEPENDENCIES= $(LIBRARIES)
ma_test1_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
$(top_builddir)/storage/myisam/libmyisam.a \
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
index 94ea9656e8b..62c3968c0ca 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -2151,6 +2151,9 @@ int ha_maria::create(const char *name, register TABLE *table_arg,
error;
?
Why fool the user?
+ Shouldn't this test be pushed down to maria_create()? Because currently,
+ ma_test1 -T crashes: it creates a table with DYNAMIC_RECORD but has
+ born_transactional==1, which confuses some recovery-related code.
*/
#endif
create_info.transactional= (row_type == BLOCK_RECORD &&
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index b12035c9cfa..0d1a530dbfc 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -300,6 +300,32 @@ typedef struct st_maria_extent_cursor
} MARIA_EXTENT_CURSOR;
+/**
+ @brief Structure for passing down info to write_hook_for_clr_end().
+ This hooks needs to know the variation of the live checksum caused by the
+ current operation to update state.checksum under log's mutex,
+ needs to know the transaction's previous undo_lsn to set
+ trn->undo_lsn under log mutex, and needs to know the type of UNDO being
+ undone now to modify state.records under log mutex.
+*/
+struct st_msg_to_write_hook_for_clr_end
+{
+ LSN previous_undo_lsn;
+ enum translog_record_type undone_record_type;
+ ha_checksum checksum_delta;
+};
+/** S:share,D:checksum_delta,E:expression,P:pointer_into_record,L:length */
+#define store_checksum_in_rec(S,D,E,P,L) do \
+ { \
+ D= 0; \
+ if ((S)->calc_checksum != NULL) \
+ { \
+ D= (E); \
+ ha_checksum_store(P, D); \
+ L+= HA_CHECKSUM_STORE_SIZE; \
+ } \
+ } while (0)
+
static my_bool delete_tails(MARIA_HA *info, MARIA_RECORD_POS *tails);
static my_bool delete_head_or_tail(MARIA_HA *info,
ulonglong page, uint record_number,
@@ -1387,7 +1413,7 @@ static my_bool write_tail(MARIA_HA *info,
if (translog_write_record(&lsn, LOGREC_REDO_INSERT_ROW_TAIL,
info->trn, info, sizeof(log_data) + length,
TRANSLOG_INTERNAL_PARTS + 2, log_array,
- log_data))
+ log_data, NULL))
DBUG_RETURN(1);
}
@@ -1642,7 +1668,7 @@ static my_bool free_full_pages(MARIA_HA *info, MARIA_ROW *row)
if (translog_write_record(&lsn, LOGREC_REDO_PURGE_BLOCKS, info->trn,
info, sizeof(log_data) + extents_length,
TRANSLOG_INTERNAL_PARTS + 2, log_array,
- log_data))
+ log_data, NULL))
DBUG_RETURN(1);
DBUG_RETURN(_ma_bitmap_free_full_pages(info, row->extents,
@@ -1689,7 +1715,7 @@ static my_bool free_full_page_range(MARIA_HA *info, ulonglong page, uint count)
if (translog_write_record(&lsn, LOGREC_REDO_PURGE_BLOCKS,
info->trn, info, sizeof(log_data),
TRANSLOG_INTERNAL_PARTS + 1, log_array,
- log_data))
+ log_data, NULL))
res= 1;
}
@@ -1716,6 +1742,9 @@ static my_bool free_full_page_range(MARIA_HA *info, ulonglong page, uint count)
@param row_pos Position on head page where to put head part of
record
@param undo_lsn <> LSN_ERROR if we are executing an UNDO
+ @param old_record_checksum Checksum of old_record: ignored if table does
+ not have live checksum; otherwise if
+ old_record==NULL it must be 0.
@note
On return all pinned pages are released.
@@ -1731,7 +1760,8 @@ static my_bool write_block_record(MARIA_HA *info,
MARIA_BITMAP_BLOCKS *bitmap_blocks,
my_bool head_block_is_read,
struct st_row_pos_info *row_pos,
- LSN undo_lsn)
+ LSN undo_lsn,
+ ha_checksum old_record_checksum)
{
uchar *data, *end_of_data, *tmp_data_used, *tmp_data;
uchar *row_extents_first_part, *row_extents_second_part;
@@ -1785,7 +1815,10 @@ static my_bool write_block_record(MARIA_HA *info,
if (share->base.pack_fields)
store_key_length_inc(data, row->field_lengths_length);
if (share->calc_checksum)
+ {
*(data++)= (uchar) (row->checksum); /* store least significant byte */
+ DBUG_ASSERT(!((old_record_checksum != 0) && (old_record == NULL)));
+ }
memcpy(data, record, share->base.null_bytes);
data+= share->base.null_bytes;
memcpy(data, row->empty_bits, share->base.pack_bytes);
@@ -2211,7 +2244,7 @@ static my_bool write_block_record(MARIA_HA *info,
if (translog_write_record(&lsn, LOGREC_REDO_INSERT_ROW_HEAD, info->trn,
info, sizeof(log_data) + data_length,
TRANSLOG_INTERNAL_PARTS + 2, log_array,
- log_data))
+ log_data, NULL))
goto disk_err;
}
@@ -2328,7 +2361,7 @@ static my_bool write_block_record(MARIA_HA *info,
error= translog_write_record(&lsn, LOGREC_REDO_INSERT_ROW_BLOBS,
info->trn, info, log_entry_length,
(uint) (log_array_pos - log_array),
- log_array, log_data);
+ log_array, log_data, NULL);
if (log_array != tmp_log_array)
my_free((uchar*) log_array, MYF(0));
if (error)
@@ -2343,31 +2376,44 @@ static my_bool write_block_record(MARIA_HA *info,
if (undo_lsn != LSN_ERROR)
{
- uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE + 1];
+ uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE + HA_CHECKSUM_STORE_SIZE];
+ struct st_msg_to_write_hook_for_clr_end msg;
/* undo_lsn must be first for compression to work */
lsn_store(log_data, undo_lsn);
/*
- Store if this CLR is about an UNDO_INSERT, UNDO_DELETE or UNDO_UPDATE;
- in the first/second case, Recovery, when it sees the CLR_END in the
- REDO phase, may decrement/increment the records' count.
+ Store if this CLR is about UNDO_DELETE or UNDO_UPDATE;
+ in the first case, Recovery, when it sees the CLR_END in the
+ REDO phase, may decrement the records' count.
*/
- log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE]= old_record ?
- LOGREC_UNDO_ROW_UPDATE : LOGREC_UNDO_ROW_DELETE;
log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data;
- log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
-
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length=
+ sizeof(log_data) - HA_CHECKSUM_STORE_SIZE;
+ msg.undone_record_type=
+ old_record ? LOGREC_UNDO_ROW_UPDATE : LOGREC_UNDO_ROW_DELETE;
+ clr_type_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE,
+ msg.undone_record_type);
+ msg.previous_undo_lsn= undo_lsn;
+ store_checksum_in_rec(share, msg.checksum_delta,
+ row->checksum - old_record_checksum,
+ log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE,
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length);
if (translog_write_record(&lsn, LOGREC_CLR_END,
- info->trn, info, sizeof(log_data),
+ info->trn, info,
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length,
TRANSLOG_INTERNAL_PARTS + 1, log_array,
- log_data + LSN_STORE_SIZE))
+ log_data + LSN_STORE_SIZE, &msg))
goto disk_err;
}
else
{
uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE +
- PAGE_STORE_SIZE + DIRPOS_STORE_SIZE];
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE +
+ HA_CHECKSUM_STORE_SIZE];
+ ha_checksum checksum_delta;
- /* LOGREC_UNDO_ROW_INSERT & LOGREC_UNDO_ROW_INSERT share same header */
+ /* LOGREC_UNDO_ROW_INSERT & LOGREC_UNDO_ROW_UPDATE share same header */
lsn_store(log_data, info->trn->undo_lsn);
page_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE,
head_block->page);
@@ -2376,15 +2422,24 @@ static my_bool write_block_record(MARIA_HA *info,
row_pos->rownr);
log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data;
- log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length=
+ sizeof(log_data) - HA_CHECKSUM_STORE_SIZE;
+ store_checksum_in_rec(share, checksum_delta,
+ row->checksum - old_record_checksum,
+ log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length);
+ compile_time_assert(sizeof(ha_checksum) == HA_CHECKSUM_STORE_SIZE);
if (!old_record)
{
/* Write UNDO log record for the INSERT */
if (translog_write_record(&lsn, LOGREC_UNDO_ROW_INSERT,
- info->trn, info, sizeof(log_data),
+ info->trn, info,
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length,
TRANSLOG_INTERNAL_PARTS + 1, log_array,
- log_data + LSN_STORE_SIZE))
+ log_data + LSN_STORE_SIZE, &checksum_delta))
goto disk_err;
}
else
@@ -2397,10 +2452,11 @@ static my_bool write_block_record(MARIA_HA *info,
TRANSLOG_INTERNAL_PARTS + 1,
&row_parts_count);
if (translog_write_record(&lsn, LOGREC_UNDO_ROW_UPDATE, info->trn,
- info, sizeof(log_data) + row_length,
+ info, log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length + row_length,
TRANSLOG_INTERNAL_PARTS + 1 +
- row_parts_count,
- log_array, log_data + LSN_STORE_SIZE))
+ row_parts_count, log_array,
+ log_data + LSN_STORE_SIZE, &checksum_delta))
goto disk_err;
}
}
@@ -2517,10 +2573,18 @@ static my_bool allocate_and_write_block_record(MARIA_HA *info,
DBUG_RETURN(1);
row->lastpos= ma_recordpos(blocks->block->page, row_pos.rownr);
if (info->s->calc_checksum)
- row->checksum= (info->s->calc_checksum)(info, record);
+ {
+ if (undo_lsn == LSN_ERROR)
+ row->checksum= (info->s->calc_checksum)(info, record);
+ else
+ {
+ /* _ma_apply_undo_row_delete() already set row's checksum. Verify it. */
+ DBUG_ASSERT(row->checksum == (info->s->calc_checksum)(info, record));
+ }
+ }
if (write_block_record(info, (uchar*) 0, record, row,
blocks, blocks->block->org_bitmap_value != 0,
- &row_pos, undo_lsn))
+ &row_pos, undo_lsn, 0))
DBUG_RETURN(1); /* Error reading bitmap */
DBUG_PRINT("exit", ("Rowid: %lu (%lu:%u)", (ulong) row->lastpos,
(ulong) ma_recordpos_to_page(row->lastpos),
@@ -2592,6 +2656,7 @@ my_bool _ma_write_abort_block_record(MARIA_HA *info)
MARIA_BITMAP_BLOCKS *blocks= &info->cur_row.insert_blocks;
MARIA_BITMAP_BLOCK *block, *end;
LSN lsn= LSN_IMPOSSIBLE;
+ MARIA_SHARE *share= info->s;
DBUG_ENTER("_ma_write_abort_block_record");
if (delete_head_or_tail(info,
@@ -2619,13 +2684,14 @@ my_bool _ma_write_abort_block_record(MARIA_HA *info)
}
}
- if (info->s->now_transactional)
+ if (share->now_transactional)
{
- LSN previous_undo_lsn;
TRANSLOG_HEADER_BUFFER rec;
LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
- uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE + 1];
+ uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE + HA_CHECKSUM_STORE_SIZE];
int len;
+ struct st_msg_to_write_hook_for_clr_end msg;
/*
We do need the code above (delete_head_or_tail() etc) for
non-transactional tables.
@@ -2644,15 +2710,24 @@ my_bool _ma_write_abort_block_record(MARIA_HA *info)
goto end;
}
DBUG_ASSERT(rec.type == LOGREC_UNDO_ROW_INSERT);
- previous_undo_lsn= lsn_korr(rec.header);
- lsn_store(log_data, previous_undo_lsn);
- log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE]= LOGREC_UNDO_ROW_INSERT;
+ memcpy(log_data, rec.header, LSN_STORE_SIZE); /* previous UNDO LSN */
+ msg.previous_undo_lsn= lsn_korr(rec.header);
+ msg.undone_record_type= LOGREC_UNDO_ROW_INSERT;
+ clr_type_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE,
+ LOGREC_UNDO_ROW_INSERT);
log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data;
- log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length=
+ sizeof(log_data) - HA_CHECKSUM_STORE_SIZE;
+ store_checksum_in_rec(share, msg.checksum_delta,
+ - info->cur_row.checksum,
+ log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE,
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length);
if (translog_write_record(&lsn, LOGREC_CLR_END,
- info->trn, info, sizeof(log_data),
+ info->trn, info,
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length,
TRANSLOG_INTERNAL_PARTS + 1, log_array,
- log_data + LSN_STORE_SIZE))
+ log_data + LSN_STORE_SIZE, &msg))
res= 1;
}
end:
@@ -2685,6 +2760,8 @@ static my_bool _ma_update_block_record2(MARIA_HA *info,
uchar *dir;
ulonglong page;
struct st_row_pos_info row_pos;
+ my_bool res;
+ ha_checksum old_checksum;
MARIA_SHARE *share= info->s;
DBUG_ENTER("_ma_update_block_record2");
DBUG_PRINT("enter", ("rowid: %lu", (long) record_pos));
@@ -2694,7 +2771,11 @@ static my_bool _ma_update_block_record2(MARIA_HA *info,
DBUG_DUMP("newrec", record, share->base.reclength);
#endif
- /* checksum was computed by maria_update() already and put into cur_row */
+ /*
+ Checksums of new and old rows were computed by callers already; new
+ row's was put into cur_row, old row's was put into new_row.
+ */
+ old_checksum= new_row->checksum;
new_row->checksum= cur_row->checksum;
calc_record_size(info, record, new_row);
page= ma_recordpos_to_page(record_pos);
@@ -2747,8 +2828,9 @@ static my_bool _ma_update_block_record2(MARIA_HA *info,
if (cur_row->extents_count && free_full_pages(info, cur_row))
goto err;
- DBUG_RETURN(write_block_record(info, oldrec, record, new_row, blocks,
- 1, &row_pos, undo_lsn));
+ res= write_block_record(info, oldrec, record, new_row, blocks,
+ 1, &row_pos, undo_lsn, old_checksum);
+ DBUG_RETURN(res);
}
/*
Allocate all size in block for record
@@ -2781,8 +2863,9 @@ static my_bool _ma_update_block_record2(MARIA_HA *info,
row_pos.dir= dir;
row_pos.data= buff + uint2korr(dir);
row_pos.length= head_length;
- DBUG_RETURN(write_block_record(info, oldrec, record, new_row, blocks, 1,
- &row_pos, undo_lsn));
+ res= write_block_record(info, oldrec, record, new_row, blocks, 1,
+ &row_pos, undo_lsn, old_checksum);
+ DBUG_RETURN(res);
err:
_ma_unpin_all_pages_and_finalize_row(info, 0);
@@ -2949,7 +3032,7 @@ static my_bool delete_head_or_tail(MARIA_HA *info,
LOGREC_REDO_PURGE_ROW_TAIL),
info->trn, info, sizeof(log_data),
TRANSLOG_INTERNAL_PARTS + 1, log_array,
- log_data))
+ log_data, NULL))
DBUG_RETURN(1);
}
if (pagecache_write(share->pagecache,
@@ -2976,7 +3059,7 @@ static my_bool delete_head_or_tail(MARIA_HA *info,
if (translog_write_record(&lsn, LOGREC_REDO_PURGE_BLOCKS,
info->trn, info, sizeof(log_data),
TRANSLOG_INTERNAL_PARTS + 1, log_array,
- log_data))
+ log_data, NULL))
DBUG_RETURN(1);
}
/* Write the empty page (needed only for REPAIR to work) */
@@ -3044,6 +3127,7 @@ my_bool _ma_delete_block_record(MARIA_HA *info, const uchar *record)
{
ulonglong page;
uint record_number;
+ MARIA_SHARE *share= info->s;
DBUG_ENTER("_ma_delete_block_record");
page= ma_recordpos_to_page(info->cur_row.lastpos);
@@ -3058,13 +3142,14 @@ my_bool _ma_delete_block_record(MARIA_HA *info, const uchar *record)
if (info->cur_row.extents && free_full_pages(info, &info->cur_row))
goto err;
- if (info->s->now_transactional)
+ if (share->now_transactional)
{
LSN lsn;
uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE +
- DIR_COUNT_SIZE];
+ DIRPOS_STORE_SIZE + HA_CHECKSUM_STORE_SIZE];
size_t row_length;
uint row_parts_count;
+ ha_checksum checksum_delta;
/* Write UNDO record */
lsn_store(log_data, info->trn->undo_lsn);
@@ -3073,15 +3158,26 @@ my_bool _ma_delete_block_record(MARIA_HA *info, const uchar *record)
PAGE_STORE_SIZE, record_number);
info->log_row_parts[TRANSLOG_INTERNAL_PARTS].str= (char*) log_data;
- info->log_row_parts[TRANSLOG_INTERNAL_PARTS].length= sizeof(log_data);
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS].length=
+ sizeof(log_data) - HA_CHECKSUM_STORE_SIZE;
+ store_checksum_in_rec(share, checksum_delta,
+ - info->cur_row.checksum,
+ log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS +
+ 0].length);
+
row_length= fill_insert_undo_parts(info, record, info->log_row_parts +
TRANSLOG_INTERNAL_PARTS + 1,
&row_parts_count);
if (translog_write_record(&lsn, LOGREC_UNDO_ROW_DELETE, info->trn,
- info, sizeof(log_data) + row_length,
+ info,
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS +
+ 0].length + row_length,
TRANSLOG_INTERNAL_PARTS + 1 + row_parts_count,
- info->log_row_parts, log_data + LSN_STORE_SIZE))
+ info->log_row_parts, log_data + LSN_STORE_SIZE,
+ &checksum_delta))
goto err;
}
@@ -3377,7 +3473,8 @@ static my_bool read_long_data(MARIA_HA *info, uchar *to, ulong length,
cur_row.extents_counts contains number of extents
cur_row.empty_bits is set to empty bits
cur_row.field_lengths contains packed length of all fields
- cur_row.blob_length contains total length of all blobs.
+ cur_row.blob_length contains total length of all blobs
+ cur_row.checksum contains checksum of read record.
RETURN
0 ok
@@ -4577,6 +4674,211 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
}
/***************************************************************************
+ In-write hooks called under log's lock when log record is written
+***************************************************************************/
+
+/**
+ @brief Sets transaction's rec_lsn if needed
+
+ A transaction sometimes writes a REDO even before the page is in the
+ pagecache (example: brand new head or tail pages; full pages). So, if
+ Checkpoint happens just after the REDO write, it needs to know that the
+ REDO phase must start before this REDO. Scanning the pagecache cannot
+ tell that as the page is not in the cache. So, transaction sets its rec_lsn
+ to the REDO's LSN or somewhere before, and Checkpoint reads the
+ transaction's rec_lsn.
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_redo(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn, void *hook_arg
+ __attribute__ ((unused)))
+{
+ /*
+ Users of dummy_transaction_object must keep this TRN clean as it
+ is used by many threads (like those manipulating non-transactional
+ tables). It might be dangerous if one user sets rec_lsn or some other
+ member and it is picked up by another user (like putting this rec_lsn into
+ a page of a non-transactional table); it's safer if all members stay 0. So
+ non-transactional log records (REPAIR, CREATE, RENAME, DROP) should not
+ call this hook; we trust them but verify ;)
+ */
+ DBUG_ASSERT(trn->trid != 0);
+ /*
+ If the hook stays so simple, it would be faster to pass
+ !trn->rec_lsn ? trn->rec_lsn : some_dummy_lsn
+ to translog_write_record(), like Monty did in his original code, and not
+ have a hook. For now we keep it like this.
+ */
+ if (trn->rec_lsn == 0)
+ trn->rec_lsn= *lsn;
+ return 0;
+}
+
+
+/**
+ @brief Sets transaction's undo_lsn, first_undo_lsn if needed
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn, void *hook_arg
+ __attribute__ ((unused)))
+{
+ DBUG_ASSERT(trn->trid != 0);
+ trn->undo_lsn= *lsn;
+ if (unlikely(LSN_WITH_FLAGS_TO_LSN(trn->first_undo_lsn) == 0))
+ trn->first_undo_lsn=
+ trn->undo_lsn | LSN_WITH_FLAGS_TO_FLAGS(trn->first_undo_lsn);
+ DBUG_ASSERT(tbl_info->state == &tbl_info->s->state.state);
+ return 0;
+ /*
+ when we implement purging, we will specialize this hook: UNDO_PURGE
+ records will additionally set trn->undo_purge_lsn
+ */
+}
+
+
+/**
+ @brief Sets the table's records count and checksum to 0, then calls the
+ generic REDO hook.
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_redo_delete_all(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn, void *hook_arg)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ DBUG_ASSERT(tbl_info->state == &tbl_info->s->state.state);
+ share->state.state.records= share->state.state.checksum= 0;
+ return write_hook_for_redo(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/**
+ @brief Upates "records" and "checksum" and calls the generic UNDO hook
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo_row_insert(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ share->state.state.records++;
+ share->state.state.checksum+= *(ha_checksum *)hook_arg;
+ return write_hook_for_undo(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/**
+ @brief Upates "records" and calls the generic UNDO hook
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo_row_delete(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ share->state.state.records--;
+ share->state.state.checksum+= *(ha_checksum *)hook_arg;
+ return write_hook_for_undo(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/**
+ @brief Upates "records" and "checksum" and calls the generic UNDO hook
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo_row_update(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ share->state.state.checksum+= *(ha_checksum *)hook_arg;
+ return write_hook_for_undo(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/**
+ @brief Sets transaction's undo_lsn, first_undo_lsn if needed
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_clr_end(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn __attribute__ ((unused)),
+ void *hook_arg)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ struct st_msg_to_write_hook_for_clr_end *msg=
+ (struct st_msg_to_write_hook_for_clr_end *)hook_arg;
+ DBUG_ASSERT(trn->trid != 0);
+ trn->undo_lsn= msg->previous_undo_lsn;
+ share->state.state.checksum+= msg->checksum_delta;
+
+ switch (msg->undone_record_type) {
+ case LOGREC_UNDO_ROW_DELETE:
+ share->state.state.records++;
+ break;
+ case LOGREC_UNDO_ROW_INSERT:
+ share->state.state.records--;
+ break;
+ case LOGREC_UNDO_ROW_UPDATE:
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ if (trn->undo_lsn == LSN_IMPOSSIBLE) /* has fully rolled back */
+ trn->first_undo_lsn= LSN_WITH_FLAGS_TO_FLAGS(trn->first_undo_lsn);
+ return 0;
+}
+
+
+/**
+ @brief Updates table's lsn_of_file_id.
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_file_id(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn
+ __attribute__ ((unused)),
+ MARIA_HA *tbl_info,
+ LSN *lsn __attribute__ ((unused)),
+ void *hook_arg
+ __attribute__ ((unused)))
+{
+ DBUG_ASSERT(cmp_translog_addr(tbl_info->s->lsn_of_file_id, *lsn) < 0);
+ tbl_info->s->lsn_of_file_id= *lsn;
+ return 0;
+}
+
+/***************************************************************************
Applying of REDO log records
***************************************************************************/
@@ -4609,6 +4911,9 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
uint block_size= share->block_size;
uint rec_offset;
uchar *buff= info->keyread_buff, *dir;
+ MARIA_PINNED_PAGE page_link;
+ enum pagecache_page_lock unlock_method;
+ enum pagecache_page_pin unpin_method;
DBUG_ENTER("_ma_apply_redo_insert_row_head_or_tail");
info->keyread_buff_used= 1;
@@ -4635,26 +4940,31 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
empty_space= (block_size - PAGE_OVERHEAD_SIZE);
rec_offset= PAGE_HEADER_SIZE;
dir= buff+ block_size - PAGE_SUFFIX_SIZE - DIR_ENTRY_SIZE;
+ unlock_method= PAGECACHE_LOCK_LEFT_UNLOCKED;
+ unpin_method= PAGECACHE_PIN_LEFT_UNPINNED;
}
else
{
uint max_entry;
- if (!(buff= pagecache_read(share->pagecache,
- &info->dfile,
- page, 0,
- buff, PAGECACHE_PLAIN_PAGE,
- PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
+ if (!(buff= pagecache_read(share->pagecache, &info->dfile,
+ page, 0, 0,
+ PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
+ &page_link.link)))
DBUG_RETURN(my_errno);
- if (lsn_korr(buff) >= lsn)
+ if (lsn_korr(buff) >= lsn) /* Test if already applied */
{
- /* Already applied */
-
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE);
/* Fix bitmap, just in case */
empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
DBUG_RETURN(my_errno);
DBUG_RETURN(0);
}
+ unlock_method= PAGECACHE_LOCK_WRITE_UNLOCK;
+ unpin_method= PAGECACHE_UNPIN;
max_entry= (uint) ((uchar*) buff)[DIR_COUNT_OFFSET];
if (((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) != page_type))
@@ -4725,8 +5035,7 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
if (pagecache_write(share->pagecache,
&info->dfile, page, 0,
buff, PAGECACHE_PLAIN_PAGE,
- PAGECACHE_LOCK_LEFT_UNLOCKED,
- PAGECACHE_PIN_LEFT_UNPINNED,
+ unlock_method, unpin_method,
PAGECACHE_WRITE_DELAY, 0))
DBUG_RETURN(my_errno);
@@ -4747,6 +5056,11 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
DBUG_RETURN(0);
err:
+ if (unlock_method == PAGECACHE_LOCK_WRITE_UNLOCK)
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE);
DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
}
@@ -4778,6 +5092,8 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
uint rownr, empty_space;
uint block_size= share->block_size;
uchar *buff= info->keyread_buff;
+ int result;
+ MARIA_PINNED_PAGE page_link;
DBUG_ENTER("_ma_apply_redo_purge_row_head_or_tail");
page= page_korr(header);
@@ -4788,11 +5104,10 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
info->keyread_buff_used= 1;
- if (!(buff= pagecache_read(share->pagecache,
- &info->dfile,
- page, 0,
- buff, PAGECACHE_PLAIN_PAGE,
- PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
+ if (!(buff= pagecache_read(share->pagecache, &info->dfile,
+ page, 0, 0,
+ PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
+ &page_link.link)))
DBUG_RETURN(my_errno);
if (lsn_korr(buff) >= lsn)
@@ -4802,6 +5117,11 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
Note that in case the page is not anymore a head or tail page
a future redo will fix the bitmap.
*/
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE);
+
if ((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == page_type)
{
empty_space= uint2korr(buff+EMPTY_SPACE_OFFSET);
@@ -4815,22 +5135,30 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
DBUG_ASSERT((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == (uchar) page_type);
if (delete_dir_entry(buff, block_size, rownr, &empty_space) < 0)
- DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
+ goto err;
lsn_store(buff, lsn);
+ result= 0;
if (pagecache_write(share->pagecache,
&info->dfile, page, 0,
buff, PAGECACHE_PLAIN_PAGE,
- PAGECACHE_LOCK_LEFT_UNLOCKED,
- PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_LOCK_WRITE_UNLOCK, PAGECACHE_UNPIN,
PAGECACHE_WRITE_DELAY, 0))
- DBUG_RETURN(my_errno);
+ result= my_errno;
/* This will work even if the page was marked as UNALLOCATED_PAGE */
if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
- DBUG_RETURN(my_errno);
+ result= my_errno;
+
+ DBUG_RETURN(result);
+
+err:
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE);
+ DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
- DBUG_RETURN(0);
}
@@ -4872,16 +5200,21 @@ uint _ma_apply_redo_purge_blocks(MARIA_HA *info,
for (i= 0; i < page_range ; i++)
{
+ MARIA_PINNED_PAGE page_link;
if (!(buff= pagecache_read(share->pagecache,
&info->dfile,
page+i, 0,
buff, PAGECACHE_PLAIN_PAGE,
- PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
+ PAGECACHE_LOCK_WRITE, &page_link.link)))
DBUG_RETURN(my_errno);
if (lsn_korr(buff) >= lsn)
{
/* Already applied */
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE);
continue;
}
buff[PAGE_TYPE_OFFSET]= UNALLOCATED_PAGE;
@@ -4889,8 +5222,7 @@ uint _ma_apply_redo_purge_blocks(MARIA_HA *info,
if (pagecache_write(share->pagecache,
&info->dfile, page+i, 0,
buff, PAGECACHE_PLAIN_PAGE,
- PAGECACHE_LOCK_LEFT_UNLOCKED,
- PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_LOCK_WRITE_UNLOCK, PAGECACHE_UNPIN,
PAGECACHE_WRITE_DELAY, 0))
DBUG_RETURN(my_errno);
}
@@ -4914,19 +5246,25 @@ my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn,
ulonglong page;
uint rownr;
LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
- uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE + 1], *buff;
+ uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE + HA_CHECKSUM_STORE_SIZE],
+ *buff;
my_bool res= 1;
MARIA_PINNED_PAGE page_link;
LSN lsn;
+ MARIA_SHARE *share= info->s;
+ struct st_msg_to_write_hook_for_clr_end msg;
DBUG_ENTER("_ma_apply_undo_row_insert");
page= page_korr(header);
- rownr= dirpos_korr(header + PAGE_STORE_SIZE);
+ header+= PAGE_STORE_SIZE;
+ rownr= dirpos_korr(header);
+ header+= DIRPOS_STORE_SIZE;
DBUG_PRINT("enter", ("Page: %lu rownr: %u", (ulong) page, rownr));
- if (!(buff= pagecache_read(info->s->pagecache,
+ if (!(buff= pagecache_read(share->pagecache,
&info->dfile, page, 0,
- info->buff, info->s->page_type,
+ info->buff, share->page_type,
PAGECACHE_LOCK_WRITE,
&page_link.link)))
DBUG_RETURN(1);
@@ -4947,14 +5285,24 @@ my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn,
/* undo_lsn must be first for compression to work */
lsn_store(log_data, undo_lsn);
- log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE]= LOGREC_UNDO_ROW_INSERT;
+ clr_type_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE,
+ LOGREC_UNDO_ROW_INSERT);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length=
+ sizeof(log_data) - HA_CHECKSUM_STORE_SIZE;
+ msg.undone_record_type= LOGREC_UNDO_ROW_INSERT;
+ msg.previous_undo_lsn= undo_lsn;
+ store_checksum_in_rec(share, msg.checksum_delta,
+ - ha_checksum_korr(header),
+ log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE,
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length);
log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data;
- log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
if (translog_write_record(&lsn, LOGREC_CLR_END,
- info->trn, info, sizeof(log_data),
+ info->trn, info, log_array[TRANSLOG_INTERNAL_PARTS
+ + 0].length,
TRANSLOG_INTERNAL_PARTS + 1, log_array,
- log_data + LSN_STORE_SIZE))
+ log_data + LSN_STORE_SIZE, &msg))
goto err;
res= 0;
@@ -4984,6 +5332,16 @@ my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn,
some buffers to point directly to 'header'
*/
memcpy(&row, &info->cur_row, sizeof(row));
+ if (share->calc_checksum)
+ {
+ /*
+ We extract the checksum delta here, saving a recomputation in
+ allocate_and_write_block_record(). It's only an optimization.
+ */
+ row.checksum= - ha_checksum_korr(header);
+ header+= HA_CHECKSUM_STORE_SIZE;
+ }
+
null_field_lengths= row.null_field_lengths;
blob_lengths= row.blob_lengths;
@@ -5154,18 +5512,25 @@ my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
uchar *current_record, *orig_record;
int error= 1;
MARIA_RECORD_POS record_pos;
+ ha_checksum checksum_delta;
DBUG_ENTER("_ma_apply_undo_row_update");
page= page_korr(header);
- rownr= dirpos_korr(header + PAGE_STORE_SIZE);
+ header+= PAGE_STORE_SIZE;
+ rownr= dirpos_korr(header);
+ header+= DIRPOS_STORE_SIZE;
record_pos= ma_recordpos(page, rownr);
DBUG_PRINT("enter", ("Page: %lu rownr: %u", (ulong) page, rownr));
+ if (share->calc_checksum)
+ {
+ checksum_delta= ha_checksum_korr(header);
+ header+= HA_CHECKSUM_STORE_SIZE;
+ }
/*
Set header to point to old field values, generated by
fill_update_undo_parts()
*/
- header+= PAGE_STORE_SIZE + DIRPOS_STORE_SIZE;
field_length_header= ma_get_length((uchar**) &header);
field_length_data= header;
header+= field_length_header;
@@ -5260,14 +5625,14 @@ my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
if (share->calc_checksum)
{
- info->cur_row.checksum= (*share->calc_checksum)(info, orig_record);
- info->state->checksum+= (info->cur_row.checksum -
- (*share->calc_checksum)(info, current_record));
+ info->new_row.checksum= checksum_delta +
+ (info->cur_row.checksum= (*share->calc_checksum)(info, orig_record));
+ /* verify that record's content is sane */
+ DBUG_ASSERT(info->new_row.checksum ==
+ (*share->calc_checksum)(info, current_record));
}
- /*
- Now records are up to date, execute the update to original values
- */
+ /* Now records are up to date, execute the update to original values */
if (_ma_update_block_record2(info, record_pos, current_record, orig_record,
undo_lsn))
goto err;
diff --git a/storage/maria/ma_blockrec.h b/storage/maria/ma_blockrec.h
index 30dffe1c0c0..0bce4015daf 100644
--- a/storage/maria/ma_blockrec.h
+++ b/storage/maria/ma_blockrec.h
@@ -193,3 +193,28 @@ my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn,
const uchar *header, size_t length);
my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
const uchar *header, size_t length);
+
+my_bool write_hook_for_redo(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
+my_bool write_hook_for_undo(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
+my_bool write_hook_for_redo_delete_all(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+my_bool write_hook_for_undo_row_insert(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+my_bool write_hook_for_undo_row_delete(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+my_bool write_hook_for_undo_row_update(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+my_bool write_hook_for_clr_end(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
+my_bool write_hook_for_file_id(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c
index 465c57a21a4..dec70028596 100644
--- a/storage/maria/ma_check.c
+++ b/storage/maria/ma_check.c
@@ -5603,11 +5603,10 @@ static int write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info)
record).
*/
LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
- uchar log_data[LSN_STORE_SIZE];
+ uchar log_data[FILEID_STORE_SIZE + 4];
LSN lsn;
- compile_time_assert(LSN_STORE_SIZE >= (FILEID_STORE_SIZE + 4));
log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data;
- log_array[TRANSLOG_INTERNAL_PARTS + 0].length= FILEID_STORE_SIZE + 4;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
/*
testflag gives an idea of what REPAIR did (in particular T_QUICK
or not: did it touch the data file or not?).
@@ -5615,10 +5614,9 @@ static int write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info)
int4store(log_data + FILEID_STORE_SIZE, param->testflag);
if (unlikely(translog_write_record(&lsn, LOGREC_REDO_REPAIR_TABLE,
&dummy_transaction_object, info,
- log_array[TRANSLOG_INTERNAL_PARTS +
- 0].length,
+ sizeof(log_data),
sizeof(log_array)/sizeof(log_array[0]),
- log_array, log_data) ||
+ log_array, log_data, NULL) ||
translog_flush(lsn)))
return 1;
/*
diff --git a/storage/maria/ma_check_standalone.h b/storage/maria/ma_check_standalone.h
new file mode 100644
index 00000000000..3874d722d6c
--- /dev/null
+++ b/storage/maria/ma_check_standalone.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ All standalone programs which need to use functions from ma_check.c
+ (like maria_repair()) must define their version of _ma_killed_ptr()
+ and _ma_check_print_info|warning|error(). Indeed, linking with ma_check.o
+ brings in the dependencies of ma_check.o which are definitions of the above
+ functions; if the program does not define them then the ones of
+ ha_maria.o are used i.e. ha_maria.o is linked into the program, and this
+ brings dependencies of ha_maria.o on mysqld.o into the program's linking
+ which thus fails, as the program is not linked with mysqld.o.
+ This file contains the versions of these functions used by maria_chk and
+ maria_read_log.
+*/
+
+/*
+ Check if check/repair operation was killed by a signal
+*/
+
+static int not_killed= 0;
+
+volatile int *_ma_killed_ptr(HA_CHECK *param __attribute__((unused)))
+{
+ return &not_killed; /* always NULL */
+}
+
+ /* print warnings and errors */
+ /* VARARGS */
+
+void _ma_check_print_info(HA_CHECK *param __attribute__((unused)),
+ const char *fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("_ma_check_print_info");
+ DBUG_PRINT("enter", ("format: %s", fmt));
+
+ va_start(args,fmt);
+ VOID(vfprintf(stdout, fmt, args));
+ VOID(fputc('\n',stdout));
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+/* VARARGS */
+
+void _ma_check_print_warning(HA_CHECK *param, const char *fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("_ma_check_print_warning");
+ DBUG_PRINT("enter", ("format: %s", fmt));
+
+ fflush(stdout);
+ if (!param->warning_printed && !param->error_printed)
+ {
+ if (param->testflag & T_SILENT)
+ fprintf(stderr,"%s: MARIA file %s\n",my_progname_short,
+ param->isam_file_name);
+ param->out_flag|= O_DATA_LOST;
+ }
+ param->warning_printed=1;
+ va_start(args,fmt);
+ fprintf(stderr,"%s: warning: ",my_progname_short);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ fflush(stderr);
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+/* VARARGS */
+
+void _ma_check_print_error(HA_CHECK *param, const char *fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("_ma_check_print_error");
+ DBUG_PRINT("enter", ("format: %s", fmt));
+
+ fflush(stdout);
+ if (!param->warning_printed && !param->error_printed)
+ {
+ if (param->testflag & T_SILENT)
+ fprintf(stderr,"%s: MARIA file %s\n",my_progname_short,param->isam_file_name);
+ param->out_flag|= O_DATA_LOST;
+ }
+ param->error_printed|=1;
+ va_start(args,fmt);
+ fprintf(stderr,"%s: error: ",my_progname_short);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ fflush(stderr);
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
diff --git a/storage/maria/ma_checkpoint.c b/storage/maria/ma_checkpoint.c
index 4446285fce9..76eacaede0d 100644
--- a/storage/maria/ma_checkpoint.c
+++ b/storage/maria/ma_checkpoint.c
@@ -266,7 +266,7 @@ static int really_execute_checkpoint(void)
&dummy_transaction_object, NULL,
total_rec_length,
sizeof(log_array)/sizeof(log_array[0]),
- log_array, NULL) ||
+ log_array, NULL, NULL) ||
translog_flush(lsn)))
goto err;
@@ -652,7 +652,7 @@ pthread_handler_t ma_checkpoint_background(void *arg __attribute__((unused)))
break;
#if 0 /* good for testing, to do a lot of checkpoints, finds a lot of bugs */
pthread_mutex_unlock(&LOCK_checkpoint);
- my_sleep(100000); // a tenth of a second
+ my_sleep(100000); /* a tenth of a second */
pthread_mutex_lock(&LOCK_checkpoint);
#else
/* To have a killable sleep, we use timedwait like our SQL GET_LOCK() */
@@ -893,7 +893,7 @@ static int collect_tables(LEX_STRING *str, LSN checkpoint_start_log_horizon)
filter_param.pages_covered_by_bitmap= share->bitmap.pages_covered;
/* OS file descriptors are ints which we stored in 4 bytes */
- compile_time_assert(sizeof(int) == 4);
+ compile_time_assert(sizeof(int) <= 4);
pthread_mutex_lock(&share->intern_lock);
/*
Tables in a normal state have their two file descriptors open.
diff --git a/storage/maria/ma_commit.c b/storage/maria/ma_commit.c
index 36ea2f6e6e4..8a0a4c136bb 100644
--- a/storage/maria/ma_commit.c
+++ b/storage/maria/ma_commit.c
@@ -64,7 +64,7 @@ int ma_commit(TRN *trn)
res= (translog_write_record(&commit_lsn, LOGREC_COMMIT,
trn, NULL, 0,
sizeof(log_array)/sizeof(log_array[0]),
- log_array, NULL) ||
+ log_array, NULL, NULL) ||
translog_flush(commit_lsn) ||
trnman_commit_trn(trn));
/*
diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c
index 43e596708b9..d2ec3bc0d68 100644
--- a/storage/maria/ma_create.c
+++ b/storage/maria/ma_create.c
@@ -998,7 +998,7 @@ int maria_create(const char *name, enum data_file_type datafile_type,
&dummy_transaction_object, NULL,
total_rec_length,
sizeof(log_array)/sizeof(log_array[0]),
- log_array, NULL) ||
+ log_array, NULL, NULL) ||
translog_flush(lsn)))
goto err;
/*
diff --git a/storage/maria/ma_delete.c b/storage/maria/ma_delete.c
index f711102e491..3f88f9025a3 100644
--- a/storage/maria/ma_delete.c
+++ b/storage/maria/ma_delete.c
@@ -44,10 +44,10 @@ int maria_delete(MARIA_HA *info,const uchar *record)
/* Test if record is in datafile */
DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_usage",
- maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_print_error(share, HA_ERR_CRASHED);
DBUG_RETURN(my_errno= HA_ERR_CRASHED););
DBUG_EXECUTE_IF("my_error_test_undefined_error",
- maria_print_error(info->s, INT_MAX);
+ maria_print_error(share, INT_MAX);
DBUG_RETURN(my_errno= INT_MAX););
if (!(info->update & HA_STATE_AKTIV))
{
@@ -70,17 +70,17 @@ int maria_delete(MARIA_HA *info,const uchar *record)
old_key= info->lastkey2;
for (i=0 ; i < share->base.keys ; i++ )
{
- if (maria_is_key_active(info->s->state.key_map, i))
+ if (maria_is_key_active(share->state.key_map, i))
{
- info->s->keyinfo[i].version++;
- if (info->s->keyinfo[i].flag & HA_FULLTEXT )
+ share->keyinfo[i].version++;
+ if (share->keyinfo[i].flag & HA_FULLTEXT )
{
if (_ma_ft_del(info, i, old_key, record, info->cur_row.lastpos))
goto err;
}
else
{
- if (info->s->keyinfo[i].ck_delete(info,i,old_key,
+ if (share->keyinfo[i].ck_delete(info,i,old_key,
_ma_make_key(info, i, old_key,
record,
info->cur_row.lastpos)))
@@ -91,19 +91,20 @@ int maria_delete(MARIA_HA *info,const uchar *record)
}
}
- if ((*share->delete_record)(info, record))
- goto err; /* Remove record from database */
-
- /*
- We can't use the row based checksum as this doesn't have enough
- precision.
- */
- if (info->s->calc_checksum)
+ if (share->calc_checksum)
{
- info->cur_row.checksum= (*info->s->calc_checksum)(info,record);
- info->state->checksum-= info->cur_row.checksum;
+ /*
+ We can't use the row based checksum as this doesn't have enough
+ precision.
+ */
+ info->cur_row.checksum= (*share->calc_checksum)(info, record);
}
+ if ((*share->delete_record)(info, record))
+ goto err; /* Remove record from database */
+
+ info->state->checksum+= - !share->now_transactional *
+ info->cur_row.checksum;
info->update= HA_STATE_CHANGED+HA_STATE_DELETED+HA_STATE_ROW_CHANGED;
info->state->records-= !share->now_transactional;
share->state.changed|= STATE_NOT_OPTIMIZED_ROWS;
@@ -113,8 +114,8 @@ int maria_delete(MARIA_HA *info,const uchar *record)
allow_break(); /* Allow SIGHUP & SIGINT */
if (info->invalidator != 0)
{
- DBUG_PRINT("info", ("invalidator... '%s' (delete)", info->s->open_file_name));
- (*info->invalidator)(info->s->open_file_name);
+ DBUG_PRINT("info", ("invalidator... '%s' (delete)", share->open_file_name));
+ (*info->invalidator)(share->open_file_name);
info->invalidator=0;
}
DBUG_RETURN(0);
@@ -124,7 +125,7 @@ err:
mi_sizestore(lastpos, info->cur_row.lastpos);
if (save_errno != HA_ERR_RECORD_CHANGED)
{
- maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_print_error(share, HA_ERR_CRASHED);
maria_mark_crashed(info); /* mark table crashed */
}
VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
@@ -133,7 +134,7 @@ err:
my_errno=save_errno;
if (save_errno == HA_ERR_KEY_NOT_FOUND)
{
- maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_print_error(share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
}
diff --git a/storage/maria/ma_delete_all.c b/storage/maria/ma_delete_all.c
index 8cb4fdb8a3e..408ca31b3c6 100644
--- a/storage/maria/ma_delete_all.c
+++ b/storage/maria/ma_delete_all.c
@@ -64,14 +64,15 @@ int maria_delete_all_rows(MARIA_HA *info)
if (unlikely(translog_write_record(&lsn, LOGREC_REDO_DELETE_ALL,
info->trn, info, 0,
sizeof(log_array)/sizeof(log_array[0]),
- log_array, log_data) ||
+ log_array, log_data, NULL) ||
translog_flush(lsn)))
goto err;
}
/*
For recovery it matters that this is called after writing the log record,
- so that resetting state.records actually happens under log's mutex.
+ so that resetting state.records and state.checksum actually happens under
+ log's mutex.
*/
_ma_reset_status(info);
@@ -147,10 +148,6 @@ void _ma_reset_status(MARIA_HA *info)
info->state->key_file_length= share->base.keystart;
info->state->data_file_length= 0;
info->state->empty= info->state->key_empty= 0;
- /**
- @todo RECOVERY BUG
- the line below must happen under log's mutex when writing the REDO
- */
info->state->checksum= 0;
/* Drop the delete key chain. */
diff --git a/storage/maria/ma_delete_table.c b/storage/maria/ma_delete_table.c
index 693c68c7e5f..e6cbd961b7a 100644
--- a/storage/maria/ma_delete_table.c
+++ b/storage/maria/ma_delete_table.c
@@ -92,7 +92,7 @@ int maria_delete_table(const char *name)
log_array[TRANSLOG_INTERNAL_PARTS +
0].length,
sizeof(log_array)/sizeof(log_array[0]),
- log_array, NULL) ||
+ log_array, NULL, NULL) ||
translog_flush(lsn)))
DBUG_RETURN(1);
}
diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c
index f3c90ceb1f5..a4e5404815d 100644
--- a/storage/maria/ma_loghandler.c
+++ b/storage/maria/ma_loghandler.c
@@ -14,8 +14,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "maria_def.h"
-#include "ma_blockrec.h"
-#include "trnman.h"
+#include "ma_blockrec.h" /* for some constants and in-write hooks */
+#include "trnman.h" /* for access to members of TRN */
/**
@file
@@ -208,31 +208,6 @@ static MARIA_SHARE **id_to_share= NULL;
/* lock for id_to_share */
static my_atomic_rwlock_t LOCK_id_to_share;
-static my_bool write_hook_for_redo(enum translog_record_type type,
- TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
- struct st_translog_parts *parts);
-static my_bool write_hook_for_undo(enum translog_record_type type,
- TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
- struct st_translog_parts *parts);
-static my_bool write_hook_for_redo_delete_all(enum translog_record_type type,
- TRN *trn, MARIA_HA *tbl_info,
- LSN *lsn,
- struct st_translog_parts *parts);
-static my_bool write_hook_for_undo_row_insert(enum translog_record_type type,
- TRN *trn, MARIA_HA *tbl_info,
- LSN *lsn,
- struct st_translog_parts *parts);
-static my_bool write_hook_for_undo_row_delete(enum translog_record_type type,
- TRN *trn, MARIA_HA *tbl_info,
- LSN *lsn,
- struct st_translog_parts *parts);
-static my_bool write_hook_for_clr_end(enum translog_record_type type,
- TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
- struct st_translog_parts *parts);
-static my_bool write_hook_for_file_id(enum translog_record_type type,
- TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
- struct st_translog_parts *parts);
-
static my_bool translog_page_validator(uchar *page_addr, uchar* data_ptr);
/*
@@ -437,8 +412,8 @@ static LOG_DESC INIT_LOGREC_REDO_UNDELETE_ROW=
"redo_undelete_row", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_CLR_END=
-{LOGRECTYPE_PSEUDOFIXEDLENGTH, LSN_STORE_SIZE + FILEID_STORE_SIZE + 1,
- LSN_STORE_SIZE + FILEID_STORE_SIZE + 1, NULL, write_hook_for_clr_end, NULL, 1,
+{LOGRECTYPE_VARIABLE_LENGTH, 0, LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE, NULL, write_hook_for_clr_end, NULL, 1,
"clr_end", LOGREC_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_PURGE_END=
@@ -446,8 +421,7 @@ static LOG_DESC INIT_LOGREC_PURGE_END=
"purge_end", LOGREC_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_UNDO_ROW_INSERT=
-{LOGRECTYPE_PSEUDOFIXEDLENGTH,
- LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
NULL, write_hook_for_undo_row_insert, NULL, 1,
"undo_row_insert", LOGREC_LAST_IN_GROUP, NULL, NULL};
@@ -461,7 +435,7 @@ static LOG_DESC INIT_LOGREC_UNDO_ROW_DELETE=
static LOG_DESC INIT_LOGREC_UNDO_ROW_UPDATE=
{LOGRECTYPE_VARIABLE_LENGTH, 0,
LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
- NULL, write_hook_for_undo, NULL, 1,
+ NULL, write_hook_for_undo_row_update, NULL, 1,
"undo_row_update", LOGREC_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_UNDO_KEY_INSERT=
@@ -640,22 +614,25 @@ static void translog_check_cursor(struct st_buffer_cursor *cursor)
translog_filename_by_fileno()
file_no Number of the log we want to open
path Pointer to buffer where file name will be
- stored (must be FN_REFLEN bytes at least
+ stored (must be FN_REFLEN bytes at least)
RETURN
pointer to path
*/
static char *translog_filename_by_fileno(uint32 file_no, char *path)
{
- char file_name[10 + 8 + 1]; /* See fallowing my_sprintf() call */
- char *res;
+ char buff[11], *end;
+ uint length;
DBUG_ENTER("translog_filename_by_fileno");
DBUG_ASSERT(file_no <= 0xfffffff);
- my_sprintf(file_name, (file_name, "maria_log.%08u", file_no));
- res= fn_format(path, file_name, log_descriptor.directory, "", MYF(MY_WME));
- DBUG_PRINT("info", ("Path: '%s' path: 0x%lx res: 0x%lx",
- res, (ulong) path, (ulong) res));
- DBUG_RETURN(res);
+
+ /* log_descriptor.directory is already formated */
+ end= strxmov(path, log_descriptor.directory, "maria_log.0000000", NullS);
+ length= (uint) (int10_to_str(file_no, buff, 10) - buff);
+ strmov(end-length+1, buff);
+
+ DBUG_PRINT("info", ("Path: '%s' path: 0x%lx", path, (ulong) path));
+ DBUG_RETURN(path);
}
@@ -986,10 +963,11 @@ static void translog_mark_file_finished(uint32 file)
{
int i;
struct st_file_counter *fc_ptr;
-
DBUG_ENTER("translog_mark_file_finished");
DBUG_PRINT("enter", ("file: %lu", (ulong) file));
+ LINT_INIT(fc_ptr);
+
pthread_mutex_lock(&log_descriptor.unfinished_files_lock);
DBUG_ASSERT(log_descriptor.unfinished_files.elements > 0);
@@ -2296,21 +2274,21 @@ my_bool translog_unlock()
}
-/*
- Get log page by file number and offset of the beginning of the page
+/**
+ @brief Get log page by file number and offset of the beginning of the page
- SYNOPSIS
- translog_get_page()
- data validator data, which contains the page address
- buffer buffer for page placing
+ @param data validator data, which contains the page address
+ @param buffer buffer for page placing
(might not be used in some cache implementations)
+ @param direct_link if it is not NULL then caller can accept direct
+ link to the page cache
- RETURN
- NULL - Error
- # pointer to the page cache which should be used to read this page
+ @retval NULL Error
+ @retval # pointer to the page cache which should be used to read this page
*/
-static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer)
+static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer,
+ PAGECACHE_BLOCK_LINK **direct_link)
{
TRANSLOG_ADDRESS addr= *(data->addr), in_buffers;
uint cache_index;
@@ -2324,6 +2302,9 @@ static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer)
/* it is really page address */
DBUG_ASSERT(LSN_OFFSET(addr) % TRANSLOG_PAGE_SIZE == 0);
+ if (direct_link)
+ *direct_link= NULL;
+
in_buffers= translog_only_in_buffers();
DBUG_PRINT("info", ("in_buffers: (%lu,0x%lx)",
LSN_IN_PARTS(in_buffers)));
@@ -2336,7 +2317,9 @@ static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer)
if (cmp_translog_addr(addr, in_buffers) >= 0)
{
uint16 buffer_no= log_descriptor.bc.buffer_no;
+#ifndef DBUG_OFF
uint16 buffer_start= buffer_no;
+#endif
struct st_translog_buffer *buffer_unlock= log_descriptor.bc.buffer;
struct st_translog_buffer *curr_buffer= log_descriptor.bc.buffer;
for (;;)
@@ -2437,13 +2420,23 @@ static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer)
}
file.file= log_descriptor.log_file_num[cache_index];
- buffer= (uchar*)
- pagecache_valid_read(log_descriptor.pagecache, &file,
- LSN_OFFSET(addr) / TRANSLOG_PAGE_SIZE,
- 3, (char*) buffer,
- PAGECACHE_PLAIN_PAGE,
- PAGECACHE_LOCK_LEFT_UNLOCKED, 0,
- &translog_page_validator, (uchar*) data);
+ buffer=
+ (uchar*) (direct_link ?
+ pagecache_valid_read(log_descriptor.pagecache, &file,
+ LSN_OFFSET(addr) / TRANSLOG_PAGE_SIZE,
+ 3, NULL,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_READ, direct_link,
+ &translog_page_validator, (uchar*) data) :
+ pagecache_valid_read(log_descriptor.pagecache, &file,
+ LSN_OFFSET(addr) / TRANSLOG_PAGE_SIZE,
+ 3, (char*) buffer,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, direct_link,
+ &translog_page_validator, (uchar*) data));
+ DBUG_PRINT("info", ("Direct link is assigned to : 0x%lx * 0x%lx",
+ (ulong) direct_link,
+ (ulong)(direct_link ? *direct_link : NULL)));
}
else
{
@@ -2468,6 +2461,24 @@ static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer)
DBUG_RETURN(buffer);
}
+/**
+ @brief free direct log page link
+
+ @param direct_link the direct log page link to be freed
+
+*/
+
+static void translog_free_link(PAGECACHE_BLOCK_LINK *direct_link)
+{
+ DBUG_ENTER("translog_free_link");
+ DBUG_PRINT("info", ("Direct link: 0x%lx",
+ (ulong) direct_link));
+ if (direct_link)
+ pagecache_unlock_by_link(log_descriptor.pagecache, direct_link,
+ PAGECACHE_LOCK_READ_UNLOCK, PAGECACHE_UNPIN,
+ LSN_IMPOSSIBLE, LSN_IMPOSSIBLE);
+ DBUG_VOID_RETURN;
+}
/*
Finds last page of the given log file
@@ -2796,7 +2807,7 @@ my_bool translog_init(const char *directory,
TRANSLOG_VALIDATOR_DATA data;
uchar buffer[TRANSLOG_PAGE_SIZE], *page;
data.addr= &current_page;
- if ((page= translog_get_page(&data, buffer)) == NULL)
+ if ((page= translog_get_page(&data, buffer, NULL)) == NULL)
DBUG_RETURN(1);
if (data.was_recovered)
{
@@ -2848,7 +2859,7 @@ my_bool translog_init(const char *directory,
/* continue old log */
DBUG_ASSERT(LSN_FILE_NO(last_valid_page)==
LSN_FILE_NO(log_descriptor.horizon));
- if ((page= translog_get_page(&data, buffer)) == NULL ||
+ if ((page= translog_get_page(&data, buffer, NULL)) == NULL ||
(chunk_offset= translog_get_first_chunk_offset(page)) == 0)
DBUG_RETURN(1);
@@ -3641,23 +3652,23 @@ static translog_size_t translog_get_current_group_size()
}
-/*
- Write variable record in 1 group
+/**
+ @brief Write variable record in 1 group.
- SYNOPSIS
- translog_write_variable_record_1group()
- lsn LSN of the record will be written here
- type the log record type
- short_trid Short transaction ID or 0 if it has no sense
- parts Descriptor of record source parts
- buffer_to_flush Buffer which have to be flushed if it is not 0
- header_length Calculated header length of chunk type 0
- trn Transaction structure pointer for hooks by
- record log type, for short_id
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param buffer_to_flush Buffer which have to be flushed if it is not 0
+ @param header_length Calculated header length of chunk type 0
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
- RETURN
- 0 OK
- 1 Error
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
*/
static my_bool
@@ -3668,7 +3679,7 @@ translog_write_variable_record_1group(LSN *lsn,
struct st_translog_parts *parts,
struct st_translog_buffer
*buffer_to_flush, uint16 header_length,
- TRN *trn)
+ TRN *trn, void *hook_arg)
{
TRANSLOG_ADDRESS horizon;
struct st_buffer_cursor cursor;
@@ -3684,7 +3695,7 @@ translog_write_variable_record_1group(LSN *lsn,
*lsn, TRUE) ||
(log_record_type_descriptor[type].inwrite_hook &&
(*log_record_type_descriptor[type].inwrite_hook)(type, trn, tbl_info,
- lsn, parts)))
+ lsn, hook_arg)))
{
translog_unlock();
DBUG_RETURN(1);
@@ -3793,23 +3804,23 @@ translog_write_variable_record_1group(LSN *lsn,
}
-/*
- Write variable record in 1 chunk
+/**
+ @brief Write variable record in 1 chunk.
- SYNOPSIS
- translog_write_variable_record_1chunk()
- lsn LSN of the record will be written here
- type the log record type
- short_trid Short transaction ID or 0 if it has no sense
- parts Descriptor of record source parts
- buffer_to_flush Buffer which have to be flushed if it is not 0
- header_length Calculated header length of chunk type 0
- trn Transaction structure pointer for hooks by
- record log type, for short_id
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param buffer_to_flush Buffer which have to be flushed if it is not 0
+ @param header_length Calculated header length of chunk type 0
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
- RETURN
- 0 OK
- 1 Error
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
*/
static my_bool
@@ -3820,7 +3831,7 @@ translog_write_variable_record_1chunk(LSN *lsn,
struct st_translog_parts *parts,
struct st_translog_buffer
*buffer_to_flush, uint16 header_length,
- TRN *trn)
+ TRN *trn, void *hook_arg)
{
int rc;
uchar chunk0_header[1 + 2 + 5 + 2];
@@ -3834,7 +3845,7 @@ translog_write_variable_record_1chunk(LSN *lsn,
*lsn, TRUE) ||
(log_record_type_descriptor[type].inwrite_hook &&
(*log_record_type_descriptor[type].inwrite_hook)(type, trn, tbl_info,
- lsn, parts)))
+ lsn, hook_arg)))
{
translog_unlock();
DBUG_RETURN(1);
@@ -4159,24 +4170,24 @@ static my_bool translog_relative_LSN_encode(struct st_translog_parts *parts,
}
-/*
- Write multi-group variable-size record
+/**
+ @brief Write multi-group variable-size record.
- SYNOPSIS
- translog_write_variable_record_mgroup()
- lsn LSN of the record will be written here
- type the log record type
- short_trid Short transaction ID or 0 if it has no sense
- parts Descriptor of record source parts
- buffer_to_flush Buffer which have to be flushed if it is not 0
- header_length Header length calculated for 1 group
- buffer_rest Beginning from which we plan to write in full pages
- trn Transaction structure pointer for hooks by
- record log type, for short_id
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param buffer_to_flush Buffer which have to be flushed if it is not 0
+ @param header_length Header length calculated for 1 group
+ @param buffer_rest Beginning from which we plan to write in full pages
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
- RETURN
- 0 OK
- 1 Error
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
*/
static my_bool
@@ -4189,7 +4200,7 @@ translog_write_variable_record_mgroup(LSN *lsn,
*buffer_to_flush,
uint16 header_length,
translog_size_t buffer_rest,
- TRN *trn)
+ TRN *trn, void *hook_arg)
{
TRANSLOG_ADDRESS horizon;
struct st_buffer_cursor cursor;
@@ -4517,7 +4528,7 @@ translog_write_variable_record_mgroup(LSN *lsn,
if (log_record_type_descriptor[type].inwrite_hook &&
(*log_record_type_descriptor[type].inwrite_hook) (type, trn,
tbl_info,
- lsn, parts))
+ lsn, hook_arg))
goto err;
}
@@ -4589,21 +4600,21 @@ err:
}
-/*
- Write the variable length log record
+/**
+ @brief Write the variable length log record.
- SYNOPSIS
- translog_write_variable_record()
- lsn LSN of the record will be written here
- type the log record type
- short_trid Short transaction ID or 0 if it has no sense
- parts Descriptor of record source parts
- trn Transaction structure pointer for hooks by
- record log type, for short_id
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
- RETURN
- 0 OK
- 1 Error
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
*/
static my_bool translog_write_variable_record(LSN *lsn,
@@ -4611,7 +4622,7 @@ static my_bool translog_write_variable_record(LSN *lsn,
MARIA_HA *tbl_info,
SHORT_TRANSACTION_ID short_trid,
struct st_translog_parts *parts,
- TRN *trn)
+ TRN *trn, void *hook_arg)
{
struct st_translog_buffer *buffer_to_flush= NULL;
uint header_length1= 1 + 2 + 2 +
@@ -4688,7 +4699,7 @@ static my_bool translog_write_variable_record(LSN *lsn,
res= translog_write_variable_record_1chunk(lsn, type, tbl_info,
short_trid,
parts, buffer_to_flush,
- header_length1, trn);
+ header_length1, trn, hook_arg);
DBUG_RETURN(res);
}
@@ -4700,7 +4711,7 @@ static my_bool translog_write_variable_record(LSN *lsn,
res= translog_write_variable_record_1group(lsn, type, tbl_info,
short_trid,
parts, buffer_to_flush,
- header_length1, trn);
+ header_length1, trn, hook_arg);
DBUG_RETURN(res);
}
/* following function makes translog_unlock(); */
@@ -4708,26 +4719,26 @@ static my_bool translog_write_variable_record(LSN *lsn,
short_trid,
parts, buffer_to_flush,
header_length1,
- buffer_rest, trn);
+ buffer_rest, trn, hook_arg);
DBUG_RETURN(res);
}
-/*
- Write the fixed and pseudo-fixed log record
+/**
+ @brief Write the fixed and pseudo-fixed log record.
- SYNOPSIS
- translog_write_fixed_record()
- lsn LSN of the record will be written here
- type the log record type
- short_trid Short transaction ID or 0 if it has no sense
- parts Descriptor of record source parts
- trn Transaction structure pointer for hooks by
- record log type, for short_id
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
- RETURN
- 0 OK
- 1 Error
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
*/
static my_bool translog_write_fixed_record(LSN *lsn,
@@ -4735,7 +4746,7 @@ static my_bool translog_write_fixed_record(LSN *lsn,
MARIA_HA *tbl_info,
SHORT_TRANSACTION_ID short_trid,
struct st_translog_parts *parts,
- TRN *trn)
+ TRN *trn, void *hook_arg)
{
struct st_translog_buffer *buffer_to_flush= NULL;
uchar chunk1_header[1 + 2];
@@ -4787,7 +4798,7 @@ static my_bool translog_write_fixed_record(LSN *lsn,
*lsn, TRUE) ||
(log_record_type_descriptor[type].inwrite_hook &&
(*log_record_type_descriptor[type].inwrite_hook) (type, trn, tbl_info,
- lsn, parts)))
+ lsn, hook_arg)))
{
rc= 1;
goto err;
@@ -4862,6 +4873,9 @@ err:
@param store_share_id if tbl_info!=NULL then share's id will
automatically be stored in the two first bytes
pointed (so pointer is assumed to be !=NULL)
+ @param hook_arg argument which will be passed to pre-write and
+ in-write hooks of this record.
+
@return Operation status
@retval 0 OK
@retval 1 Error
@@ -4873,7 +4887,8 @@ my_bool translog_write_record(LSN *lsn,
translog_size_t rec_len,
uint part_no,
LEX_STRING *parts_data,
- uchar *store_share_id)
+ uchar *store_share_id,
+ void *hook_arg)
{
struct st_translog_parts parts;
LEX_STRING *part;
@@ -4918,7 +4933,7 @@ my_bool translog_write_record(LSN *lsn,
if (unlikely(translog_write_record(&dummy_lsn, LOGREC_LONG_TRANSACTION_ID,
trn, NULL, sizeof(log_data),
sizeof(log_array)/sizeof(log_array[0]),
- log_array, NULL)))
+ log_array, NULL, NULL)))
DBUG_RETURN(1);
}
@@ -4981,17 +4996,17 @@ my_bool translog_write_record(LSN *lsn,
if (!(rc= (log_record_type_descriptor[type].prewrite_hook &&
(*log_record_type_descriptor[type].prewrite_hook) (type, trn,
tbl_info,
- &parts))))
+ hook_arg))))
{
switch (log_record_type_descriptor[type].class) {
case LOGRECTYPE_VARIABLE_LENGTH:
rc= translog_write_variable_record(lsn, type, tbl_info,
- short_trid, &parts, trn);
+ short_trid, &parts, trn, hook_arg);
break;
case LOGRECTYPE_PSEUDOFIXEDLENGTH:
case LOGRECTYPE_FIXEDLENGTH:
rc= translog_write_fixed_record(lsn, type, tbl_info,
- short_trid, &parts, trn);
+ short_trid, &parts, trn, hook_arg);
break;
case LOGRECTYPE_NOT_ALLOWED:
default:
@@ -5148,33 +5163,72 @@ static my_bool translog_scanner_set_last_page(TRANSLOG_SCANNER_DATA
*scanner)
{
my_bool page_ok;
+ if (LSN_FILE_NO(scanner->page_addr) == LSN_FILE_NO(scanner->horizon))
+ {
+ /* It is last file => we can easy find last page address by horizon */
+ uint pagegrest= LSN_OFFSET(scanner->horizon) % TRANSLOG_PAGE_SIZE;
+ scanner->last_file_page= (scanner->horizon -
+ (pagegrest ? pagegrest : TRANSLOG_PAGE_SIZE));
+ return (0);
+ }
scanner->last_file_page= scanner->page_addr;
return (translog_get_last_page_addr(&scanner->last_file_page, &page_ok));
}
-/*
- Initialize reader scanner
+/**
+ @brief Get page from page cache according to requested method
- SYNOPSIS
- translog_init_scanner()
- lsn LSN with which it have to be inited
- fixed_horizon true if it is OK do not read records which was written
+ @param scanner The scanner data
+
+ @return operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool
+translog_scanner_get_page(TRANSLOG_SCANNER_DATA *scanner)
+{
+ TRANSLOG_VALIDATOR_DATA data;
+ DBUG_ENTER("translog_scanner_get_page");
+ data.addr= &scanner->page_addr;
+ data.was_recovered= 0;
+ DBUG_RETURN((scanner->page=
+ translog_get_page(&data, scanner->buffer,
+ (scanner->use_direct_link ?
+ &scanner->direct_link :
+ NULL))) ==
+ NULL);
+}
+
+
+/**
+ @brief Initialize reader scanner.
+
+ @param lsn LSN with which it have to be inited
+ @param fixed_horizon true if it is OK do not read records which was written
after scanning beginning
- scanner scanner which have to be inited
+ @param scanner scanner which have to be inited
+ @param use_direct prefer using direct lings from page handler
+ where it is possible.
- RETURN
- 0 OK
- 1 Error
+ @note If direct link was used translog_destroy_scanner should be
+ called after it using
+
+ @return status of the operation
+ @retval 0 OK
+ @retval 1 Error
*/
my_bool translog_init_scanner(LSN lsn,
my_bool fixed_horizon,
- struct st_translog_scanner_data *scanner)
+ TRANSLOG_SCANNER_DATA *scanner,
+ my_bool use_direct)
{
TRANSLOG_VALIDATOR_DATA data;
DBUG_ENTER("translog_init_scanner");
- DBUG_PRINT("enter", ("LSN: (0x%lu,0x%lx)", LSN_IN_PARTS(lsn)));
+ DBUG_PRINT("enter", ("Scanner: 0x%lx LSN: (0x%lu,0x%lx)",
+ (ulong) scanner, LSN_IN_PARTS(lsn)));
DBUG_ASSERT(LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE != 0);
DBUG_ASSERT(translog_inited == 1);
@@ -5184,6 +5238,8 @@ my_bool translog_init_scanner(LSN lsn,
scanner->page_offset= LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE;
scanner->fixed_horizon= fixed_horizon;
+ scanner->use_direct_link= use_direct;
+ scanner->direct_link= NULL;
scanner->horizon= translog_get_horizon();
DBUG_PRINT("info", ("horizon: (0x%lu,0x%lx)",
@@ -5198,12 +5254,27 @@ my_bool translog_init_scanner(LSN lsn,
if (translog_scanner_set_last_page(scanner))
DBUG_RETURN(1);
- if ((scanner->page= translog_get_page(&data, scanner->buffer)) == NULL)
+ if (translog_scanner_get_page(scanner))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
+/**
+ @brief Destroy scanner object;
+
+ @param scanner The scanner object to destroy
+*/
+
+void translog_destroy_scanner(TRANSLOG_SCANNER_DATA *scanner)
+{
+ DBUG_ENTER("translog_destroy_scanner");
+ DBUG_PRINT("enter", ("Scanner: 0x%lx", (ulong)scanner));
+ translog_free_link(scanner->direct_link);
+ DBUG_VOID_RETURN;
+}
+
+
/*
Checks End of the Log
@@ -5298,7 +5369,6 @@ static my_bool translog_scanner_eof(TRANSLOG_SCANNER_DATA *scanner)
scanner->last_file_page);
}
-
/*
Move scanner to the next chunk
@@ -5315,7 +5385,6 @@ static my_bool
translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner)
{
uint16 len;
- TRANSLOG_VALIDATOR_DATA data;
DBUG_ENTER("translog_get_next_chunk");
if ((len= translog_get_total_chunk_length(scanner->page,
@@ -5331,6 +5400,8 @@ translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner)
}
if (translog_scanner_eop(scanner))
{
+ /* before reading next page we should unpin current one if it was pinned */
+ translog_free_link(scanner->direct_link);
if (translog_scanner_eof(scanner))
{
DBUG_PRINT("info", ("horizon: (%lu,0x%lx) pageaddr: (%lu,0x%lx)",
@@ -5350,9 +5421,7 @@ translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner)
scanner->page_addr+= TRANSLOG_PAGE_SIZE; /* offset increased */
}
- data.addr= &scanner->page_addr;
- data.was_recovered= 0;
- if ((scanner->page= translog_get_page(&data, scanner->buffer)) == NULL)
+ if (translog_scanner_get_page(scanner))
DBUG_RETURN(1);
scanner->page_offset= translog_get_first_chunk_offset(scanner->page);
@@ -5482,7 +5551,7 @@ translog_variable_length_header(uchar *page, translog_size_t page_offset,
{
DBUG_PRINT("info", ("use internal scanner for header reading"));
scanner= &internal_scanner;
- if (translog_init_scanner(buff->lsn, 1, scanner))
+ if (translog_init_scanner(buff->lsn, 1, scanner, 0))
DBUG_RETURN(RECHEADER_READ_ERROR);
}
if (translog_get_next_chunk(scanner))
@@ -5500,15 +5569,20 @@ translog_variable_length_header(uchar *page, translog_size_t page_offset,
DBUG_PRINT("info", ("use internal scanner"));
scanner= &internal_scanner;
}
-
+ else
+ {
+ translog_destroy_scanner(scanner);
+ }
base_lsn= buff->groups[0].addr;
- translog_init_scanner(base_lsn, 1, scanner);
+ translog_init_scanner(base_lsn, 1, scanner, scanner == &internal_scanner);
/* first group chunk is always chunk type 2 */
page= scanner->page;
page_offset= scanner->page_offset;
src= page + page_offset + 1;
page_rest= TRANSLOG_PAGE_SIZE - (src - page);
body_len= page_rest;
+ if (scanner == &internal_scanner)
+ translog_destroy_scanner(scanner);
}
if (lsns)
{
@@ -5615,6 +5689,7 @@ int translog_read_record_header(LSN lsn, TRANSLOG_HEADER_BUFFER *buff)
{
uchar buffer[TRANSLOG_PAGE_SIZE], *page;
translog_size_t res, page_offset= LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE;
+ PAGECACHE_BLOCK_LINK *direct_link;
TRANSLOG_ADDRESS addr;
TRANSLOG_VALIDATOR_DATA data;
DBUG_ENTER("translog_read_record_header");
@@ -5628,8 +5703,10 @@ int translog_read_record_header(LSN lsn, TRANSLOG_HEADER_BUFFER *buff)
data.was_recovered= 0;
addr= lsn;
addr-= page_offset; /* offset decreasing */
- res= (!(page= translog_get_page(&data, buffer))) ? RECHEADER_READ_ERROR :
+ res= (!(page= translog_get_page(&data, buffer, &direct_link))) ?
+ RECHEADER_READ_ERROR :
translog_read_record_header_from_buffer(page, page_offset, buff, 0);
+ translog_free_link(direct_link);
DBUG_RETURN(res);
}
@@ -5774,8 +5851,9 @@ static my_bool translog_record_read_next_chunk(struct st_translog_reader_data
data->current_group++;
data->current_chunk= 0;
DBUG_PRINT("info", ("skip to group: #%u", data->current_group));
+ translog_destroy_scanner(&data->scanner);
translog_init_scanner(data->header.groups[data->current_group].addr,
- 1, &data->scanner);
+ 1, &data->scanner, 1);
}
else
{
@@ -5794,7 +5872,8 @@ static my_bool translog_record_read_next_chunk(struct st_translog_reader_data
DBUG_ASSERT(data->header.groups_no - 1 == data->current_group);
DBUG_ASSERT(data->header.lsn ==
data->scanner.page_addr + data->scanner.page_offset);
- translog_init_scanner(data->header.chunk0_data_addr, 1, &data->scanner);
+ translog_destroy_scanner(&data->scanner);
+ translog_init_scanner(data->header.chunk0_data_addr, 1, &data->scanner, 1);
data->chunk_size= data->header.chunk0_data_len;
data->body_offset= data->scanner.page_offset;
data->current_offset= new_current_offset;
@@ -5844,7 +5923,7 @@ static my_bool translog_init_reader_data(LSN lsn,
{
int read_header;
DBUG_ENTER("translog_init_reader_data");
- if (translog_init_scanner(lsn, 1, &data->scanner) ||
+ if (translog_init_scanner(lsn, 1, &data->scanner, 1) ||
((read_header=
translog_read_record_header_scan(&data->scanner, &data->header, 1))
== RECHEADER_READ_ERROR))
@@ -5865,13 +5944,23 @@ static my_bool translog_init_reader_data(LSN lsn,
}
+/**
+ @brief Destroy reader data object
+*/
+
+static void translog_destroy_reader_data(struct st_translog_reader_data *data)
+{
+ translog_destroy_scanner(&data->scanner);
+}
+
+
/*
Read a part of the record.
SYNOPSIS
translog_read_record_header()
lsn log record serial number (address of the record)
- offset From the beginning of the record beginning (read§
+ offset From the beginning of the record beginning (read
by translog_read_record_header).
length Length of record part which have to be read.
buffer Buffer where to read the record part (have to be at
@@ -5924,7 +6013,10 @@ translog_size_t translog_read_record(LSN lsn,
memcpy(buffer, data->header.header + offset, len);
length-= len;
if (length == 0)
+ {
+ translog_destroy_reader_data(data);
DBUG_RETURN(requested_length);
+ }
offset+= len;
buffer+= len;
DBUG_PRINT("info",
@@ -5946,13 +6038,17 @@ translog_size_t translog_read_record(LSN lsn,
if (offset < page_end)
{
uint len= page_end - offset;
+ set_if_smaller(len, length); /* in case we read beyond record's end */
DBUG_ASSERT(offset >= data->current_offset);
memcpy(buffer,
data->scanner.page + data->body_offset +
(offset - data->current_offset), len);
length-= len;
if (length == 0)
+ {
+ translog_destroy_reader_data(data);
DBUG_RETURN(requested_length);
+ }
offset+= len;
buffer+= len;
DBUG_PRINT("info",
@@ -5961,7 +6057,10 @@ translog_size_t translog_read_record(LSN lsn,
(ulong) length));
}
if (translog_record_read_next_chunk(data))
+ {
+ translog_destroy_reader_data(data);
DBUG_RETURN(requested_length - length);
+ }
}
}
@@ -6220,207 +6319,6 @@ out:
/**
- @brief Sets transaction's rec_lsn if needed
-
- A transaction sometimes writes a REDO even before the page is in the
- pagecache (example: brand new head or tail pages; full pages). So, if
- Checkpoint happens just after the REDO write, it needs to know that the
- REDO phase must start before this REDO. Scanning the pagecache cannot
- tell that as the page is not in the cache. So, transaction sets its rec_lsn
- to the REDO's LSN or somewhere before, and Checkpoint reads the
- transaction's rec_lsn.
-
- @todo move it to a separate file
-
- @return Operation status, always 0 (success)
-*/
-
-static my_bool write_hook_for_redo(enum translog_record_type type
- __attribute__ ((unused)),
- TRN *trn, MARIA_HA *tbl_info
- __attribute__ ((unused)),
- LSN *lsn,
- struct st_translog_parts *parts
- __attribute__ ((unused)))
-{
- /*
- Users of dummy_transaction_object must keep this TRN clean as it
- is used by many threads (like those manipulating non-transactional
- tables). It might be dangerous if one user sets rec_lsn or some other
- member and it is picked up by another user (like putting this rec_lsn into
- a page of a non-transactional table); it's safer if all members stay 0. So
- non-transactional log records (REPAIR, CREATE, RENAME, DROP) should not
- call this hook; we trust them but verify ;)
- */
- DBUG_ASSERT(trn->trid != 0);
- /*
- If the hook stays so simple, it would be faster to pass
- !trn->rec_lsn ? trn->rec_lsn : some_dummy_lsn
- to translog_write_record(), like Monty did in his original code, and not
- have a hook. For now we keep it like this.
- */
- if (trn->rec_lsn == 0)
- trn->rec_lsn= *lsn;
- return 0;
-}
-
-
-/**
- @brief Sets transaction's undo_lsn, first_undo_lsn if needed
-
- @todo move it to a separate file
-
- @return Operation status, always 0 (success)
-*/
-
-static my_bool write_hook_for_undo(enum translog_record_type type
- __attribute__ ((unused)),
- TRN *trn, MARIA_HA *tbl_info
- __attribute__ ((unused)),
- LSN *lsn,
- struct st_translog_parts *parts
- __attribute__ ((unused)))
-{
- DBUG_ASSERT(trn->trid != 0);
- trn->undo_lsn= *lsn;
- if (unlikely(LSN_WITH_FLAGS_TO_LSN(trn->first_undo_lsn) == 0))
- trn->first_undo_lsn=
- trn->undo_lsn | LSN_WITH_FLAGS_TO_FLAGS(trn->first_undo_lsn);
- return 0;
- /*
- when we implement purging, we will specialize this hook: UNDO_PURGE
- records will additionally set trn->undo_purge_lsn
- */
-}
-
-
-/**
- @brief Sets the table's records count to 0, then calls the generic REDO
- hook.
-
- @todo move it to a separate file
-
- @return Operation status, always 0 (success)
-*/
-
-static my_bool write_hook_for_redo_delete_all(enum translog_record_type type
- __attribute__ ((unused)),
- TRN *trn, MARIA_HA *tbl_info
- __attribute__ ((unused)),
- LSN *lsn,
- struct st_translog_parts *parts
- __attribute__ ((unused)))
-{
- tbl_info->s->state.state.records= 0;
- return write_hook_for_redo(type, trn, tbl_info, lsn, parts);
-}
-
-
-/**
- @brief Upates "records" and calls the generic UNDO hook
-
- @todo move it to a separate file
-
- @return Operation status, always 0 (success)
-*/
-
-static my_bool write_hook_for_undo_row_insert(enum translog_record_type type
- __attribute__ ((unused)),
- TRN *trn, MARIA_HA *tbl_info,
- LSN *lsn,
- struct st_translog_parts *parts
- __attribute__ ((unused)))
-{
- tbl_info->s->state.state.records++;
- return write_hook_for_undo(type, trn, tbl_info, lsn, parts);
-}
-
-
-/**
- @brief Upates "records" and calls the generic UNDO hook
-
- @todo move it to a separate file
-
- @return Operation status, always 0 (success)
-*/
-
-static my_bool write_hook_for_undo_row_delete(enum translog_record_type type
- __attribute__ ((unused)),
- TRN *trn, MARIA_HA *tbl_info,
- LSN *lsn,
- struct st_translog_parts *parts
- __attribute__ ((unused)))
-{
- tbl_info->s->state.state.records--;
- return write_hook_for_undo(type, trn, tbl_info, lsn, parts);
-}
-
-
-/**
- @brief Sets transaction's undo_lsn, first_undo_lsn if needed
-
- @todo move it to a separate file
-
- @return Operation status, always 0 (success)
-*/
-
-static my_bool write_hook_for_clr_end(enum translog_record_type type
- __attribute__ ((unused)),
- TRN *trn, MARIA_HA *tbl_info
- __attribute__ ((unused)),
- LSN *lsn
- __attribute__ ((unused)),
- struct st_translog_parts *parts)
-{
- char *ptr= parts->parts[TRANSLOG_INTERNAL_PARTS + 0].str;
- enum translog_record_type undone_record_type=
- ptr[LSN_STORE_SIZE + FILEID_STORE_SIZE];
-
- DBUG_ASSERT(trn->trid != 0);
- trn->undo_lsn= lsn_korr(ptr);
- switch (undone_record_type) {
- case LOGREC_UNDO_ROW_DELETE:
- tbl_info->s->state.state.records++;
- break;
- case LOGREC_UNDO_ROW_INSERT:
- tbl_info->s->state.state.records--;
- break;
- case LOGREC_UNDO_ROW_UPDATE:
- break;
- default:
- DBUG_ASSERT(0);
- }
- if (trn->undo_lsn == LSN_IMPOSSIBLE) /* has fully rolled back */
- trn->first_undo_lsn= LSN_WITH_FLAGS_TO_FLAGS(trn->first_undo_lsn);
- return 0;
-}
-
-
-/**
- @brief Updates table's lsn_of_file_id.
-
- @todo move it to a separate file
-
- @return Operation status, always 0 (success)
-*/
-
-static my_bool write_hook_for_file_id(enum translog_record_type type
- __attribute__ ((unused)),
- TRN *trn
- __attribute__ ((unused)),
- MARIA_HA *tbl_info,
- LSN *lsn
- __attribute__ ((unused)),
- struct st_translog_parts *parts
- __attribute__ ((unused)))
-{
- DBUG_ASSERT(cmp_translog_addr(tbl_info->s->lsn_of_file_id, *lsn) < 0);
- tbl_info->s->lsn_of_file_id= *lsn;
- return 0;
-}
-
-
-/**
@brief Gives a 2-byte-id to MARIA_SHARE and logs this fact
If a MARIA_SHARE does not yet have a 2-byte-id (unique over all currently
@@ -6490,7 +6388,7 @@ int translog_assign_id_to_share(MARIA_HA *tbl_info, TRN *trn)
log_array[TRANSLOG_INTERNAL_PARTS +
1].length,
sizeof(log_array)/sizeof(log_array[0]),
- log_array, log_data)))
+ log_array, log_data, NULL)))
return 1;
}
pthread_mutex_unlock(&share->intern_lock);
@@ -6624,6 +6522,7 @@ LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon)
{
uint chunk_type;
TRANSLOG_SCANNER_DATA scanner;
+ LSN result;
DBUG_ENTER("translog_next_LSN");
if (horizon == LSN_IMPOSSIBLE)
@@ -6632,7 +6531,7 @@ LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon)
if (addr == horizon)
DBUG_RETURN(LSN_IMPOSSIBLE);
- translog_init_scanner(addr, 0, &scanner);
+ translog_init_scanner(addr, 0, &scanner, 1);
chunk_type= scanner.page[scanner.page_offset] & TRANSLOG_CHUNK_TYPE;
DBUG_PRINT("info", ("type: %x byte: %x", (uint) chunk_type,
@@ -6647,9 +6546,13 @@ LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon)
DBUG_PRINT("info", ("type: %x byte: %x", (uint) chunk_type,
(uint) scanner.page[scanner.page_offset]));
}
+
if (scanner.page[scanner.page_offset] == 0)
- DBUG_RETURN(LSN_IMPOSSIBLE); /* reached page filler */
- DBUG_RETURN(scanner.page_addr + scanner.page_offset);
+ result= LSN_IMPOSSIBLE; /* reached page filler */
+ else
+ result= scanner.page_addr + scanner.page_offset;
+ translog_destroy_scanner(&scanner);
+ DBUG_RETURN(result);
}
/**
@@ -6681,7 +6584,7 @@ LSN translog_first_lsn_in_log()
data.addr= &addr;
{
uchar buffer[TRANSLOG_PAGE_SIZE];
- if ((page= translog_get_page(&data, buffer)) == NULL ||
+ if ((page= translog_get_page(&data, buffer, NULL)) == NULL ||
(chunk_offset= translog_get_first_chunk_offset(page)) == 0)
DBUG_RETURN(LSN_ERROR);
}
@@ -6719,7 +6622,7 @@ LSN translog_first_theoretical_lsn()
addr= MAKE_LSN(1, TRANSLOG_PAGE_SIZE); /* the first page of the file */
data.addr= &addr;
- if ((page= translog_get_page(&data, buffer)) == NULL)
+ if ((page= translog_get_page(&data, buffer, NULL)) == NULL)
DBUG_RETURN(LSN_ERROR);
DBUG_RETURN(MAKE_LSN(1, TRANSLOG_PAGE_SIZE +
diff --git a/storage/maria/ma_loghandler.h b/storage/maria/ma_loghandler.h
index 164ff013b10..9ea3bfca263 100644
--- a/storage/maria/ma_loghandler.h
+++ b/storage/maria/ma_loghandler.h
@@ -48,6 +48,7 @@ typedef uint16 SHORT_TRANSACTION_ID;
struct st_maria_info;
+/* Changing one of the "SIZE" below will break backward-compatibility! */
/* Length of CRC at end of pages */
#define CRC_LENGTH 4
/* Size of file id in logs */
@@ -57,16 +58,23 @@ struct st_maria_info;
/* Size of page ranges in log */
#define PAGERANGE_STORE_SIZE ROW_EXTENT_COUNT_SIZE
#define DIRPOS_STORE_SIZE 1
+#define CLR_TYPE_STORE_SIZE 1
+/* If table has live checksum we store its changes in UNDOs */
+#define HA_CHECKSUM_STORE_SIZE 4
/* Store methods to match the above sizes */
#define fileid_store(T,A) int2store(T,A)
#define page_store(T,A) int5store(T,A)
#define dirpos_store(T,A) ((*(uchar*) (T)) = A)
#define pagerange_store(T,A) int2store(T,A)
+#define clr_type_store(T,A) ((*(uchar*) (T)) = A)
+#define ha_checksum_store(T,A) int4store(T,A)
#define fileid_korr(P) uint2korr(P)
#define page_korr(P) uint5korr(P)
#define dirpos_korr(P) ((P)[0])
#define pagerange_korr(P) uint2korr(P)
+#define clr_type_korr(P) ((P)[0])
+#define ha_checksum_korr(P) uint4korr(P)
/*
Length of disk drive sector size (we assume that writing it
@@ -182,10 +190,14 @@ typedef struct st_translog_scanner_data
TRANSLOG_ADDRESS horizon;
TRANSLOG_ADDRESS last_file_page; /* Last page on in this file */
uchar *page; /* page content pointer */
+ /* direct link on the current page or NULL if not supported/requested */
+ PAGECACHE_BLOCK_LINK *direct_link;
/* offset of the chunk in the page */
translog_size_t page_offset;
/* set horizon only once at init */
my_bool fixed_horizon;
+ /* try to get direct link on the page if it is possible */
+ my_bool use_direct_link;
} TRANSLOG_SCANNER_DATA;
@@ -226,7 +238,8 @@ translog_write_record(LSN *lsn, enum translog_record_type type,
struct st_transaction *trn,
struct st_maria_info *tbl_info,
translog_size_t rec_len, uint part_no,
- LEX_STRING *parts_data, uchar *store_share_id);
+ LEX_STRING *parts_data, uchar *store_share_id,
+ void *hook_arg);
extern void translog_destroy();
@@ -245,7 +258,9 @@ extern my_bool translog_flush(LSN lsn);
extern my_bool translog_init_scanner(LSN lsn,
my_bool fixed_horizon,
- struct st_translog_scanner_data *scanner);
+ struct st_translog_scanner_data *scanner,
+ my_bool use_direct_link);
+extern void translog_destroy_scanner(TRANSLOG_SCANNER_DATA *scanner);
extern int translog_read_next_record_header(TRANSLOG_SCANNER_DATA *scanner,
TRANSLOG_HEADER_BUFFER *buff);
@@ -293,12 +308,11 @@ struct st_translog_parts
typedef my_bool(*prewrite_rec_hook) (enum translog_record_type type,
TRN *trn, struct st_maria_info *tbl_info,
- struct st_translog_parts *parts);
+ void *hook_arg);
typedef my_bool(*inwrite_rec_hook) (enum translog_record_type type,
TRN *trn, struct st_maria_info *tbl_info,
- LSN *lsn,
- struct st_translog_parts *parts);
+ LSN *lsn, void *hook_arg);
typedef uint16(*read_rec_hook) (enum translog_record_type type,
uint16 read_length, uchar *read_buff,
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
index 8a002832092..39d2c1c7422 100644
--- a/storage/maria/ma_open.c
+++ b/storage/maria/ma_open.c
@@ -58,7 +58,7 @@ if (pos > end_pos) \
** In MySQL the server will handle version issues.
******************************************************************************/
-MARIA_HA *_ma_test_if_reopen(char *filename)
+MARIA_HA *_ma_test_if_reopen(const char *filename)
{
LIST *pos;
@@ -177,7 +177,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, int mode,
share->delay_key_write=1;
info.state= &share->state.state; /* Change global values by default */
- if (!share->base.born_transactional) /* but for transactional ones ... */
+ if (!share->base.born_transactional) /* For transactional ones ... */
info.trn= &dummy_transaction_object; /* ... force crash if no trn given */
pthread_mutex_unlock(&share->intern_lock);
@@ -1002,7 +1002,9 @@ uint _ma_state_info_write(MARIA_SHARE *share, uint pWrite)
if (pWrite & 4)
pthread_mutex_lock(&share->intern_lock);
else if (maria_multi_threaded)
+ {
safe_mutex_assert_owner(&share->intern_lock);
+ }
if (share->base.born_transactional && translog_inited &&
!maria_in_recovery)
{
diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c
index 702d8c6d857..aa21a8bfacb 100755
--- a/storage/maria/ma_pagecache.c
+++ b/storage/maria/ma_pagecache.c
@@ -96,7 +96,7 @@
#define PCBLOCK_INFO(B) \
DBUG_PRINT("info", \
("block: 0x%lx file: %lu page: %lu s: %0x hshL: 0x%lx req: %u/%u " \
- "wrlocks: %u", \
+ "wrlocks: %u pins: %u", \
(ulong)(B), \
(ulong)((B)->hash_link ? \
(B)->hash_link->file.file : \
@@ -110,7 +110,8 @@
(uint)((B)->hash_link ? \
(B)->hash_link->requests : \
0), \
- block->wlocks))
+ block->wlocks, \
+ (uint)(B)->pins))
/* TODO: put it to my_static.c */
my_bool my_disable_flush_pagecache_blocks= 0;
@@ -457,8 +458,10 @@ error:
#define FLUSH_CACHE 2000 /* sort this many blocks at once */
static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block);
+#ifndef DBUG_OFF
static void test_key_cache(PAGECACHE *pagecache,
const char *where, my_bool lock);
+#endif
#define PAGECACHE_HASH(p, f, pos) (((ulong) (pos) + \
(ulong) (f).file) & (p->hash_entries-1))
@@ -655,11 +658,11 @@ static inline uint next_power(uint value)
*/
-int init_pagecache(PAGECACHE *pagecache, size_t use_mem,
- uint division_limit, uint age_threshold,
- uint block_size)
+ulong init_pagecache(PAGECACHE *pagecache, size_t use_mem,
+ uint division_limit, uint age_threshold,
+ uint block_size)
{
- uint blocks, hash_links, length;
+ ulong blocks, hash_links, length;
int error;
DBUG_ENTER("init_pagecache");
DBUG_ASSERT(block_size >= 512);
@@ -689,10 +692,10 @@ int init_pagecache(PAGECACHE *pagecache, size_t use_mem,
block_size));
DBUG_ASSERT(((uint)(1 << pagecache->shift)) == block_size);
- blocks= (int) (use_mem / (sizeof(PAGECACHE_BLOCK_LINK) +
- 2 * sizeof(PAGECACHE_HASH_LINK) +
- sizeof(PAGECACHE_HASH_LINK*) *
- 5/4 + block_size));
+ blocks= (ulong) (use_mem / (sizeof(PAGECACHE_BLOCK_LINK) +
+ 2 * sizeof(PAGECACHE_HASH_LINK) +
+ sizeof(PAGECACHE_HASH_LINK*) *
+ 5/4 + block_size));
/*
We need to support page cache with just one block to be able to do
scanning of rows-in-block files
@@ -714,7 +717,7 @@ int init_pagecache(PAGECACHE *pagecache, size_t use_mem,
ALIGN_SIZE(hash_links * sizeof(PAGECACHE_HASH_LINK)) +
ALIGN_SIZE(sizeof(PAGECACHE_HASH_LINK*) *
pagecache->hash_entries))) +
- (((ulong) blocks) << pagecache->shift) > use_mem)
+ (blocks << pagecache->shift) > use_mem)
blocks--;
/* Allocate memory for cache page buffers */
if ((pagecache->block_mem=
@@ -726,7 +729,7 @@ int init_pagecache(PAGECACHE *pagecache, size_t use_mem,
For each block 2 hash links are allocated
*/
if ((pagecache->block_root=
- (PAGECACHE_BLOCK_LINK*) my_malloc((uint) length, MYF(0))))
+ (PAGECACHE_BLOCK_LINK*) my_malloc((size_t) length, MYF(0))))
break;
my_large_free(pagecache->block_mem, MYF(0));
pagecache->block_mem= 0;
@@ -738,8 +741,8 @@ int init_pagecache(PAGECACHE *pagecache, size_t use_mem,
}
blocks= blocks / 4*3;
}
- pagecache->blocks_unused= (ulong) blocks;
- pagecache->disk_blocks= (int) blocks;
+ pagecache->blocks_unused= blocks;
+ pagecache->disk_blocks= (long) blocks;
pagecache->hash_links= hash_links;
pagecache->hash_root=
(PAGECACHE_HASH_LINK**) ((char*) pagecache->block_root +
@@ -781,8 +784,8 @@ int init_pagecache(PAGECACHE *pagecache, size_t use_mem,
pagecache->waiting_for_hash_link.last_thread= NULL;
pagecache->waiting_for_block.last_thread= NULL;
DBUG_PRINT("exit",
- ("disk_blocks: %d block_root: 0x%lx hash_entries: %d\
- hash_root: 0x%lx hash_links: %d hash_link_root: 0x%lx",
+ ("disk_blocks: %ld block_root: 0x%lx hash_entries: %ld\
+ hash_root: 0x%lx hash_links: %ld hash_link_root: 0x%lx",
pagecache->disk_blocks, (long) pagecache->block_root,
pagecache->hash_entries, (long) pagecache->hash_root,
pagecache->hash_links, (long) pagecache->hash_link_root));
@@ -795,7 +798,7 @@ int init_pagecache(PAGECACHE *pagecache, size_t use_mem,
}
pagecache->blocks= pagecache->disk_blocks > 0 ? pagecache->disk_blocks : 0;
- DBUG_RETURN((int) pagecache->disk_blocks);
+ DBUG_RETURN((ulong) pagecache->disk_blocks);
err:
error= my_errno;
@@ -886,11 +889,11 @@ static int flush_all_key_blocks(PAGECACHE *pagecache)
So we disable it for now.
*/
#if NOT_USED /* keep disabled until code is fixed see above !! */
-int resize_pagecache(PAGECACHE *pagecache,
- size_t use_mem, uint division_limit,
- uint age_threshold)
+ulong resize_pagecache(PAGECACHE *pagecache,
+ size_t use_mem, uint division_limit,
+ uint age_threshold)
{
- int blocks;
+ ulong blocks;
#ifdef THREAD
struct st_my_thread_var *thread;
WQUEUE *wqueue;
@@ -1281,8 +1284,10 @@ static void unlink_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
DBUG_ENTER("unlink_block");
DBUG_PRINT("unlink_block", ("unlink 0x%lx", (ulong)block));
if (block->next_used == block)
+ {
/* The list contains only one member */
pagecache->used_last= pagecache->used_ins= NULL;
+ }
else
{
block->next_used->prev_used= block->prev_used;
@@ -2660,13 +2665,12 @@ void pagecache_unpin(PAGECACHE *pagecache,
*/
void pagecache_unlock_by_link(PAGECACHE *pagecache,
- PAGECACHE_PAGE_LINK *link,
+ PAGECACHE_BLOCK_LINK *block,
enum pagecache_page_lock lock,
enum pagecache_page_pin pin,
LSN first_REDO_LSN_for_page,
LSN lsn)
{
- PAGECACHE_BLOCK_LINK *block= (PAGECACHE_BLOCK_LINK *)link;
DBUG_ENTER("pagecache_unlock_by_link");
DBUG_PRINT("enter", ("block: 0x%lx fd: %u page: %lu %s %s",
(ulong) block,
@@ -2751,10 +2755,9 @@ void pagecache_unlock_by_link(PAGECACHE *pagecache,
*/
void pagecache_unpin_by_link(PAGECACHE *pagecache,
- PAGECACHE_PAGE_LINK *link,
+ PAGECACHE_BLOCK_LINK *block,
LSN lsn)
{
- PAGECACHE_BLOCK_LINK *block= (PAGECACHE_BLOCK_LINK *)link;
DBUG_ENTER("pagecache_unpin_by_link");
DBUG_PRINT("enter", ("block: 0x%lx fd: %u page: %lu",
(ulong) block,
@@ -2819,16 +2822,28 @@ void pagecache_unpin_by_link(PAGECACHE *pagecache,
Pin will be chosen according to lock parameter (see lock_to_pin)
*/
-static enum pagecache_page_pin lock_to_pin[]=
+static enum pagecache_page_pin lock_to_pin[2][8]=
{
- PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_UNLOCKED*/,
- PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_READLOCKED*/,
- PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/,
- PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ*/,
- PAGECACHE_PIN /*PAGECACHE_LOCK_WRITE*/,
- PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ_UNLOCK*/,
- PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_UNLOCK*/,
- PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_TO_READ*/
+ {
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_UNLOCKED*/,
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_READLOCKED*/,
+ PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/,
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ*/,
+ PAGECACHE_PIN /*PAGECACHE_LOCK_WRITE*/,
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ_UNLOCK*/,
+ PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_UNLOCK*/,
+ PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_TO_READ*/
+ },
+ {
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_UNLOCKED*/,
+ PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_LEFT_READLOCKED*/,
+ PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/,
+ PAGECACHE_PIN /*PAGECACHE_LOCK_READ*/,
+ PAGECACHE_PIN /*PAGECACHE_LOCK_WRITE*/,
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ_UNLOCK*/,
+ PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_UNLOCK*/,
+ PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_WRITE_TO_READ*/
+ }
};
uchar *pagecache_valid_read(PAGECACHE *pagecache,
@@ -2838,24 +2853,27 @@ uchar *pagecache_valid_read(PAGECACHE *pagecache,
uchar *buff,
enum pagecache_page_type type,
enum pagecache_page_lock lock,
- PAGECACHE_PAGE_LINK *link,
+ PAGECACHE_BLOCK_LINK **link,
pagecache_disk_read_validator validator,
uchar* validator_data)
{
int error= 0;
- enum pagecache_page_pin pin= lock_to_pin[lock];
- PAGECACHE_PAGE_LINK fake_link;
+ enum pagecache_page_pin pin= lock_to_pin[test(buff==0)][lock];
+ PAGECACHE_BLOCK_LINK *fake_link;
DBUG_ENTER("pagecache_valid_read");
- DBUG_PRINT("enter", ("fd: %u page: %lu level: %u t:%s %s %s",
- (uint) file->file, (ulong) pageno, level,
+ DBUG_PRINT("enter", ("fd: %u page: %lu buffer: 0x%lx level: %u "
+ "t:%s %s %s",
+ (uint) file->file, (ulong) pageno,
+ (ulong) buff, level,
page_cache_page_type_str[type],
page_cache_page_lock_str[lock],
page_cache_page_pin_str[pin]));
+ DBUG_ASSERT(buff != 0 || (buff == 0 && (pin == PAGECACHE_PIN ||
+ pin == PAGECACHE_PIN_LEFT_PINNED)));
if (!link)
link= &fake_link;
- else
- *link= 0;
+ *link= 0; /* Catch errors */
restart:
@@ -2909,19 +2927,25 @@ restart:
goto restart;
}
- if (! ((status= block->status) & PCBLOCK_ERROR))
+ status= block->status;
+ if (!buff)
+ buff= block->buffer;
+ else
{
+ if (!(status & PCBLOCK_ERROR))
+ {
#if !defined(SERIALIZED_READ_FROM_CACHE)
- pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
#endif
- DBUG_ASSERT((pagecache->block_size & 511) == 0);
- /* Copy data from the cache buffer */
- bmove512(buff, block->buffer, pagecache->block_size);
+ DBUG_ASSERT((pagecache->block_size & 511) == 0);
+ /* Copy data from the cache buffer */
+ bmove512(buff, block->buffer, pagecache->block_size);
#if !defined(SERIALIZED_READ_FROM_CACHE)
- pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
#endif
+ }
}
remove_reader(block);
@@ -2933,7 +2957,7 @@ restart:
if (pin == PAGECACHE_PIN_LEFT_UNPINNED || pin == PAGECACHE_UNPIN)
unreg_request(pagecache, block, 1);
else
- *link= (PAGECACHE_PAGE_LINK)block;
+ *link= block;
dec_counter_for_resize_op(pagecache);
@@ -2982,7 +3006,7 @@ my_bool pagecache_delete(PAGECACHE *pagecache,
my_bool flush)
{
int error= 0;
- enum pagecache_page_pin pin= lock_to_pin[lock];
+ enum pagecache_page_pin pin= lock_to_pin[0][lock];
DBUG_ENTER("pagecache_delete");
DBUG_PRINT("enter", ("fd: %u page: %lu %s %s",
(uint) file->file, (ulong) pageno,
@@ -3187,13 +3211,13 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
enum pagecache_page_lock lock,
enum pagecache_page_pin pin,
enum pagecache_write_mode write_mode,
- PAGECACHE_PAGE_LINK *link,
+ PAGECACHE_BLOCK_LINK **link,
uint offset, uint size,
pagecache_disk_read_validator validator,
uchar* validator_data)
{
PAGECACHE_BLOCK_LINK *block= NULL;
- PAGECACHE_PAGE_LINK fake_link;
+ PAGECACHE_BLOCK_LINK *fake_link;
int error= 0;
int need_lock_change= write_lock_change_table[lock].need_lock_change;
DBUG_ENTER("pagecache_write_part");
@@ -3209,10 +3233,10 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
DBUG_ASSERT(lock != PAGECACHE_LOCK_LEFT_READLOCKED);
DBUG_ASSERT(lock != PAGECACHE_LOCK_READ_UNLOCK);
DBUG_ASSERT(offset + size <= pagecache->block_size);
+
if (!link)
link= &fake_link;
- else
- *link= 0;
+ *link= 0;
restart:
@@ -3337,7 +3361,7 @@ restart:
if (pin == PAGECACHE_PIN_LEFT_UNPINNED || pin == PAGECACHE_UNPIN)
unreg_request(pagecache, block, 1);
else
- *link= (PAGECACHE_PAGE_LINK)block;
+ *link= block;
if (block->status & PCBLOCK_ERROR)
error= 1;
@@ -3829,7 +3853,8 @@ int flush_pagecache_blocks(PAGECACHE *pagecache,
0 on success (always because it can't fail)
*/
-int reset_pagecache_counters(const char *name, PAGECACHE *pagecache)
+int reset_pagecache_counters(const char *name __attribute__((unused)),
+ PAGECACHE *pagecache)
{
DBUG_ENTER("reset_pagecache_counters");
if (!pagecache->inited)
@@ -3873,7 +3898,7 @@ my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache,
LSN *min_rec_lsn)
{
my_bool error= 0;
- uint stored_list_size= 0;
+ ulong stored_list_size= 0;
uint file_hash;
char *ptr;
LSN minimum_rec_lsn= LSN_MAX;
@@ -3916,8 +3941,8 @@ my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache,
}
}
- compile_time_assert(sizeof(pagecache->blocks == 4));
- str->length= 4 + /* number of dirty pages */
+ compile_time_assert(sizeof(pagecache->blocks) <= 8);
+ str->length= 8 + /* number of dirty pages */
(4 + /* file */
4 + /* pageno */
LSN_STORE_SIZE /* rec_lsn */
@@ -3925,8 +3950,8 @@ my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache,
if (NULL == (str->str= my_malloc(str->length, MYF(MY_WME))))
goto err;
ptr= str->str;
- int4store(ptr, stored_list_size);
- ptr+= 4;
+ int8store(ptr, (ulonglong)stored_list_size);
+ ptr+= 8;
if (!stored_list_size)
goto end;
for (file_hash= 0; file_hash < PAGECACHE_CHANGED_BLOCKS_HASH; file_hash++)
@@ -3938,8 +3963,8 @@ my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache,
{
if (block->type != PAGECACHE_LSN_PAGE)
continue; /* no need to store it in the checkpoint record */
- compile_time_assert((4 == sizeof(block->hash_link->file.file)));
- compile_time_assert((4 == sizeof(block->hash_link->pageno)));
+ compile_time_assert(sizeof(block->hash_link->file.file) <= 4);
+ compile_time_assert(sizeof(block->hash_link->pageno) <= 4);
int4store(ptr, block->hash_link->file.file);
ptr+= 4;
int4store(ptr, block->hash_link->pageno);
diff --git a/storage/maria/ma_pagecache.h b/storage/maria/ma_pagecache.h
index 0e2aff3644d..23a443a5b97 100644
--- a/storage/maria/ma_pagecache.h
+++ b/storage/maria/ma_pagecache.h
@@ -73,8 +73,6 @@ enum pagecache_write_mode
PAGECACHE_WRITE_DONE
};
-typedef void *PAGECACHE_PAGE_LINK;
-
/* file descriptor for Maria */
typedef struct st_pagecache_file
{
@@ -106,25 +104,22 @@ typedef my_bool (*pagecache_disk_read_validator)(uchar *page, uchar *data);
typedef struct st_pagecache
{
- my_bool inited;
- my_bool resize_in_flush; /* true during flush of resize operation */
- my_bool can_be_used; /* usage of cache for read/write is allowed */
- uint shift; /* block size = 2 ^ shift */
- size_t mem_size; /* specified size of the cache memory */
- uint32 block_size; /* size of the page buffer of a cache block */
+ size_t mem_size; /* specified size of the cache memory */
ulong min_warm_blocks; /* min number of warm blocks; */
ulong age_threshold; /* age threshold for hot blocks */
ulonglong time; /* total number of block link operations */
- uint hash_entries; /* max number of entries in the hash table */
- int hash_links; /* max number of hash links */
- int hash_links_used; /* number of hash links taken from free links pool */
- int disk_blocks; /* max number of blocks in the cache */
+ ulong hash_entries; /* max number of entries in the hash table */
+ long hash_links; /* max number of hash links */
+ long hash_links_used; /* number of hash links taken from free links pool */
+ long disk_blocks; /* max number of blocks in the cache */
ulong blocks_used; /* maximum number of concurrently used blocks */
ulong blocks_unused; /* number of currently unused blocks */
ulong blocks_changed; /* number of currently dirty blocks */
ulong warm_blocks; /* number of blocks in warm sub-chain */
ulong cnt_for_resize_op; /* counter to block resize operation */
ulong blocks_available; /* number of blocks available in the LRU chain */
+ long blocks; /* max number of blocks in the cache */
+ uint32 block_size; /* size of the page buffer of a cache block */
PAGECACHE_HASH_LINK **hash_root;/* arr. of entries into hash table buckets */
PAGECACHE_HASH_LINK *hash_link_root;/* memory for hash table links */
PAGECACHE_HASH_LINK *free_hash_list;/* list of free hash links */
@@ -159,19 +154,22 @@ typedef struct st_pagecache
ulonglong global_cache_r_requests;/* number of read requests (read hits) */
ulonglong global_cache_read; /* number of reads from files to cache */
- int blocks; /* max number of blocks in the cache */
+ uint shift; /* block size = 2 ^ shift */
+ my_bool inited;
+ my_bool resize_in_flush; /* true during flush of resize operation */
+ my_bool can_be_used; /* usage of cache for read/write is allowed */
my_bool in_init; /* Set to 1 in MySQL during init/resize */
} PAGECACHE;
/* The default key cache */
extern PAGECACHE dflt_pagecache_var, *dflt_pagecache;
-extern int init_pagecache(PAGECACHE *pagecache, size_t use_mem,
- uint division_limit, uint age_threshold,
- uint block_size);
-extern int resize_pagecache(PAGECACHE *pagecache,
- size_t use_mem, uint division_limit,
- uint age_threshold);
+extern ulong init_pagecache(PAGECACHE *pagecache, size_t use_mem,
+ uint division_limit, uint age_threshold,
+ uint block_size);
+extern ulong resize_pagecache(PAGECACHE *pagecache,
+ size_t use_mem, uint division_limit,
+ uint age_threshold);
extern void change_pagecache_param(PAGECACHE *pagecache, uint division_limit,
uint age_threshold);
@@ -185,7 +183,7 @@ extern uchar *pagecache_valid_read(PAGECACHE *pagecache,
uchar *buff,
enum pagecache_page_type type,
enum pagecache_page_lock lock,
- PAGECACHE_PAGE_LINK *link,
+ PAGECACHE_BLOCK_LINK **link,
pagecache_disk_read_validator validator,
uchar* validator_data);
@@ -205,7 +203,7 @@ extern my_bool pagecache_write_part(PAGECACHE *pagecache,
enum pagecache_page_lock lock,
enum pagecache_page_pin pin,
enum pagecache_write_mode write_mode,
- PAGECACHE_PAGE_LINK *link,
+ PAGECACHE_BLOCK_LINK **link,
uint offset,
uint size,
pagecache_disk_read_validator validator,
@@ -218,7 +216,7 @@ extern void pagecache_unlock(PAGECACHE *pagecache,
LSN first_REDO_LSN_for_page,
LSN lsn);
extern void pagecache_unlock_by_link(PAGECACHE *pagecache,
- PAGECACHE_PAGE_LINK *link,
+ PAGECACHE_BLOCK_LINK *block,
enum pagecache_page_lock lock,
enum pagecache_page_pin pin,
LSN first_REDO_LSN_for_page,
@@ -228,7 +226,7 @@ extern void pagecache_unpin(PAGECACHE *pagecache,
pgcache_page_no_t pageno,
LSN lsn);
extern void pagecache_unpin_by_link(PAGECACHE *pagecache,
- PAGECACHE_PAGE_LINK *link,
+ PAGECACHE_BLOCK_LINK *link,
LSN lsn);
extern int flush_pagecache_blocks(PAGECACHE *keycache,
PAGECACHE_FILE *file,
diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c
index e740e334b5f..631a10b8025 100644
--- a/storage/maria/ma_recovery.c
+++ b/storage/maria/ma_recovery.c
@@ -50,6 +50,7 @@ static LSN current_group_end_lsn,
static TrID max_long_trid= 0; /**< max long trid seen by REDO phase */
static FILE *tracef; /**< trace file for debugging */
static my_bool skip_DDLs; /**< if REDO phase should skip DDL records */
+static ulonglong now; /**< for tracking execution time of phases */
#define prototype_redo_exec_hook(R) \
static int exec_REDO_LOGREC_ ## R(const TRANSLOG_HEADER_BUFFER *rec)
@@ -105,6 +106,7 @@ static int new_table(uint16 sid, const char *name,
static int new_page(File fileid, pgcache_page_no_t pageid, LSN rec_lsn,
struct st_dirty_page *dirty_page);
static int close_all_tables(void);
+static my_bool close_one_table(const char *name, LSN addr);
static void print_redo_phase_progress(TRANSLOG_ADDRESS addr);
/** @brief global [out] buffer for translog_read_record(); never shrinks */
@@ -123,13 +125,16 @@ static my_bool redo_phase_message_printed;
/** @brief Prints to a trace file if it is not NULL */
void tprint(FILE *trace_file, const char *format, ...)
ATTRIBUTE_FORMAT(printf, 2, 3);
-void tprint(FILE *trace_file, const char *format, ...)
+void tprint(FILE *trace_file __attribute__ ((unused)),
+ const char *format __attribute__ ((unused)), ...)
{
+#ifdef EXTRA_DEBUG
va_list args;
va_start(args, format);
if (trace_file != NULL)
vfprintf(trace_file, format, args);
va_end(args);
+#endif
}
#define ALERT_USER() DBUG_ASSERT(0)
@@ -157,7 +162,7 @@ int maria_recover(void)
DBUG_ASSERT(!maria_in_recovery);
maria_in_recovery= TRUE;
-#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+#ifdef EXTRA_DEBUG
trace_file= fopen("maria_recovery.trace", "w");
#else
trace_file= NULL; /* no trace file for being fast */
@@ -308,8 +313,12 @@ end:
log_record_buffer.length= 0;
if (tracef != stdout && redo_phase_message_printed)
{
+ ulonglong old_now= now;
+ now= my_getsystime();
+ float previous_phase_took= (now - old_now)/10000000.0;
/** @todo RECOVERY BUG all prints to stderr should go to error log */
- fprintf(stderr, "\n");
+ /** @todo RECOVERY BUG all prints to stderr should go to error log */
+ fprintf(stderr, " (%.1f seconds)\n", previous_phase_took);
}
/* we don't cleanly close tables if we hit some error (may corrupt them) */
DBUG_RETURN(error);
@@ -415,6 +424,8 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
uint flags;
int error= 1, create_mode= O_RDWR | O_TRUNC;
MARIA_HA *info= NULL;
+ uint kfile_size_before_extension, keystart;
+
if (skip_DDLs)
{
tprint(tracef, "we skip DDLs\n");
@@ -431,6 +442,12 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
}
name= log_record_buffer.str;
tprint(tracef, "Table '%s'", name);
+ if (close_one_table(name, rec->lsn))
+ {
+ tprint(tracef, " got error %d on close\n", my_errno);
+ ALERT_USER();
+ goto end;
+ }
/* we try hard to get create_rename_lsn, to avoid mistakes if possible */
info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR);
if (info)
@@ -474,7 +491,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
info= NULL;
}
else /* one or two files absent, or header corrupted... */
- tprint(tracef, "can't be opened, probably does not exist");
+ tprint(tracef, " can't be opened, probably does not exist");
/* if does not exist, or is older, overwrite it */
/** @todo symlinks */
ptr= name + strlen(name) + 1;
@@ -490,13 +507,13 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
if ((kfile= my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
MYF(MY_WME|create_flag))) < 0)
{
- tprint(tracef, "Failed to create index file\n");
+ tprint(tracef, " Failed to create index file\n");
goto end;
}
ptr++;
- uint kfile_size_before_extension= uint2korr(ptr);
+ kfile_size_before_extension= uint2korr(ptr);
ptr+= 2;
- uint keystart= uint2korr(ptr);
+ keystart= uint2korr(ptr);
ptr+= 2;
/* set create_rename_lsn (for maria_read_log to be idempotent) */
lsn_store(ptr + sizeof(info->s->state.header) + 2, rec->lsn);
@@ -507,7 +524,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
kfile_size_before_extension, 0, MYF(MY_NABP|MY_WME)) ||
my_chsize(kfile, keystart, 0, MYF(MY_WME)))
{
- tprint(tracef, "Failed to write to index file\n");
+ tprint(tracef, " Failed to write to index file\n");
goto end;
}
if (!(flags & HA_DONT_TOUCH_DATA))
@@ -521,7 +538,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
MYF(MY_WME | create_flag))) < 0) ||
my_close(dfile, MYF(MY_WME)))
{
- tprint(tracef, "Failed to create data file\n");
+ tprint(tracef, " Failed to create data file\n");
goto end;
}
/*
@@ -533,7 +550,7 @@ prototype_redo_exec_hook(REDO_CREATE_TABLE)
if (((info= maria_open(name, O_RDONLY, 0)) == NULL) ||
_ma_initialize_data_file(info->s, info->dfile.file))
{
- tprint(tracef, "Failed to open new table or write to data file\n");
+ tprint(tracef, " Failed to open new table or write to data file\n");
goto end;
}
}
@@ -766,27 +783,17 @@ prototype_redo_exec_hook(REDO_REPAIR_TABLE)
than the mapping, so we can repair.
*/
tprint(tracef, " repairing...\n");
- /**
- @todo RECOVERY BUG fix this:
- the maria_chk_init() call causes a heap of linker errors in ha_maria.cc!
- */
-#if 0
HA_CHECK param;
maria_chk_init(&param);
param.isam_file_name= info->s->open_file_name;
param.testflag= uint4korr(rec->header);
- if (maria_repair(&param, info, info->s->open_file_name,
- param.testflag & T_QUICK))
+ if (maria_repair(&param, info, info->s->open_file_name, param.testflag))
goto end;
if (_ma_update_create_rename_lsn(info->s, rec->lsn, TRUE))
goto end;
error= 0;
end:
return error;
-#else
- DBUG_ASSERT("fix this table repairing" == NULL);
- return error;
-#endif
}
@@ -1199,12 +1206,25 @@ prototype_redo_exec_hook(UNDO_ROW_INSERT)
MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
if (info == NULL)
return 0;
+ MARIA_SHARE *share= info->s;
set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
- if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) >= 0)
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
{
tprint(tracef, " state older than record, updating rows' count\n");
- info->s->state.state.records++;
- /** @todo RECOVERY BUG Also update the table's checksum */
+ share->state.state.records++;
+ if (share->calc_checksum)
+ {
+ uchar buff[HA_CHECKSUM_STORE_SIZE];
+ if (translog_read_record(rec->lsn, LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ HA_CHECKSUM_STORE_SIZE, buff, NULL) !=
+ HA_CHECKSUM_STORE_SIZE)
+ {
+ tprint(tracef, "Failed to read record\n");
+ return 1;
+ }
+ share->state.state.checksum+= ha_checksum_korr(buff);
+ }
/**
@todo some bits below will rather be set when executing UNDOs related
to keys
@@ -1222,15 +1242,29 @@ prototype_redo_exec_hook(UNDO_ROW_DELETE)
MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
if (info == NULL)
return 0;
+ MARIA_SHARE *share= info->s;
set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
- if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) >= 0)
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
{
tprint(tracef, " state older than record, updating rows' count\n");
- info->s->state.state.records--;
- info->s->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
+ share->state.state.records--;
+ if (share->calc_checksum)
+ {
+ uchar buff[HA_CHECKSUM_STORE_SIZE];
+ if (translog_read_record(rec->lsn, LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ HA_CHECKSUM_STORE_SIZE, buff, NULL) !=
+ HA_CHECKSUM_STORE_SIZE)
+ {
+ tprint(tracef, "Failed to read record\n");
+ return 1;
+ }
+ share->state.state.checksum+= ha_checksum_korr(buff);
+ }
+ share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES;
}
- tprint(tracef, " rows' count %lu\n", (ulong)info->s->state.state.records);
+ tprint(tracef, " rows' count %lu\n", (ulong)share->state.state.records);
return 0;
}
@@ -1240,10 +1274,24 @@ prototype_redo_exec_hook(UNDO_ROW_UPDATE)
MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
if (info == NULL)
return 0;
+ MARIA_SHARE *share= info->s;
set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
- if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) >= 0)
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
{
- info->s->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
+ if (share->calc_checksum)
+ {
+ uchar buff[HA_CHECKSUM_STORE_SIZE];
+ if (translog_read_record(rec->lsn, LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ HA_CHECKSUM_STORE_SIZE, buff, NULL) !=
+ HA_CHECKSUM_STORE_SIZE)
+ {
+ tprint(tracef, "Failed to read record\n");
+ return 1;
+ }
+ share->state.state.checksum+= ha_checksum_korr(buff);
+ }
+ share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES;
}
return 0;
@@ -1294,33 +1342,46 @@ prototype_redo_exec_hook(CLR_END)
MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
if (info == NULL)
return 0;
+ MARIA_SHARE *share= info->s;
LSN previous_undo_lsn= lsn_korr(rec->header);
enum translog_record_type undone_record_type=
- (rec->header)[LSN_STORE_SIZE + FILEID_STORE_SIZE];
+ clr_type_korr(rec->header + LSN_STORE_SIZE + FILEID_STORE_SIZE);
const LOG_DESC *log_desc= &log_record_type_descriptor[undone_record_type];
set_undo_lsn_for_active_trans(rec->short_trid, previous_undo_lsn);
tprint(tracef, " CLR_END was about %s, undo_lsn now LSN (%lu,0x%lx)\n",
log_desc->name, LSN_IN_PARTS(previous_undo_lsn));
- if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) >= 0)
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
{
tprint(tracef, " state older than record, updating rows' count\n");
+ if (share->calc_checksum)
+ {
+ uchar buff[HA_CHECKSUM_STORE_SIZE];
+ if (translog_read_record(rec->lsn, LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE, HA_CHECKSUM_STORE_SIZE,
+ buff, NULL) != HA_CHECKSUM_STORE_SIZE)
+ {
+ tprint(tracef, "Failed to read record\n");
+ return 1;
+ }
+ share->state.state.checksum+= ha_checksum_korr(buff);
+ }
switch (undone_record_type) {
case LOGREC_UNDO_ROW_DELETE:
- info->s->state.state.records++;
+ share->state.state.records++;
break;
case LOGREC_UNDO_ROW_INSERT:
- info->s->state.state.records--;
+ share->state.state.records--;
break;
case LOGREC_UNDO_ROW_UPDATE:
break;
default:
DBUG_ASSERT(0);
}
- info->s->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
+ share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES;
}
- tprint(tracef, " rows' count %lu\n", (ulong)info->s->state.state.records);
+ tprint(tracef, " rows' count %lu\n", (ulong)share->state.state.records);
return 0;
}
@@ -1341,12 +1402,33 @@ prototype_undo_exec_hook(UNDO_ROW_INSERT)
*/
return 1;
}
- info->s->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
+ MARIA_SHARE *share= info->s;
+ share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES;
+ const uchar *record_ptr= rec->header;
+ if (share->calc_checksum)
+ {
+ /*
+ We need to read more of the record to put the checksum into the record
+ buffer used by _ma_apply_undo_row_insert().
+ If the table has no live checksum, rec->header will be enough.
+ */
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ tprint(tracef, "Failed to read record\n");
+ return 1;
+ }
+ record_ptr= log_record_buffer.str;
+ }
+
info->trn= trn;
error= _ma_apply_undo_row_insert(info, previous_undo_lsn,
- rec->header + LSN_STORE_SIZE +
+ record_ptr + LSN_STORE_SIZE +
FILEID_STORE_SIZE);
info->trn= 0;
/* trn->undo_lsn is updated in an inwrite_hook when writing the CLR_END */
@@ -1366,7 +1448,8 @@ prototype_undo_exec_hook(UNDO_ROW_DELETE)
if (info == NULL)
return 1;
- info->s->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
+ MARIA_SHARE *share= info->s;
+ share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES;
enlarge_buffer(rec);
@@ -1393,8 +1476,7 @@ prototype_undo_exec_hook(UNDO_ROW_DELETE)
PAGE_STORE_SIZE + DIRPOS_STORE_SIZE));
info->trn= 0;
tprint(tracef, " rows' count %lu\n undo_lsn now LSN (%lu,0x%lx)\n",
- (ulong)info->s->state.state.records,
- LSN_IN_PARTS(previous_undo_lsn));
+ (ulong)share->state.state.records, LSN_IN_PARTS(previous_undo_lsn));
return error;
}
@@ -1407,8 +1489,8 @@ prototype_undo_exec_hook(UNDO_ROW_UPDATE)
if (info == NULL)
return 1;
-
- info->s->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
+ MARIA_SHARE *share= info->s;
+ share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES;
enlarge_buffer(rec);
@@ -1436,6 +1518,11 @@ prototype_undo_exec_hook(UNDO_ROW_UPDATE)
static int run_redo_phase(LSN lsn, my_bool apply)
{
+ TRANSLOG_HEADER_BUFFER rec;
+ struct st_translog_scanner_data scanner;
+ int len;
+ uint i;
+
/* install hooks for execution */
#define install_redo_exec_hook(R) \
log_record_type_descriptor[LOGREC_ ## R].record_execute_in_redo_phase= \
@@ -1467,8 +1554,6 @@ static int run_redo_phase(LSN lsn, my_bool apply)
current_group_end_lsn= LSN_IMPOSSIBLE;
- TRANSLOG_HEADER_BUFFER rec;
-
if (unlikely(lsn == LSN_IMPOSSIBLE || lsn == translog_get_horizon()))
{
tprint(tracef, "checkpoint address refers to the log end log or "
@@ -1476,7 +1561,7 @@ static int run_redo_phase(LSN lsn, my_bool apply)
return 0;
}
- int len= translog_read_record_header(lsn, &rec);
+ len= translog_read_record_header(lsn, &rec);
/** @todo EOF should be detected */
if (len == RECHEADER_READ_ERROR)
@@ -1484,13 +1569,11 @@ static int run_redo_phase(LSN lsn, my_bool apply)
tprint(tracef, "Failed to read header of the first record.\n");
return 1;
}
- struct st_translog_scanner_data scanner;
- if (translog_init_scanner(lsn, 1, &scanner))
+ if (translog_init_scanner(lsn, 1, &scanner, 1))
{
tprint(tracef, "Scanner init failed\n");
return 1;
}
- uint i;
for (i= 1;;i++)
{
uint16 sid= rec.short_trid;
@@ -1519,24 +1602,25 @@ static int run_redo_phase(LSN lsn, my_bool apply)
}
else
{
+ struct st_translog_scanner_data scanner2;
+ TRANSLOG_HEADER_BUFFER rec2;
/*
There is a complete group for this transaction, containing more
than this event.
*/
tprint(tracef, " ends a group:\n");
- struct st_translog_scanner_data scanner2;
- TRANSLOG_HEADER_BUFFER rec2;
len=
- translog_read_record_header(all_active_trans[sid].group_start_lsn, &rec2);
+ translog_read_record_header(all_active_trans[sid].group_start_lsn,
+ &rec2);
if (len < 0) /* EOF or error */
{
tprint(tracef, "Cannot find record where it should be\n");
- return 1;
+ goto err;
}
- if (translog_init_scanner(rec2.lsn, 1, &scanner2))
+ if (translog_init_scanner(rec2.lsn, 1, &scanner2, 1))
{
tprint(tracef, "Scanner2 init failed\n");
- return 1;
+ goto err;
}
current_group_end_lsn= rec.lsn;
do
@@ -1546,13 +1630,16 @@ static int run_redo_phase(LSN lsn, my_bool apply)
const LOG_DESC *log_desc2= &log_record_type_descriptor[rec2.type];
display_record_position(log_desc2, &rec2, 0);
if (apply && display_and_apply_record(log_desc2, &rec2))
- return 1;
+ {
+ translog_destroy_scanner(&scanner2);
+ goto err;
+ }
}
len= translog_read_next_record_header(&scanner2, &rec2);
if (len < 0) /* EOF or error */
{
tprint(tracef, "Cannot find record where it should be\n");
- return 1;
+ goto err;
}
}
while (rec2.lsn < rec.lsn);
@@ -1561,10 +1648,11 @@ static int run_redo_phase(LSN lsn, my_bool apply)
all_active_trans[sid].group_start_lsn= LSN_IMPOSSIBLE;
current_group_end_lsn= LSN_IMPOSSIBLE; /* for debugging */
display_record_position(log_desc, &rec, 0);
+ translog_destroy_scanner(&scanner2);
}
}
if (apply && display_and_apply_record(log_desc, &rec))
- return 1;
+ goto err;
}
else /* record does not end group */
{
@@ -1585,13 +1673,18 @@ static int run_redo_phase(LSN lsn, my_bool apply)
break;
case RECHEADER_READ_ERROR:
tprint(tracef, "Error reading log\n");
- return 1;
+ goto err;
}
break;
}
}
+ translog_destroy_scanner(&scanner);
translog_free_record_header(&rec);
return 0;
+
+err:
+ translog_destroy_scanner(&scanner);
+ return 1;
}
@@ -1607,10 +1700,11 @@ static uint end_of_redo_phase(my_bool prepare_for_undo_phase)
{
uint sid, unfinished= 0;
char llbuf[22];
+ LSN addr;
hash_free(&all_dirty_pages);
/*
- hash_free() can be called multiple times probably, but be safe it that
+ hash_free() can be called multiple times probably, but be safe if that
changes
*/
bzero(&all_dirty_pages, sizeof(all_dirty_pages));
@@ -1628,11 +1722,8 @@ static uint end_of_redo_phase(my_bool prepare_for_undo_phase)
LSN gslsn= all_active_trans[sid].group_start_lsn;
TRN *trn;
if (gslsn != LSN_IMPOSSIBLE)
- {
tprint(tracef, "Group at LSN (%lu,0x%lx) short_trid %u aborted\n",
LSN_IN_PARTS(gslsn), sid);
- ALERT_USER();
- }
if (all_active_trans[sid].undo_lsn != LSN_IMPOSSIBLE)
{
char llbuf[22];
@@ -1667,7 +1758,7 @@ static uint end_of_redo_phase(my_bool prepare_for_undo_phase)
The UNDO phase uses some normal run-time code of ROLLBACK: generates log
records, etc; prepare tables for that
*/
- LSN addr= translog_get_horizon();
+ addr= translog_get_horizon();
for (sid= 0; sid <= SHARE_ID_MAX; sid++)
{
MARIA_HA *info= all_tables[sid].info;
@@ -1710,8 +1801,12 @@ static int run_undo_phase(uint unfinished)
{
if (tracef != stdout)
{
+ ulonglong old_now= now;
+ now= my_getsystime();
+ float previous_phase_took= (now - old_now)/10000000.0;
/** @todo RECOVERY BUG all prints to stderr should go to error log */
- fprintf(stderr, " 100%%; transactions to roll back:");
+ fprintf(stderr, " 100%% (%.1f seconds); transactions to roll back:",
+ previous_phase_took);
}
tprint(tracef, "%u transactions will be rolled back\n", unfinished);
for( ; ; )
@@ -1898,7 +1993,7 @@ static MARIA_HA *get_MARIA_HA_from_UNDO_record(const
static LSN parse_checkpoint_record(LSN lsn)
{
- uint i;
+ ulong i;
TRANSLOG_HEADER_BUFFER rec;
tprint(tracef, "Loading data from checkpoint record at LSN (%lu,0x%lx)\n",
@@ -1982,9 +2077,9 @@ static LSN parse_checkpoint_record(LSN lsn)
}
/* dirty pages */
- uint nb_dirty_pages= uint4korr(ptr);
- ptr+= 4;
- tprint(tracef, "%u dirty pages\n", nb_dirty_pages);
+ ulong nb_dirty_pages= uint8korr(ptr);
+ ptr+= 8;
+ tprint(tracef, "%lu dirty pages\n", nb_dirty_pages);
if (hash_init(&all_dirty_pages, &my_charset_bin, nb_dirty_pages,
offsetof(struct st_dirty_page, file_and_page_id),
sizeof(((struct st_dirty_page *)NULL)->file_and_page_id),
@@ -2046,8 +2141,11 @@ static int close_all_tables(void)
tprint(tracef, "Closing all tables\n");
if (tracef != stdout && redo_phase_message_printed)
{
+ ulonglong old_now= now;
+ now= my_getsystime();
+ float previous_phase_took= (now - old_now)/10000000.0;
/** @todo RECOVERY BUG all prints to stderr should go to error log */
- fprintf(stderr, "; flushing tables");
+ fprintf(stderr, " (%.1f seconds); flushing tables", previous_phase_took);
}
/*
@@ -2070,6 +2168,42 @@ end:
return error;
}
+
+/* Close one table during redo phase */
+
+static my_bool close_one_table(const char *open_name, LSN addr)
+{
+ my_bool res= 0;
+ LIST *pos;
+ /* There are no other threads using the tables, so we don't need any locks */
+ for (pos=maria_open_list ; pos ;)
+ {
+ MARIA_HA *info= (MARIA_HA*) pos->data;
+ MARIA_SHARE *share= info->s;
+ pos= pos->next;
+ if (!strcmp(share->open_file_name, open_name))
+ {
+ struct st_table_for_recovery *internal_table, *end;
+
+ for (internal_table= all_tables, end= internal_table + SHARE_ID_MAX + 1;
+ internal_table < end ;
+ internal_table++)
+ {
+ if (internal_table->info == info)
+ {
+ internal_table->info= 0;
+ break;
+ }
+ }
+ prepare_table_for_close(info, addr);
+ if (maria_close(info))
+ res= 1;
+ }
+ }
+ return res;
+}
+
+
static void print_redo_phase_progress(TRANSLOG_ADDRESS addr)
{
static int end_logno= FILENO_IMPOSSIBLE, end_offset, percentage_printed= 0;
@@ -2081,6 +2215,7 @@ static void print_redo_phase_progress(TRANSLOG_ADDRESS addr)
/** @todo RECOVERY BUG all prints to stderr should go to error log */
fprintf(stderr, "Maria engine: starting recovery; recovered pages: 0%%");
redo_phase_message_printed= TRUE;
+ now= my_getsystime();
}
if (end_logno == FILENO_IMPOSSIBLE)
{
@@ -2106,7 +2241,7 @@ static void print_redo_phase_progress(TRANSLOG_ADDRESS addr)
}
#ifdef MARIA_EXTERNAL_LOCKING
-#error Maria's Checkpoint and Recovery are really not ready for it
+#error Marias Checkpoint and Recovery are really not ready for it
#endif
/*
diff --git a/storage/maria/ma_rename.c b/storage/maria/ma_rename.c
index 44cd60711da..57d35f6c066 100644
--- a/storage/maria/ma_rename.c
+++ b/storage/maria/ma_rename.c
@@ -85,7 +85,7 @@ int maria_rename(const char *old_name, const char *new_name)
&dummy_transaction_object, NULL,
old_name_len + new_name_len,
sizeof(log_array)/sizeof(log_array[0]),
- log_array, NULL) ||
+ log_array, NULL, NULL) ||
translog_flush(lsn)))
{
maria_close(info);
diff --git a/storage/maria/ma_test_recovery.expected b/storage/maria/ma_test_recovery.expected
index 926943b11b3..70339fc69b6 100644
--- a/storage/maria/ma_test_recovery.expected
+++ b/storage/maria/ma_test_recovery.expected
@@ -4,10 +4,6 @@ TEST WITH ma_test1 -s -M -T -c
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 3757530372
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -21,10 +17,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 3757530372
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -78,10 +70,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 221293111
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -95,10 +83,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 221293111
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -112,10 +96,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 221293111
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -137,10 +117,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 3697324514
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -158,10 +134,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 2428948025
----
-> Checksum: 3026590807
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -175,10 +147,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 2428948025
----
-> Checksum: 3026590807
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -192,10 +160,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 2428948025
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -253,10 +217,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 221293111
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -270,10 +230,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 221293111
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -287,10 +243,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 221293111
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -312,10 +264,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 3697324514
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -333,10 +281,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 2428948025
----
-> Checksum: 3026590807
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -350,10 +294,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 2428948025
----
-> Checksum: 3026590807
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -367,10 +307,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 2428948025
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -428,10 +364,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 221293111
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -445,10 +377,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 221293111
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -462,10 +390,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 221293111
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -487,10 +411,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 3697324514
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -508,10 +428,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 2428948025
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -525,10 +441,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 2428948025
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -542,10 +454,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 2428948025
----
-> Checksum: 0
11c11
< Datafile length: 16384 Keyfile length: 16384
---
@@ -603,10 +511,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 411409161
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -620,10 +524,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 411409161
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -637,10 +537,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 411409161
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -662,10 +558,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 4024695312
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -683,10 +575,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 529753687
----
-> Checksum: 800025671
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -700,10 +588,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 529753687
----
-> Checksum: 800025671
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -717,10 +601,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 529753687
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -778,10 +658,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 411409161
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -795,10 +671,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 411409161
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -812,10 +684,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 411409161
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -837,10 +705,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 4024695312
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -858,10 +722,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 529753687
----
-> Checksum: 800025671
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -875,10 +735,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 529753687
----
-> Checksum: 800025671
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -892,10 +748,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 529753687
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -953,10 +805,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 411409161
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -970,10 +818,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 411409161
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -987,10 +831,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 411409161
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -1012,10 +852,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 4024695312
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -1033,10 +869,6 @@ Dying on request without maria_commit()/maria_close()
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 529753687
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -1050,10 +882,6 @@ testing idempotency
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 529753687
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
@@ -1067,10 +895,6 @@ testing applying of CLRs to recreate table
applying log
Differences in maria_chk -dvv, recovery not yet perfect !
========DIFF START=======
-7c7
-< Checksum: 529753687
----
-> Checksum: 0
11c11
< Datafile length: 49152 Keyfile length: 16384
---
diff --git a/storage/maria/ma_update.c b/storage/maria/ma_update.c
index 759f94e6450..3c10cdab976 100644
--- a/storage/maria/ma_update.c
+++ b/storage/maria/ma_update.c
@@ -27,11 +27,9 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
bool auto_key_changed=0;
ulonglong changed;
MARIA_SHARE *share=info->s;
- ha_checksum old_checksum;
DBUG_ENTER("maria_update");
LINT_INIT(new_key);
LINT_INIT(changed);
- LINT_INIT(old_checksum);
DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_usage",
maria_print_error(info->s, HA_ERR_CRASHED);
@@ -59,16 +57,6 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
goto err_end; /* Record has changed */
}
- if (share->calc_checksum)
- {
- /*
- We can't use the row based checksum as this doesn't have enough
- precision.
- */
- if (info->s->calc_checksum)
- old_checksum= (*info->s->calc_checksum)(info, oldrec);
- }
-
/* Calculate and check all unique constraints */
key_changed=0;
for (i=0 ; i < share->state.header.uniques ; i++)
@@ -137,19 +125,23 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
}
}
}
- /*
- If we are running with external locking, we must update the index file
- that something has changed.
- */
- if (changed || !my_disable_locking)
- key_changed|= HA_STATE_CHANGED;
if (share->calc_checksum)
{
- info->cur_row.checksum= (*share->calc_checksum)(info,newrec);
- info->state->checksum+= (info->cur_row.checksum - old_checksum);
- /* Store new checksum in index file header */
- key_changed|= HA_STATE_CHANGED;
+ /*
+ We can't use the row based checksum as this doesn't have enough
+ precision (one byte, while the table's is more bytes).
+ At least _ma_check_unique() modifies the 'newrec' record, so checksum
+ has to be computed _after_ it. Nobody apparently modifies 'oldrec'.
+ We need to pass the old row's checksum down to (*update_record)(), we do
+ this via info->new_row.checksum (not intuitive but existing code
+ mandated that cur_row is the new row).
+ If (*update_record)() fails, table will be marked corrupted so no need
+ to revert the live checksum change.
+ */
+ info->state->checksum+= !share->now_transactional *
+ ((info->cur_row.checksum= (*share->calc_checksum)(info, newrec)) -
+ (info->new_row.checksum= (*share->calc_checksum)(info, oldrec)));
}
{
/*
@@ -165,14 +157,9 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
org_delete_link= share->state.dellink;
if ((*share->update_record)(info, pos, oldrec, newrec))
goto err;
- if (!key_changed &&
- (memcmp((char*) &state, (char*) info->state, sizeof(state)) ||
- org_split != share->state.split ||
- org_delete_link != share->state.dellink))
- key_changed|= HA_STATE_CHANGED; /* Must update index file */
}
if (auto_key_changed)
- set_if_bigger(info->s->state.auto_increment,
+ set_if_bigger(share->state.auto_increment,
ma_retrieve_auto_increment(info, newrec));
/*
@@ -195,8 +182,8 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
allow_break(); /* Allow SIGHUP & SIGINT */
if (info->invalidator != 0)
{
- DBUG_PRINT("info", ("invalidator... '%s' (update)", info->s->open_file_name));
- (*info->invalidator)(info->s->open_file_name);
+ DBUG_PRINT("info", ("invalidator... '%s' (update)", share->open_file_name));
+ (*info->invalidator)(share->open_file_name);
info->invalidator=0;
}
DBUG_RETURN(0);
@@ -232,7 +219,7 @@ err:
}
else
{
- maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_print_error(share, HA_ERR_CRASHED);
maria_mark_crashed(info);
}
info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_ROW_CHANGED |
@@ -243,7 +230,7 @@ err:
allow_break(); /* Allow SIGHUP & SIGINT */
if (save_errno == HA_ERR_KEY_NOT_FOUND)
{
- maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_print_error(share, HA_ERR_CRASHED);
save_errno=HA_ERR_CRASHED;
}
DBUG_RETURN(my_errno=save_errno);
diff --git a/storage/maria/ma_write.c b/storage/maria/ma_write.c
index 9982d770c81..c62b168d008 100644
--- a/storage/maria/ma_write.c
+++ b/storage/maria/ma_write.c
@@ -162,10 +162,6 @@ int maria_write(MARIA_HA *info, uchar *record)
rw_unlock(&share->key_root_lock[i]);
}
}
- /**
- @todo RECOVERY BUG
- this += must happen under log's mutex when writing the UNDO
- */
if (share->calc_write_checksum)
info->cur_row.checksum= (*share->calc_write_checksum)(info,record);
if (filepos != HA_OFFSET_ERROR)
@@ -176,7 +172,8 @@ int maria_write(MARIA_HA *info, uchar *record)
@todo when we enable multiple writers, we will have to protect
'records' and 'checksum' somehow.
*/
- info->state->checksum+= info->cur_row.checksum;
+ info->state->checksum+= !share->now_transactional *
+ info->cur_row.checksum;
}
if (share->base.auto_key)
set_if_bigger(info->s->state.auto_increment,
diff --git a/storage/maria/maria_chk.c b/storage/maria/maria_chk.c
index 227eb9727e4..8c5c11bc3a7 100644
--- a/storage/maria/maria_chk.c
+++ b/storage/maria/maria_chk.c
@@ -154,7 +154,7 @@ int main(int argc, char **argv)
enum options_mc {
OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
- OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
+ OPT_CORRECT_CHECKSUM, OPT_PAGE_BUFFER_SIZE,
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MARIA_BLOCK_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,
@@ -296,7 +296,7 @@ static struct my_option my_long_options[] =
{"wait", 'w',
"Wait if table is locked.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- { "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
+ { "page_buffer_size", OPT_PAGE_BUFFER_SIZE, "",
(uchar**) &check_param.use_buffers, (uchar**) &check_param.use_buffers, 0,
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
(long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
@@ -1758,84 +1758,4 @@ err:
} /* sort_record_index */
-
-/*
- Check if maria_chk was killed by a signal
- This is overloaded by other programs that want to be able to abort
- sorting
-*/
-
-static int not_killed= 0;
-
-volatile int *_ma_killed_ptr(HA_CHECK *param __attribute__((unused)))
-{
- return &not_killed; /* always NULL */
-}
-
- /* print warnings and errors */
- /* VARARGS */
-
-void _ma_check_print_info(HA_CHECK *param __attribute__((unused)),
- const char *fmt,...)
-{
- va_list args;
- DBUG_ENTER("_ma_check_print_info");
- DBUG_PRINT("enter", ("format: %s", fmt));
-
- va_start(args,fmt);
- VOID(vfprintf(stdout, fmt, args));
- VOID(fputc('\n',stdout));
- va_end(args);
- DBUG_VOID_RETURN;
-}
-
-/* VARARGS */
-
-void _ma_check_print_warning(HA_CHECK *param, const char *fmt,...)
-{
- va_list args;
- DBUG_ENTER("_ma_check_print_warning");
- DBUG_PRINT("enter", ("format: %s", fmt));
-
- fflush(stdout);
- if (!param->warning_printed && !param->error_printed)
- {
- if (param->testflag & T_SILENT)
- fprintf(stderr,"%s: MARIA file %s\n",my_progname_short,
- param->isam_file_name);
- param->out_flag|= O_DATA_LOST;
- }
- param->warning_printed=1;
- va_start(args,fmt);
- fprintf(stderr,"%s: warning: ",my_progname_short);
- VOID(vfprintf(stderr, fmt, args));
- VOID(fputc('\n',stderr));
- fflush(stderr);
- va_end(args);
- DBUG_VOID_RETURN;
-}
-
-/* VARARGS */
-
-void _ma_check_print_error(HA_CHECK *param, const char *fmt,...)
-{
- va_list args;
- DBUG_ENTER("_ma_check_print_error");
- DBUG_PRINT("enter", ("format: %s", fmt));
-
- fflush(stdout);
- if (!param->warning_printed && !param->error_printed)
- {
- if (param->testflag & T_SILENT)
- fprintf(stderr,"%s: MARIA file %s\n",my_progname_short,param->isam_file_name);
- param->out_flag|= O_DATA_LOST;
- }
- param->error_printed|=1;
- va_start(args,fmt);
- fprintf(stderr,"%s: error: ",my_progname_short);
- VOID(vfprintf(stderr, fmt, args));
- VOID(fputc('\n',stderr));
- fflush(stderr);
- va_end(args);
- DBUG_VOID_RETURN;
-}
+#include "ma_check_standalone.h"
diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h
index cf8ab10e22f..bd5746cbb94 100644
--- a/storage/maria/maria_def.h
+++ b/storage/maria/maria_def.h
@@ -632,7 +632,7 @@ typedef struct st_maria_s_param
/* Used to store reference to pinned page */
typedef struct st_pinned_page
{
- PAGECACHE_PAGE_LINK link;
+ PAGECACHE_BLOCK_LINK *link;
enum pagecache_page_lock unlock;
} MARIA_PINNED_PAGE;
@@ -842,7 +842,7 @@ typedef struct st_maria_block_info
#define UPDATE_AUTO_INC 8
#define UPDATE_OPEN_COUNT 16
-#define USE_BUFFER_INIT (((1024L*512L-MALLOC_OVERHEAD)/IO_SIZE)*IO_SIZE)
+#define USE_BUFFER_INIT (((1024L*1024L*10-MALLOC_OVERHEAD)/8192)*8192)
#define READ_BUFFER_INIT (1024L*256L-MALLOC_OVERHEAD)
#define SORT_BUFFER_INIT (2048L*1024L-MALLOC_OVERHEAD)
#define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD)
@@ -906,7 +906,7 @@ my_bool _ma_check_status(void *param);
void _ma_reset_status(MARIA_HA *maria);
#include "ma_commit.h"
-extern MARIA_HA *_ma_test_if_reopen(char *filename);
+extern MARIA_HA *_ma_test_if_reopen(const char *filename);
my_bool _ma_check_table_is_closed(const char *name, const char *where);
int _ma_open_datafile(MARIA_HA *info, MARIA_SHARE *share, File file_to_dup);
int _ma_open_keyfile(MARIA_SHARE *share);
@@ -923,7 +923,10 @@ C_MODE_START
int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index,
enum flush_type flush_type_for_data,
enum flush_type flush_type_for_index);
-/* Functions needed by _ma_check (are overrided in MySQL) */
+/*
+ Functions needed by _ma_check (are overridden in MySQL/ha_maria.cc).
+ See ma_check_standalone.h .
+*/
volatile int *_ma_killed_ptr(HA_CHECK *param);
void _ma_check_print_error _VARARGS((HA_CHECK *param, const char *fmt, ...));
void _ma_check_print_warning _VARARGS((HA_CHECK *param, const char *fmt, ...));
diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c
index a7a6370b1c4..59882f81d9a 100644
--- a/storage/maria/maria_read_log.c
+++ b/storage/maria/maria_read_log.c
@@ -17,7 +17,6 @@
#include "ma_recovery.h"
#include <my_getopt.h>
-#define PCACHE_SIZE (1024*1024*10)
#define LOG_FLAGS 0
#define LOG_FILE_SIZE (1024L*1024L)
@@ -30,13 +29,16 @@ const char *default_dbug_option= "d:t:i:O,\\maria_read_log.trace";
const char *default_dbug_option= "d:t:i:o,/tmp/maria_read_log.trace";
#endif
#endif /* DBUG_OFF */
-static my_bool opt_only_display, opt_display_and_apply;
+static my_bool opt_only_display, opt_apply, opt_apply_undo, opt_silent;
+static ulong opt_page_buffer_size;
+static const char *my_progname_short;
int main(int argc, char **argv)
{
LSN lsn;
char **default_argv;
MY_INIT(argv[0]);
+ my_progname_short= my_progname+dirname_length(my_progname);
load_defaults("my", load_default_groups, &argc, &argv);
default_argv= argv;
@@ -63,7 +65,7 @@ int main(int argc, char **argv)
}
/* same page cache for log and data; assumes same page size... */
DBUG_ASSERT(maria_block_size == TRANSLOG_PAGE_SIZE);
- if (init_pagecache(maria_pagecache, PCACHE_SIZE, 0, 0,
+ if (init_pagecache(maria_pagecache, opt_page_buffer_size, 0, 0,
TRANSLOG_PAGE_SIZE) == 0)
{
fprintf(stderr, "Got error in init_pagecache() (errno: %d)\n", errno);
@@ -100,15 +102,15 @@ int main(int argc, char **argv)
LSN_IN_PARTS(lsn));
fprintf(stdout, "TRACE of the last maria_read_log\n");
- if (maria_apply_log(lsn, opt_display_and_apply, stdout,
- opt_display_and_apply, FALSE))
+ if (maria_apply_log(lsn, opt_apply, opt_silent ? NULL : stdout,
+ opt_apply_undo, FALSE))
goto err;
- fprintf(stdout, "%s: SUCCESS\n", my_progname);
+ fprintf(stdout, "%s: SUCCESS\n", my_progname_short);
goto end;
err:
/* don't touch anything more, in case we hit a bug */
- fprintf(stderr, "%s: FAILED\n", my_progname);
+ fprintf(stderr, "%s: FAILED\n", my_progname_short);
exit(1);
end:
maria_end();
@@ -119,21 +121,37 @@ end:
}
+#include "ma_check_standalone.h"
+
+
static struct my_option my_long_options[] =
{
+ {"apply", 'a',
+ "Apply log to tables. Will display a lot of information if not run with --silent",
+ (uchar **) &opt_apply, (uchar **) &opt_apply, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DBUG_OFF
+ {"debug", '#', "Output debug log. Often the argument is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
{"help", '?', "Display this help and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"only-display", 'o', "display brief info about records's header",
(uchar **) &opt_only_display, (uchar **) &opt_only_display, 0, GET_BOOL,
NO_ARG,0, 0, 0, 0, 0, 0},
- {"display-and-apply", 'a',
- "like --only-display but displays more info and modifies tables",
- (uchar **) &opt_display_and_apply, (uchar **) &opt_display_and_apply, 0,
+ { "page_buffer_size", 'P', "",
+ (uchar**) &opt_page_buffer_size, (uchar**) &opt_page_buffer_size, 0,
+ GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT,
+ (long) MALLOC_OVERHEAD, (long) ~(ulong) 0, (long) MALLOC_OVERHEAD,
+ (long) IO_SIZE, 0},
+ {"silent", 's', "Print less information during apply/undo phase",
+ (uchar **) &opt_silent, (uchar **) &opt_silent, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
-#ifndef DBUG_OFF
- {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
- 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
-#endif
+ {"undo", 'u', "Apply undos to tables. (disable with --disable-undo)",
+ (uchar **) &opt_apply_undo, (uchar **) &opt_apply_undo, 0,
+ GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+ {"version", 'V', "Print version and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -141,8 +159,8 @@ static struct my_option my_long_options[] =
static void print_version(void)
{
- VOID(printf("%s Ver 1.0 for %s on %s\n",
- my_progname, SYSTEM_TYPE, MACHINE_TYPE));
+ VOID(printf("%s Ver 1.1 for %s on %s\n",
+ my_progname_short, SYSTEM_TYPE, MACHINE_TYPE));
NETWARE_SET_SCREEN_MODE(1);
}
@@ -156,7 +174,7 @@ static void usage(void)
puts("Display and apply log records from a MARIA transaction log");
puts("found in the current directory (for now)");
- VOID(printf("\nUsage: %s OPTIONS\n", my_progname));
+ VOID(printf("\nUsage: %s OPTIONS\n", my_progname_short));
puts("You need to use one of -o or -a");
my_print_help(my_long_options);
print_defaults("my", load_default_groups);
@@ -174,6 +192,9 @@ get_one_option(int optid __attribute__((unused)),
case '?':
usage();
exit(0);
+ case 'V':
+ print_version();
+ exit(0);
#ifndef DBUG_OFF
case '#':
DBUG_SET_INITIAL(argument ? argument : default_dbug_option);
@@ -187,12 +208,13 @@ static void get_options(int *argc,char ***argv)
{
int ho_error;
- my_progname= argv[0][0];
-
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
exit(ho_error);
- if ((opt_only_display + opt_display_and_apply) != 1)
+ if (!opt_apply)
+ opt_apply_undo= FALSE;
+
+ if ((opt_only_display + opt_apply) != 1)
{
usage();
exit(1);
diff --git a/storage/maria/unittest/ma_control_file-t.c b/storage/maria/unittest/ma_control_file-t.c
index a7472361dad..db0a1690ab8 100644
--- a/storage/maria/unittest/ma_control_file-t.c
+++ b/storage/maria/unittest/ma_control_file-t.c
@@ -407,7 +407,7 @@ static void version()
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
+ char *argument __attribute__((unused)))
{
switch(optid) {
case 'V':
diff --git a/storage/maria/unittest/ma_test_loghandler-t.c b/storage/maria/unittest/ma_test_loghandler-t.c
index 6ea45f80433..d9627409c80 100644
--- a/storage/maria/unittest/ma_test_loghandler-t.c
+++ b/storage/maria/unittest/ma_test_loghandler-t.c
@@ -198,8 +198,8 @@ int main(int argc __attribute__((unused)), char *argv[])
trn->first_undo_lsn= TRANSACTION_LOGGED_LONG_ID;
if (translog_write_record(&lsn,
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
- trn, NULL,
- 6, TRANSLOG_INTERNAL_PARTS + 1, parts, NULL))
+ trn, NULL, 6, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
@@ -220,8 +220,8 @@ int main(int argc __attribute__((unused)), char *argv[])
/* check auto-count feature */
parts[TRANSLOG_INTERNAL_PARTS + 1].str= NULL;
parts[TRANSLOG_INTERNAL_PARTS + 1].length= 0;
- if (translog_write_record(&lsn, LOGREC_FIXED_RECORD_1LSN_EXAMPLE,
- trn, NULL, LSN_STORE_SIZE, 0, parts, NULL))
+ if (translog_write_record(&lsn, LOGREC_FIXED_RECORD_1LSN_EXAMPLE, trn,
+ NULL, LSN_STORE_SIZE, 0, parts, NULL, NULL))
{
fprintf(stderr, "1 Can't write reference defore record #%lu\n",
(ulong) i);
@@ -241,7 +241,7 @@ int main(int argc __attribute__((unused)), char *argv[])
if (translog_write_record(&lsn,
LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE,
trn, NULL, 0, TRANSLOG_INTERNAL_PARTS + 2,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "1 Can't write var reference defore record #%lu\n",
(ulong) i);
@@ -259,8 +259,8 @@ int main(int argc __attribute__((unused)), char *argv[])
parts[TRANSLOG_INTERNAL_PARTS + 0].length= 23;
if (translog_write_record(&lsn,
LOGREC_FIXED_RECORD_2LSN_EXAMPLE,
- trn, NULL,
- 23, TRANSLOG_INTERNAL_PARTS + 1, parts, NULL))
+ trn, NULL, 23, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
{
fprintf(stderr, "0 Can't write reference defore record #%lu\n",
(ulong) i);
@@ -280,7 +280,8 @@ int main(int argc __attribute__((unused)), char *argv[])
if (translog_write_record(&lsn,
LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE,
trn, NULL, 14 + rec_len,
- TRANSLOG_INTERNAL_PARTS + 2, parts, NULL))
+ TRANSLOG_INTERNAL_PARTS + 2, parts, NULL,
+ NULL))
{
fprintf(stderr, "0 Can't write var reference defore record #%lu\n",
(ulong) i);
@@ -297,7 +298,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
trn, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) i);
translog_destroy();
@@ -316,7 +317,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE,
trn, NULL, rec_len,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write variable record #%lu\n", (ulong) i);
translog_destroy();
@@ -363,7 +364,7 @@ int main(int argc __attribute__((unused)), char *argv[])
read_ok(&rec);
translog_free_record_header(&rec);
lsn= first_lsn;
- if (translog_init_scanner(first_lsn, 1, &scanner))
+ if (translog_init_scanner(first_lsn, 1, &scanner, 0))
{
fprintf(stderr, "scanner init failed\n");
goto err;
diff --git a/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c b/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
index 28233ae04cb..845e33b63a5 100644
--- a/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
@@ -106,7 +106,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
diff --git a/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c b/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c
index d6f0bde7a8e..68561443a02 100644
--- a/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c
@@ -96,7 +96,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
diff --git a/storage/maria/unittest/ma_test_loghandler_multigroup-t.c b/storage/maria/unittest/ma_test_loghandler_multigroup-t.c
index d5f00bdb6fd..e5afa0b40db 100644
--- a/storage/maria/unittest/ma_test_loghandler_multigroup-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_multigroup-t.c
@@ -194,8 +194,8 @@ int main(int argc __attribute__((unused)), char *argv[])
trn->short_id= 0;
trn->first_undo_lsn= TRANSACTION_LOGGED_LONG_ID;
if (translog_write_record(&lsn, LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
- trn, NULL,
- 6, TRANSLOG_INTERNAL_PARTS + 1, parts, NULL))
+ trn, NULL, 6, TRANSLOG_INTERNAL_PARTS + 1, parts,
+ NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
@@ -214,10 +214,9 @@ int main(int argc __attribute__((unused)), char *argv[])
parts[TRANSLOG_INTERNAL_PARTS + 0].length= LSN_STORE_SIZE;
trn->short_id= i % 0xFFFF;
if (translog_write_record(&lsn,
- LOGREC_FIXED_RECORD_1LSN_EXAMPLE,
- trn, NULL,
- LSN_STORE_SIZE,
- TRANSLOG_INTERNAL_PARTS + 1, parts, NULL))
+ LOGREC_FIXED_RECORD_1LSN_EXAMPLE, trn, NULL,
+ LSN_STORE_SIZE, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
{
fprintf(stderr, "1 Can't write reference before record #%lu\n",
(ulong) i);
@@ -237,7 +236,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE,
trn, NULL, LSN_STORE_SIZE + rec_len,
TRANSLOG_INTERNAL_PARTS + 2,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "1 Can't write var reference before record #%lu\n",
(ulong) i);
@@ -256,9 +255,8 @@ int main(int argc __attribute__((unused)), char *argv[])
trn->short_id= i % 0xFFFF;
if (translog_write_record(&lsn,
LOGREC_FIXED_RECORD_2LSN_EXAMPLE,
- trn, NULL, 23,
- TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ trn, NULL, 23, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
{
fprintf(stderr, "0 Can't write reference before record #%lu\n",
(ulong) i);
@@ -279,7 +277,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE,
trn, NULL, LSN_STORE_SIZE * 2 + rec_len,
TRANSLOG_INTERNAL_PARTS + 2,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "0 Can't write var reference before record #%lu\n",
(ulong) i);
@@ -296,7 +294,7 @@ int main(int argc __attribute__((unused)), char *argv[])
if (translog_write_record(&lsn,
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
trn, NULL, 6,
- TRANSLOG_INTERNAL_PARTS + 1, parts, NULL))
+ TRANSLOG_INTERNAL_PARTS + 1, parts, NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) i);
translog_destroy();
@@ -314,7 +312,7 @@ int main(int argc __attribute__((unused)), char *argv[])
if (translog_write_record(&lsn,
LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE,
trn, NULL, rec_len,
- TRANSLOG_INTERNAL_PARTS + 1, parts, NULL))
+ TRANSLOG_INTERNAL_PARTS + 1, parts, NULL, NULL))
{
fprintf(stderr, "Can't write variable record #%lu\n", (ulong) i);
translog_destroy();
@@ -378,7 +376,7 @@ int main(int argc __attribute__((unused)), char *argv[])
ok(1, "read record");
translog_free_record_header(&rec);
lsn= first_lsn;
- if (translog_init_scanner(first_lsn, 1, &scanner))
+ if (translog_init_scanner(first_lsn, 1, &scanner, 0))
{
fprintf(stderr, "scanner init failed\n");
goto err;
diff --git a/storage/maria/unittest/ma_test_loghandler_multithread-t.c b/storage/maria/unittest/ma_test_loghandler_multithread-t.c
index 6255c11db89..0a81aeac55f 100644
--- a/storage/maria/unittest/ma_test_loghandler_multithread-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_multithread-t.c
@@ -138,7 +138,7 @@ void writer(int num)
if (translog_write_record(&lsn,
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&trn, NULL, 6, TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write LOGREC_FIXED_RECORD_0LSN_EXAMPLE record #%lu "
"thread %i\n", (ulong) i, num);
@@ -155,7 +155,7 @@ void writer(int num)
LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE,
&trn, NULL,
len, TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write variable record #%lu\n", (ulong) i);
translog_destroy();
@@ -307,7 +307,7 @@ int main(int argc __attribute__((unused)),
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write the first record\n");
translog_destroy();
@@ -373,7 +373,7 @@ int main(int argc __attribute__((unused)),
bzero(indeces, sizeof(indeces));
- if (translog_init_scanner(first_lsn, 1, &scanner))
+ if (translog_init_scanner(first_lsn, 1, &scanner, 0))
{
fprintf(stderr, "scanner init failed\n");
goto err;
diff --git a/storage/maria/unittest/ma_test_loghandler_noflush-t.c b/storage/maria/unittest/ma_test_loghandler_noflush-t.c
index 2c3afb9a76b..a53e6257314 100644
--- a/storage/maria/unittest/ma_test_loghandler_noflush-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_noflush-t.c
@@ -85,7 +85,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
diff --git a/storage/maria/unittest/ma_test_loghandler_pagecache-t.c b/storage/maria/unittest/ma_test_loghandler_pagecache-t.c
index 276640dfd17..fa6fcd544a3 100644
--- a/storage/maria/unittest/ma_test_loghandler_pagecache-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_pagecache-t.c
@@ -97,7 +97,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
diff --git a/storage/maria/unittest/ma_test_loghandler_purge-t.c b/storage/maria/unittest/ma_test_loghandler_purge-t.c
index c638aa85ac6..d9001b9d3ad 100644
--- a/storage/maria/unittest/ma_test_loghandler_purge-t.c
+++ b/storage/maria/unittest/ma_test_loghandler_purge-t.c
@@ -80,7 +80,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
@@ -102,7 +102,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
translog_destroy();
@@ -125,7 +125,7 @@ int main(int argc __attribute__((unused)), char *argv[])
if (translog_write_record(&lsn,
LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, LONG_BUFFER_SIZE,
- TRANSLOG_INTERNAL_PARTS + 1, parts, NULL))
+ TRANSLOG_INTERNAL_PARTS + 1, parts, NULL, NULL))
{
fprintf(stderr, "Can't write variable record\n");
translog_destroy();
@@ -150,7 +150,7 @@ int main(int argc __attribute__((unused)), char *argv[])
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
&dummy_transaction_object, NULL, 6,
TRANSLOG_INTERNAL_PARTS + 1,
- parts, NULL))
+ parts, NULL, NULL))
{
fprintf(stderr, "Can't write last record\n");
translog_destroy();