Commit 59402fe0 authored by Satya Bodapati's avatar Satya Bodapati

Bug#16752251 - INNODB DOESN'T REDO-LOG INSERT BUFFER MERGE OPERATION IF

	       IT IS DONE IN-PLACE

With change buffer enabled, InnoDB doesn't write a transaction log
record when it merges a record from the insert buffer to an secondary
index page if the insertion is performed as an update-in-place.

Fixed by logging the 'update-in-place' operation on secondary index
pages.

Approved by Marko. rb#2429
parent 42501173
if (!`SHOW VARIABLES LIKE 'innodb_change_buffering_debug'`)
{
# innodb_change_buffering_debug is enabled by UNIV_DEBUG or
# UNIV_IBUF_DEBUG
--skip Test requires binary with UNIV_DEBUG enabled
}
# Purpose:
# Simple search with Perl for a pattern in some file.
#
# The advantages compared to thinkable auxiliary constructs using the
# mysqltest language and SQL are:
# 1. We do not need a running MySQL server.
# 2. SQL causes "noise" during debugging and increases the size of logs.
# Perl code does not disturb at all.
#
# The environment variables SEARCH_FILE and SEARCH_PATTERN must be set
# before sourcing this routine.
#
# In case of
# - SEARCH_FILE and/or SEARCH_PATTERN is not set
# - SEARCH_FILE cannot be opened
# - SEARCH_FILE does not contain SEARCH_PATTERN
# the test will abort immediate.
# MTR will report something like
# ....
# worker[1] Using MTR_BUILD_THREAD 300, with reserved ports 13000..13009
# main.1st [ pass ] 3
# innodb.innodb_page_size [ fail ]
# Test ended at 2011-11-11 18:15:58
#
# CURRENT_TEST: innodb.innodb_page_size
# # ERROR: The file '<name>' does not contain the expected pattern <pattern>
# mysqltest: In included file "./include/search_pattern_in_file.inc":
# included from ./include/search_pattern_in_file.inc at line 36:
# At line 25: command "perl" failed with error 255. my_errno=175
#
# The result from queries just before the failure was:
# ...
# - saving '<some path>' to '<some path>'
# main.1st [ pass ] 2
#
# Typical use case (check invalid server startup options):
# let $error_log= $MYSQLTEST_VARDIR/log/my_restart.err;
# --error 0,1
# --remove_file $error_log
# let SEARCH_FILE= $error_log;
# # Stop the server
# let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
# --exec echo "wait" > $restart_file
# --shutdown_server 10
# --source include/wait_until_disconnected.inc
#
# --error 1
# --exec $MYSQLD_CMD <whatever wrong setting> > $error_log 2>&1
# # The server restart aborts
# let SEARCH_PATTERN= \[ERROR\] Aborting;
# --source include/search_pattern_in_file.inc
#
# Created: 2011-11-11 mleich
#
perl;
use strict;
my $search_file= $ENV{'SEARCH_FILE'} or die "SEARCH_FILE not set";
my $search_pattern= $ENV{'SEARCH_PATTERN'} or die "SEARCH_PATTERN not set";
open(FILE, "$search_file") or die("Unable to open '$search_file': $!\n");
read(FILE, my $file_content, 50000, 0);
close(FILE);
if ( not $file_content =~ m{$search_pattern} ) {
die("# ERROR: The file '$search_file' does not contain the expected pattern $search_pattern\n->$file_content<-\n");
}
EOF
...@@ -31,6 +31,7 @@ Created 10/16/1994 Heikki Tuuri ...@@ -31,6 +31,7 @@ Created 10/16/1994 Heikki Tuuri
#include "btr0sea.h" #include "btr0sea.h"
#include "row0upd.h" #include "row0upd.h"
#include "trx0rec.h" #include "trx0rec.h"
#include "trx0undo.h"
#include "trx0roll.h" /* trx_roll_crash_recv_trx */ #include "trx0roll.h" /* trx_roll_crash_recv_trx */
#include "que0que.h" #include "que0que.h"
#include "row0row.h" #include "row0row.h"
...@@ -1363,18 +1364,31 @@ btr_cur_update_in_place_log( ...@@ -1363,18 +1364,31 @@ btr_cur_update_in_place_log(
return; return;
} }
/* The code below assumes index is a clustered index: change index to /* For secondary indexes, we could skip writing the dummy system fields
the clustered index if we are updating a secondary index record (or we to the redo log but we have to change redo log parsing of
could as well skip writing the sys col values to the log in this case MLOG_REC_UPDATE_IN_PLACE/MLOG_COMP_REC_UPDATE_IN_PLACE or we have to add
because they are not needed for a secondary index record update) */ new redo log record. For now, just write dummy sys fields to the redo
log if we are updating a secondary index record.
index = dict_table_get_first_index(index->table); */
mach_write_to_1(log_ptr, flags); mach_write_to_1(log_ptr, flags);
log_ptr++; log_ptr++;
log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr, if (index->type & DICT_CLUSTERED) {
mtr); log_ptr = row_upd_write_sys_vals_to_log(
index, trx, roll_ptr, log_ptr, mtr);
} else {
/* Dummy system fields for a secondary index */
/* TRX_ID Position */
log_ptr += mach_write_compressed(log_ptr, 0);
/* ROLL_PTR */
trx_write_roll_ptr(log_ptr, ut_dulint_zero);
log_ptr += DATA_ROLL_PTR_LEN;
/* TRX_ID */
log_ptr += mach_dulint_write_compressed(log_ptr,
ut_dulint_zero);
}
mach_write_to_2(log_ptr, page_offset(rec)); mach_write_to_2(log_ptr, page_offset(rec));
log_ptr += 2; log_ptr += 2;
......
...@@ -3024,6 +3024,24 @@ updated_in_place: ...@@ -3024,6 +3024,24 @@ updated_in_place:
/* This is the easy case. Do something similar /* This is the easy case. Do something similar
to btr_cur_update_in_place(). */ to btr_cur_update_in_place(). */
row_upd_rec_in_place(rec, offsets, update); row_upd_rec_in_place(rec, offsets, update);
/* Log the update in place operation. During recovery
MLOG_COMP_REC_UPDATE_IN_PLACE/MLOG_REC_UPDATE_IN_PLACE
expects trx_id, roll_ptr for secondary indexes. So we
just write dummy trx_id(0), roll_ptr(0) */
btr_cur_update_in_place_log(BTR_KEEP_SYS_FLAG, rec,
index, update,
NULL,
ut_dulint_zero, mtr);
DBUG_EXECUTE_IF(
"crash_after_log_ibuf_upd_inplace",
log_buffer_flush_to_disk();
fprintf(stderr,
"InnoDB: Wrote log record for ibuf "
"update in place operation\n");
DBUG_SUICIDE();
);
goto updated_in_place; goto updated_in_place;
} }
......
...@@ -558,6 +558,19 @@ btr_push_update_extern_fields( ...@@ -558,6 +558,19 @@ btr_push_update_extern_fields(
const ulint* offsets,/* in: array returned by rec_get_offsets() */ const ulint* offsets,/* in: array returned by rec_get_offsets() */
upd_t* update);/* in: update vector or NULL */ upd_t* update);/* in: update vector or NULL */
/***************************************************************
Writes a redo log record of updating a record in-place. */
UNIV_INLINE
void
btr_cur_update_in_place_log(
/*========================*/
ulint flags, /* in: flags */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: index where cursor positioned */
upd_t* update, /* in: update vector */
trx_t* trx, /* in: transaction */
dulint roll_ptr, /* in: roll ptr */
mtr_t* mtr); /* in: mtr */
/*######################################################################*/ /*######################################################################*/
......
...@@ -58,6 +58,7 @@ Created 10/16/1994 Heikki Tuuri ...@@ -58,6 +58,7 @@ Created 10/16/1994 Heikki Tuuri
#include "btr0btr.h" #include "btr0btr.h"
#include "btr0sea.h" #include "btr0sea.h"
#include "trx0rec.h" #include "trx0rec.h"
#include "trx0undo.h"
#include "trx0roll.h" /* trx_is_recv() */ #include "trx0roll.h" /* trx_is_recv() */
#include "que0que.h" #include "que0que.h"
#include "row0row.h" #include "row0row.h"
...@@ -1557,18 +1558,31 @@ btr_cur_update_in_place_log( ...@@ -1557,18 +1558,31 @@ btr_cur_update_in_place_log(
return; return;
} }
/* The code below assumes index is a clustered index: change index to /* For secondary indexes, we could skip writing the dummy system fields
the clustered index if we are updating a secondary index record (or we to the redo log but we have to change redo log parsing of
could as well skip writing the sys col values to the log in this case MLOG_REC_UPDATE_IN_PLACE/MLOG_COMP_REC_UPDATE_IN_PLACE or we have to add
because they are not needed for a secondary index record update) */ new redo log record. For now, just write dummy sys fields to the redo
log if we are updating a secondary index record.
index = dict_table_get_first_index(index->table); */
mach_write_to_1(log_ptr, flags); mach_write_to_1(log_ptr, flags);
log_ptr++; log_ptr++;
log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr, if (index->type & DICT_CLUSTERED) {
mtr); log_ptr = row_upd_write_sys_vals_to_log(
index, trx, roll_ptr, log_ptr, mtr);
} else {
/* Dummy system fields for a secondary index */
/* TRX_ID Position */
log_ptr += mach_write_compressed(log_ptr, 0);
/* ROLL_PTR */
trx_write_roll_ptr(log_ptr, ut_dulint_zero);
log_ptr += DATA_ROLL_PTR_LEN;
/* TRX_ID */
log_ptr += mach_dulint_write_compressed(log_ptr,
ut_dulint_zero);
}
mach_write_to_2(log_ptr, page_offset(rec)); mach_write_to_2(log_ptr, page_offset(rec));
log_ptr += 2; log_ptr += 2;
......
...@@ -3072,6 +3072,24 @@ updated_in_place: ...@@ -3072,6 +3072,24 @@ updated_in_place:
to btr_cur_update_in_place(). */ to btr_cur_update_in_place(). */
row_upd_rec_in_place(rec, index, offsets, row_upd_rec_in_place(rec, index, offsets,
update, page_zip); update, page_zip);
/* Log the update in place operation. During recovery
MLOG_COMP_REC_UPDATE_IN_PLACE/MLOG_REC_UPDATE_IN_PLACE
expects trx_id, roll_ptr for secondary indexes. So we
just write dummy trx_id(0), roll_ptr(0) */
btr_cur_update_in_place_log(BTR_KEEP_SYS_FLAG, rec,
index, update,
NULL,
ut_dulint_zero, mtr);
DBUG_EXECUTE_IF(
"crash_after_log_ibuf_upd_inplace",
log_buffer_flush_to_disk();
fprintf(stderr,
"InnoDB: Wrote log record for ibuf "
"update in place operation\n");
DBUG_SUICIDE();
);
goto updated_in_place; goto updated_in_place;
} }
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -636,6 +636,21 @@ btr_push_update_extern_fields( ...@@ -636,6 +636,21 @@ btr_push_update_extern_fields(
mem_heap_t* heap) /*!< in: memory heap */ mem_heap_t* heap) /*!< in: memory heap */
__attribute__((nonnull)); __attribute__((nonnull));
/***********************************************************//**
Writes a redo log record of updating a record in-place. */
UNIV_INLINE
void
btr_cur_update_in_place_log(
/*========================*/
ulint flags, /*!< in: flags */
rec_t* rec, /*!< in: record */
dict_index_t* index, /*!< in: index where cursor
positioned */
const upd_t* update, /*!< in: update vector */
trx_t* trx, /*!< in: transaction */
roll_ptr_t roll_ptr, /*!< in: roll ptr */
mtr_t* mtr); /*!< in: mtr */
/*######################################################################*/ /*######################################################################*/
/** In the pessimistic delete, if the page data size drops below this /** In the pessimistic delete, if the page data size drops below this
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment