mirror of
https://github.com/MariaDB/server.git
synced 2026-05-10 09:04:29 +02:00
Bug#12612184 Race condition after btr_cur_pessimistic_update()
btr_cur_compress_if_useful(), btr_compress(): Add the parameter ibool adjust. If adjust=TRUE, adjust the cursor position after compressing the page. btr_lift_page_up(): Return a pointer to the father page. BTR_KEEP_POS_FLAG: A new flag for btr_cur_pessimistic_update(). btr_cur_pessimistic_update(): If *big_rec != NULL and flags & BTR_KEEP_POS_FLAG, keep the cursor positioned on the updated record. Also, do not release the index tree x-lock if *big_rec != NULL. btr_cur_mtr_commit_and_start(): Commits and restarts a mini-transaction so that it will retain an x-lock on index->lock and the page of the cursor. This is invoked when btr_cur_pessimistic_update() returns *big_rec != NULL. In all callers of btr_cur_pessimistic_update() that do not pass BTR_KEEP_POS_FLAG, assert that *big_rec == NULL. btr_cur_compress(): Unused function [in the built-in MySQL 5.1], remove. page_rec_get_nth(): Return the nth record on the page (an inverse function of page_rec_get_n_recs_before()). Refactored from page_get_middle_rec(). page_get_middle_rec(): Invoke page_rec_get_nth(). page_cur_insert_rec_zip_reorg(): Make use of the page directory shortcuts in page_rec_get_nth() instead of scanning the whole list of records. row_ins_clust_index_entry_by_modify(): Pass BTR_KEEP_POS_FLAG to btr_cur_pessimistic_update(). row_ins_index_entry_low(): If row_ins_clust_index_entry_by_modify() returns a big_rec, invoke btr_cur_mtr_commit_and_start() in order to commit and start the mini-transaction without releasing the x-locks on index->lock and the cursor page, and write the big_rec. Releasing the page latch in mtr_commit() caused a race condition. row_upd_clust_rec(): Pass BTR_KEEP_POS_FLAG to btr_cur_pessimistic_update(). If it returns a big_rec, invoke btr_cur_mtr_commit_and_start() in order to commit and start the mini-transaction without releasing the x-locks on index->lock and the cursor page, and write the big_rec. Releasing the page latch in mtr_commit() caused a race condition. sync_thread_add_level(): Add the parameter ibool relock. When TRUE, bypass the latching order rules. rw_lock_add_debug_info(): For nested X-lock requests, pass relock=TRUE to sync_thread_add_level(). rb:678 approved by Jimmy Yang
This commit is contained in:
parent
a862937699
commit
5b4ceba58d
34 changed files with 650 additions and 223 deletions
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1994, 2011, 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
|
||||
|
|
@ -470,11 +470,14 @@ UNIV_INTERN
|
|||
ibool
|
||||
btr_compress(
|
||||
/*=========*/
|
||||
btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift;
|
||||
the page must not be empty: in record delete
|
||||
use btr_discard_page if the page would become
|
||||
empty */
|
||||
mtr_t* mtr); /*!< in: mtr */
|
||||
btr_cur_t* cursor, /*!< in/out: cursor on the page to merge
|
||||
or lift; the page must not be empty:
|
||||
when deleting records, use btr_discard_page()
|
||||
if the page would become empty */
|
||||
ibool adjust, /*!< in: TRUE if should adjust the
|
||||
cursor position even if compression occurs */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull));
|
||||
/*************************************************************//**
|
||||
Discards a page from a B-tree. This is used to remove the last record from
|
||||
a B-tree page: the whole page must be removed at the same time. This cannot
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1994, 2011, 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
|
||||
|
|
@ -36,6 +36,9 @@ Created 10/16/1994 Heikki Tuuri
|
|||
#define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */
|
||||
#define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the
|
||||
update vector or inserted entry */
|
||||
#define BTR_KEEP_POS_FLAG 8 /* btr_cur_pessimistic_update()
|
||||
must keep cursor position when
|
||||
moving columns to big_rec */
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
#include "que0types.h"
|
||||
|
|
@ -309,7 +312,9 @@ btr_cur_pessimistic_update(
|
|||
/*=======================*/
|
||||
ulint flags, /*!< in: undo logging, locking, and rollback
|
||||
flags */
|
||||
btr_cur_t* cursor, /*!< in: cursor on the record to update */
|
||||
btr_cur_t* cursor, /*!< in/out: cursor on the record to update;
|
||||
cursor may become invalid if *big_rec == NULL
|
||||
|| !(flags & BTR_KEEP_POS_FLAG) */
|
||||
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
|
||||
big_rec_t** big_rec,/*!< out: big rec vector whose fields have to
|
||||
be stored externally by the caller, or NULL */
|
||||
|
|
@ -321,6 +326,16 @@ btr_cur_pessimistic_update(
|
|||
que_thr_t* thr, /*!< in: query thread */
|
||||
mtr_t* mtr); /*!< in: mtr; must be committed before
|
||||
latching any further pages */
|
||||
/*****************************************************************
|
||||
Commits and restarts a mini-transaction so that it will retain an
|
||||
x-lock on index->lock and the cursor page. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
btr_cur_mtr_commit_and_start(
|
||||
/*=========================*/
|
||||
btr_cur_t* cursor, /*!< in: cursor */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull));
|
||||
/***********************************************************//**
|
||||
Marks a clustered index record deleted. Writes an undo log record to
|
||||
undo log on this delete marking. Writes in the trx id field the id
|
||||
|
|
@ -376,10 +391,13 @@ UNIV_INTERN
|
|||
ibool
|
||||
btr_cur_compress_if_useful(
|
||||
/*=======================*/
|
||||
btr_cur_t* cursor, /*!< in: cursor on the page to compress;
|
||||
btr_cur_t* cursor, /*!< in/out: cursor on the page to compress;
|
||||
cursor does not stay valid if compression
|
||||
occurs */
|
||||
mtr_t* mtr); /*!< in: mtr */
|
||||
ibool adjust, /*!< in: TRUE if should adjust the
|
||||
cursor position even if compression occurs */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull));
|
||||
/*******************************************************//**
|
||||
Removes the record on which the tree cursor is positioned. It is assumed
|
||||
that the mtr has an x-latch on the page where the cursor is positioned,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1994, 2011, 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
|
||||
|
|
@ -139,7 +139,7 @@ btr_cur_compress_recommendation(
|
|||
btr_cur_t* cursor, /*!< in: btr cursor */
|
||||
mtr_t* mtr) /*!< in: mtr */
|
||||
{
|
||||
page_t* page;
|
||||
const page_t* page;
|
||||
|
||||
ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
|
||||
MTR_MEMO_PAGE_X_FIX));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1995, 2011, 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
|
||||
|
|
@ -467,6 +467,31 @@ buf_block_get_modify_clock(
|
|||
#else /* !UNIV_HOTBACKUP */
|
||||
# define buf_block_modify_clock_inc(block) ((void) 0)
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
/*******************************************************************//**
|
||||
Increments the bufferfix count. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_block_buf_fix_inc_func(
|
||||
/*=======================*/
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
const char* file, /*!< in: file name */
|
||||
ulint line, /*!< in: line */
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
buf_block_t* block) /*!< in/out: block to bufferfix */
|
||||
__attribute__((nonnull));
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
/** Increments the bufferfix count.
|
||||
@param b in/out: block to bufferfix
|
||||
@param f in: file name where requested
|
||||
@param l in: line number where requested */
|
||||
# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b)
|
||||
#else /* UNIV_SYNC_DEBUG */
|
||||
/** Increments the bufferfix count.
|
||||
@param b in/out: block to bufferfix
|
||||
@param f in: file name where requested
|
||||
@param l in: line number where requested */
|
||||
# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b)
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
/********************************************************************//**
|
||||
Calculates a page checksum which is stored to the page when it is written
|
||||
to a file. Note that we must be careful to calculate the same value
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
|
|
@ -871,19 +871,6 @@ buf_block_buf_fix_inc_func(
|
|||
|
||||
block->page.buf_fix_count++;
|
||||
}
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
/** Increments the bufferfix count.
|
||||
@param b in/out: block to bufferfix
|
||||
@param f in: file name where requested
|
||||
@param l in: line number where requested */
|
||||
# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b)
|
||||
#else /* UNIV_SYNC_DEBUG */
|
||||
/** Increments the bufferfix count.
|
||||
@param b in/out: block to bufferfix
|
||||
@param f in: file name where requested
|
||||
@param l in: line number where requested */
|
||||
# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b)
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
|
||||
/*******************************************************************//**
|
||||
Decrements the bufferfix count. */
|
||||
|
|
@ -1071,7 +1058,7 @@ buf_block_dbg_add_level(
|
|||
where we have acquired latch */
|
||||
ulint level) /*!< in: latching order level */
|
||||
{
|
||||
sync_thread_add_level(&block->lock, level);
|
||||
sync_thread_add_level(&block->lock, level, FALSE);
|
||||
}
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1994, 2011, 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
|
||||
|
|
@ -27,6 +27,8 @@ Created 10/4/1994 Heikki Tuuri
|
|||
#include "buf0types.h"
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
# include "rem0cmp.h"
|
||||
|
||||
/*********************************************************//**
|
||||
Gets pointer to the page frame where the cursor is positioned.
|
||||
@return page */
|
||||
|
|
@ -268,6 +270,7 @@ page_cur_tuple_insert(
|
|||
index, rec, offsets, mtr);
|
||||
}
|
||||
|
||||
ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, offsets));
|
||||
mem_heap_free(heap);
|
||||
return(rec);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1994, 2011, 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
|
||||
|
|
@ -284,16 +284,42 @@ page_get_supremum_offset(
|
|||
const page_t* page); /*!< in: page which must have record(s) */
|
||||
#define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page))
|
||||
#define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page))
|
||||
|
||||
/************************************************************//**
|
||||
Returns the middle record of record list. If there are an even number
|
||||
of records in the list, returns the first record of upper half-list.
|
||||
@return middle record */
|
||||
Returns the nth record of the record list.
|
||||
This is the inverse function of page_rec_get_n_recs_before().
|
||||
@return nth record */
|
||||
UNIV_INTERN
|
||||
const rec_t*
|
||||
page_rec_get_nth_const(
|
||||
/*===================*/
|
||||
const page_t* page, /*!< in: page */
|
||||
ulint nth) /*!< in: nth record */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
/************************************************************//**
|
||||
Returns the nth record of the record list.
|
||||
This is the inverse function of page_rec_get_n_recs_before().
|
||||
@return nth record */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
page_rec_get_nth(
|
||||
/*=============*/
|
||||
page_t* page, /*< in: page */
|
||||
ulint nth) /*!< in: nth record */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/************************************************************//**
|
||||
Returns the middle record of the records on the page. If there is an
|
||||
even number of records in the list, returns the first record of the
|
||||
upper half-list.
|
||||
@return middle record */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
page_get_middle_rec(
|
||||
/*================*/
|
||||
page_t* page); /*!< in: page */
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
page_t* page) /*!< in: page */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
/*************************************************************//**
|
||||
Compares a data tuple to a physical record. Differs from the function
|
||||
cmp_dtuple_rec_with_match in the way that the record must reside on an
|
||||
|
|
@ -348,6 +374,7 @@ page_get_n_recs(
|
|||
/***************************************************************//**
|
||||
Returns the number of records before the given record in chain.
|
||||
The number includes infimum and supremum records.
|
||||
This is the inverse function of page_rec_get_nth().
|
||||
@return number of records */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1994, 2011, 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
|
||||
|
|
@ -420,7 +420,37 @@ page_rec_is_infimum(
|
|||
return(page_rec_is_infimum_low(page_offset(rec)));
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
Returns the nth record of the record list.
|
||||
This is the inverse function of page_rec_get_n_recs_before().
|
||||
@return nth record */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
page_rec_get_nth(
|
||||
/*=============*/
|
||||
page_t* page, /*!< in: page */
|
||||
ulint nth) /*!< in: nth record */
|
||||
{
|
||||
return((rec_t*) page_rec_get_nth_const(page, nth));
|
||||
}
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/************************************************************//**
|
||||
Returns the middle record of the records on the page. If there is an
|
||||
even number of records in the list, returns the first record of the
|
||||
upper half-list.
|
||||
@return middle record */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
page_get_middle_rec(
|
||||
/*================*/
|
||||
page_t* page) /*!< in: page */
|
||||
{
|
||||
ulint middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2;
|
||||
|
||||
return(page_rec_get_nth(page, middle));
|
||||
}
|
||||
|
||||
/*************************************************************//**
|
||||
Compares a data tuple to a physical record. Differs from the function
|
||||
cmp_dtuple_rec_with_match in the way that the record must reside on an
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
|
|
@ -603,16 +603,16 @@ rw_lock_x_unlock_direct(
|
|||
|
||||
ut_ad((lock->lock_word % X_LOCK_DECR) == 0);
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
|
||||
#endif
|
||||
|
||||
if (lock->lock_word == 0) {
|
||||
lock->recursive = FALSE;
|
||||
UNIV_MEM_INVALID(&lock->writer_thread,
|
||||
sizeof lock->writer_thread);
|
||||
}
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
|
||||
#endif
|
||||
|
||||
lock->lock_word += X_LOCK_DECR;
|
||||
|
||||
ut_ad(!lock->waiters);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
|
||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
|
|
@ -219,8 +219,10 @@ void
|
|||
sync_thread_add_level(
|
||||
/*==================*/
|
||||
void* latch, /*!< in: pointer to a mutex or an rw-lock */
|
||||
ulint level); /*!< in: level in the latching order; if
|
||||
ulint level, /*!< in: level in the latching order; if
|
||||
SYNC_LEVEL_VARYING, nothing is done */
|
||||
ibool relock) /*!< in: TRUE if re-entering an x-lock */
|
||||
__attribute__((nonnull));
|
||||
/******************************************************************//**
|
||||
Removes a latch from the thread level array if it is found there.
|
||||
@return TRUE if found in the array; it is no error if the latch is
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue