Uploaded image for project: 'Ignite'
  1. Ignite
  2. IGNITE-19247

BatchUpdateException: Replication is timed out" upon inserting rows in batches via JDBC

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Critical
    • Resolution: Cannot Reproduce
    • 3.0
    • 3.0
    • general

    Description

      Start single node cluster:

      git commit 78946d4c
      https://github.com/apache/ignite-3.git branch mainbuild by:
          ./gradlew clean allDistZip -x test -x integrationTest -x check -x modernizer 
      start by:  
          /tmp/ignite3-3.0.0-SNAPSHOT/ignite3-db-3.0.0-SNAPSHOT$ export IGNITE_HOME=$(pwd)
          /tmp/ignite3-3.0.0-SNAPSHOT/ignite3-db-3.0.0-SNAPSHOT$ bin/ignite3db start
              Starting Ignite 3...
              Node named defaultNode started successfully. REST addresses are [http://127.0.1.1:10300]
          /tmp/ignite3-3.0.0-SNAPSHOT/ignite3-cli-3.0.0-SNAPSHOT$ bin/ignite3 cluster init --cluster-endpoint-url=http://localhost:10300 --cluster-name=c1 --meta-storage-node=defaultNode
              Cluster was initialized successfully

      Code below just create <TABLES> tables with <COLUMNS+1> columns (int key and varchar cols) and insert <ROWS> rows into each table (with SLEEP ms interval between operations, with <RETRY> attemps.

       

      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.PreparedStatement;
      import java.sql.ResultSet;
      import java.sql.SQLException;
      import java.sql.Statement;
      
      public class TimeoutExceptionReproducer {
          private static final String DB_URL = "jdbc:ignite:thin://127.0.0.1:10800";
          private static final int COLUMNS = 10;
      
          private static final String TABLE_NAME = "K";
          private static final int ROWS = 100000;
      
          private static final int TABLES = 3;
      
          private static final int BATCH_SIZE = 100;
      
          private static final int SLEEP = 0;
      
          private static final int RETRY = 1;
      
          private static String getCreateSql(String tableName) {
              StringBuilder sql = new StringBuilder("create table ").append(tableName).append(" (id int primary key");
      
              for (int i = 0; i < COLUMNS; i++) {
                  sql.append(", col").append(i).append(" varchar NOT NULL");
              }
      
              sql.append(")");
      
              return sql.toString();
          }
      
          private static final void s() {
              if (SLEEP > 0) {
                  try {
                      Thread.sleep(SLEEP);
                  } catch (InterruptedException e) {
                      // NoOp
                  }
              }
          }
      
          private static void createTables(Connection connection, String tableName) throws SQLException {
              try (Statement stmt = connection.createStatement()) {
                  System.out.println("Creating " + tableName);
      
                  stmt.executeUpdate("drop table if exists " + tableName );
                  s();
                  stmt.executeUpdate(getCreateSql(tableName));
                  s();
              }
          }
      
          private static String getInsertSql(String tableName) {
              StringBuilder sql = new StringBuilder("insert into ").append(tableName).append(" values(?");
      
              for (int i = 0; i < COLUMNS; i++) {
                  sql.append(", ?");
              }
      
              sql.append(")");
      
              return sql.toString();
          }
      
          private static void insertBatch(PreparedStatement ps) {
              int retryCounter = 0;
              while(retryCounter <= RETRY) {
                  try {
                      ps.executeBatch();
      
                      return;
                  } catch (SQLException e) {
                      System.err.println(retryCounter + " error while executing " + ps + ":" + e);
      
                      retryCounter++;
                  }
              }
          }
      
          private static void insertData(Connection connection, String tableName) throws SQLException {
              long ts = System.currentTimeMillis();
              try (PreparedStatement ps = connection.prepareStatement(getInsertSql(tableName))) {
                  int batch = 0;
      
                  for (int i = 0; i < ROWS; i++) {
                      ps.setInt(1, i);
      
                      for (int j = 2; j < COLUMNS + 2; j++) {
                          ps.setString(j, "value" + i + "_" + j);
                      }
      
                      ps.addBatch();
                      batch++;
      
                      if (batch == BATCH_SIZE) {
                          batch = 0;
                          insertBatch(ps);
                          ps.clearBatch();
      
                          System.out.println("Batch " + BATCH_SIZE + " took " + (System.currentTimeMillis() - ts) + " to get " + i + " rows");
      
                          s();
                          ts = System.currentTimeMillis();
                      }
                  }
      
                  if (batch > 0) {
                      insertBatch(ps);
                      ps.clearBatch();
                      s();
                  }
              }
          }
      
          private static int testData(Connection connection, String tableName) throws SQLException {
              try (Statement stmt = connection.createStatement();
                  ResultSet rs = stmt.executeQuery("select count(*) from " + tableName);) {
                  rs.next();
      
                  int count = rs.getInt(1);
      
                  int result = ROWS - count;
      
                  if (result == 0) {
                      System.out.println("Found " + count + " rows in " + tableName);
                  } else {
                      System.err.println("Found " + count + " rows in " + tableName + " instead of " + ROWS);
                  }
      
                  s();
      
                  return result;
              }
          }
      
          public static void main(String[] args) throws SQLException {
              int lostRows = 0;
              try (Connection connection = DriverManager.getConnection(DB_URL)) {
                  for (int i = 0; i < TABLES; i++) {
                      String tableName = TABLE_NAME + i;
                      createTables(connection, tableName);
      
                      insertData(connection, tableName);
      
                      lostRows += testData(connection, tableName);
                  }
              }
      
              System.exit(lostRows);
          }
      }
       

       Leads to

      1) Replication timeout exceptions like:

      0 error while executing org.apache.ignite.internal.jdbc.JdbcPreparedStatement@68999068:java.sql.BatchUpdateException: IGN-CMN-65535 TraceId:335d779d-bee2-41be-a723-8a34a3b40347 Remote query execution
      0 error while executing org.apache.ignite.internal.jdbc.JdbcPreparedStatement@6973b51b:java.sql.BatchUpdateException: IGN-REP-3 TraceId:b2d7a459-f3bf-497b-9bfb-bc7126813cd5 Replication is timed out [replicaGrpId=d3c988c3-0c7f-483e-bbc3-b9b124df144c_part_20]

      2) Data loss. Queries:

       Count(*) from  K1

      Found 99877 rows in K1 instead of 100000.

      See server logs in the attachment (serverLog.zip), TimeoutExceptionReproducer (ReplicationTimeoutReproducerClientLog.zip).

       

      Attachments

        1. node_0.log.zip
          94 kB
          Igor
        2. node_1.log.zip
          58 kB
          Igor
        3. ReplicationTimeoutReproducerClientLog.zip
          14 kB
          Alexander Belyak
        4. serverLog.zip
          179 kB
          Alexander Belyak
        5. test.log
          14 kB
          Igor

        Issue Links

          Activity

            People

              xtern Pavel Pereslegin
              Berkov Alexander Belyak
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: