1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

Merge 10.1 into 10.2

This commit is contained in:
Marko Mäkelä
2018-05-29 16:36:16 +03:00
34 changed files with 293 additions and 222 deletions

View File

@@ -948,6 +948,8 @@ pthread_handler_t connection_thread(void *arg)
end_thread:
cn->query_done= 1;
mysql_close(cn->mysql);
cn->mysql= 0;
mysql_thread_end();
pthread_exit(0);
return 0;

View File

@@ -2345,7 +2345,18 @@ CREATE TABLE t1 (i INT);
insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
End of 10.1 tests.
#
# MDEV-16093
# Assertion `global_status_var.global_memory_used == 0' failed or
# bytes lost after inserting into table with non-null blob and trigger
#
CREATE TABLE t1 (b BLOB NOT NULL);
CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW BEGIN END;
INSERT INTO t1 VALUES ('foo');
DROP TABLE t1;
#
# End of 10.1 tests.
#
create table t1 (i int);
create trigger tr1 after insert on t1 for each row set @a=@a+1;
create trigger tr2 after insert on t1 for each row set @a=@a+1;

View File

@@ -0,0 +1,10 @@
#
# MDEV-10679
# Server crashes in in mysql_create_frm_image upon query from
# performance schema in ps-protocol mode
#
CREATE TABLE t1 (i INT);
ALTER TABLE t1 ADD PARTITION (PARTITION p VALUES LESS THAN (1));
ERROR HY000: Partition management on a not partitioned table is not possible
SELECT * FROM performance_schema.events_stages_summary_by_user_by_event_name;
DROP TABLE t1;

View File

@@ -0,0 +1,16 @@
--source include/have_perfschema.inc
--source include/have_partition.inc
--echo #
--echo # MDEV-10679
--echo # Server crashes in in mysql_create_frm_image upon query from
--echo # performance schema in ps-protocol mode
--echo #
CREATE TABLE t1 (i INT);
--error ER_PARTITION_MGMT_ON_NONPARTITIONED
ALTER TABLE t1 ADD PARTITION (PARTITION p VALUES LESS THAN (1));
--disable_result_log
SELECT * FROM performance_schema.events_stages_summary_by_user_by_event_name;
--enable_result_log
DROP TABLE t1;

View File

@@ -2665,8 +2665,20 @@ insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
--echo #
--echo # MDEV-16093
--echo # Assertion `global_status_var.global_memory_used == 0' failed or
--echo # bytes lost after inserting into table with non-null blob and trigger
--echo #
--echo End of 10.1 tests.
CREATE TABLE t1 (b BLOB NOT NULL);
CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW BEGIN END;
INSERT INTO t1 VALUES ('foo');
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests.
--echo #
#
# MDEV-10915 Count number of executed triggers

View File

@@ -1216,7 +1216,9 @@ err:
}
close_thread_tables(thd); // Shouldn't be needed
thd->mdl_context.release_transactional_locks();
#ifdef WITH_PARTITION_STORAGE_ENGINE
err2:
#endif
thd->resume_subsequent_commits(suspended_wfc);
DBUG_RETURN(TRUE);
}

View File

@@ -263,8 +263,8 @@ bool Sql_cmd_alter_table::execute(THD *thd)
- For temporary MERGE tables we do not track if their child tables are
base or temporary. As result we can't guarantee that privilege check
which was done in presence of temporary child will stay relevant later
as this temporary table might be removed.
which was done in presence of temporary child will stay relevant
later as this temporary table might be removed.
If SELECT_ACL | UPDATE_ACL | DELETE_ACL privileges were not checked for
the underlying *base* tables, it would create a security breach as in
@@ -304,6 +304,9 @@ bool Sql_cmd_alter_table::execute(THD *thd)
create_info.data_file_name= create_info.index_file_name= NULL;
thd->enable_slow_log= opt_log_slow_admin_statements;
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0;
#endif
#ifdef WITH_WSREP
if ((!thd->is_current_stmt_binlog_format_row() ||

View File

@@ -2962,10 +2962,6 @@ mysql_execute_command(THD *thd)
#endif
DBUG_ENTER("mysql_execute_command");
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0;
#endif
DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt);
/*
Each statement or replication event which might produce deadlock
@@ -3815,6 +3811,7 @@ mysql_execute_command(THD *thd)
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0;
{
partition_info *part_info= thd->lex->part_info;
if (part_info && !(part_info= part_info->get_clone(thd)))

View File

@@ -187,7 +187,16 @@ bool String::copy(const char *str,size_t arg_length, CHARSET_INFO *cs)
if (alloc(arg_length))
return TRUE;
DBUG_ASSERT(arg_length < UINT_MAX32);
if ((str_length=arg_length))
if (Ptr == str && arg_length == uint32(str_length))
{
/*
This can happen in some cases. This code is here mainly to avoid
warnings from valgrind, but can also be an indication of error.
*/
DBUG_PRINT("warning", ("Copying string on itself: %p %zu",
str, arg_length));
}
else if ((str_length=uint32(arg_length)))
memcpy(Ptr,str,arg_length);
Ptr[arg_length]=0;
str_charset=cs;

View File

@@ -6123,6 +6123,7 @@ remove_key:
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
DBUG_ASSERT(thd->work_part_info == 0);
partition_info *tab_part_info= table->part_info;
thd->work_part_info= thd->lex->part_info;
if (tab_part_info)
@@ -8719,6 +8720,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
DBUG_ENTER("mysql_alter_table");
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0; // Used by partitioning
#endif
/*
Check if we attempt to alter mysql.slow_log or
mysql.general_log table and return an error if

View File

@@ -623,6 +623,7 @@ end:
#endif /* WITH_WSREP */
}
/**
Build stmt_query to write it in the bin-log, the statement to write in
the trigger file and the trigger definer.
@@ -1182,6 +1183,12 @@ Table_triggers_list::~Table_triggers_list()
}
}
}
/* Free blobs used in insert */
if (record0_field)
for (Field **fld_ptr= record0_field; *fld_ptr; fld_ptr++)
(*fld_ptr)->free();
if (record1_field)
for (Field **fld_ptr= record1_field; *fld_ptr; fld_ptr++)
delete *fld_ptr;

View File

@@ -2663,6 +2663,9 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
goto ret;
thd->lex->create_info.db_type= hton;
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0; // For partitioning
#endif
if (tabledef_version.str)
thd->lex->create_info.tabledef_version= tabledef_version;

View File

@@ -2,7 +2,7 @@
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2017, MariaDB Corporation.
Copyright (c) 2017, 2018, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -1177,7 +1177,8 @@ retry:
#endif
ut_ad(btr_search_enabled);
ut_ad(block->page.id.space() == index->space);
ut_ad(index->space == FIL_NULL
|| block->page.id.space() == index->space);
ut_a(index_id == index->id);
ut_a(!dict_index_is_ibuf(index));
#ifdef UNIV_DEBUG
@@ -1300,15 +1301,10 @@ cleanup:
ut_free(folds);
}
/** Drop any adaptive hash index entries that may point to an index
page that may be in the buffer pool, when a page is evicted from the
buffer pool or freed in a file segment.
@param[in] page_id page id
@param[in] page_size page size */
void
btr_search_drop_page_hash_when_freed(
const page_id_t& page_id,
const page_size_t& page_size)
/** Drop possible adaptive hash index entries when a page is evicted
from the buffer pool or freed in a file, or the index is being dropped.
@param[in] page_id page id */
void btr_search_drop_page_hash_when_freed(const page_id_t& page_id)
{
buf_block_t* block;
mtr_t mtr;
@@ -1324,7 +1320,7 @@ btr_search_drop_page_hash_when_freed(
are possibly holding, we cannot s-latch the page, but must
(recursively) x-latch it, even though we are only reading. */
block = buf_page_get_gen(page_id, page_size, RW_X_LATCH, NULL,
block = buf_page_get_gen(page_id, univ_page_size, RW_X_LATCH, NULL,
BUF_PEEK_IF_IN_POOL, __FILE__, __LINE__,
&mtr, &err);

View File

@@ -4203,10 +4203,12 @@ buf_page_get_gen(
#ifdef UNIV_DEBUG
switch (mode) {
case BUF_EVICT_IF_IN_POOL:
case BUF_PEEK_IF_IN_POOL:
/* After DISCARD TABLESPACE, the tablespace would not exist,
but in IMPORT TABLESPACE, PageConverter::operator() must
replace any old pages, which were not evicted during DISCARD.
Skip the assertion on space_page_size. */
Similarly, btr_search_drop_page_hash_when_freed() must
remove any old pages. Skip the assertion on page_size. */
break;
default:
ut_error;
@@ -4215,7 +4217,6 @@ buf_page_get_gen(
/* fall through */
case BUF_GET:
case BUF_GET_IF_IN_POOL:
case BUF_PEEK_IF_IN_POOL:
case BUF_GET_IF_IN_POOL_OR_WATCH:
case BUF_GET_POSSIBLY_FREED:
bool found;

View File

@@ -224,30 +224,21 @@ buf_LRU_evict_from_unzip_LRU(
/** Attempts to drop page hash index on a batch of pages belonging to a
particular space id.
@param[in] space_id space id
@param[in] page_size page size
@param[in] arr array of page_no
@param[in] count number of entries in array */
static
void
buf_LRU_drop_page_hash_batch(
ulint space_id,
const page_size_t& page_size,
const ulint* arr,
ulint count)
buf_LRU_drop_page_hash_batch(ulint space_id, const ulint* arr, ulint count)
{
ut_ad(count <= BUF_LRU_DROP_SEARCH_SIZE);
for (ulint i = 0; i < count; ++i, ++arr) {
for (const ulint* const end = arr + count; arr != end; ) {
/* While our only caller
buf_LRU_drop_page_hash_for_tablespace()
is being executed for DROP TABLE or similar,
the table cannot be evicted from the buffer pool.
Note: this should not be executed for DROP TABLESPACE,
because DROP TABLESPACE would be refused if tables existed
in the tablespace, and a previous DROP TABLE would have
already removed the AHI entries. */
the table cannot be evicted from the buffer pool. */
btr_search_drop_page_hash_when_freed(
page_id_t(space_id, *arr), page_size);
page_id_t(space_id, *arr++));
}
}
@@ -263,15 +254,6 @@ buf_LRU_drop_page_hash_for_tablespace(
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
ulint id) /*!< in: space id */
{
bool found;
const page_size_t page_size(fil_space_get_page_size(id, &found));
if (!found) {
/* Somehow, the tablespace does not exist. Nothing to drop. */
ut_ad(0);
return;
}
ulint* page_arr = static_cast<ulint*>(ut_malloc_nokey(
sizeof(ulint) * BUF_LRU_DROP_SEARCH_SIZE));
@@ -338,8 +320,7 @@ next_page:
the latching order. */
buf_pool_mutex_exit(buf_pool);
buf_LRU_drop_page_hash_batch(
id, page_size, page_arr, num_entries);
buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
num_entries = 0;
@@ -371,9 +352,31 @@ next_page:
buf_pool_mutex_exit(buf_pool);
/* Drop any remaining batch of search hashed pages. */
buf_LRU_drop_page_hash_batch(id, page_size, page_arr, num_entries);
buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
ut_free(page_arr);
}
/** Drop the adaptive hash index for a tablespace.
@param[in,out] table table */
void buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table)
{
for (dict_index_t* index = dict_table_get_first_index(table);
index != NULL;
index = dict_table_get_next_index(index)) {
if (btr_search_info_get_ref_count(btr_search_get_info(index),
index)) {
goto drop_ahi;
}
}
return;
drop_ahi:
ulint id = table->space;
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
buf_LRU_drop_page_hash_for_tablespace(buf_pool_from_array(i),
id);
}
}
#endif /* BTR_CUR_HASH_ADAPT */
/******************************************************************//**
@@ -697,26 +700,13 @@ buf_flush_dirty_pages(
@param[in] id tablespace identifier
@param[in] observer flush observer,
or NULL if nothing is to be written */
void
buf_LRU_flush_or_remove_pages(
ulint id,
FlushObserver* observer
#ifdef BTR_CUR_HASH_ADAPT
, bool drop_ahi /*!< whether to drop the adaptive hash index */
#endif /* BTR_CUR_HASH_ADAPT */
)
void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer)
{
/* Pages in the system tablespace must never be discarded. */
ut_ad(id || observer);
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
buf_pool_t* buf_pool = buf_pool_from_array(i);
#ifdef BTR_CUR_HASH_ADAPT
if (drop_ahi) {
buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
}
#endif /* BTR_CUR_HASH_ADAPT */
buf_flush_dirty_pages(buf_pool, id, observer);
buf_flush_dirty_pages(buf_pool_from_array(i), id, observer);
}
if (observer && !observer->is_interrupted()) {

View File

@@ -1649,11 +1649,7 @@ dict_table_rename_in_cache(
return(DB_OUT_OF_MEMORY);
}
fil_delete_tablespace(table->space
#ifdef BTR_CUR_HASH_ADAPT
, true
#endif /* BTR_CUR_HASH_ADAPT */
);
fil_delete_tablespace(table->space);
/* Delete any temp file hanging around. */
if (os_file_status(filepath, &exists, &ftype)
@@ -2657,28 +2653,13 @@ dict_index_remove_from_cache_low(
zero. See also: dict_table_can_be_evicted() */
do {
ulint ref_count = btr_search_info_get_ref_count(info, index);
if (ref_count == 0) {
if (!btr_search_info_get_ref_count(info, index)) {
break;
}
/* Sleep for 10ms before trying again. */
os_thread_sleep(10000);
++retries;
buf_LRU_drop_page_hash_for_tablespace(table);
if (retries % 500 == 0) {
/* No luck after 5 seconds of wait. */
ib::error() << "Waited for " << retries / 100
<< " secs for hash index"
" ref_count (" << ref_count << ") to drop to 0."
" index: " << index->name
<< " table: " << table->name;
}
/* To avoid a hang here we commit suicide if the
ref_count doesn't drop to zero in 600 seconds. */
ut_a(retries < 60000);
ut_a(++retries < 10000);
} while (srv_shutdown_state == SRV_SHUTDOWN_NONE || !lru_evict);
#endif /* BTR_CUR_HASH_ADAPT */

View File

@@ -3030,11 +3030,7 @@ fil_delete_tablespace(
To deal with potential read requests, we will check the
::stop_new_ops flag in fil_io(). */
buf_LRU_flush_or_remove_pages(id, NULL
#ifdef BTR_CUR_HASH_ADAPT
, drop_ahi
#endif /* BTR_CUR_HASH_ADAPT */
);
buf_LRU_flush_or_remove_pages(id, NULL);
/* If it is a delete then also delete any generated files, otherwise
when we drop the database the remove directory will fail. */
@@ -3314,11 +3310,7 @@ fil_discard_tablespace(
{
dberr_t err;
switch (err = fil_delete_tablespace(id
#ifdef BTR_CUR_HASH_ADAPT
, true
#endif /* BTR_CUR_HASH_ADAPT */
)) {
switch (err = fil_delete_tablespace(id)) {
case DB_SUCCESS:
break;

View File

@@ -3057,7 +3057,7 @@ fseg_free_page_low(
if (ahi) {
btr_search_drop_page_hash_when_freed(
page_id_t(space->id, offset), page_size);
page_id_t(space->id, offset));
}
#endif /* BTR_CUR_HASH_ADAPT */
@@ -3261,8 +3261,7 @@ fseg_free_extent(
btr_search_drop_page_hash_when_freed(
page_id_t(space->id,
first_page_in_extent + i),
page_size);
first_page_in_extent + i));
}
}
}

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, MariaDB Corporation.
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
@@ -129,15 +130,10 @@ btr_search_move_or_delete_hash_entries(
void
btr_search_drop_page_hash_index(buf_block_t* block);
/** Drop any adaptive hash index entries that may point to an index
page that may be in the buffer pool, when a page is evicted from the
buffer pool or freed in a file segment.
@param[in] page_id page id
@param[in] page_size page size */
void
btr_search_drop_page_hash_when_freed(
const page_id_t& page_id,
const page_size_t& page_size);
/** Drop possible adaptive hash index entries when a page is evicted
from the buffer pool or freed in a file, or the index is being dropped.
@param[in] page_id page id */
void btr_search_drop_page_hash_when_freed(const page_id_t& page_id);
/** Updates the page hash index when a single record is inserted on a page.
@param[in] cursor cursor which was positioned to the place to insert

View File

@@ -50,18 +50,20 @@ These are low-level functions
/** Minimum LRU list length for which the LRU_old pointer is defined */
#define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */
#ifdef BTR_CUR_HASH_ADAPT
struct dict_table_t;
/** Drop the adaptive hash index for a tablespace.
@param[in,out] table table */
void buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table);
#else
# define buf_LRU_drop_page_hash_for_tablespace(table)
#endif /* BTR_CUR_HASH_ADAPT */
/** Empty the flush list for all pages belonging to a tablespace.
@param[in] id tablespace identifier
@param[in,out] observer flush observer,
or NULL if nothing is to be written */
void
buf_LRU_flush_or_remove_pages(
ulint id,
FlushObserver* observer
#ifdef BTR_CUR_HASH_ADAPT
, bool drop_ahi = false /*!< whether to drop the adaptive hash index */
#endif /* BTR_CUR_HASH_ADAPT */
);
void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
/********************************************************************//**

View File

@@ -28,6 +28,7 @@ Created 2012-02-08 by Sunny Bains.
#include "row0import.h"
#include "btr0pcur.h"
#include "btr0sea.h"
#include "que0que.h"
#include "dict0boot.h"
#include "ibuf0ibuf.h"
@@ -3883,6 +3884,17 @@ row_import_for_mysql(
return(row_import_cleanup(prebuilt, trx, err));
}
/* On DISCARD TABLESPACE, we did not drop any adaptive hash
index entries. If we replaced the discarded tablespace with a
smaller one here, there could still be some adaptive hash
index entries that point to cached garbage pages in the buffer
pool, because PageConverter::operator() only evicted those
pages that were replaced by the imported pages. We must
discard all remaining adaptive hash index entries, because the
adaptive hash index must be a subset of the table contents;
false positives are not tolerated. */
buf_LRU_drop_page_hash_for_tablespace(table);
row_mysql_lock_data_dictionary(trx);
/* If the table is stored in a remote tablespace, we need to

View File

@@ -3626,6 +3626,20 @@ row_drop_table_for_mysql(
/* As we don't insert entries to SYSTEM TABLES for temp-tables
we need to avoid running removal of these entries. */
if (!dict_table_is_temporary(table)) {
if (table->space != TRX_SYS_SPACE) {
/* On DISCARD TABLESPACE, we would not drop the
adaptive hash index entries. If the tablespace is
missing here, delete-marking the record in SYS_INDEXES
would not free any pages in the buffer pool. Thus,
dict_index_remove_from_cache() would hang due to
adaptive hash index entries existing in the buffer
pool. To prevent this hang, and also to guarantee
that btr_search_drop_page_hash_when_freed() will avoid
calling btr_search_drop_page_hash_index() while we
hold the InnoDB dictionary lock, we will drop any
adaptive hash index entries upfront. */
buf_LRU_drop_page_hash_for_tablespace(table);
}
/* We use the private SQL parser of Innobase to generate the
query graphs needed in deleting the dictionary data from system

View File

@@ -17,7 +17,7 @@
#pragma implementation // gcc: Class implementation
#endif
#if _MSC_VER>=1400
#if defined(_MSC_VER) && _MSC_VER>=1400
#define _CRT_SECURE_NO_DEPRECATE 1
#define _CRT_NONSTDC_NO_DEPRECATE 1
#endif
@@ -64,7 +64,7 @@
#define MSG_WAITALL 0
#endif
#if _MSC_VER>=1400
#if defined(_MSC_VER) && _MSC_VER>=1400
#pragma warning(push,4)
#endif
@@ -3501,8 +3501,11 @@ int ha_sphinx::create ( const char * name, TABLE * table_arg, HA_CREATE_INFO * )
// report and bail
if ( sError[0] )
{
my_error ( ER_CANT_CREATE_TABLE, MYF(0),
table_arg->s->db.str, table_arg->s->table_name, sError );
my_printf_error(ER_CANT_CREATE_TABLE,
"Can\'t create table %s.%s (Error: %s)",
MYF(0),
table_arg->s->db.str,
table_arg->s->table_name.str, sError);
SPH_RET(-1);
}

View File

@@ -2,6 +2,7 @@
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2018, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -1287,17 +1288,11 @@ cleanup:
mem_free(folds);
}
/********************************************************************//**
Drops a possible page hash index when a page is evicted from the buffer pool
or freed in a file segment. */
/** Drop possible adaptive hash index entries when a page is evicted
from the buffer pool or freed in a file, or the index is being dropped. */
UNIV_INTERN
void
btr_search_drop_page_hash_when_freed(
/*=================================*/
ulint space, /*!< in: space id */
ulint zip_size, /*!< in: compressed page size in bytes
or 0 for uncompressed pages */
ulint page_no) /*!< in: page number */
btr_search_drop_page_hash_when_freed(ulint space, ulint page_no)
{
buf_block_t* block;
mtr_t mtr;
@@ -1310,7 +1305,7 @@ btr_search_drop_page_hash_when_freed(
are possibly holding, we cannot s-latch the page, but must
(recursively) x-latch it, even though we are only reading. */
block = buf_page_get_gen(space, zip_size, page_no, RW_X_LATCH, NULL,
block = buf_page_get_gen(space, 0, page_no, RW_X_LATCH, NULL,
BUF_PEEK_IF_IN_POOL, __FILE__, __LINE__,
&mtr);

View File

@@ -2972,17 +2972,18 @@ buf_page_get_gen(
#ifdef UNIV_DEBUG
switch (mode) {
case BUF_EVICT_IF_IN_POOL:
case BUF_PEEK_IF_IN_POOL:
/* After DISCARD TABLESPACE, the tablespace would not exist,
but in IMPORT TABLESPACE, PageConverter::operator() must
replace any old pages, which were not evicted during DISCARD.
Skip the assertion on zip_size. */
Similarly, btr_search_drop_page_hash_when_freed() must
remove any old pages. Skip the assertion on zip_size. */
break;
case BUF_GET_NO_LATCH:
ut_ad(rw_latch == RW_NO_LATCH);
/* fall through */
case BUF_GET:
case BUF_GET_IF_IN_POOL:
case BUF_PEEK_IF_IN_POOL:
case BUF_GET_IF_IN_POOL_OR_WATCH:
case BUF_GET_POSSIBLY_FREED:
ut_ad(zip_size == fil_space_get_zip_size(space));
@@ -3159,7 +3160,8 @@ got_block:
fix_mutex = buf_page_get_mutex(&fix_block->page);
ut_ad(page_zip_get_size(&block->page.zip) == zip_size);
ut_ad(page_zip_get_size(&block->page.zip) == zip_size
|| mode == BUF_PEEK_IF_IN_POOL);
switch (mode) {
case BUF_GET_IF_IN_POOL:

View File

@@ -238,8 +238,6 @@ void
buf_LRU_drop_page_hash_batch(
/*=========================*/
ulint space_id, /*!< in: space id */
ulint zip_size, /*!< in: compressed page size in bytes
or 0 for uncompressed pages */
const ulint* arr, /*!< in: array of page_no */
ulint count) /*!< in: number of entries in array */
{
@@ -249,8 +247,7 @@ buf_LRU_drop_page_hash_batch(
ut_ad(count <= BUF_LRU_DROP_SEARCH_SIZE);
for (i = 0; i < count; ++i) {
btr_search_drop_page_hash_when_freed(space_id, zip_size,
arr[i]);
btr_search_drop_page_hash_when_freed(space_id, arr[i]);
}
}
@@ -269,15 +266,6 @@ buf_LRU_drop_page_hash_for_tablespace(
buf_page_t* bpage;
ulint* page_arr;
ulint num_entries;
ulint zip_size;
zip_size = fil_space_get_zip_size(id);
if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
/* Somehow, the tablespace does not exist. Nothing to drop. */
ut_ad(0);
return;
}
page_arr = static_cast<ulint*>(ut_malloc(
sizeof(ulint) * BUF_LRU_DROP_SEARCH_SIZE));
@@ -331,8 +319,7 @@ next_page:
the latching order. */
mutex_exit(&buf_pool->LRU_list_mutex);
buf_LRU_drop_page_hash_batch(
id, zip_size, page_arr, num_entries);
buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
num_entries = 0;
@@ -363,10 +350,32 @@ next_page:
mutex_exit(&buf_pool->LRU_list_mutex);
/* Drop any remaining batch of search hashed pages. */
buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, num_entries);
buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
ut_free(page_arr);
}
/** Drop the adaptive hash index for a tablespace.
@param[in,out] table table */
UNIV_INTERN void buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table)
{
for (dict_index_t* index = dict_table_get_first_index(table);
index != NULL;
index = dict_table_get_next_index(index)) {
if (btr_search_info_get_ref_count(btr_search_get_info(index),
index)) {
goto drop_ahi;
}
}
return;
drop_ahi:
ulint id = table->space;
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
buf_LRU_drop_page_hash_for_tablespace(buf_pool_from_array(i),
id);
}
}
/******************************************************************//**
While flushing (or removing dirty) pages from a tablespace we don't
want to hog the CPU and resources. Release the buffer pool and block
@@ -733,18 +742,11 @@ buf_flush_dirty_pages(buf_pool_t* buf_pool, ulint id, const trx_t* trx)
/** Empty the flush list for all pages belonging to a tablespace.
@param[in] id tablespace identifier
@param[in] trx transaction, for checking for user interrupt;
or NULL if nothing is to be written
@param[in] drop_ahi whether to drop the adaptive hash index */
UNIV_INTERN
void
buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx, bool drop_ahi)
or NULL if nothing is to be written */
UNIV_INTERN void buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx)
{
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
buf_pool_t* buf_pool = buf_pool_from_array(i);
if (drop_ahi) {
buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
}
buf_flush_dirty_pages(buf_pool, id, trx);
buf_flush_dirty_pages(buf_pool_from_array(i), id, trx);
}
if (trx && !trx_is_interrupted(trx)) {

View File

@@ -2,7 +2,7 @@
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2017, MariaDB Corporation.
Copyright (c) 2013, 2018, MariaDB Corporation.
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
@@ -1680,7 +1680,7 @@ dict_table_rename_in_cache(
filepath = fil_make_ibd_name(table->name, false);
}
fil_delete_tablespace(table->space, true);
fil_delete_tablespace(table->space);
/* Delete any temp file hanging around. */
if (os_file_status(filepath, &exists, &ftype)
@@ -2729,36 +2729,12 @@ dict_index_remove_from_cache_low(
zero. See also: dict_table_can_be_evicted() */
do {
ulint ref_count = btr_search_info_get_ref_count(info,
index);
if (ref_count == 0) {
if (!btr_search_info_get_ref_count(info, index)) {
break;
}
/* Sleep for 10ms before trying again. */
os_thread_sleep(10000);
++retries;
if (retries % 500 == 0) {
/* No luck after 5 seconds of wait. */
fprintf(stderr, "InnoDB: Error: Waited for"
" %lu secs for hash index"
" ref_count (%lu) to drop"
" to 0.\n"
"index: \"%s\""
" table: \"%s\"\n",
retries/100,
ref_count,
index->name,
table->name);
}
/* To avoid a hang here we commit suicide if the
ref_count doesn't drop to zero in 600 seconds. */
if (retries >= 60000) {
ut_error;
}
buf_LRU_drop_page_hash_for_tablespace(table);
ut_a(++retries < 10000);
} while (srv_shutdown_state == SRV_SHUTDOWN_NONE || !lru_evict);
rw_lock_free(&index->lock);

View File

@@ -2936,7 +2936,7 @@ fil_delete_tablespace(ulint id, bool drop_ahi)
To deal with potential read requests by checking the
::stop_new_ops flag in fil_io() */
buf_LRU_flush_or_remove_pages(id, NULL, drop_ahi);
buf_LRU_flush_or_remove_pages(id, NULL);
#endif /* !UNIV_HOTBACKUP */
@@ -3047,7 +3047,7 @@ fil_discard_tablespace(
{
dberr_t err;
switch (err = fil_delete_tablespace(id, true)) {
switch (err = fil_delete_tablespace(id)) {
case DB_SUCCESS:
break;

View File

@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
Copyright (c) 2017, 2018, MariaDB Corporation.
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
@@ -3035,7 +3035,7 @@ fseg_free_page_low(
/* Drop search system page hash index if the page is found in
the pool and is hashed */
btr_search_drop_page_hash_when_freed(space, zip_size, page);
btr_search_drop_page_hash_when_freed(space, page);
descr = xdes_get_descriptor(space, zip_size, page, mtr);
@@ -3261,7 +3261,7 @@ fseg_free_extent(
found in the pool and is hashed */
btr_search_drop_page_hash_when_freed(
space, zip_size, first_page_in_extent + i);
space, first_page_in_extent + i);
}
}

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, MariaDB Corporation.
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
@@ -142,17 +143,11 @@ btr_search_drop_page_hash_index(
s- or x-latched, or an index page
for which we know that
block->buf_fix_count == 0 */
/********************************************************************//**
Drops a possible page hash index when a page is evicted from the buffer pool
or freed in a file segment. */
/** Drop possible adaptive hash index entries when a page is evicted
from the buffer pool or freed in a file, or the index is being dropped. */
UNIV_INTERN
void
btr_search_drop_page_hash_when_freed(
/*=================================*/
ulint space, /*!< in: space id */
ulint zip_size, /*!< in: compressed page size in bytes
or 0 for uncompressed pages */
ulint page_no); /*!< in: page number */
btr_search_drop_page_hash_when_freed(ulint space, ulint page_no);
/********************************************************************//**
Updates the page hash index when a single record is inserted on a page. */
UNIV_INTERN

View File

@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
Copyright (c) 2017, 2018, MariaDB Corporation.
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,7 @@ Created 11/5/1995 Heikki Tuuri
// Forward declaration
struct trx_t;
struct dict_table_t;
/******************************************************************//**
Returns TRUE if less than 25 % of the buffer pool is available. This can be
@@ -54,14 +55,15 @@ These are low-level functions
/** Minimum LRU list length for which the LRU_old pointer is defined */
#define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */
/** Drop the adaptive hash index for a tablespace.
@param[in,out] table table */
UNIV_INTERN void buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table);
/** Empty the flush list for all pages belonging to a tablespace.
@param[in] id tablespace identifier
@param[in] trx transaction, for checking for user interrupt;
or NULL if nothing is to be written
@param[in] drop_ahi whether to drop the adaptive hash index */
UNIV_INTERN
void
buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx, bool drop_ahi=false);
or NULL if nothing is to be written */
UNIV_INTERN void buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
/********************************************************************//**

View File

@@ -31,6 +31,7 @@ Created 2012-02-08 by Sunny Bains.
#endif
#include "btr0pcur.h"
#include "btr0sea.h"
#include "que0que.h"
#include "dict0boot.h"
#include "ibuf0ibuf.h"
@@ -3982,6 +3983,17 @@ row_import_for_mysql(
return(row_import_cleanup(prebuilt, trx, err));
}
/* On DISCARD TABLESPACE, we did not drop any adaptive hash
index entries. If we replaced the discarded tablespace with a
smaller one here, there could still be some adaptive hash
index entries that point to cached garbage pages in the buffer
pool, because PageConverter::operator() only evicted those
pages that were replaced by the imported pages. We must
discard all remaining adaptive hash index entries, because the
adaptive hash index must be a subset of the table contents;
false positives are not tolerated. */
buf_LRU_drop_page_hash_for_tablespace(table);
row_mysql_lock_data_dictionary(trx);
/* If the table is stored in a remote tablespace, we need to

View File

@@ -3540,6 +3540,8 @@ row_truncate_table_for_mysql(
fil_space_release(space);
}
buf_LRU_drop_page_hash_for_tablespace(table);
if (flags != ULINT_UNDEFINED
&& fil_discard_tablespace(space_id) == DB_SUCCESS) {
@@ -4239,6 +4241,21 @@ row_drop_table_for_mysql(
rw_lock_x_unlock(dict_index_get_lock(index));
}
if (table->space != TRX_SYS_SPACE) {
/* On DISCARD TABLESPACE, we would not drop the
adaptive hash index entries. If the tablespace is
missing here, delete-marking the record in SYS_INDEXES
would not free any pages in the buffer pool. Thus,
dict_index_remove_from_cache() would hang due to
adaptive hash index entries existing in the buffer
pool. To prevent this hang, and also to guarantee
that btr_search_drop_page_hash_when_freed() will avoid
calling btr_search_drop_page_hash_index() while we
hold the InnoDB dictionary lock, we will drop any
adaptive hash index entries upfront. */
buf_LRU_drop_page_hash_for_tablespace(table);
}
/* We use the private SQL parser of Innobase to generate the
query graphs needed in deleting the dictionary data from system
tables in Innobase. Deleting a row from SYS_INDEXES table also

View File

@@ -4665,9 +4665,27 @@ wrong_offs:
ulint lock_type;
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level <= TRX_ISO_READ_COMMITTED) {
/* At READ COMMITTED or READ UNCOMMITTED
isolation levels, do not lock committed
delete-marked records. */
if (!rec_get_deleted_flag(rec, comp)) {
goto no_gap_lock;
}
if (trx_id_t trx_id = index == clust_index
? row_get_rec_trx_id(rec, index, offsets)
: row_vers_impl_x_locked(rec, index, offsets)) {
if (trx_rw_is_active(trx_id, NULL)) {
/* The record belongs to an active
transaction. We must acquire a lock. */
goto no_gap_lock;
}
}
goto locks_ok_del_marked;
}
if (!set_also_gap_locks
|| srv_locks_unsafe_for_binlog
|| trx->isolation_level <= TRX_ISO_READ_COMMITTED
|| (unique_search && !rec_get_deleted_flag(rec, comp))) {
goto no_gap_lock;
@@ -4862,20 +4880,9 @@ locks_ok:
page_rec_is_comp() cannot be used! */
if (rec_get_deleted_flag(rec, comp)) {
locks_ok_del_marked:
/* The record is delete-marked: we can skip it */
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level <= TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE
&& !did_semi_consistent_read) {
/* No need to keep a lock on a delete-marked record
if we do not want to use next-key locking. */
row_unlock_for_mysql(prebuilt, TRUE);
}
/* This is an optimization to skip setting the next key lock
on the record that follows this delete-marked record. This
optimization works because of the unique search criteria