--source include/have_debug.inc
--source include/have_rocksdb.inc
--source include/master-slave.inc


# initialization/insert
--source include/rpl_connection_master.inc
create table t1 (id int primary key, value int) Engine=RocksDB;
insert into t1 values (1,1), (2,2), (3,3), (4,4);
--source include/sync_slave_sql_with_master.inc

--let $diff_tables= master:t1, slave:t1

--echo
--echo # regular update/delete. With rocks_read_free_rpl=PK_SK, rocksdb_rows_read does not increase on slaves
--echo
--source include/rpl_connection_slave.inc
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
update t1 set value=value+1 where id=1;
delete from t1 where id=4;
select * from t1;
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
select * from t1;


--echo
--echo # "rocks_read_free_rpl=PK_SK" makes "row not found error" not happen anymore
--echo
--source include/rpl_connection_slave.inc
--source include/stop_slave.inc
delete from t1 where id in (2, 3);
--source include/start_slave.inc
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';

--source include/rpl_connection_master.inc
update t1 set value=value+1 where id=3;
delete from t1 where id=2;
select * from t1;
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
select * from t1;


--echo
--echo ## tables without primary key -- read free replication should be disabled
--echo
--echo
--echo #no index
--echo
--source include/rpl_connection_master.inc
drop table t1;
create table t1 (c1 int, c2 int) Engine=RocksDB;
insert into t1 values (1,1), (2,2),(3,3),(4,4),(5,5);
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
update t1 set c2=100 where c1=3;
delete from t1 where c1 <= 2;
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
select * from t1;

--echo
--echo #secondary index only
--echo
--source include/rpl_connection_master.inc
drop table t1;
create table t1 (c1 int, c2 int, index i(c1)) Engine=RocksDB;
insert into t1 values (1,1), (2,2),(3,3),(4,4),(5,5);
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
update t1 set c2=100 where c1=3;
delete from t1 where c1 <= 2;
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
select * from t1;



--echo
--echo ## large row operations -- primary key modification, secondary key modification
--echo
--source include/rpl_connection_master.inc
drop table t1;
create table t1 (id1 bigint, id2 bigint, c1 bigint, c2 bigint, c3 bigint, c4 bigint, c5 bigint, c6 bigint, c7 bigint, primary key (id1, id2), index i(c1, c2)) Engine=RocksDB;

--disable_query_log
let $i=1;
while ($i<=10000)
{
  eval insert t1(id1,id2,c1,c2,c3,c4,c5,c6,c7)
  values($i,0,$i,0,0,0,0,0,0);
  inc $i;
}
--enable_query_log

--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc

--echo
--echo #updating all secondary keys by 1
--echo
--disable_query_log
let $i=1;
while ($i<=10000)
{
  eval update t1 set c2=c2+1 where id1=$i and id2=0;
  inc $i;
}
--enable_query_log
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
--source include/diff_tables.inc

--echo
--echo #updating all primary keys by 2
--echo
--source include/rpl_connection_slave.inc
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
--disable_query_log
let $i=1;
while ($i<=10000)
{
  eval update t1 set id2=id2+2 where id1=$i and id2=0;
  inc $i;
}
--enable_query_log
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
--source include/diff_tables.inc

--echo
--echo #updating secondary keys after truncating t1 on slave
--echo
--source include/rpl_connection_slave.inc
truncate table t1;
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
update t1 set c2=c2+10;
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
--source include/diff_tables.inc

--echo
--echo #updating primary keys after truncating t1 on slave
--echo
--source include/rpl_connection_slave.inc
truncate table t1;
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
update t1 set id2=id2+10;
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
--source include/diff_tables.inc

--echo
--echo #deleting half rows
--echo
--source include/rpl_connection_slave.inc
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
delete from t1 where id1 <= 5000;
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
--source include/diff_tables.inc

--echo
--echo # rocksdb_read_free_rpl = PK_ONLY i.e. it only works on tables with only PK
--echo
--source include/rpl_connection_slave.inc
--echo [on slave]
--source include/stop_slave.inc
set @@global.rocksdb_read_free_rpl = PK_ONLY;
--source include/start_slave.inc
--source include/rpl_connection_master.inc
--echo [on master]
create table t2 (id int primary key, i1 int, i2 int, value int) Engine=RocksDB;
create table u2 (id int primary key, i1 int, i2 int, value int, index(i1), index(i2)) Engine=RocksDB;
insert into t2 values (1,1,1,1),(2,2,2,2),(3,3,3,3);
insert into u2 values (1,1,1,1),(2,2,2,2),(3,3,3,3);
--source include/sync_slave_sql_with_master.inc

# make a mismatch between the slave and the master
--source include/rpl_connection_slave.inc
--echo [on slave]
delete from t2 where id <= 2;
delete from u2 where id <= 2;

# make changes on the master
--source include/rpl_connection_master.inc
--echo [on master]
update t2 set i2=100, value=100 where id=1;
update u2 set i2=100, value=100 where id=1;

--source include/rpl_connection_slave.inc
--echo [on slave]
call mtr.add_suppression("Slave SQL.*Could not execute Update_rows event on table test.u2.*Error_code.*");
call mtr.add_suppression("Slave: Can't find record in 'u2'.*");
# wait until we have the expected error
--let $slave_sql_errno= convert_error(ER_KEY_NOT_FOUND)
--source include/wait_for_slave_sql_error.inc

# query the t2 table on the slave
--source include/rpl_connection_slave.inc
select count(*) from t2 force index(primary);
select * from t2 where id=1;
select i1 from t2 where i1=1;
select i2 from t2 where i2=100;

# query the u2 table on the slave
select count(*) from u2 force index(primary);
select count(*) from u2 force index(i1);
select count(*) from u2 force index(i2);
select * from u2 where id=1;
select i1 from u2 where i1=1;
select i2 from u2 where i2=100;

# the slave replication thread stopped because of the errors;
# cleanup the problem and restart it
--disable_query_log
insert into u2 values(1,1,1,1), (2,2,2,2);
start slave sql_thread;
--source include/wait_for_slave_sql_to_start.inc
--enable_query_log

--source include/rpl_connection_slave.inc
--echo [on slave]
--source include/stop_slave.inc
set @@global.rocksdb_read_free_rpl = PK_SK;
--source include/start_slave.inc

if (0) { # Percona Server disabled rocksdb_read_free_rpl_tables as it's dangerous to use
--echo
--echo # some tables with read-free replication on and some with it off
--echo
# We'll set the table filter to all tables starting with 't'
--source include/rpl_connection_slave.inc
--echo [on slave]
--source include/stop_slave.inc
set @@global.rocksdb_read_free_rpl_tables = "t.*";
--source include/start_slave.inc
--source include/rpl_connection_master.inc
--echo [on master]
drop table if exists t2;
drop table if exists u2;
create table t2 (id int primary key, i1 int, i2 int, value int) Engine=RocksDB;
create table u2 (id int primary key, i1 int, i2 int, value int) Engine=RocksDB;
insert into t2 values (1,1,1,1),(2,2,2,2),(3,3,3,3);
insert into u2 values (1,1,1,1),(2,2,2,2),(3,3,3,3);
--source include/sync_slave_sql_with_master.inc

# make a mismatch between the slave and the master
--source include/rpl_connection_slave.inc
--echo [on slave]
delete from t2 where id <= 2;
delete from u2 where id <= 2;

# make changes on the master
--source include/rpl_connection_master.inc
--echo [on master]
update t2 set i2=100, value=100 where id=1;
update u2 set i2=100, value=100 where id=1;

--source include/rpl_connection_slave.inc
--echo [on slave]
call mtr.add_suppression("Slave SQL.*Could not execute Update_rows event on table test.u2.*Error_code.*");
call mtr.add_suppression("Slave: Can't find record in 'u2'.*");
# wait until we have the expected error
--let $slave_sql_errno= convert_error(ER_KEY_NOT_FOUND)
--source include/wait_for_slave_sql_error.inc

# query the t2 table on the slave
--source include/rpl_connection_slave.inc
select count(*) from t2 force index(primary);
select * from t2 where id=1;
select i1 from t2 where i1=1;
select i2 from t2 where i2=100;

# query the u2 table on the slave
select count(*) from u2 force index(primary);
select * from u2 where id=1;
select i1 from u2 where i1=1;
select i2 from u2 where i2=100;

# the slave replication thread stopped because of the errors;
# cleanup the problem and restart it
--disable_query_log
insert into u2 values(1,1,1,1), (2,2,2,2);
start slave sql_thread;
--source include/wait_for_slave_sql_to_start.inc
--enable_query_log

--source include/rpl_connection_slave.inc
--echo [on slave]
--source include/stop_slave.inc
set @@global.rocksdb_read_free_rpl_tables = ".*";
--source include/start_slave.inc
} # if (0)

--echo
--echo # secondary keys lose rows
--echo
--source include/rpl_connection_master.inc
--echo [on master]
create table t3 (id int primary key, i1 int, i2 int, value int, index(i1),
index(i2)) Engine=RocksDB;
insert into t3 values (1,1,1,1),(2,2,2,2),(3,3,3,3);
--source include/sync_slave_sql_with_master.inc

# make a mismatch between the slave and the master
--source include/rpl_connection_slave.inc
--echo [on slave]
delete from t3 where id <= 2;

# make changes on the master
--source include/rpl_connection_master.inc
--echo [on master]
update t3 set i2=100, value=100 where id=1;

# make sure the slave is caught up
--source include/sync_slave_sql_with_master.inc

# query the t3 table on the slave
--source include/rpl_connection_slave.inc
select count(*) from t3 force index(primary);
select count(*) from t3 force index(i1);
select count(*) from t3 force index(i2);
select * from t3 where id=1;
select i1 from t3 where i1=1;
select i2 from t3 where i2=100;

--echo
--echo # secondary keys have extra rows
--echo
--source include/rpl_connection_master.inc
--echo [on master]
create table t4 (id int primary key, i1 int, i2 int, value int, index(i1), index(i2)) Engine=RocksDB;
insert into t4 values (1,1,1,1),(2,2,2,2),(3,3,3,3);
--source include/sync_slave_sql_with_master.inc

# make a mismatch between the slave and the master
--source include/rpl_connection_slave.inc
--echo [on slave]
update t4 set i1=100 where id=1;

# make changes on the master
--source include/rpl_connection_master.inc
--echo [on master]
delete from t4 where id=1;

# make sure the slave is caught up
--source include/sync_slave_sql_with_master.inc

# query the t4 table on the slave
--source include/rpl_connection_slave.inc
--echo [on slave]
select count(*) from t4 force index(primary);
select count(*) from t4 force index(i1);
select count(*) from t4 force index(i2);
select i1 from t4 where i1=100;

--echo
--echo # inserts are also read-free
--echo
--source include/rpl_connection_master.inc
--echo [on master]
drop table if exists t2;
drop table if exists t3;
create table t2 (id int primary key, i1 int, i2 int) Engine=RocksDB;
create table t3 (id int primary key, i1 int, i2 int, key(i1)) Engine=RocksDB;
--source include/rpl_connection_slave.inc
select variable_value into @up from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
--source include/rpl_connection_master.inc
insert into t2 values(1, 1, 1);
insert into t2 values(2, 2, 2);
insert into t3 values(1, 1, 1);
insert into t3 values(2, 2, 2);
--source include/sync_slave_sql_with_master.inc
--source include/rpl_connection_slave.inc
select case when variable_value-@up > 0 then 'false' else 'true' end as read_free from performance_schema.global_status where variable_name='rocksdb_num_get_for_update_calls';
select * from t2;
select * from t3;

# cleanup
--source include/rpl_connection_master.inc
drop table t1, t2, t3, t4, u2;

--source include/rpl_end.inc

