mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
MDEV-19526 heap number overflow on innodb_page_size=64k
InnoDB only reserves 13 bits for the heap number in the record header, limiting the heap number to be at most 8191. But, when using innodb_page_size=64k and secondary index records of 7 bytes each, it is possible to exceed the maximum heap number. btr_cur_optimistic_insert(): Let the operation fail if the maximum number of records would be exceeded. page_mem_alloc_heap(): Move to the same compilation unit with the only caller, and let the operation fail if the maximum heap number has been allocated already.
This commit is contained in:
parent
7ad4709a3b
commit
efd8af535a
10 changed files with 139 additions and 122 deletions
|
@ -1084,3 +1084,10 @@ update t2 set col145=@b;
|
|||
COMMIT;
|
||||
drop table t2;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-19526 heap number overflow
|
||||
#
|
||||
CREATE TABLE t1(a SMALLINT NOT NULL UNIQUE AUTO_INCREMENT, KEY(a))
|
||||
ENGINE=InnoDB;
|
||||
INSERT INTO t1 (a) SELECT seq FROM seq_1_to_8191;
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# Tests for setting innodb-page-size=64k;
|
||||
--source include/have_innodb.inc
|
||||
--source include/have_innodb_64k.inc
|
||||
--source include/have_sequence.inc
|
||||
|
||||
call mtr.add_suppression("InnoDB: Warning: innodb_page_size has been changed from default value *");
|
||||
call mtr.add_suppression("InnoDB: Resizing redo log from *");
|
||||
|
@ -650,6 +651,15 @@ COMMIT;
|
|||
|
||||
drop table t2;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-19526 heap number overflow
|
||||
--echo #
|
||||
CREATE TABLE t1(a SMALLINT NOT NULL UNIQUE AUTO_INCREMENT, KEY(a))
|
||||
ENGINE=InnoDB;
|
||||
INSERT INTO t1 (a) SELECT seq FROM seq_1_to_8191;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# restore environment to the state it was before this test execution
|
||||
#
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2015, 2017, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2020, MariaDB Corporation.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
Google, Inc. Those modifications are gratefully acknowledged and are described
|
||||
|
@ -1433,17 +1433,23 @@ fail_err:
|
|||
}
|
||||
|
||||
ulint max_size = page_get_max_insert_size_after_reorganize(page, 1);
|
||||
if (max_size < rec_size) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const ulint n_recs = page_get_n_recs(page);
|
||||
if (UNIV_UNLIKELY(n_recs >= 8189)) {
|
||||
ut_ad(srv_page_size == 65536);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (page_has_garbage(page)) {
|
||||
if ((max_size < rec_size
|
||||
|| max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT)
|
||||
&& page_get_n_recs(page) > 1
|
||||
if (max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT
|
||||
&& n_recs > 1
|
||||
&& page_get_max_insert_size(page, 1) < rec_size) {
|
||||
|
||||
goto fail;
|
||||
}
|
||||
} else if (max_size < rec_size) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* If there have been many consecutive inserts to the
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2013, 2018, MariaDB Corporation.
|
||||
Copyright (c) 2013, 2020, 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
|
||||
|
@ -759,21 +759,6 @@ page_mem_alloc_free(
|
|||
free record list */
|
||||
ulint need); /*!< in: number of bytes allocated */
|
||||
/************************************************************//**
|
||||
Allocates a block of memory from the heap of an index page.
|
||||
@return pointer to start of allocated buffer, or NULL if allocation fails */
|
||||
UNIV_INTERN
|
||||
byte*
|
||||
page_mem_alloc_heap(
|
||||
/*================*/
|
||||
page_t* page, /*!< in/out: index page */
|
||||
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
|
||||
space available for inserting the record,
|
||||
or NULL */
|
||||
ulint need, /*!< in: total number of bytes needed */
|
||||
ulint* heap_no);/*!< out: this contains the heap number
|
||||
of the allocated record
|
||||
if allocation succeeds */
|
||||
/************************************************************//**
|
||||
Puts a record to free list. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2020, 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
|
||||
|
@ -941,6 +942,52 @@ page_cur_parse_insert_rec(
|
|||
return(ptr + end_seg_len);
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
Allocates a block of memory from the heap of an index page.
|
||||
@return pointer to start of allocated buffer, or NULL if allocation fails */
|
||||
static
|
||||
byte*
|
||||
page_mem_alloc_heap(
|
||||
/*================*/
|
||||
page_t* page, /*!< in/out: index page */
|
||||
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
|
||||
space available for inserting the record,
|
||||
or NULL */
|
||||
ulint need, /*!< in: total number of bytes needed */
|
||||
ulint* heap_no)/*!< out: this contains the heap number
|
||||
of the allocated record
|
||||
if allocation succeeds */
|
||||
{
|
||||
byte* block;
|
||||
ulint avl_space;
|
||||
|
||||
ut_ad(page && heap_no);
|
||||
|
||||
avl_space = page_get_max_insert_size(page, 1);
|
||||
|
||||
if (avl_space >= need) {
|
||||
const ulint h = page_dir_get_n_heap(page);
|
||||
if (UNIV_UNLIKELY(h >= 8191)) {
|
||||
/* At the minimum record size of 5+2 bytes,
|
||||
we can only reach this condition when using
|
||||
innodb_page_size=64k. */
|
||||
ut_ad(srv_page_size == 65536);
|
||||
return(NULL);
|
||||
}
|
||||
*heap_no = h;
|
||||
|
||||
block = page_header_get_ptr(page, PAGE_HEAP_TOP);
|
||||
|
||||
page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP,
|
||||
block + need);
|
||||
page_dir_set_n_heap(page, page_zip, 1 + *heap_no);
|
||||
|
||||
return(block);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/***********************************************************//**
|
||||
Inserts a record next to page cursor on an uncompressed page.
|
||||
Returns pointer to inserted record if succeed, i.e., enough
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2018, MariaDB Corporation.
|
||||
Copyright (c) 2018, 2020, 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
|
||||
|
@ -235,44 +235,6 @@ page_set_max_trx_id(
|
|||
}
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
Allocates a block of memory from the heap of an index page.
|
||||
@return pointer to start of allocated buffer, or NULL if allocation fails */
|
||||
UNIV_INTERN
|
||||
byte*
|
||||
page_mem_alloc_heap(
|
||||
/*================*/
|
||||
page_t* page, /*!< in/out: index page */
|
||||
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
|
||||
space available for inserting the record,
|
||||
or NULL */
|
||||
ulint need, /*!< in: total number of bytes needed */
|
||||
ulint* heap_no)/*!< out: this contains the heap number
|
||||
of the allocated record
|
||||
if allocation succeeds */
|
||||
{
|
||||
byte* block;
|
||||
ulint avl_space;
|
||||
|
||||
ut_ad(page && heap_no);
|
||||
|
||||
avl_space = page_get_max_insert_size(page, 1);
|
||||
|
||||
if (avl_space >= need) {
|
||||
block = page_header_get_ptr(page, PAGE_HEAP_TOP);
|
||||
|
||||
page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP,
|
||||
block + need);
|
||||
*heap_no = page_dir_get_n_heap(page);
|
||||
|
||||
page_dir_set_n_heap(page, page_zip, 1 + *heap_no);
|
||||
|
||||
return(block);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/**********************************************************//**
|
||||
Writes a log record of page creation. */
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2015, 2017, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2020, MariaDB Corporation.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
Google, Inc. Those modifications are gratefully acknowledged and are described
|
||||
|
@ -1542,17 +1542,23 @@ fail_err:
|
|||
}
|
||||
|
||||
ulint max_size = page_get_max_insert_size_after_reorganize(page, 1);
|
||||
if (max_size < rec_size) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const ulint n_recs = page_get_n_recs(page);
|
||||
if (UNIV_UNLIKELY(n_recs >= 8189)) {
|
||||
ut_ad(srv_page_size == 65536);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (page_has_garbage(page)) {
|
||||
if ((max_size < rec_size
|
||||
|| max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT)
|
||||
&& page_get_n_recs(page) > 1
|
||||
if (max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT
|
||||
&& n_recs > 1
|
||||
&& page_get_max_insert_size(page, 1) < rec_size) {
|
||||
|
||||
goto fail;
|
||||
}
|
||||
} else if (max_size < rec_size) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* If there have been many consecutive inserts to the
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2013, 2018, MariaDB Corporation.
|
||||
Copyright (c) 2013, 2020, 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
|
||||
|
@ -749,21 +749,6 @@ page_mem_alloc_free(
|
|||
free record list */
|
||||
ulint need); /*!< in: number of bytes allocated */
|
||||
/************************************************************//**
|
||||
Allocates a block of memory from the heap of an index page.
|
||||
@return pointer to start of allocated buffer, or NULL if allocation fails */
|
||||
UNIV_INTERN
|
||||
byte*
|
||||
page_mem_alloc_heap(
|
||||
/*================*/
|
||||
page_t* page, /*!< in/out: index page */
|
||||
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
|
||||
space available for inserting the record,
|
||||
or NULL */
|
||||
ulint need, /*!< in: total number of bytes needed */
|
||||
ulint* heap_no);/*!< out: this contains the heap number
|
||||
of the allocated record
|
||||
if allocation succeeds */
|
||||
/************************************************************//**
|
||||
Puts a record to free list. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2020, 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
|
||||
|
@ -941,6 +942,52 @@ page_cur_parse_insert_rec(
|
|||
return(ptr + end_seg_len);
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
Allocates a block of memory from the heap of an index page.
|
||||
@return pointer to start of allocated buffer, or NULL if allocation fails */
|
||||
static
|
||||
byte*
|
||||
page_mem_alloc_heap(
|
||||
/*================*/
|
||||
page_t* page, /*!< in/out: index page */
|
||||
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
|
||||
space available for inserting the record,
|
||||
or NULL */
|
||||
ulint need, /*!< in: total number of bytes needed */
|
||||
ulint* heap_no)/*!< out: this contains the heap number
|
||||
of the allocated record
|
||||
if allocation succeeds */
|
||||
{
|
||||
byte* block;
|
||||
ulint avl_space;
|
||||
|
||||
ut_ad(page && heap_no);
|
||||
|
||||
avl_space = page_get_max_insert_size(page, 1);
|
||||
|
||||
if (avl_space >= need) {
|
||||
const ulint h = page_dir_get_n_heap(page);
|
||||
if (UNIV_UNLIKELY(h >= 8191)) {
|
||||
/* At the minimum record size of 5+2 bytes,
|
||||
we can only reach this condition when using
|
||||
innodb_page_size=64k. */
|
||||
ut_ad(srv_page_size == 65536);
|
||||
return(NULL);
|
||||
}
|
||||
*heap_no = h;
|
||||
|
||||
block = page_header_get_ptr(page, PAGE_HEAP_TOP);
|
||||
|
||||
page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP,
|
||||
block + need);
|
||||
page_dir_set_n_heap(page, page_zip, 1 + *heap_no);
|
||||
|
||||
return(block);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/***********************************************************//**
|
||||
Inserts a record next to page cursor on an uncompressed page.
|
||||
Returns pointer to inserted record if succeed, i.e., enough
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2018, MariaDB Corporation.
|
||||
Copyright (c) 2018, 2020, 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
|
||||
|
@ -240,44 +240,6 @@ page_set_max_trx_id(
|
|||
}
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
Allocates a block of memory from the heap of an index page.
|
||||
@return pointer to start of allocated buffer, or NULL if allocation fails */
|
||||
UNIV_INTERN
|
||||
byte*
|
||||
page_mem_alloc_heap(
|
||||
/*================*/
|
||||
page_t* page, /*!< in/out: index page */
|
||||
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
|
||||
space available for inserting the record,
|
||||
or NULL */
|
||||
ulint need, /*!< in: total number of bytes needed */
|
||||
ulint* heap_no)/*!< out: this contains the heap number
|
||||
of the allocated record
|
||||
if allocation succeeds */
|
||||
{
|
||||
byte* block;
|
||||
ulint avl_space;
|
||||
|
||||
ut_ad(page && heap_no);
|
||||
|
||||
avl_space = page_get_max_insert_size(page, 1);
|
||||
|
||||
if (avl_space >= need) {
|
||||
block = page_header_get_ptr(page, PAGE_HEAP_TOP);
|
||||
|
||||
page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP,
|
||||
block + need);
|
||||
*heap_no = page_dir_get_n_heap(page);
|
||||
|
||||
page_dir_set_n_heap(page, page_zip, 1 + *heap_no);
|
||||
|
||||
return(block);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/**********************************************************//**
|
||||
Writes a log record of page creation. */
|
||||
|
|
Loading…
Reference in a new issue