[Commits] baf5e0efc8c: DML statements that are transactions on their own should also read the committed data with range locking

Sergei Petrunia psergey at askmonty.org
Mon Jan 28 15:24:00 EET 2019


revision-id: baf5e0efc8c73a043180a621df1d2a13e3a4d4e5 (fb-prod201801-200-gbaf5e0efc8c)
parent(s): 77d8f9447661f6147143b21ef43a1ac0f45139b5
author: Sergei Petrunia
committer: Sergei Petrunia
timestamp: 2019-01-28 16:24:00 +0300
message:

DML statements that are transactions on their own should also read the committed data with range locking

---
 mysql-test/suite/rocksdb/r/range_locking.result | 35 +++++++++++++++++++
 mysql-test/suite/rocksdb/t/range_locking.test   | 46 +++++++++++++++++++++++++
 storage/rocksdb/ha_rocksdb.cc                   | 10 ++++++
 3 files changed, 91 insertions(+)

diff --git a/mysql-test/suite/rocksdb/r/range_locking.result b/mysql-test/suite/rocksdb/r/range_locking.result
index b0217d5269a..bba4726323e 100644
--- a/mysql-test/suite/rocksdb/r/range_locking.result
+++ b/mysql-test/suite/rocksdb/r/range_locking.result
@@ -301,3 +301,38 @@ commit;
 disconnect con1;
 connection default;
 drop table t1;
+#
+# Another no-snapshot-checking test, this time for single-statement
+# transaction
+#
+create table t1 (pk int primary key, a int, name varchar(16)) engine=rocksdb;
+insert into t1 values (1,1, 'row1'), (2,2,'row2');
+connect  con1,localhost,root,,;
+connection con1;
+select get_lock('row1', 100);
+get_lock('row1', 100)
+1
+connection default;
+# The following will read the first row (1,1,'row1'), and stop.
+update t1 set a=a+100 where get_lock(name, 1000)=1;
+connection con1;
+update t1 set a=5 where pk=2;
+select release_lock('row1');
+release_lock('row1')
+1
+connection default;
+# Look at the row with pk=2:
+#  2, 105, row2 - means the UPDATE was reading current data (Correct)
+#  2, 102, row - means the UPDATE read the snapshot (incorrect)
+select * from t1;
+pk	a	name
+1	101	row1
+2	105	row2
+# Try releasing both locks (in 5.6, we will be holding only the second one)
+select release_lock(name) from t1;
+release_lock(name)
+NULL
+1
+disconnect con1;
+connection default;
+drop table t1;
diff --git a/mysql-test/suite/rocksdb/t/range_locking.test b/mysql-test/suite/rocksdb/t/range_locking.test
index e1e8ac92bdc..068bb3be4b1 100644
--- a/mysql-test/suite/rocksdb/t/range_locking.test
+++ b/mysql-test/suite/rocksdb/t/range_locking.test
@@ -306,3 +306,49 @@ commit;
 disconnect con1;
 connection default;
 drop table t1;
+
+--echo #
+--echo # Another no-snapshot-checking test, this time for single-statement
+--echo # transaction
+--echo #
+
+create table t1 (pk int primary key, a int, name varchar(16)) engine=rocksdb;
+insert into t1 values (1,1, 'row1'), (2,2,'row2');
+
+connect (con1,localhost,root,,);
+connection con1;
+select get_lock('row1', 100);
+
+connection default;
+
+--echo # The following will read the first row (1,1,'row1'), and stop.
+
+send update t1 set a=a+100 where get_lock(name, 1000)=1;
+
+# Wait till the default connection has stopped:
+connection con1;
+
+let $wait_condition=
+  SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = "User lock"
+  AND INFO = "update t1 set a=a+100 where get_lock(name, 1000)=1";
+--source include/wait_condition.inc
+
+# Update the second row
+update t1 set a=5 where pk=2;
+
+select release_lock('row1');
+
+connection default;
+reap;
+
+--echo # Look at the row with pk=2:
+--echo #  2, 105, row2 - means the UPDATE was reading current data (Correct)
+--echo #  2, 102, row - means the UPDATE read the snapshot (incorrect)
+select * from t1;
+
+--echo # Try releasing both locks (in 5.6, we will be holding only the second one)
+select release_lock(name) from t1;
+
+disconnect con1;
+connection default;
+drop table t1;
diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc
index 8871a43c048..9f67b388e44 100644
--- a/storage/rocksdb/ha_rocksdb.cc
+++ b/storage/rocksdb/ha_rocksdb.cc
@@ -2628,6 +2628,7 @@ public:
   virtual bool is_tx_started() const = 0;
   virtual void start_tx() = 0;
   virtual void start_stmt(bool is_dml_statement) = 0;
+  virtual void start_autocommit_stmt(bool is_dml_statement){}
 
   void set_initial_savepoint() {
     /*
@@ -3082,6 +3083,12 @@ public:
     acquire_snapshot(false);
   }
 
+  void start_autocommit_stmt(bool is_dml_statement) override {
+    if (rocksdb_use_range_locking && is_dml_statement) {
+      start_ignore_snapshot();
+    }
+  }
+
   /*
     This must be called when last statement is rolled back, but the transaction
     continues
@@ -3696,6 +3703,7 @@ static int rocksdb_commit(handlerton *const hton, THD *const thd,
          - For a COMMIT statement that finishes a multi-statement transaction
          - For a statement that has its own transaction
       */
+      tx->end_ignore_snapshot_if_needed();
       if (tx->commit()) {
         DBUG_RETURN(HA_ERR_ROCKSDB_COMMIT_FAILED);
       }
@@ -4303,6 +4311,8 @@ static inline void rocksdb_register_tx(handlerton *const hton, THD *const thd,
   if (my_core::thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
     tx->start_stmt(is_dml_stmt);
     trans_register_ha(thd, TRUE, rocksdb_hton);
+  } else {
+    tx->start_autocommit_stmt(is_dml_stmt);
   }
 }
 


More information about the commits mailing list