Skip to content

Invalid table-level KEY_BLOCK_SIZE leaves stale per-index DD metadata after InnoDB fallback #746

Description

@Ty-Ian

MySQL version / commit

MySQL Community Server trunk

Steps to reproduce

Prerequisites:

  • innodb_page_size=16384
  • innodb_file_per_table=ON
  • InnoDB ROW_FORMAT=COMPRESSED is supported

When innodb_strict_mode is OFF, create a compressed table using the invalid
table-level KEY_BLOCK_SIZE=32:

SELECT VERSION(),
       @@GLOBAL.innodb_page_size,
       @@GLOBAL.innodb_file_per_table;

DROP TABLE IF EXISTS k;
SET SESSION innodb_strict_mode=OFF;

CREATE TABLE k (
  id INT PRIMARY KEY,
  c1 INT,
  KEY idx_c1 (c1)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=32;

SHOW WARNINGS;
SHOW CREATE TABLE k;

SELECT NAME, ROW_FORMAT, ZIP_PAGE_SIZE
FROM information_schema.INNODB_TABLES
WHERE NAME=CONCAT(DATABASE(), '/k');

-- The stale per-index values survive a table rebuild.
ALTER TABLE k FORCE;
SHOW CREATE TABLE k;

-- Rebuilding the primary key also retains the stale value.
ALTER TABLE k DROP PRIMARY KEY, ADD PRIMARY KEY (id);
SHOW CREATE TABLE k;

-- Rebuilding the secondary index clears its stale value.
ALTER TABLE k DROP INDEX idx_c1;
ALTER TABLE k ADD INDEX idx_c1 (c1);
SHOW CREATE TABLE k;

DROP TABLE k;

### Expected vs actual result

Expected result
===============

After InnoDB rejects the invalid table-level KEY_BLOCK_SIZE=32 and selects the
final compressed page size, inherited per-index metadata should not retain the
invalid value.

For this case, the inherited index block_size values should either be
normalized to 8 or omitted as inherited metadata. PRIMARY and secondary index
rebuilds should produce consistent metadata.

Actual result
=============

CREATE TABLE emits the expected warning:

Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=32.

InnoDB correctly selects an 8KB compressed page size:

ROW_FORMAT  ZIP_PAGE_SIZE
Compressed  8192

The table-level DD value is also corrected to KEY_BLOCK_SIZE=8. However,
SHOW CREATE TABLE reports stale index-level values:

CREATE TABLE `k` (
  `id` int NOT NULL,
  `c1` int DEFAULT NULL,
  PRIMARY KEY (`id`) KEY_BLOCK_SIZE=32,
  KEY `idx_c1` (`c1`) KEY_BLOCK_SIZE=32
) ENGINE=InnoDB ... ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8

The index-level KEY_BLOCK_SIZE=32 clauses survive ALTER TABLE FORCE and
DROP/ADD PRIMARY KEY.

Dropping and re-adding idx_c1 clears the value for that secondary index, while
PRIMARY still retains KEY_BLOCK_SIZE=32. Primary and secondary index rebuilds
therefore behave inconsistently.

A debug build confirms that mysql.indexes.options contains:

name     options
idx_c1   block_size=32;flags=0;
PRIMARY  block_size=32;flags=0;

The physical compressed page size is correct, and no data corruption has been
observed. This appears to be a data-dictionary metadata consistency issue.

Suspected cause
===============

The server copies a table-level KEY_BLOCK_SIZE into KEY::block_size for each
index, and persists nonzero values as the index DD "block_size" option.

In InnoDB dd_set_table_options(), the final table-level key_block_size is
derived from the finalized InnoDB flags, but the compressed-table path does
not normalize the already-created per-index block_size options. Consequently,
the ignored user value remains in the index DD metadata.

### Platform / compiler

Linux x86_64 GCC/G++ 12.3.0 CMake 3.26.5 Debug build

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugneeds-triageSignals maintainers should review, route and prioritize the issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions