Skip to content

MDEV-41012 Galera appliers hang with foreign key of types UUID, INET4, INET6 - #5634

Open
sjaakola wants to merge 3 commits into
10.11from
10.11-MDEV-41012
Open

MDEV-41012 Galera appliers hang with foreign key of types UUID, INET4, INET6#5634
sjaakola wants to merge 3 commits into
10.11from
10.11-MDEV-41012

Conversation

@sjaakola

@sjaakola sjaakola commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

wsrep_store_key_val_for_row() built the certification key of a row by collating the column value whenever the field reports MYSQL_TYPE_STRING or MYSQL_TYPE_VAR_STRING, taking the collation from Field::charset().

The data types implemented on Field_fbt - UUID, INET6 and INET4
report MYSQL_TYPE_STRING, and their charset() is my_charset_numeric,
which is latin1. Their values are however plain binary and accordingly
get_innobase_type_from_mysql_type() maps them to DATA_FIXBINARY. Their
keys were therefore run through latin1_swedish_ci, which
folds them. That corrupts the key in two ways:

  1. A key mismatch for one and the same row. The reference key that
    wsrep_rec_get_foreign_key() appends for the parent of a child INSERT is
    built from the InnoDB record and is not collated, so it no longer
    matched the primary key carried by the parent row's own writeset.
    Certification saw no dependency between a child INSERT and a concurrent
    parent UPDATE, and two appliers could apply them in parallel causing
    a hang or crash.

  2. A key collision between distinct rows. The folding is many to one, so
    different values collapse onto one key, Certification compares keys byte
    for byte, so unrelated rows were treated as the same row. Concurrent
    transactions on them certified as a conflict and one was aborted with
    ER_LOCK_DEADLOCK.

Fix is for wsrep_store_key_val_for_row() to skip the collation for
fields that InnoDB stores as binary, using the same condition as
get_innobase_type_from_mysql_type(). This is a no-op for the types that
worked before.

…, INET6

Added a deterministic test for reproducing the issue
…, INET6

Added second test for testing key collisions from transactions modifying
separate rows
…, INET6

wsrep_store_key_val_for_row() built the certification key of a row by
collating the column value whenever the field reports MYSQL_TYPE_STRING
or MYSQL_TYPE_VAR_STRING, taking the collation from Field::charset().

The data types implemented on Field_fbt - UUID, INET6 and INET4
report MYSQL_TYPE_STRING, and their charset() is my_charset_numeric,
which is latin1. Their values are however plain binary and accordingly
get_innobase_type_from_mysql_type() maps them to DATA_FIXBINARY. Their
keys were therefore run through latin1_swedish_ci, which
folds them. That corrupts the key in two ways:

1. A key mismatch for one and the same row. The reference key that
wsrep_rec_get_foreign_key() appends for the parent of a child INSERT is
built from the InnoDB record and is not collated, so it no longer
matched the primary key carried by the parent row's own writeset.
Certification saw no dependency between a child INSERT and a concurrent
parent UPDATE, and two appliers could apply them in parallel causing
a hang or crash.

2. A key collision between distinct rows. The folding is many to one, so
different values collapse onto one key, Certification compares keys byte
 for byte, so unrelated rows were treated as the same row. Concurrent
transactions on them certified as a conflict and one was aborted with
ER_LOCK_DEADLOCK.

Fix is for  wsrep_store_key_val_for_row() to skip the collation for
fields that InnoDB stores as binary, using the same condition as
get_innobase_type_from_mysql_type(). This is a no-op for the types that
worked before.

@janlindstrom janlindstrom left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix and test cases looks correct, but in my understanding changing binary format requires protocol change.

Style: wsrep_store_key_val_for_row is too long and complicated, it is getting to state where it is not maintainable or understandable. Consider splitting.

Because your branch is against MariaDB repository only Buildbot testing is run and it lacks most of the debug full testing. https://github.com/mariadb-corporation/codership-galera is only repository currently where full CI is run.

Future: Maybe we should get these wsrep-only functions to separate file e.g. ha_innodb_wsrep.cc, but before anyone does that better ask Marko if he agrees/cares.

if character set is multi byte.

Fields that InnoDB stores as DATA_BINARY,
DATA_FIXBINARY or DATA_BLOB must not be collated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor : DATA_BLOB is not handled in this branch see line 6845.

Major: Write-set key encoding for UUID/INET4/INET6 changes with no wsrep_protocol_version gate; in a mixed-version cluster old and new nodes compute different keys for the same row, so concurrent same-PK INSERTs both certify and the applier then fails with ER_DUP_ENTRY, dropping a node. Every other format change in this file is version-gated.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants