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

CREATE TABLE ... AS SELECT is not replicated in Galera when the table is partitioned

    XMLWordPrintable

Details

    Description

      I had AI analyze MDEV-34269 based on a new report about an incomplete fix. Here is what it found.

      In a Galera cluster, CREATE TABLE ... AS SELECT is not replicated when the new table is partitioned. The statement succeeds on the node that runs it, and no error or warning is given anywhere, but the table does not appear on the other node. This holds with and without --log-bin, and for an empty source table as well as a populated one.

      MDEV-34269 changed the same handlerton read in sql_parse.cc and sql_load.cc. The one in select_create::send_eof() still reads ->ht. git log dates that line to the Galera 4 merge in 2019, so it does not look like a regression from MDEV-34269.

      MTR Testcase:

      --source include/galera_cluster.inc
      --source include/have_partition.inc
      --source include/have_innodb.inc
      --source include/log_bin.inc
       
      --connection node_1
      CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB;
      INSERT INTO t1 VALUES (1,0),(2,0),(3,0);
      CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB PARTITION BY LIST (a MOD 2) (PARTITION p0 VALUES IN (0), PARTITION p1 VALUES IN (1)) AS SELECT * FROM t1;
      SELECT COUNT(*) FROM t2;
       
      --connection node_2
      --let $c= query_get_value(SELECT COUNT(*) AS c FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2', c, 1)
      if ($c != 1) {
        --die The new partitioned table exists on node 1 but not on node 2. It was not replicated to the cluster.
      }
      --let $c= query_get_value(SELECT COUNT(*) AS c FROM t2, c, 1)
      if ($c != 3) {
        --die The new partitioned table on node 2 is missing rows. The rows selected on node 1 were not replicated to the cluster.
      }
       
      --connection node_1
      DROP TABLE t1, t2;
       
      CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB;
      CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB PARTITION BY LIST (a MOD 2) (PARTITION p0 VALUES IN (0), PARTITION p1 VALUES IN (1)) AS SELECT * FROM t1;
      SELECT COUNT(*) FROM t2;
       
      --connection node_2
      --let $c= query_get_value(SELECT COUNT(*) AS c FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2', c, 1)
      if ($c != 1) {
        --die The new partitioned table exists on node 1 but not on node 2, with an empty source table. It was not replicated to the cluster.
      }
       
      --connection node_1
      DROP TABLE t1, t2;
      

      Leads to:

      galera.galera_ctas_partition 'binlogon'  [ fail ]
      mysqltest: At line 15: The new partitioned table exists on node 1 but not on node 2. It was not replicated to the cluster.
       
      The result from queries just before the failure was:
      connection node_1;
      CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB;
      INSERT INTO t1 VALUES (1,0),(2,0),(3,0);
      CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB PARTITION BY LIST (a MOD 2) (PARTITION p0 VALUES IN (0), PARTITION p1 VALUES IN (1)) AS SELECT * FROM t1;
      SELECT COUNT(*) FROM t2;
      COUNT(*)
      3
      connection node_2;
       
      galera.galera_ctas_partition 'binlogoff' [ fail ]
      mysqltest: At line 15: The new partitioned table exists on node 1 but not on node 2. It was not replicated to the cluster.
      Completed: Failed 2/2 tests, 0.00% were successful.
      

      What the analysis points to:

        CREATE TABLE t2 (...) PARTITION BY LIST (...) AS SELECT * FROM t1
          |
          v
        select_create::send_eof()
          table->file->ht->db_type  ->  DB_TYPE_PARTITION_DB   (not DB_TYPE_INNODB)
          |
          +--  wsrep_start_transaction()  not called
          +--  the new table keys         not appended
          |
          v
        the commit produces no writeset
          node_1:  table created and filled
          node_2:  table does not exist
      

      The proposed fix:

      sql/sql_insert.cc   In select_create::send_eof(), read the handlerton through
                          partition_ht(), as MDEV-34269 did in sql_parse.cc and
                          sql_load.cc.
      

      diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
      index 8df98b09..e08d9cbd 100644
      --- a/sql/sql_insert.cc
      +++ b/sql/sql_insert.cc
      @@ -5404,8 +5404,9 @@ bool select_create::send_eof()
         if (!table->s->tmp_table)
         {
       #ifdef WITH_WSREP
      +    /* For a partitioned table use the partition implementing storage engine */
           if (WSREP(thd) &&
      -        table->file->ht->db_type == DB_TYPE_INNODB)
      +        table->file->partition_ht()->db_type == DB_TYPE_INNODB)
           {
             if (thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID)
             {
      

      The patch is formatted for 10.11 (37d8577aee3bd87b5b04464144d064063b169039).

      Testing:

      • The testcase dies on 10.11.19 and passes patched, with and without the binary log.
      • Same result for LIST, HASH and RANGE with subpartitions, for CREATE OR REPLACE and CREATE TABLE IF NOT EXISTS, for a partitioned source table, and with wsrep_OSU_method=RSU.
      • Also tested with galera.galera_ctas, galera_create_table_as_select, galera_concurrent_ctas, galera_as_slave_ctas, galera_forced_binlog_format_ctas, galera_partition, galera_partition_key, galera_partitioned_tables, galera_myisam_autocommit, mdev-22063, MDEV-37935, galera_sr.galera_sr_create_drop, main.partition and main.create_select. These pass on both builds, and again under --ps-protocol on the patched build.
      • The changed code is the same in 11.4, 11.8, 12.3, 13.0 and 13.1, and the patch applies to each.

      .result file:

      connection node_2;
      connection node_1;
      connection node_1;
      CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB;
      INSERT INTO t1 VALUES (1,0),(2,0),(3,0);
      CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB PARTITION BY LIST (a MOD 2) (PARTITION p0 VALUES IN (0), PARTITION p1 VALUES IN (1)) AS SELECT * FROM t1;
      SELECT COUNT(*) FROM t2;
      COUNT(*)
      3
      connection node_2;
      connection node_1;
      DROP TABLE t1, t2;
      CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB;
      CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, PRIMARY KEY (a,b)) ENGINE=InnoDB PARTITION BY LIST (a MOD 2) (PARTITION p0 VALUES IN (0), PARTITION p1 VALUES IN (1)) AS SELECT * FROM t1;
      SELECT COUNT(*) FROM t2;
      COUNT(*)
      0
      connection node_2;
      connection node_1;
      DROP TABLE t1, t2;
      

      I've confirmed the identical failing test passes on the fixed tree.

      janlindstrom Would you please review & finalize/push the patch? Thank you

      Attachments

        Issue Links

          Activity

            People

              janlindstrom Jan Lindström
              Roel Roel Van de Paar
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - Not Specified
                  Not Specified
                  Logged:
                  Time Spent - 0.5d
                  0.5d

                  Git Integration

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