Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-40723

ROW/MIXED replication loses a MyISAM insert rolled back to a savepoint inside a stored function

    XMLWordPrintable

Details

    • Unexpected results
    • Hide
      In MariaDB primary/replica replication, a stored function can write to a nontransactional MyISAM table, then execute {{ROLLBACK TO SAVEPOINT}} before returning to the outer transaction. On the primary, the MyISAM row remains visible because the table is nontransactional. With {{binlog_format=ROW}} and {{binlog_format=MIXED}}, the replica reaches the primary binary-log position but the MyISAM row is missing on the replica.
      Show
      In MariaDB primary/replica replication, a stored function can write to a nontransactional MyISAM table, then execute {{ROLLBACK TO SAVEPOINT}} before returning to the outer transaction. On the primary, the MyISAM row remains visible because the table is nontransactional. With {{binlog_format=ROW}} and {{binlog_format=MIXED}}, the replica reaches the primary binary-log position but the MyISAM row is missing on the replica.

    Description

      Summary

      In MariaDB primary/replica replication, a stored function can write to a
      nontransactional MyISAM table, then execute ROLLBACK TO SAVEPOINT before
      returning to the outer transaction. On the primary, the MyISAM row remains
      visible because the table is nontransactional. With binlog_format=ROW and
      binlog_format=MIXED, the replica reaches the primary binary-log position
      but the MyISAM row is missing on the replica.

      The same SQL schedule reproduces on MariaDB 10.3, 10.6, and 12.2.2. The same
      test schedule did not reproduce on MySQL 5.6, 5.7, or 8.0.36 in local controls.

      Environment

      • Product: MariaDB Server
      • Observed versions:
        • MariaDB 10.3, primary/replica
        • MariaDB 10.6, primary/replica
        • MariaDB 12.2.2, primary/replica
      • Topology: one primary and one replica
      • Replication: asynchronous file/position replication
      • Binary logging modes showing the mismatch:
        • binlog_format=ROW
        • binlog_format=MIXED
      • Storage engines:
        • InnoDB for ordinary transactional tables
        • MyISAM for the nontransactional side-effect table

      Steps to reproduce

      Set up an ordinary MariaDB primary/replica pair using file/position replication.
      Run the following SQL on an empty primary database and wait until the replica
      has caught up after the DDL.

      CREATE TABLE base_t (
        id BIGINT NOT NULL PRIMARY KEY,
        code INT NOT NULL UNIQUE,
        payload INT NOT NULL
      ) ENGINE=InnoDB;
       
      CREATE TABLE transactional_side (
        id INT PRIMARY KEY,
        payload INT NOT NULL
      ) ENGINE=InnoDB;
       
      CREATE TABLE nontransactional_side (
        id INT PRIMARY KEY,
        payload INT NOT NULL
      ) ENGINE=MyISAM;
       
      CREATE FUNCTION write_sides() RETURNS INT
      DETERMINISTIC MODIFIES SQL DATA
      BEGIN
        SAVEPOINT routine_savepoint;
        INSERT INTO transactional_side VALUES (1, 50);
        INSERT INTO nontransactional_side VALUES (1, 60);
        ROLLBACK TO SAVEPOINT routine_savepoint;
        RETURN 0;
      END;
      

      Use row-based binary logging for the first reproduction:

      SET GLOBAL binlog_format='ROW';
      

      Then run this transaction on the primary:

      BEGIN;
      SELECT write_sides();
      INSERT INTO base_t(id, code, payload) VALUES (1, 1, 20);
      SAVEPOINT before_update;
      UPDATE base_t SET payload = payload + 1 WHERE code = 1;
      ROLLBACK TO SAVEPOINT before_update;
      COMMIT;
      

      After the replica reaches the corresponding primary binary-log position,
      inspect all three tables on both endpoints:

      SELECT * FROM base_t ORDER BY id;
      SELECT * FROM transactional_side ORDER BY id;
      SELECT * FROM nontransactional_side ORDER BY id;
      SHOW SLAVE STATUS\G
      

      Repeat the same schedule with binlog_format=MIXED.

      Expected result

      The replica should reflect the committed persistent state of the primary.

      The InnoDB write inside the stored function is rolled back by
      ROLLBACK TO SAVEPOINT routine_savepoint, so transactional_side should be
      empty on both endpoints.

      The MyISAM write is nontransactional, so it remains visible on the primary even
      after the savepoint rollback. Since the primary committed and the replica
      reached the corresponding binary-log position without a SQL-thread error, the
      same MyISAM row should be visible on the replica:

      base_t:
        (1, 1, 20)
       
      transactional_side:
        empty
       
      nontransactional_side:
        (1, 60)
      

      Actual result

      The ordinary InnoDB table converges and the rolled-back transactional side
      effect is absent on both endpoints, but the nontransactional MyISAM row is
      present only on the primary.

      Observed with binlog_format=ROW:

      primary.base_t:
        (1, 1, 20)
       
      replica.base_t:
        (1, 1, 20)
       
      primary.transactional_side:
        empty
       
      replica.transactional_side:
        empty
       
      primary.nontransactional_side:
        (1, 60)
       
      replica.nontransactional_side:
        empty
      

      Observed with binlog_format=MIXED:

      primary.nontransactional_side:
        (1, 60)
       
      replica.nontransactional_side:
        empty
      

      The replica reached the primary binary-log position and the replica SQL thread
      did not report a SQL error in these runs.

      Relevant controls

      The following controls were run with the same primary/replica setup and the
      same comparison:

      • MyISAM write without the stored function/savepoint shape: both endpoints
        matched.
      • Stored function plus MyISAM write, without the savepoint rollback inside the
        function: both endpoints matched.
      • Savepoint rollback plus stored function, without the MyISAM table: both
        endpoints matched.
      • The full three-part schedule with binlog_format=STATEMENT matched in the
        sampled runs, because the replica re-executed the stored function and created
        the MyISAM row locally.

      The mismatch therefore requires the combination of:

      stored function
      + savepoint rollback inside the function
      + nontransactional MyISAM side effect inside the rolled-back region
      + ROW or MIXED replication
      

      Repetition and scope

      The minimized schedule reproduced the mismatch on every tested MariaDB version:

      MariaDB 10.3, ROW/MIXED:   reproduced
      MariaDB 10.6, ROW/MIXED:   reproduced
      MariaDB 12.2.2, ROW/MIXED: reproduced
      

      The same minimized schedule did not reproduce in local MySQL-family controls:

      MySQL 5.6, ROW/MIXED:    matched
      MySQL 5.7, ROW/MIXED:    matched
      MySQL 8.0.36, ROW/MIXED: matched
      

      The broader generated search also found the same mismatch independently in a
      different sampled schema on MariaDB 10.6 and MariaDB 12.2.2.

      Nearby issues checked

      The behavior is not a replica-local trigger or replica-local constraint case;
      the primary and replica have the same schema, and no replica-local SQL object is
      installed.

      The behavior is also not a simple MyISAM rollback surprise on one server: the
      primary keeps the MyISAM row, as expected for a nontransactional table. The
      mismatch appears after ROW/MIXED replication applies the committed transaction.

      Could the MariaDB ROW/MIXED logging or apply path for stored-function side
      effects inside a savepoint rollback be checked? In particular, should the
      nontransactional table row that remains visible on the primary after
      ROLLBACK TO SAVEPOINT also be represented on the replica after the
      transaction commits?

      Attachments

        Activity

          People

            Deepthi ES Deepthi Eranti Sreenivas
            JaysonL Zhensheng Luo
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:

              Git Integration

                Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.