Commit d82eaad5 authored by Marko Mäkelä's avatar Marko Mäkelä

Bug#16138582 MTR_MEMO_RELEASE AND DYN_ARRAY TOGETHER ARE VERY INEFFICIENT

Get rid of O(n^2) scan in dyn array (mtr->memo) operations, accessing
the dyn array blocks directly.

dyn_array_get_last_block(), dyn_array_get_next_block(),
dyn_array_get_prev_block(): Define as a constness-preserving macro.

Add const qualifiers to many dyn_array functions.

mtr_memo_slot_release_func(): Renamed from mtr_memo_slot_release():
Make mtr_t* a debug-only parameter. Assume that slot->object != NULL.

mtr_memo_pop_all(): Access the dyn_array blocks directly, replacing
O(n^2) operation with O(n).

mtr_memo_release(): Access the dyn_array blocks directly, replacing
O(n^2) operation with O(n). This caused the performance problem.

rb#1540 approved by Jimmy Yang
parent b29e22d5
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 1996, 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
...@@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ...@@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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 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 this program; if not, write to the Free Software Foundation, Inc.,
Place, Suite 330, Boston, MA 02111-1307 USA 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/ *****************************************************************************/
...@@ -35,7 +35,7 @@ UNIV_INTERN ...@@ -35,7 +35,7 @@ UNIV_INTERN
dyn_block_t* dyn_block_t*
dyn_array_add_block( dyn_array_add_block(
/*================*/ /*================*/
dyn_array_t* arr) /*!< in: dyn array */ dyn_array_t* arr) /*!< in/out: dyn array */
{ {
mem_heap_t* heap; mem_heap_t* heap;
dyn_block_t* block; dyn_block_t* block;
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 1996, 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
...@@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ...@@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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 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 this program; if not, write to the Free Software Foundation, Inc.,
Place, Suite 330, Boston, MA 02111-1307 USA 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/ *****************************************************************************/
...@@ -47,15 +47,17 @@ UNIV_INLINE ...@@ -47,15 +47,17 @@ UNIV_INLINE
dyn_array_t* dyn_array_t*
dyn_array_create( dyn_array_create(
/*=============*/ /*=============*/
dyn_array_t* arr); /*!< in: pointer to a memory buffer of dyn_array_t* arr) /*!< in/out memory buffer of
size sizeof(dyn_array_t) */ size sizeof(dyn_array_t) */
__attribute__((nonnull));
/************************************************************//** /************************************************************//**
Frees a dynamic array. */ Frees a dynamic array. */
UNIV_INLINE UNIV_INLINE
void void
dyn_array_free( dyn_array_free(
/*===========*/ /*===========*/
dyn_array_t* arr); /*!< in: dyn array */ dyn_array_t* arr) /*!< in,own: dyn array */
__attribute__((nonnull));
/*********************************************************************//** /*********************************************************************//**
Makes room on top of a dyn array and returns a pointer to a buffer in it. Makes room on top of a dyn array and returns a pointer to a buffer in it.
After copying the elements, the caller must close the buffer using After copying the elements, the caller must close the buffer using
...@@ -66,8 +68,9 @@ byte* ...@@ -66,8 +68,9 @@ byte*
dyn_array_open( dyn_array_open(
/*===========*/ /*===========*/
dyn_array_t* arr, /*!< in: dynamic array */ dyn_array_t* arr, /*!< in: dynamic array */
ulint size); /*!< in: size in bytes of the buffer; MUST be ulint size) /*!< in: size in bytes of the buffer; MUST be
smaller than DYN_ARRAY_DATA_SIZE! */ smaller than DYN_ARRAY_DATA_SIZE! */
__attribute__((nonnull, warn_unused_result));
/*********************************************************************//** /*********************************************************************//**
Closes the buffer returned by dyn_array_open. */ Closes the buffer returned by dyn_array_open. */
UNIV_INLINE UNIV_INLINE
...@@ -75,7 +78,8 @@ void ...@@ -75,7 +78,8 @@ void
dyn_array_close( dyn_array_close(
/*============*/ /*============*/
dyn_array_t* arr, /*!< in: dynamic array */ dyn_array_t* arr, /*!< in: dynamic array */
byte* ptr); /*!< in: buffer space from ptr up was not used */ const byte* ptr) /*!< in: end of used space */
__attribute__((nonnull));
/*********************************************************************//** /*********************************************************************//**
Makes room on top of a dyn array and returns a pointer to Makes room on top of a dyn array and returns a pointer to
the added element. The caller must copy the element to the added element. The caller must copy the element to
...@@ -85,8 +89,9 @@ UNIV_INLINE ...@@ -85,8 +89,9 @@ UNIV_INLINE
void* void*
dyn_array_push( dyn_array_push(
/*===========*/ /*===========*/
dyn_array_t* arr, /*!< in: dynamic array */ dyn_array_t* arr, /*!< in/out: dynamic array */
ulint size); /*!< in: size in bytes of the element */ ulint size) /*!< in: size in bytes of the element */
__attribute__((nonnull, warn_unused_result));
/************************************************************//** /************************************************************//**
Returns pointer to an element in dyn array. Returns pointer to an element in dyn array.
@return pointer to element */ @return pointer to element */
...@@ -94,9 +99,10 @@ UNIV_INLINE ...@@ -94,9 +99,10 @@ UNIV_INLINE
void* void*
dyn_array_get_element( dyn_array_get_element(
/*==================*/ /*==================*/
dyn_array_t* arr, /*!< in: dyn array */ const dyn_array_t* arr, /*!< in: dyn array */
ulint pos); /*!< in: position of element as bytes ulint pos) /*!< in: position of element
from array start */ in bytes from array start */
__attribute__((nonnull, warn_unused_result));
/************************************************************//** /************************************************************//**
Returns the size of stored data in a dyn array. Returns the size of stored data in a dyn array.
@return data size in bytes */ @return data size in bytes */
...@@ -104,30 +110,33 @@ UNIV_INLINE ...@@ -104,30 +110,33 @@ UNIV_INLINE
ulint ulint
dyn_array_get_data_size( dyn_array_get_data_size(
/*====================*/ /*====================*/
dyn_array_t* arr); /*!< in: dyn array */ const dyn_array_t* arr) /*!< in: dyn array */
__attribute__((nonnull, warn_unused_result, pure));
/************************************************************//** /************************************************************//**
Gets the first block in a dyn array. */ Gets the first block in a dyn array.
UNIV_INLINE @param arr dyn array
dyn_block_t* @return first block */
dyn_array_get_first_block( #define dyn_array_get_first_block(arr) (arr)
/*======================*/
dyn_array_t* arr); /*!< in: dyn array */
/************************************************************//** /************************************************************//**
Gets the last block in a dyn array. */ Gets the last block in a dyn array.
UNIV_INLINE @param arr dyn array
dyn_block_t* @return last block */
dyn_array_get_last_block( #define dyn_array_get_last_block(arr) \
/*=====================*/ ((arr)->heap ? UT_LIST_GET_LAST((arr)->base) : (arr))
dyn_array_t* arr); /*!< in: dyn array */
/********************************************************************//** /********************************************************************//**
Gets the next block in a dyn array. Gets the next block in a dyn array.
@return pointer to next, NULL if end of list */ @param arr dyn array
UNIV_INLINE @param block dyn array block
dyn_block_t* @return pointer to next, NULL if end of list */
dyn_array_get_next_block( #define dyn_array_get_next_block(arr, block) \
/*=====================*/ ((arr)->heap ? UT_LIST_GET_NEXT(list, block) : NULL)
dyn_array_t* arr, /*!< in: dyn array */ /********************************************************************//**
dyn_block_t* block); /*!< in: dyn array block */ Gets the previous block in a dyn array.
@param arr dyn array
@param block dyn array block
@return pointer to previous, NULL if end of list */
#define dyn_array_get_prev_block(arr, block) \
((arr)->heap ? UT_LIST_GET_PREV(list, block) : NULL)
/********************************************************************//** /********************************************************************//**
Gets the number of used bytes in a dyn array block. Gets the number of used bytes in a dyn array block.
@return number of bytes used */ @return number of bytes used */
...@@ -135,7 +144,8 @@ UNIV_INLINE ...@@ -135,7 +144,8 @@ UNIV_INLINE
ulint ulint
dyn_block_get_used( dyn_block_get_used(
/*===============*/ /*===============*/
dyn_block_t* block); /*!< in: dyn array block */ const dyn_block_t* block) /*!< in: dyn array block */
__attribute__((nonnull, warn_unused_result, pure));
/********************************************************************//** /********************************************************************//**
Gets pointer to the start of data in a dyn array block. Gets pointer to the start of data in a dyn array block.
@return pointer to data */ @return pointer to data */
...@@ -143,16 +153,18 @@ UNIV_INLINE ...@@ -143,16 +153,18 @@ UNIV_INLINE
byte* byte*
dyn_block_get_data( dyn_block_get_data(
/*===============*/ /*===============*/
dyn_block_t* block); /*!< in: dyn array block */ const dyn_block_t* block) /*!< in: dyn array block */
__attribute__((nonnull, warn_unused_result, pure));
/********************************************************//** /********************************************************//**
Pushes n bytes to a dyn array. */ Pushes n bytes to a dyn array. */
UNIV_INLINE UNIV_INLINE
void void
dyn_push_string( dyn_push_string(
/*============*/ /*============*/
dyn_array_t* arr, /*!< in: dyn array */ dyn_array_t* arr, /*!< in/out: dyn array */
const byte* str, /*!< in: string to write */ const byte* str, /*!< in: string to write */
ulint len); /*!< in: string length */ ulint len) /*!< in: string length */
__attribute__((nonnull));
/*#################################################################*/ /*#################################################################*/
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 1996, 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
...@@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ...@@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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 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 this program; if not, write to the Free Software Foundation, Inc.,
Place, Suite 330, Boston, MA 02111-1307 USA 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/ *****************************************************************************/
...@@ -35,56 +35,8 @@ UNIV_INTERN ...@@ -35,56 +35,8 @@ UNIV_INTERN
dyn_block_t* dyn_block_t*
dyn_array_add_block( dyn_array_add_block(
/*================*/ /*================*/
dyn_array_t* arr); /*!< in: dyn array */ dyn_array_t* arr) /*!< in/out: dyn array */
__attribute__((nonnull, warn_unused_result));
/************************************************************//**
Gets the first block in a dyn array. */
UNIV_INLINE
dyn_block_t*
dyn_array_get_first_block(
/*======================*/
dyn_array_t* arr) /*!< in: dyn array */
{
return(arr);
}
/************************************************************//**
Gets the last block in a dyn array. */
UNIV_INLINE
dyn_block_t*
dyn_array_get_last_block(
/*=====================*/
dyn_array_t* arr) /*!< in: dyn array */
{
if (arr->heap == NULL) {
return(arr);
}
return(UT_LIST_GET_LAST(arr->base));
}
/********************************************************************//**
Gets the next block in a dyn array.
@return pointer to next, NULL if end of list */
UNIV_INLINE
dyn_block_t*
dyn_array_get_next_block(
/*=====================*/
dyn_array_t* arr, /*!< in: dyn array */
dyn_block_t* block) /*!< in: dyn array block */
{
ut_ad(arr && block);
if (arr->heap == NULL) {
ut_ad(arr == block);
return(NULL);
}
return(UT_LIST_GET_NEXT(list, block));
}
/********************************************************************//** /********************************************************************//**
Gets the number of used bytes in a dyn array block. Gets the number of used bytes in a dyn array block.
...@@ -93,7 +45,7 @@ UNIV_INLINE ...@@ -93,7 +45,7 @@ UNIV_INLINE
ulint ulint
dyn_block_get_used( dyn_block_get_used(
/*===============*/ /*===============*/
dyn_block_t* block) /*!< in: dyn array block */ const dyn_block_t* block) /*!< in: dyn array block */
{ {
ut_ad(block); ut_ad(block);
...@@ -107,11 +59,11 @@ UNIV_INLINE ...@@ -107,11 +59,11 @@ UNIV_INLINE
byte* byte*
dyn_block_get_data( dyn_block_get_data(
/*===============*/ /*===============*/
dyn_block_t* block) /*!< in: dyn array block */ const dyn_block_t* block) /*!< in: dyn array block */
{ {
ut_ad(block); ut_ad(block);
return(block->data); return((byte*) block->data);
} }
/*********************************************************************//** /*********************************************************************//**
...@@ -121,7 +73,7 @@ UNIV_INLINE ...@@ -121,7 +73,7 @@ UNIV_INLINE
dyn_array_t* dyn_array_t*
dyn_array_create( dyn_array_create(
/*=============*/ /*=============*/
dyn_array_t* arr) /*!< in: pointer to a memory buffer of dyn_array_t* arr) /*!< in/out: memory buffer of
size sizeof(dyn_array_t) */ size sizeof(dyn_array_t) */
{ {
ut_ad(arr); ut_ad(arr);
...@@ -132,10 +84,9 @@ dyn_array_create( ...@@ -132,10 +84,9 @@ dyn_array_create(
arr->heap = NULL; arr->heap = NULL;
arr->used = 0; arr->used = 0;
#ifdef UNIV_DEBUG ut_d(arr->buf_end = 0);
arr->buf_end = 0; ut_d(arr->magic_n = DYN_BLOCK_MAGIC_N);
arr->magic_n = DYN_BLOCK_MAGIC_N;
#endif
return(arr); return(arr);
} }
...@@ -151,9 +102,7 @@ dyn_array_free( ...@@ -151,9 +102,7 @@ dyn_array_free(
mem_heap_free(arr->heap); mem_heap_free(arr->heap);
} }
#ifdef UNIV_DEBUG ut_d(arr->magic_n = 0);
arr->magic_n = 0;
#endif
} }
/*********************************************************************//** /*********************************************************************//**
...@@ -164,7 +113,7 @@ UNIV_INLINE ...@@ -164,7 +113,7 @@ UNIV_INLINE
void* void*
dyn_array_push( dyn_array_push(
/*===========*/ /*===========*/
dyn_array_t* arr, /*!< in: dynamic array */ dyn_array_t* arr, /*!< in/out: dynamic array */
ulint size) /*!< in: size in bytes of the element */ ulint size) /*!< in: size in bytes of the element */
{ {
dyn_block_t* block; dyn_block_t* block;
...@@ -176,24 +125,23 @@ dyn_array_push( ...@@ -176,24 +125,23 @@ dyn_array_push(
ut_ad(size); ut_ad(size);
block = arr; block = arr;
used = block->used;
if (used + size > DYN_ARRAY_DATA_SIZE) { if (block->used + size > DYN_ARRAY_DATA_SIZE) {
/* Get the last array block */ /* Get the last array block */
block = dyn_array_get_last_block(arr); block = dyn_array_get_last_block(arr);
used = block->used;
if (used + size > DYN_ARRAY_DATA_SIZE) { if (block->used + size > DYN_ARRAY_DATA_SIZE) {
block = dyn_array_add_block(arr); block = dyn_array_add_block(arr);
used = block->used;
} }
} }
used = block->used;
block->used = used + size; block->used = used + size;
ut_ad(block->used <= DYN_ARRAY_DATA_SIZE); ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
return((block->data) + used); return(block->data + used);
} }
/*********************************************************************//** /*********************************************************************//**
...@@ -210,7 +158,6 @@ dyn_array_open( ...@@ -210,7 +158,6 @@ dyn_array_open(
smaller than DYN_ARRAY_DATA_SIZE! */ smaller than DYN_ARRAY_DATA_SIZE! */
{ {
dyn_block_t* block; dyn_block_t* block;
ulint used;
ut_ad(arr); ut_ad(arr);
ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
...@@ -218,28 +165,23 @@ dyn_array_open( ...@@ -218,28 +165,23 @@ dyn_array_open(
ut_ad(size); ut_ad(size);
block = arr; block = arr;
used = block->used;
if (used + size > DYN_ARRAY_DATA_SIZE) { if (block->used + size > DYN_ARRAY_DATA_SIZE) {
/* Get the last array block */ /* Get the last array block */
block = dyn_array_get_last_block(arr); block = dyn_array_get_last_block(arr);
used = block->used;
if (used + size > DYN_ARRAY_DATA_SIZE) { if (block->used + size > DYN_ARRAY_DATA_SIZE) {
block = dyn_array_add_block(arr); block = dyn_array_add_block(arr);
used = block->used;
ut_a(size <= DYN_ARRAY_DATA_SIZE); ut_a(size <= DYN_ARRAY_DATA_SIZE);
} }
} }
ut_ad(block->used <= DYN_ARRAY_DATA_SIZE); ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
#ifdef UNIV_DEBUG
ut_ad(arr->buf_end == 0); ut_ad(arr->buf_end == 0);
ut_d(arr->buf_end = block->used + size);
arr->buf_end = used + size; return(block->data + block->used);
#endif
return((block->data) + used);
} }
/*********************************************************************//** /*********************************************************************//**
...@@ -248,8 +190,8 @@ UNIV_INLINE ...@@ -248,8 +190,8 @@ UNIV_INLINE
void void
dyn_array_close( dyn_array_close(
/*============*/ /*============*/
dyn_array_t* arr, /*!< in: dynamic array */ dyn_array_t* arr, /*!< in/out: dynamic array */
byte* ptr) /*!< in: buffer space from ptr up was not used */ const byte* ptr) /*!< in: end of used space */
{ {
dyn_block_t* block; dyn_block_t* block;
...@@ -264,9 +206,7 @@ dyn_array_close( ...@@ -264,9 +206,7 @@ dyn_array_close(
ut_ad(block->used <= DYN_ARRAY_DATA_SIZE); ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
#ifdef UNIV_DEBUG ut_d(arr->buf_end = 0);
arr->buf_end = 0;
#endif
} }
/************************************************************//** /************************************************************//**
...@@ -276,12 +216,11 @@ UNIV_INLINE ...@@ -276,12 +216,11 @@ UNIV_INLINE
void* void*
dyn_array_get_element( dyn_array_get_element(
/*==================*/ /*==================*/
dyn_array_t* arr, /*!< in: dyn array */ const dyn_array_t* arr, /*!< in: dyn array */
ulint pos) /*!< in: position of element as bytes ulint pos) /*!< in: position of element
from array start */ in bytes from array start */
{ {
dyn_block_t* block; const dyn_block_t* block;
ulint used;
ut_ad(arr); ut_ad(arr);
ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
...@@ -290,21 +229,23 @@ dyn_array_get_element( ...@@ -290,21 +229,23 @@ dyn_array_get_element(
block = dyn_array_get_first_block(arr); block = dyn_array_get_first_block(arr);
if (arr->heap != NULL) { if (arr->heap != NULL) {
used = dyn_block_get_used(block); for (;;) {
ulint used = dyn_block_get_used(block);
if (pos < used) {
break;
}
while (pos >= used) {
pos -= used; pos -= used;
block = UT_LIST_GET_NEXT(list, block); block = UT_LIST_GET_NEXT(list, block);
ut_ad(block); ut_ad(block);
used = dyn_block_get_used(block);
} }
} }
ut_ad(block); ut_ad(block);
ut_ad(dyn_block_get_used(block) >= pos); ut_ad(dyn_block_get_used(block) >= pos);
return(block->data + pos); return((byte*) block->data + pos);
} }
/************************************************************//** /************************************************************//**
...@@ -314,10 +255,10 @@ UNIV_INLINE ...@@ -314,10 +255,10 @@ UNIV_INLINE
ulint ulint
dyn_array_get_data_size( dyn_array_get_data_size(
/*====================*/ /*====================*/
dyn_array_t* arr) /*!< in: dyn array */ const dyn_array_t* arr) /*!< in: dyn array */
{ {
dyn_block_t* block; const dyn_block_t* block;
ulint sum = 0; ulint sum = 0;
ut_ad(arr); ut_ad(arr);
ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N); ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
...@@ -344,7 +285,7 @@ UNIV_INLINE ...@@ -344,7 +285,7 @@ UNIV_INLINE
void void
dyn_push_string( dyn_push_string(
/*============*/ /*============*/
dyn_array_t* arr, /*!< in: dyn array */ dyn_array_t* arr, /*!< in/out: dyn array */
const byte* str, /*!< in: string to write */ const byte* str, /*!< in: string to write */
ulint len) /*!< in: string length */ ulint len) /*!< in: string length */
{ {
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 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
...@@ -295,9 +295,10 @@ UNIV_INTERN ...@@ -295,9 +295,10 @@ UNIV_INTERN
void void
mtr_memo_release( mtr_memo_release(
/*=============*/ /*=============*/
mtr_t* mtr, /*!< in: mtr */ mtr_t* mtr, /*!< in/out: mini-transaction */
void* object, /*!< in: object */ void* object, /*!< in: object */
ulint type); /*!< in: object type: MTR_MEMO_S_LOCK, ... */ ulint type) /*!< in: object type: MTR_MEMO_S_LOCK, ... */
__attribute__((nonnull));
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
# ifndef UNIV_HOTBACKUP # ifndef UNIV_HOTBACKUP
/**********************************************************//** /**********************************************************//**
...@@ -309,7 +310,8 @@ mtr_memo_contains( ...@@ -309,7 +310,8 @@ mtr_memo_contains(
/*==============*/ /*==============*/
mtr_t* mtr, /*!< in: mtr */ mtr_t* mtr, /*!< in: mtr */
const void* object, /*!< in: object to search */ const void* object, /*!< in: object to search */
ulint type); /*!< in: type of object */ ulint type) /*!< in: type of object */
__attribute__((warn_unused_result, nonnull));
/**********************************************************//** /**********************************************************//**
Checks if memo contains the given page. Checks if memo contains the given page.
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 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
...@@ -39,72 +39,81 @@ Created 11/26/1995 Heikki Tuuri ...@@ -39,72 +39,81 @@ Created 11/26/1995 Heikki Tuuri
# include "log0recv.h" # include "log0recv.h"
/*****************************************************************//** /*****************************************************************//**
Releases the item in the slot given. */ Releases the item in the slot given. */
static static __attribute__((nonnull))
void void
mtr_memo_slot_release( mtr_memo_slot_release_func(
/*==================*/ /*=======================*/
mtr_t* mtr, /*!< in: mtr */ #ifdef UNIV_DEBUG
mtr_t* mtr, /*!< in/out: mini-transaction */
#endif /* UNIV_DEBUG */
mtr_memo_slot_t* slot) /*!< in: memo slot */ mtr_memo_slot_t* slot) /*!< in: memo slot */
{ {
void* object; void* object = slot->object;
ulint type; slot->object = NULL;
ut_ad(mtr);
ut_ad(slot);
#ifndef UNIV_DEBUG
UT_NOT_USED(mtr);
#endif /* UNIV_DEBUG */
object = slot->object;
type = slot->type;
if (UNIV_LIKELY(object != NULL)) { /* slot release is a local operation for the current mtr.
if (type <= MTR_MEMO_BUF_FIX) { We must not be holding the flush_order mutex while
buf_page_release((buf_block_t*)object, type); doing this. */
} else if (type == MTR_MEMO_S_LOCK) { ut_ad(!log_flush_order_mutex_own());
rw_lock_s_unlock((rw_lock_t*)object);
switch (slot->type) {
case MTR_MEMO_PAGE_S_FIX:
case MTR_MEMO_PAGE_X_FIX:
case MTR_MEMO_BUF_FIX:
buf_page_release((buf_block_t*) object, slot->type);
break;
case MTR_MEMO_S_LOCK:
rw_lock_s_unlock((rw_lock_t*) object);
break;
case MTR_MEMO_X_LOCK:
rw_lock_x_unlock((rw_lock_t*) object);
break;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
} else if (type != MTR_MEMO_X_LOCK) { default:
ut_ad(type == MTR_MEMO_MODIFY); ut_ad(slot->type == MTR_MEMO_MODIFY);
ut_ad(mtr_memo_contains(mtr, object, ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX));
MTR_MEMO_PAGE_X_FIX));
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
} else {
rw_lock_x_unlock((rw_lock_t*)object);
}
} }
slot->object = NULL;
} }
#ifdef UNIV_DEBUG
# define mtr_memo_slot_release(mtr, slot) mtr_memo_slot_release_func(mtr, slot)
#else /* UNIV_DEBUG */
# define mtr_memo_slot_release(mtr, slot) mtr_memo_slot_release_func(slot)
#endif /* UNIV_DEBUG */
/**********************************************************//** /**********************************************************//**
Releases the mlocks and other objects stored in an mtr memo. Releases the mlocks and other objects stored in an mtr memo.
They are released in the order opposite to which they were pushed They are released in the order opposite to which they were pushed
to the memo. */ to the memo. */
static static __attribute__((nonnull))
void void
mtr_memo_pop_all( mtr_memo_pop_all(
/*=============*/ /*=============*/
mtr_t* mtr) /*!< in: mtr */ mtr_t* mtr) /*!< in/out: mini-transaction */
{ {
mtr_memo_slot_t* slot; const dyn_block_t* block;
dyn_array_t* memo;
ulint offset;
ut_ad(mtr);
ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->magic_n == MTR_MAGIC_N);
ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
commit */ commit */
memo = &(mtr->memo);
offset = dyn_array_get_data_size(memo);
while (offset > 0) { for (block = dyn_array_get_last_block(&mtr->memo);
offset -= sizeof(mtr_memo_slot_t); block;
slot = dyn_array_get_element(memo, offset); block = dyn_array_get_prev_block(&mtr->memo, block)) {
const mtr_memo_slot_t* start
mtr_memo_slot_release(mtr, slot); = (mtr_memo_slot_t*) dyn_block_get_data(block);
mtr_memo_slot_t* slot
= (mtr_memo_slot_t*) (dyn_block_get_data(block)
+ dyn_block_get_used(block));
ut_ad(!(dyn_block_get_used(block) % sizeof(mtr_memo_slot_t)));
while (slot-- != start) {
if (slot->object != NULL) {
mtr_memo_slot_release(mtr, slot);
}
}
} }
} }
...@@ -288,42 +297,36 @@ UNIV_INTERN ...@@ -288,42 +297,36 @@ UNIV_INTERN
void void
mtr_memo_release( mtr_memo_release(
/*=============*/ /*=============*/
mtr_t* mtr, /*!< in: mtr */ mtr_t* mtr, /*!< in/out: mini-transaction */
void* object, /*!< in: object */ void* object, /*!< in: object */
ulint type) /*!< in: object type: MTR_MEMO_S_LOCK, ... */ ulint type) /*!< in: object type: MTR_MEMO_S_LOCK, ... */
{ {
mtr_memo_slot_t* slot; const dyn_block_t* block;
dyn_array_t* memo;
ulint offset;
ut_ad(mtr);
ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->magic_n == MTR_MAGIC_N);
ut_ad(mtr->state == MTR_ACTIVE); ut_ad(mtr->state == MTR_ACTIVE);
/* We cannot release a page that has been written to in the
memo = &(mtr->memo); middle of a mini-transaction. */
ut_ad(!mtr->modifications || type != MTR_MEMO_PAGE_X_FIX);
offset = dyn_array_get_data_size(memo);
for (block = dyn_array_get_last_block(&mtr->memo);
log_flush_order_mutex_enter(); block;
while (offset > 0) { block = dyn_array_get_prev_block(&mtr->memo, block)) {
offset -= sizeof(mtr_memo_slot_t); const mtr_memo_slot_t* start
= (mtr_memo_slot_t*) dyn_block_get_data(block);
slot = dyn_array_get_element(memo, offset); mtr_memo_slot_t* slot
= (mtr_memo_slot_t*) (dyn_block_get_data(block)
if (object == slot->object && type == slot->type) { + dyn_block_get_used(block));
/* We cannot release a page that has been written ut_ad(!(dyn_block_get_used(block) % sizeof(mtr_memo_slot_t)));
to in the middle of a mini-transaction. */
while (slot-- != start) {
ut_ad(!(mtr->modifications if (object == slot->object && type == slot->type) {
&& slot->type == MTR_MEMO_PAGE_X_FIX)); mtr_memo_slot_release(mtr, slot);
return;
mtr_memo_slot_release(mtr, slot); }
break;
} }
} }
log_flush_order_mutex_exit();
} }
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
......
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