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
#include "btr0sea.h"
#include "row0upd.h"
#include "trx0rec.h"
#include "trx0undo.h"
#include "trx0roll.h" /* trx_roll_crash_recv_trx */
#include "que0que.h"
#include "row0row.h"
......@@ -1363,18 +1364,31 @@ btr_cur_update_in_place_log(
return;
}
/* The code below assumes index is a clustered index: change index to
the clustered index if we are updating a secondary index record (or we
could as well skip writing the sys col values to the log in this case
because they are not needed for a secondary index record update) */
index = dict_table_get_first_index(index->table);
/* For secondary indexes, we could skip writing the dummy system fields
to the redo log but we have to change redo log parsing of
MLOG_REC_UPDATE_IN_PLACE/MLOG_COMP_REC_UPDATE_IN_PLACE or we have to add
new redo log record. For now, just write dummy sys fields to the redo
log if we are updating a secondary index record.
*/
mach_write_to_1(log_ptr, flags);
log_ptr++;
log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
mtr);
if (index->type & DICT_CLUSTERED) {
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));
log_ptr += 2;
......
......@@ -3024,6 +3024,24 @@ updated_in_place:
/* This is the easy case. Do something similar
to btr_cur_update_in_place(). */
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;
}
......
......@@ -558,6 +558,19 @@ btr_push_update_extern_fields(
const ulint* offsets,/* in: array returned by rec_get_offsets() */
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
#include "btr0btr.h"
#include "btr0sea.h"
#include "trx0rec.h"
#include "trx0undo.h"
#include "trx0roll.h" /* trx_is_recv() */
#include "que0que.h"
#include "row0row.h"
......@@ -1557,18 +1558,31 @@ btr_cur_update_in_place_log(
return;
}
/* The code below assumes index is a clustered index: change index to
the clustered index if we are updating a secondary index record (or we
could as well skip writing the sys col values to the log in this case
because they are not needed for a secondary index record update) */
index = dict_table_get_first_index(index->table);
/* For secondary indexes, we could skip writing the dummy system fields
to the redo log but we have to change redo log parsing of
MLOG_REC_UPDATE_IN_PLACE/MLOG_COMP_REC_UPDATE_IN_PLACE or we have to add
new redo log record. For now, just write dummy sys fields to the redo
log if we are updating a secondary index record.
*/
mach_write_to_1(log_ptr, flags);
log_ptr++;
log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
mtr);
if (index->type & DICT_CLUSTERED) {
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));
log_ptr += 2;
......
......@@ -3072,6 +3072,24 @@ updated_in_place:
to btr_cur_update_in_place(). */
row_upd_rec_in_place(rec, index, offsets,
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;
}
......
/*****************************************************************************
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
the terms of the GNU General Public License as published by the Free Software
......@@ -636,6 +636,21 @@ btr_push_update_extern_fields(
mem_heap_t* heap) /*!< in: memory heap */
__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
......
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