Skip to content
/ server Public
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions mysql-test/suite/innodb/r/tablespace_size_warning.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#
# MDEV-38936: Proactive handling of InnoDB tablespace full condition
#
SET @old_threshold = @@global.innodb_tablespace_size_warning_threshold;
SET @old_enabled = @@global.innodb_tablespace_size_warning_enabled;
SET @old_pct = @@global.innodb_tablespace_size_warning_pct;
# Test system variables
SHOW VARIABLES LIKE 'innodb_tablespace_size_warning_threshold';
Variable_name Value
innodb_tablespace_size_warning_threshold 17592186044416
SHOW VARIABLES LIKE 'innodb_tablespace_size_warning_enabled';
Variable_name Value
innodb_tablespace_size_warning_enabled ON
SHOW VARIABLES LIKE 'innodb_tablespace_size_warning_pct';
Variable_name Value
innodb_tablespace_size_warning_pct 70
# Test basic warning emission
SET GLOBAL innodb_tablespace_size_warning_threshold = 10485760;
SET GLOBAL innodb_tablespace_size_warning_pct = 70;
CREATE TABLE t1 (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;
FOUND 1 /Tablespace 'test/t1' size .* bytes .* exceeds warning threshold/ in mysqld.1.err
DROP TABLE t1;
# Test configurable warning percentage
SET GLOBAL innodb_tablespace_size_warning_threshold = 10485760;
SET GLOBAL innodb_tablespace_size_warning_pct = 80;
CREATE TABLE t1b (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;
FOUND 1 /Tablespace 'test/t1b' size .* bytes .* exceeds warning threshold/ in mysqld.1.err
DROP TABLE t1b;
# Test threshold set to zero disables warnings
SET GLOBAL innodb_tablespace_size_warning_threshold = 0;
CREATE TABLE t2 (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;
DROP TABLE t2;
# Test andon cord disable/enable
SET GLOBAL innodb_tablespace_size_warning_threshold = 10485760;
SET GLOBAL innodb_tablespace_size_warning_pct = 70;
SET GLOBAL innodb_tablespace_size_warning_enabled = FALSE;
CREATE TABLE t3 (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;
SET GLOBAL innodb_tablespace_size_warning_enabled = TRUE;
FOUND 1 /Tablespace 'test/t3' size .* bytes .* exceeds warning threshold/ in mysqld.1.err
DROP TABLE t3;
# Test TRUNCATE TABLE resets warning state
CREATE TABLE t4 (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;
FOUND 1 /Tablespace 'test/t4' size .* bytes .* exceeds warning threshold/ in mysqld.1.err
TRUNCATE TABLE t4;
FOUND 1 /Tablespace 'test/t4' size .* bytes .* exceeds warning threshold/ in mysqld.1.err
DROP TABLE t4;
SET GLOBAL innodb_tablespace_size_warning_threshold = @old_threshold;
SET GLOBAL innodb_tablespace_size_warning_enabled = @old_enabled;
SET GLOBAL innodb_tablespace_size_warning_pct = @old_pct;
149 changes: 149 additions & 0 deletions mysql-test/suite/innodb/t/tablespace_size_warning.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
--source include/have_innodb.inc
--source include/not_embedded.inc

--disable_query_log
call mtr.add_suppression("Tablespace .* size .* bytes .* exceeds warning threshold");
--enable_query_log

--echo #
--echo # MDEV-38936: Proactive handling of InnoDB tablespace full condition
--echo #

# Save original values
SET @old_threshold = @@global.innodb_tablespace_size_warning_threshold;
SET @old_enabled = @@global.innodb_tablespace_size_warning_enabled;
SET @old_pct = @@global.innodb_tablespace_size_warning_pct;

--echo # Test system variables
SHOW VARIABLES LIKE 'innodb_tablespace_size_warning_threshold';
SHOW VARIABLES LIKE 'innodb_tablespace_size_warning_enabled';
SHOW VARIABLES LIKE 'innodb_tablespace_size_warning_pct';

--echo # Test basic warning emission
SET GLOBAL innodb_tablespace_size_warning_threshold = 10485760;
SET GLOBAL innodb_tablespace_size_warning_pct = 70;

CREATE TABLE t1 (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;

--disable_query_log
let $i = 10;
while ($i) {
eval INSERT INTO t1 (data) VALUES (REPEAT('a', 1024*1024));
dec $i;
}
--enable_query_log

let SEARCH_FILE=$MYSQLTEST_VARDIR/log/mysqld.1.err;
let SEARCH_PATTERN=Tablespace 'test/t1' size .* bytes .* exceeds warning threshold;
--source include/search_pattern_in_file.inc

DROP TABLE t1;

--echo # Test configurable warning percentage
SET GLOBAL innodb_tablespace_size_warning_threshold = 10485760;
SET GLOBAL innodb_tablespace_size_warning_pct = 80;

CREATE TABLE t1b (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;

--disable_query_log
let $i = 8;
while ($i) {
eval INSERT INTO t1b (data) VALUES (REPEAT('x', 1024*1024));
dec $i;
}
--enable_query_log

let SEARCH_PATTERN=Tablespace 'test/t1b' size .* bytes .* exceeds warning threshold;
--source include/search_pattern_in_file.inc

DROP TABLE t1b;

--echo # Test threshold set to zero disables warnings
SET GLOBAL innodb_tablespace_size_warning_threshold = 0;

CREATE TABLE t2 (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;

--disable_query_log
let $i = 5;
while ($i) {
eval INSERT INTO t2 (data) VALUES (REPEAT('b', 1024*1024));
dec $i;
}
--enable_query_log

DROP TABLE t2;

--echo # Test andon cord disable/enable
SET GLOBAL innodb_tablespace_size_warning_threshold = 10485760;
SET GLOBAL innodb_tablespace_size_warning_pct = 70;
SET GLOBAL innodb_tablespace_size_warning_enabled = FALSE;

CREATE TABLE t3 (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;

--disable_query_log
let $i = 10;
while ($i) {
eval INSERT INTO t3 (data) VALUES (REPEAT('c', 1024*1024));
dec $i;
}
--enable_query_log

SET GLOBAL innodb_tablespace_size_warning_enabled = TRUE;

--disable_query_log
INSERT INTO t3 (data) VALUES (REPEAT('d', 1024*1024));
--enable_query_log

let SEARCH_PATTERN=Tablespace 'test/t3' size .* bytes .* exceeds warning threshold;
--source include/search_pattern_in_file.inc

DROP TABLE t3;

--echo # Test TRUNCATE TABLE resets warning state
CREATE TABLE t4 (
id INT AUTO_INCREMENT PRIMARY KEY,
data LONGBLOB
) ENGINE=InnoDB;

--disable_query_log
let $i = 10;
while ($i) {
eval INSERT INTO t4 (data) VALUES (REPEAT('e', 1024*1024));
dec $i;
}
--enable_query_log

let SEARCH_PATTERN=Tablespace 'test/t4' size .* bytes .* exceeds warning threshold;
--source include/search_pattern_in_file.inc

TRUNCATE TABLE t4;

--disable_query_log
let $i = 10;
while ($i) {
eval INSERT INTO t4 (data) VALUES (REPEAT('f', 1024*1024));
dec $i;
}
--enable_query_log

let SEARCH_PATTERN=Tablespace 'test/t4' size .* bytes .* exceeds warning threshold;
--source include/search_pattern_in_file.inc

DROP TABLE t4;

# Restore original values
SET GLOBAL innodb_tablespace_size_warning_threshold = @old_threshold;
SET GLOBAL innodb_tablespace_size_warning_enabled = @old_enabled;
SET GLOBAL innodb_tablespace_size_warning_pct = @old_pct;
36 changes: 36 additions & 0 deletions mysql-test/suite/sys_vars/r/sysvars_innodb.result
Original file line number Diff line number Diff line change
Expand Up @@ -1616,6 +1616,42 @@ NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_TABLESPACE_SIZE_WARNING_ENABLED
SESSION_VALUE NULL
DEFAULT_VALUE ON
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BOOLEAN
VARIABLE_COMMENT Enable/disable tablespace size warning feature
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME INNODB_TABLESPACE_SIZE_WARNING_PCT
SESSION_VALUE NULL
DEFAULT_VALUE 70
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Percentage at which to start emitting tablespace size warnings
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 100
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_TABLESPACE_SIZE_WARNING_THRESHOLD
SESSION_VALUE NULL
DEFAULT_VALUE 17592186044416
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Threshold in bytes for tablespace size warnings (0 = disabled)
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 18446744073709551615
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_TABLE_LOCKS
SESSION_VALUE ON
DEFAULT_VALUE ON
Expand Down
81 changes: 81 additions & 0 deletions storage/innobase/fsp/fsp0fsp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,84 @@ static uint32_t fsp_get_pages_to_extend_ibd(unsigned physical_size,
return extent_size;
}

/** Check if tablespace size exceeds warning threshold.
@param[in] space Tablespace
@param[in] new_size New size in pages
@return true if warning was emitted */
static bool fsp_check_size_warning(fil_space_t *space, uint32_t new_size) noexcept
{
/* Named constant for high-resolution warning threshold */
constexpr uint8_t high_resolution_pct = 90;

if (!srv_tablespace_size_warning_enabled)
return false;

if (srv_tablespace_size_warning_threshold == 0)
return false;

/* Reset state if threshold changed */
if (space->m_last_warning_threshold != srv_tablespace_size_warning_threshold) {
space->m_last_size_warning_pct= 0;
space->m_last_warning_threshold= srv_tablespace_size_warning_threshold;
space->m_warning_count_in_decade= 0;
}

uint64_t current_bytes=
static_cast<uint64_t>(new_size) * space->physical_size();
uint64_t current_pct=
(current_bytes * 100) / srv_tablespace_size_warning_threshold;
uint64_t display_pct= std::min(current_pct, static_cast<uint64_t>(100));

bool should_warn= false;

if (display_pct < srv_tablespace_size_warning_pct)
return false;

if (display_pct >= high_resolution_pct) {
/* Above high_resolution_pct: print on every 1% increase */
should_warn= (display_pct > space->m_last_size_warning_pct);
} else {
/* Between tablespace_size_warning_pct and high_resolution_pct:
print at most twice per 10% (e.g., 70%, 77%, 81%, 89%) */
uint8_t current_decade= static_cast<uint8_t>(display_pct / 10);
uint8_t last_decade= space->m_last_size_warning_pct / 10;

/* If we've moved to a new decade, reset the counter */
if (current_decade > last_decade) {
space->m_warning_count_in_decade= 0;
}

/* Warn if we haven't warned twice yet in this decade, percentage increased,
and there's at least a 5% gap since last warning (or it's the first warning) */
if (space->m_warning_count_in_decade < 2 &&
display_pct > space->m_last_size_warning_pct &&
(space->m_warning_count_in_decade == 0 ||
display_pct >= static_cast<uint64_t>(space->m_last_size_warning_pct + 5))) {
should_warn= true;
}
}

if (should_warn) {
const auto name= space->name();
ib::warn() << "Tablespace '" << std::string_view(name.data(), name.size())
<< "' size " << current_bytes
<< " bytes (" << display_pct << "%)"
<< " exceeds warning threshold of "
<< srv_tablespace_size_warning_threshold << " bytes";

space->m_last_size_warning_pct= static_cast<uint8_t>(display_pct);

/* Increment counter only for the tiered warning range (below high_resolution_pct) */
if (display_pct < high_resolution_pct) {
space->m_warning_count_in_decade++;
}

return true;
}

return false;
}

/** Try to extend the last data file of a tablespace if it is auto-extending.
@param[in,out] space tablespace
@param[in,out] header tablespace header
Expand Down Expand Up @@ -758,6 +836,9 @@ fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr)
+ header->page.frame,
space->size_in_header);

/* Check if tablespace size exceeds warning threshold */
fsp_check_size_warning(space, space->size_in_header);

return(size_increase);
}

Expand Down
27 changes: 27 additions & 0 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19138,6 +19138,30 @@ static MYSQL_SYSVAR_ULONG(purge_batch_size, srv_purge_batch_size,
1, /* Minimum value */
innodb_purge_batch_size_MAX, 0);

static MYSQL_SYSVAR_ULONGLONG(tablespace_size_warning_threshold,
srv_tablespace_size_warning_threshold,
PLUGIN_VAR_RQCMDARG,
"Threshold in bytes for tablespace size warnings (0 = disabled)",
NULL, NULL,
17592186044416ULL, /* Default setting */
0, /* Minimum value */
ULLONG_MAX, 0); /* Maximum value */

static MYSQL_SYSVAR_UINT(tablespace_size_warning_pct,
srv_tablespace_size_warning_pct,
PLUGIN_VAR_RQCMDARG,
"Percentage at which to start emitting tablespace size warnings",
NULL, NULL,
70, /* Default setting */
0, /* Minimum value */
100, 0); /* Maximum value */

static MYSQL_SYSVAR_BOOL(tablespace_size_warning_enabled,
srv_tablespace_size_warning_enabled,
PLUGIN_VAR_OPCMDARG,
"Enable/disable tablespace size warning feature",
NULL, NULL, TRUE);

extern void srv_update_purge_thread_count(uint n);

static
Expand Down Expand Up @@ -20102,6 +20126,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(monitor_reset_all),
MYSQL_SYSVAR(purge_threads),
MYSQL_SYSVAR(purge_batch_size),
MYSQL_SYSVAR(tablespace_size_warning_threshold),
MYSQL_SYSVAR(tablespace_size_warning_pct),
MYSQL_SYSVAR(tablespace_size_warning_enabled),
MYSQL_SYSVAR(log_checkpoint_now),
#ifdef UNIV_DEBUG
MYSQL_SYSVAR(buf_flush_list_now),
Expand Down
Loading