mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
Merge 10.2 into 10.3
This commit is contained in:
commit
6373ec3ec7
36 changed files with 2729 additions and 358 deletions
|
@ -14,7 +14,6 @@ MW-286 : MDEV-18464 Killing thread can cause mutex deadlock if done concurrently
|
|||
MW-328A : MDEV-21483 galera.MW-328A galera.MW-328B
|
||||
MW-328B : MDEV-21483 galera.MW-328A galera.MW-328B
|
||||
MW-329 : MDEV-19962 Galera test failure on MW-329
|
||||
MW-336 : MDEV-17062 Test failure on galera.MW-336
|
||||
galera.galera_defaults : MDEV-21494 Galera test sporadic failure on galera.galera_defaults
|
||||
galera_account_management : MariaDB 10.0 does not support ALTER USER
|
||||
galera_as_master_gtid : Requires MySQL GTID
|
||||
|
|
119
mysql-test/suite/innodb/r/innodb_bug30113362.result
Normal file
119
mysql-test/suite/innodb/r/innodb_bug30113362.result
Normal file
|
@ -0,0 +1,119 @@
|
|||
SET GLOBAL innodb_adaptive_hash_index = false;
|
||||
SET GLOBAL innodb_stats_persistent = false;
|
||||
connect purge_control,localhost,root,,;
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
connect con2,localhost,root,,;
|
||||
CREATE TABLE t1 (
|
||||
a00 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a01 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a02 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
b INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY(a00, a01, a02)
|
||||
) charset latin1 ENGINE = InnoDB COMMENT='MERGE_THRESHOLD=45';
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 3;
|
||||
CREATE PROCEDURE data_load_t1()
|
||||
BEGIN
|
||||
DECLARE c1 INT DEFAULT 97;
|
||||
DECLARE c2 INT DEFAULT 97;
|
||||
DECLARE c3 INT DEFAULT 97;
|
||||
WHILE c1 < 102 DO
|
||||
WHILE c2 < 123 DO
|
||||
WHILE c3 < 123 DO
|
||||
INSERT INTO t1 (a00) VALUES (CHAR(c1,c2,c3));
|
||||
SET c3 = c3 + 1;
|
||||
END WHILE;
|
||||
SET c3 = 97;
|
||||
SET c2 = c2 + 1;
|
||||
END WHILE;
|
||||
SET c2 = 97;
|
||||
SET c1 = c1 + 1;
|
||||
END WHILE;
|
||||
END |
|
||||
call data_load_t1();
|
||||
DROP PROCEDURE data_load_t1;
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
1856
|
||||
connection con2;
|
||||
DELETE FROM t1 WHERE a00 = 'cnm';
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t1 SET a00 = 'cnm';
|
||||
connection purge_control;
|
||||
COMMIT;
|
||||
connection con2;
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 0;
|
||||
ROLLBACK;
|
||||
# Test start
|
||||
connection purge_control;
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
connection con2;
|
||||
DELETE FROM t1 WHERE a00 = 'bii';
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t1 SET a00 = 'bii';
|
||||
SET DEBUG_SYNC = 'rollback_undo_pk SIGNAL roll1_wait WAIT_FOR roll2';
|
||||
SET DEBUG_SYNC = 'rollback_purge_clust SIGNAL rollback_waiting WAIT_FOR resume';
|
||||
ROLLBACK;
|
||||
connection purge_control;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR roll1_wait';
|
||||
COMMIT;
|
||||
SET DEBUG_SYNC = 'now SIGNAL roll2';
|
||||
connect con1,localhost,root,,;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rollback_waiting';
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
||||
SELECT a00 FROM t1 WHERE a00 = 'bii';
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1';
|
||||
SET DEBUG_SYNC = 'now SIGNAL resume';
|
||||
connection con1;
|
||||
a00
|
||||
connection con2;
|
||||
connection default;
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
1856
|
||||
DELETE FROM t1 WHERE a00 = 'dpn';
|
||||
COMMIT;
|
||||
INSERT INTO t1 SET a00 = 'dpn';
|
||||
ROLLBACK;
|
||||
ALTER TABLE t1 COMMENT='MERGE_THRESHOLD=35';
|
||||
connection purge_control;
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
connection con2;
|
||||
DELETE FROM t1 WHERE a00 = 'cnd';
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t1 SET a00 = 'cnd';
|
||||
SET DEBUG_SYNC = 'rollback_undo_pk SIGNAL roll1_wait WAIT_FOR roll2';
|
||||
SET DEBUG_SYNC = 'rollback_purge_clust SIGNAL rollback_waiting WAIT_FOR resume EXECUTE 2';
|
||||
ROLLBACK;
|
||||
connection purge_control;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR roll1_wait';
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
SET DEBUG_SYNC = 'now SIGNAL roll2';
|
||||
connection con1;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rollback_waiting TIMEOUT 1';
|
||||
SET DEBUG_SYNC = 'now SIGNAL resume';
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rollback_waiting TIMEOUT 1';
|
||||
disconnect purge_control;
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now SIGNAL resume';
|
||||
disconnect con1;
|
||||
connection con2;
|
||||
disconnect con2;
|
||||
connection default;
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
1856
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
DROP TABLE t1;
|
372
mysql-test/suite/innodb/r/innodb_wl6326.result
Normal file
372
mysql-test/suite/innodb/r/innodb_wl6326.result
Normal file
|
@ -0,0 +1,372 @@
|
|||
DROP TABLE IF EXISTS t1;
|
||||
SET GLOBAL innodb_adaptive_hash_index = false;
|
||||
SET GLOBAL innodb_stats_persistent = false;
|
||||
connect con1,localhost,root,,;
|
||||
connect con2,localhost,root,,;
|
||||
connect con3,localhost,root,,;
|
||||
CREATE TABLE t1 (
|
||||
a00 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a01 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a02 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a03 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a04 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a05 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a06 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
b INT NOT NULL DEFAULT 0
|
||||
) ENGINE = InnoDB;
|
||||
ALTER TABLE t1 ADD PRIMARY KEY(
|
||||
a00,
|
||||
a01,
|
||||
a02,
|
||||
a03,
|
||||
a04,
|
||||
a05,
|
||||
a06
|
||||
);
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
1
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 7;
|
||||
INSERT INTO t1 (a00) VALUES ('aa');
|
||||
INSERT INTO t1 (a00) VALUES ('ab');
|
||||
INSERT INTO t1 (a00) VALUES ('ac');
|
||||
INSERT INTO t1 (a00) VALUES ('ad');
|
||||
INSERT INTO t1 (a00) VALUES ('ae');
|
||||
INSERT INTO t1 (a00) VALUES ('af');
|
||||
INSERT INTO t1 (a00) VALUES ('ag');
|
||||
INSERT INTO t1 (a00) VALUES ('ah');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
3
|
||||
INSERT INTO t1 (a00) VALUES ('ai');
|
||||
INSERT INTO t1 (a00) VALUES ('aj');
|
||||
INSERT INTO t1 (a00) VALUES ('ak');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
4
|
||||
INSERT INTO t1 (a00) VALUES ('al');
|
||||
INSERT INTO t1 (a00) VALUES ('am');
|
||||
INSERT INTO t1 (a00) VALUES ('an');
|
||||
INSERT INTO t1 (a00) VALUES ('ao');
|
||||
INSERT INTO t1 (a00) VALUES ('ap');
|
||||
INSERT INTO t1 (a00) VALUES ('aq');
|
||||
INSERT INTO t1 (a00) VALUES ('ar');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
5
|
||||
INSERT INTO t1 (a00) VALUES ('as');
|
||||
INSERT INTO t1 (a00) VALUES ('at');
|
||||
INSERT INTO t1 (a00) VALUES ('au');
|
||||
INSERT INTO t1 (a00) VALUES ('av');
|
||||
INSERT INTO t1 (a00) VALUES ('aw');
|
||||
INSERT INTO t1 (a00) VALUES ('ax');
|
||||
INSERT INTO t1 (a00) VALUES ('ay');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
6
|
||||
INSERT INTO t1 (a00) VALUES ('az');
|
||||
INSERT INTO t1 (a00) VALUES ('ba');
|
||||
INSERT INTO t1 (a00) VALUES ('bb');
|
||||
INSERT INTO t1 (a00) VALUES ('bc');
|
||||
INSERT INTO t1 (a00) VALUES ('bd');
|
||||
INSERT INTO t1 (a00) VALUES ('be');
|
||||
INSERT INTO t1 (a00) VALUES ('bf');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
7
|
||||
INSERT INTO t1 (a00) VALUES ('bg');
|
||||
INSERT INTO t1 (a00) VALUES ('bh');
|
||||
INSERT INTO t1 (a00) VALUES ('bi');
|
||||
INSERT INTO t1 (a00) VALUES ('bj');
|
||||
INSERT INTO t1 (a00) VALUES ('bk');
|
||||
INSERT INTO t1 (a00) VALUES ('bl');
|
||||
INSERT INTO t1 (a00) VALUES ('bm');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
8
|
||||
INSERT INTO t1 (a00) VALUES ('bn');
|
||||
INSERT INTO t1 (a00) VALUES ('bo');
|
||||
INSERT INTO t1 (a00) VALUES ('bp');
|
||||
INSERT INTO t1 (a00) VALUES ('bq');
|
||||
INSERT INTO t1 (a00) VALUES ('br');
|
||||
INSERT INTO t1 (a00) VALUES ('bs');
|
||||
INSERT INTO t1 (a00) VALUES ('bt');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
11
|
||||
INSERT INTO t1 (a00) VALUES ('bu');
|
||||
INSERT INTO t1 (a00) VALUES ('bv');
|
||||
INSERT INTO t1 (a00) VALUES ('bw');
|
||||
INSERT INTO t1 (a00) VALUES ('bx');
|
||||
INSERT INTO t1 (a00) VALUES ('by');
|
||||
INSERT INTO t1 (a00) VALUES ('bz');
|
||||
INSERT INTO t1 (a00) VALUES ('ca');
|
||||
INSERT INTO t1 (a00) VALUES ('cb');
|
||||
INSERT INTO t1 (a00) VALUES ('cc');
|
||||
INSERT INTO t1 (a00) VALUES ('cd');
|
||||
INSERT INTO t1 (a00) VALUES ('ce');
|
||||
INSERT INTO t1 (a00) VALUES ('cf');
|
||||
INSERT INTO t1 (a00) VALUES ('cg');
|
||||
INSERT INTO t1 (a00) VALUES ('ch');
|
||||
INSERT INTO t1 (a00) VALUES ('ci');
|
||||
INSERT INTO t1 (a00) VALUES ('cj');
|
||||
INSERT INTO t1 (a00) VALUES ('ck');
|
||||
INSERT INTO t1 (a00) VALUES ('cl');
|
||||
INSERT INTO t1 (a00) VALUES ('cm');
|
||||
INSERT INTO t1 (a00) VALUES ('cn');
|
||||
INSERT INTO t1 (a00) VALUES ('co');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
15
|
||||
INSERT INTO t1 (a00) VALUES ('cp');
|
||||
INSERT INTO t1 (a00) VALUES ('cq');
|
||||
INSERT INTO t1 (a00) VALUES ('cr');
|
||||
INSERT INTO t1 (a00) VALUES ('cs');
|
||||
INSERT INTO t1 (a00) VALUES ('ct');
|
||||
INSERT INTO t1 (a00) VALUES ('cu');
|
||||
INSERT INTO t1 (a00) VALUES ('cv');
|
||||
INSERT INTO t1 (a00) VALUES ('cw');
|
||||
INSERT INTO t1 (a00) VALUES ('cx');
|
||||
INSERT INTO t1 (a00) VALUES ('cy');
|
||||
INSERT INTO t1 (a00) VALUES ('cz');
|
||||
INSERT INTO t1 (a00) VALUES ('da');
|
||||
INSERT INTO t1 (a00) VALUES ('db');
|
||||
INSERT INTO t1 (a00) VALUES ('dc');
|
||||
INSERT INTO t1 (a00) VALUES ('dd');
|
||||
INSERT INTO t1 (a00) VALUES ('de');
|
||||
INSERT INTO t1 (a00) VALUES ('df');
|
||||
INSERT INTO t1 (a00) VALUES ('dg');
|
||||
INSERT INTO t1 (a00) VALUES ('dh');
|
||||
INSERT INTO t1 (a00) VALUES ('di');
|
||||
INSERT INTO t1 (a00) VALUES ('dj');
|
||||
INSERT INTO t1 (a00) VALUES ('dk');
|
||||
INSERT INTO t1 (a00) VALUES ('dl');
|
||||
INSERT INTO t1 (a00) VALUES ('dm');
|
||||
INSERT INTO t1 (a00) VALUES ('dn');
|
||||
INSERT INTO t1 (a00) VALUES ('do');
|
||||
INSERT INTO t1 (a00) VALUES ('dp');
|
||||
INSERT INTO t1 (a00) VALUES ('dq');
|
||||
INSERT INTO t1 (a00) VALUES ('dr');
|
||||
INSERT INTO t1 (a00) VALUES ('ds');
|
||||
INSERT INTO t1 (a00) VALUES ('dt');
|
||||
INSERT INTO t1 (a00) VALUES ('du');
|
||||
INSERT INTO t1 (a00) VALUES ('dv');
|
||||
INSERT INTO t1 (a00) VALUES ('dw');
|
||||
INSERT INTO t1 (a00) VALUES ('dx');
|
||||
INSERT INTO t1 (a00) VALUES ('dy');
|
||||
INSERT INTO t1 (a00) VALUES ('dz');
|
||||
INSERT INTO t1 (a00) VALUES ('ea');
|
||||
INSERT INTO t1 (a00) VALUES ('eb');
|
||||
INSERT INTO t1 (a00) VALUES ('ec');
|
||||
INSERT INTO t1 (a00) VALUES ('ed');
|
||||
INSERT INTO t1 (a00) VALUES ('ee');
|
||||
INSERT INTO t1 (a00) VALUES ('ef');
|
||||
INSERT INTO t1 (a00) VALUES ('eg');
|
||||
INSERT INTO t1 (a00) VALUES ('eh');
|
||||
INSERT INTO t1 (a00) VALUES ('ei');
|
||||
INSERT INTO t1 (a00) VALUES ('ej');
|
||||
INSERT INTO t1 (a00) VALUES ('ek');
|
||||
INSERT INTO t1 (a00) VALUES ('el');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
23
|
||||
INSERT INTO t1 (a00) VALUES ('em');
|
||||
INSERT INTO t1 (a00) VALUES ('en');
|
||||
INSERT INTO t1 (a00) VALUES ('eo');
|
||||
INSERT INTO t1 (a00) VALUES ('ep');
|
||||
INSERT INTO t1 (a00) VALUES ('eq');
|
||||
INSERT INTO t1 (a00) VALUES ('er');
|
||||
INSERT INTO t1 (a00) VALUES ('es');
|
||||
INSERT INTO t1 (a00) VALUES ('et');
|
||||
INSERT INTO t1 (a00) VALUES ('eu');
|
||||
INSERT INTO t1 (a00) VALUES ('ev');
|
||||
INSERT INTO t1 (a00) VALUES ('ew');
|
||||
INSERT INTO t1 (a00) VALUES ('ex');
|
||||
INSERT INTO t1 (a00) VALUES ('ey');
|
||||
INSERT INTO t1 (a00) VALUES ('ez');
|
||||
INSERT INTO t1 (a00) VALUES ('fa');
|
||||
INSERT INTO t1 (a00) VALUES ('fb');
|
||||
INSERT INTO t1 (a00) VALUES ('fc');
|
||||
INSERT INTO t1 (a00) VALUES ('fd');
|
||||
INSERT INTO t1 (a00) VALUES ('fe');
|
||||
INSERT INTO t1 (a00) VALUES ('ff');
|
||||
INSERT INTO t1 (a00) VALUES ('fg');
|
||||
INSERT INTO t1 (a00) VALUES ('fh');
|
||||
INSERT INTO t1 (a00) VALUES ('fi');
|
||||
INSERT INTO t1 (a00) VALUES ('fj');
|
||||
INSERT INTO t1 (a00) VALUES ('fk');
|
||||
INSERT INTO t1 (a00) VALUES ('fl');
|
||||
INSERT INTO t1 (a00) VALUES ('fm');
|
||||
INSERT INTO t1 (a00) VALUES ('fn');
|
||||
INSERT INTO t1 (a00) VALUES ('fo');
|
||||
INSERT INTO t1 (a00) VALUES ('fp');
|
||||
INSERT INTO t1 (a00) VALUES ('fq');
|
||||
INSERT INTO t1 (a00) VALUES ('fr');
|
||||
INSERT INTO t1 (a00) VALUES ('fs');
|
||||
INSERT INTO t1 (a00) VALUES ('ft');
|
||||
INSERT INTO t1 (a00) VALUES ('fu');
|
||||
INSERT INTO t1 (a00) VALUES ('fv');
|
||||
INSERT INTO t1 (a00) VALUES ('fw');
|
||||
INSERT INTO t1 (a00) VALUES ('fx');
|
||||
INSERT INTO t1 (a00) VALUES ('fy');
|
||||
INSERT INTO t1 (a00) VALUES ('fz');
|
||||
INSERT INTO t1 (a00) VALUES ('ga');
|
||||
INSERT INTO t1 (a00) VALUES ('gb');
|
||||
INSERT INTO t1 (a00) VALUES ('gc');
|
||||
INSERT INTO t1 (a00) VALUES ('gd');
|
||||
INSERT INTO t1 (a00) VALUES ('ge');
|
||||
INSERT INTO t1 (a00) VALUES ('gf');
|
||||
INSERT INTO t1 (a00) VALUES ('gg');
|
||||
INSERT INTO t1 (a00) VALUES ('gh');
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
29
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 0;
|
||||
# Test start
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
INSERT INTO t1 (a00) VALUES ('bfa');
|
||||
connection con1;
|
||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
||||
INSERT INTO t1 (a00) VALUES ('bfb');
|
||||
connection con2;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
||||
a00 a01
|
||||
aa a
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aq';
|
||||
a00 a01
|
||||
aq a
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'cp';
|
||||
a00 a01
|
||||
cp a
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
||||
a00 a01
|
||||
el a
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'ar';
|
||||
connection con3;
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'cn';
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1';
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2';
|
||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
||||
connection con1;
|
||||
connection con2;
|
||||
a00 a01
|
||||
ar a
|
||||
connection con3;
|
||||
a00 a01
|
||||
cn a
|
||||
connection default;
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
30
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
INSERT INTO t1 (a00) VALUES ('coa');
|
||||
connection con1;
|
||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
||||
INSERT INTO t1 (a00) VALUES ('cob');
|
||||
connection con2;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
||||
connection con3;
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1';
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2';
|
||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
||||
connection con1;
|
||||
connection con2;
|
||||
a00 a01
|
||||
aa a
|
||||
connection con3;
|
||||
a00 a01
|
||||
el a
|
||||
connection default;
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
31
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
INSERT INTO t1 (a00) VALUES ('gba');
|
||||
connection con1;
|
||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
||||
INSERT INTO t1 (a00) VALUES ('gbb');
|
||||
connection con2;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
||||
a00 a01
|
||||
aa a
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'ek';
|
||||
a00 a01
|
||||
ek a
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
||||
connection con3;
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'gb';
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1';
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2';
|
||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
||||
connection con1;
|
||||
connection con2;
|
||||
a00 a01
|
||||
el a
|
||||
connection con3;
|
||||
a00 a01
|
||||
gb a
|
||||
connection default;
|
||||
ANALYZE TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
CLUST_INDEX_SIZE
|
||||
32
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
connection default;
|
||||
disconnect con1;
|
||||
disconnect con2;
|
||||
disconnect con3;
|
||||
DROP TABLE t1;
|
449
mysql-test/suite/innodb/r/innodb_wl6326_big.result
Normal file
449
mysql-test/suite/innodb/r/innodb_wl6326_big.result
Normal file
|
@ -0,0 +1,449 @@
|
|||
CREATE SCHEMA my_schema;
|
||||
USE my_schema;
|
||||
CREATE FUNCTION f_thread_id (i INT) RETURNS CHAR(4) DETERMINISTIC
|
||||
RETURN CONCAT(LPAD(CAST(i AS CHAR),3,'_'),'_') ;
|
||||
SELECT CONCAT('->', f_thread_id( 1), '<-');
|
||||
CONCAT('->', f_thread_id( 1), '<-')
|
||||
->__1_<-
|
||||
SELECT CONCAT('->', f_thread_id(12), '<-');
|
||||
CONCAT('->', f_thread_id(12), '<-')
|
||||
->_12_<-
|
||||
SET @extra_int = 1;
|
||||
SET @extra_string = f_thread_id(@extra_int);
|
||||
SELECT @extra_int , @extra_string;
|
||||
@extra_int @extra_string
|
||||
1 __1_
|
||||
CREATE FUNCTION f_col_int1 (i INT) RETURNS INT(20) DETERMINISTIC
|
||||
RETURN i * 1000 + @extra_int ;
|
||||
SELECT f_col_int1(my_col) AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
my_result
|
||||
1001
|
||||
12001
|
||||
123001
|
||||
1234001
|
||||
12345001
|
||||
CREATE FUNCTION f_col_int2 (i INT) RETURNS INT(20) DETERMINISTIC
|
||||
RETURN @extra_int * 10000000 + i ;
|
||||
SELECT f_col_int2(my_col) AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
my_result
|
||||
10000001
|
||||
10000012
|
||||
10000123
|
||||
10001234
|
||||
10012345
|
||||
CREATE FUNCTION f_col_int3 (i INT) RETURNS INT(20) DETERMINISTIC
|
||||
RETURN @extra_int ;
|
||||
SELECT f_col_int3(my_col) AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
my_result
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
CREATE FUNCTION f_col_blob (i INT) RETURNS BLOB DETERMINISTIC
|
||||
RETURN RPAD(@extra_string,(@@innodb_page_size / 2 ) + 1,'a');
|
||||
SELECT CONCAT('->', SUBSTR(f_col_blob(my_col) FROM 1 FOR 10),
|
||||
'<-.....->', SUBSTR(f_col_blob(my_col) FROM -10 FOR 10), '<-') AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
my_result
|
||||
->__1_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
->__1_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
->__1_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
->__1_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
->__1_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
CREATE FUNCTION f_col_char0 (i INT) RETURNS CHAR(255) DETERMINISTIC
|
||||
RETURN LPAD(CAST(i AS CHAR),255,' ');
|
||||
SELECT CONCAT('->', f_col_char0(my_col), '<-') AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
my_result
|
||||
-> 1<-
|
||||
-> 12<-
|
||||
-> 123<-
|
||||
-> 1234<-
|
||||
-> 12345<-
|
||||
CREATE FUNCTION f_col_char1 (i INT) RETURNS CHAR(26) DETERMINISTIC
|
||||
RETURN
|
||||
CONCAT('B',
|
||||
LPAD(SUBSTR(CAST(i AS CHAR),1,(LENGTH(CAST(i AS CHAR)) DIV 2)),10,' '),
|
||||
@extra_string,
|
||||
RPAD(SUBSTR(CAST(i AS CHAR), -((LENGTH(CAST(i AS CHAR)) + 1) DIV 2)),10,' '),
|
||||
'E') ;
|
||||
SELECT CONCAT('->', f_col_char1(my_col), '<-') AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
my_result
|
||||
->B __1_1 E<-
|
||||
->B 1__1_2 E<-
|
||||
->B 1__1_23 E<-
|
||||
->B 12__1_34 E<-
|
||||
->B 12__1_345 E<-
|
||||
CREATE FUNCTION f_col_char2 (i INT) RETURNS CHAR(26) DETERMINISTIC
|
||||
RETURN
|
||||
CONCAT('B',
|
||||
RPAD(SUBSTR(CAST(i AS CHAR),1,(LENGTH(CAST(i AS CHAR)) DIV 2)),10,' '),
|
||||
@extra_string,
|
||||
LPAD(SUBSTR(CAST(i AS CHAR), -((LENGTH(CAST(i AS CHAR)) + 1) DIV 2)),10,' '),
|
||||
'E');
|
||||
SELECT CONCAT('->', f_col_char2(my_col), '<-') AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
my_result
|
||||
->B __1_ 1E<-
|
||||
->B1 __1_ 2E<-
|
||||
->B1 __1_ 23E<-
|
||||
->B12 __1_ 34E<-
|
||||
->B12 __1_ 345E<-
|
||||
CREATE FUNCTION f_col_char3 (i INT) RETURNS CHAR(26) DETERMINISTIC
|
||||
RETURN
|
||||
CONCAT('B',@extra_string,LPAD(CAST(i AS CHAR),20,' '),'E');
|
||||
SELECT CONCAT('->', f_col_char3(my_col), '<-') AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
my_result
|
||||
->B__1_ 1E<-
|
||||
->B__1_ 12E<-
|
||||
->B__1_ 123E<-
|
||||
->B__1_ 1234E<-
|
||||
->B__1_ 12345E<-
|
||||
CREATE FUNCTION f_col_char4 (i INT) RETURNS CHAR(26) DETERMINISTIC
|
||||
RETURN
|
||||
CONCAT('B',RPAD(CAST(i AS CHAR),20,' '),@extra_string,'E');
|
||||
SELECT CONCAT('->', f_col_char4(my_col), '<-') AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
my_result
|
||||
->B1 __1_E<-
|
||||
->B12 __1_E<-
|
||||
->B123 __1_E<-
|
||||
->B1234 __1_E<-
|
||||
->B12345 __1_E<-
|
||||
CREATE TABLE my_metrics LIKE information_schema.innodb_metrics;
|
||||
ALTER TABLE my_metrics ADD COLUMN phase ENUM('after', 'before'),
|
||||
DROP COLUMN SUBSYSTEM, DROP COLUMN TYPE, DROP COLUMN COMMENT,
|
||||
ADD PRIMARY KEY (NAME,phase);
|
||||
CREATE TABLE t1 (
|
||||
col_int0 BIGINT,
|
||||
col_int1 BIGINT,
|
||||
col_int2 BIGINT,
|
||||
col_int3 BIGINT,
|
||||
col_blob BLOB,
|
||||
col_char0 VARCHAR(255),
|
||||
col_char1 VARCHAR(30),
|
||||
col_char2 VARCHAR(30),
|
||||
col_char3 VARCHAR(30),
|
||||
col_char4 VARCHAR(30)
|
||||
) ENGINE = InnoDB;
|
||||
ALTER TABLE t1 ADD UNIQUE KEY uidx_col_int0 (col_int0),
|
||||
ADD UNIQUE KEY uidx1 (col_int1, col_char0),
|
||||
ADD UNIQUE KEY uidx2 (col_int2, col_char0, col_int1),
|
||||
ADD UNIQUE KEY uidx3 (col_int3, col_int2, col_char0),
|
||||
ADD UNIQUE KEY uidx4 (col_char1, col_char0),
|
||||
ADD UNIQUE KEY uidx5 (col_char2, col_char0, col_char1),
|
||||
ADD UNIQUE KEY uidx6 (col_char3, col_char2, col_char0),
|
||||
ADD UNIQUE KEY uidx7 (col_int1, col_int2, col_int3, col_char4,
|
||||
col_char1, col_char2, col_char3, col_char0),
|
||||
ADD KEY idx8 (col_blob(10), col_char4);
|
||||
CREATE PROCEDURE proc_fill_t1 (max_row_count INT, load_unit INT)
|
||||
BEGIN
|
||||
DECLARE my_count INTEGER DEFAULT 0;
|
||||
DECLARE max_load_count INTEGER DEFAULT 0;
|
||||
DROP TABLE IF EXISTS t0;
|
||||
CREATE TEMPORARY TABLE t0 (col_int0 BIGINT, PRIMARY KEY(col_int0));
|
||||
WHILE (my_count < load_unit ) DO
|
||||
SET my_count = my_count + 1;
|
||||
INSERT INTO t0 SET col_int0 = my_count;
|
||||
END WHILE;
|
||||
SET max_load_count = (SELECT (max_row_count DIV load_unit) + 1 );
|
||||
SELECT COUNT(col_int0) INTO @val FROM t1;
|
||||
SET my_count = 0;
|
||||
REPEAT
|
||||
INSERT INTO t1 (col_int0, col_int1, col_int2, col_int3, col_blob,
|
||||
col_char0, col_char1, col_char2,col_char3,col_char4)
|
||||
SELECT col_int0 + @val,
|
||||
f_col_int1(col_int0 + @val),
|
||||
f_col_int2(col_int0 + @val),
|
||||
f_col_int3(col_int0 + @val),
|
||||
f_col_blob(col_int0 + @val),
|
||||
f_col_char0(col_int0 + @val),
|
||||
f_col_char1(col_int0 + @val),
|
||||
f_col_char2(col_int0 + @val),
|
||||
f_col_char3(col_int0 + @val),
|
||||
f_col_char4(col_int0 + @val)
|
||||
FROM t0;
|
||||
COMMIT;
|
||||
SELECT MAX(col_int0) INTO @val FROM t1;
|
||||
SET my_count = my_count + 1;
|
||||
UNTIL( my_count > max_load_count OR @val >= max_row_count )
|
||||
END REPEAT;
|
||||
DROP TEMPORARY TABLE t0;
|
||||
END|
|
||||
CREATE PROCEDURE proc_dml (max_duration INT, t1_stripe_half INT)
|
||||
BEGIN
|
||||
DECLARE aux INTEGER DEFAULT 0;
|
||||
DECLARE start_time INT;
|
||||
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND BEGIN END;
|
||||
SET @extra_int = CONNECTION_ID();
|
||||
SET @extra_string = f_thread_id(@extra_int);
|
||||
SELECT ROUND(MAX(col_int0) / 2 ) INTO @t1_half FROM t1;
|
||||
# The user lock 'Blocker' should be already set by some other session S1.
|
||||
# S1 starts the race by releasing that lock.
|
||||
# Wait till the lock is released and the lock can be obtained.
|
||||
# In order to prevent endless waiting in case of non foreseen problems
|
||||
# limit the timespan to 30 seconds.
|
||||
SELECT GET_LOCK('Blocker', 30) INTO @aux;
|
||||
# Release the lock immediate so that the other "runner" sessions start too.
|
||||
SELECT RELEASE_LOCK('Blocker') INTO @aux;
|
||||
SET start_time = UNIX_TIMESTAMP();
|
||||
WHILE (UNIX_TIMESTAMP() - start_time < max_duration) DO
|
||||
SET @aux = @t1_half - t1_stripe_half + ROUND(RAND() * t1_stripe_half * 2);
|
||||
UPDATE t1 SET
|
||||
col_int1 = f_col_int1(col_int0),
|
||||
col_int2 = f_col_int2(col_int0),
|
||||
col_int3 = f_col_int3(col_int0),
|
||||
col_blob = f_col_blob(col_int0),
|
||||
col_char0 = f_col_char0(col_int0),
|
||||
col_char1 = f_col_char1(col_int0),
|
||||
col_char2 = f_col_char2(col_int0),
|
||||
col_char3 = f_col_char3(col_int0),
|
||||
col_char4 = f_col_char4(col_int0)
|
||||
WHERE col_int0 = @aux;
|
||||
COMMIT;
|
||||
END WHILE;
|
||||
END|
|
||||
SET GLOBAL innodb_monitor_disable = "innodb_rwlock_sx_%";
|
||||
SET @pre_reset_ts = NOW();
|
||||
SET GLOBAL innodb_monitor_reset = "innodb_rwlock_sx_%";
|
||||
SET @pre_enable_ts = NOW();
|
||||
SET GLOBAL innodb_monitor_enable = "innodb_rwlock_sx_%";
|
||||
SET @pre_collect_ts = NOW();
|
||||
DELETE FROM my_metrics;
|
||||
INSERT INTO my_metrics
|
||||
SELECT NAME, COUNT, MAX_COUNT, MIN_COUNT, AVG_COUNT,
|
||||
COUNT_RESET, MAX_COUNT_RESET, MIN_COUNT_RESET, AVG_COUNT_RESET,
|
||||
TIME_ENABLED, TIME_DISABLED, TIME_ELAPSED, TIME_RESET,
|
||||
STATUS, 'before'
|
||||
FROM information_schema.innodb_metrics
|
||||
WHERE NAME LIKE 'innodb_rwlock_sx_%';
|
||||
# TC-01 There are exact three entries "innodb_rwlock_sx_%" with the
|
||||
# with the name which follow in innodb_metrics.
|
||||
# pass
|
||||
SELECT COUNT(*) INTO @sx_count FROM my_metrics;
|
||||
# TC-02 Counting is now enabled. ALL = @sx_count entries show that.
|
||||
# pass
|
||||
# TC-03 @pre_reset_ts < TIME_RESET. ALL = @sx_count entries show that.
|
||||
# pass
|
||||
# TC-04 @pre_enable_ts < TIME_ENABLED. ALL = @sx_count entries show that.
|
||||
# pass
|
||||
# TC-05 TIME_RESET < TIME_ENABLED AND TIME_ENABLED < @pre_collect_ts
|
||||
# AND TIME_ELAPSED > 0. ALL = @sx_count entries show that.
|
||||
# pass
|
||||
# TC-06 COUNT_RESET = MAX_COUNT_RESET. ALL = @sx_count entries show that.
|
||||
# pass
|
||||
SET GLOBAL innodb_monitor_reset = "innodb_rwlock_sx_%";
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
DELETE FROM my_metrics;
|
||||
INSERT INTO my_metrics
|
||||
SELECT NAME, COUNT, MAX_COUNT, MIN_COUNT, AVG_COUNT,
|
||||
COUNT_RESET, MAX_COUNT_RESET, MIN_COUNT_RESET, AVG_COUNT_RESET,
|
||||
TIME_ENABLED, TIME_DISABLED, TIME_ELAPSED, TIME_RESET,
|
||||
STATUS, 'before'
|
||||
FROM information_schema.innodb_metrics
|
||||
WHERE NAME LIKE 'innodb_rwlock_sx_%';
|
||||
SET @extra_string = '__0_';
|
||||
SET @extra_int = 0;
|
||||
# TC-07 One session inserts some significant amount of rows into t1.
|
||||
# The system MUST survive that.
|
||||
SET @max_row_count = <max_row_count>;
|
||||
SET @load_unit = <load_unit>;
|
||||
SET @start_time = UNIX_TIMESTAMP();
|
||||
SET AUTOCOMMIT = OFF;
|
||||
CALL proc_fill_t1 (@max_row_count, @load_unit);
|
||||
# pass
|
||||
SET AUTOCOMMIT = ON;
|
||||
SELECT col_int0 INTO @t1_half FROM t1
|
||||
WHERE col_int0 >= (@val DIV 2) ORDER BY col_int0 LIMIT 1;
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
SELECT col_int0, col_int1, col_int2, col_int3,
|
||||
CONCAT('->', SUBSTR(col_blob FROM 1 FOR 10),
|
||||
'<-.....->', SUBSTR(col_blob FROM -10 FOR 10), '<-') AS col_blobx,
|
||||
CONCAT('->',col_char0,'<-') AS col_char0x,
|
||||
CONCAT('->',col_char1,'<-') AS col_char1x,
|
||||
CONCAT('->',col_char2,'<-') AS col_char2x,
|
||||
CONCAT('->',col_char3,'<-') AS col_char3x,
|
||||
CONCAT('->',col_char4,'<-') AS col_char4x
|
||||
FROM t1 WHERE col_int0 between 98 AND 102;
|
||||
col_int0 98
|
||||
col_int1 98000
|
||||
col_int2 98
|
||||
col_int3 0
|
||||
col_blobx ->__0_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
col_char0x -> 98<-
|
||||
col_char1x ->B 9__0_8 E<-
|
||||
col_char2x ->B9 __0_ 8E<-
|
||||
col_char3x ->B__0_ 98E<-
|
||||
col_char4x ->B98 __0_E<-
|
||||
col_int0 99
|
||||
col_int1 99000
|
||||
col_int2 99
|
||||
col_int3 0
|
||||
col_blobx ->__0_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
col_char0x -> 99<-
|
||||
col_char1x ->B 9__0_9 E<-
|
||||
col_char2x ->B9 __0_ 9E<-
|
||||
col_char3x ->B__0_ 99E<-
|
||||
col_char4x ->B99 __0_E<-
|
||||
col_int0 100
|
||||
col_int1 100000
|
||||
col_int2 100
|
||||
col_int3 0
|
||||
col_blobx ->__0_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
col_char0x -> 100<-
|
||||
col_char1x ->B 1__0_00 E<-
|
||||
col_char2x ->B1 __0_ 00E<-
|
||||
col_char3x ->B__0_ 100E<-
|
||||
col_char4x ->B100 __0_E<-
|
||||
col_int0 101
|
||||
col_int1 101000
|
||||
col_int2 101
|
||||
col_int3 0
|
||||
col_blobx ->__0_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
col_char0x -> 101<-
|
||||
col_char1x ->B 1__0_01 E<-
|
||||
col_char2x ->B1 __0_ 01E<-
|
||||
col_char3x ->B__0_ 101E<-
|
||||
col_char4x ->B101 __0_E<-
|
||||
col_int0 102
|
||||
col_int1 102000
|
||||
col_int2 102
|
||||
col_int3 0
|
||||
col_blobx ->__0_aaaaaa<-.....->aaaaaaaaaa<-
|
||||
col_char0x -> 102<-
|
||||
col_char1x ->B 1__0_02 E<-
|
||||
col_char2x ->B1 __0_ 02E<-
|
||||
col_char3x ->B__0_ 102E<-
|
||||
col_char4x ->B102 __0_E<-
|
||||
# TC-11 Several concurrent sessions perform updates in t1 like mad.
|
||||
# The system MUST survive this.
|
||||
# Printing of statements is partially suppressed.
|
||||
SET @start_time = UNIX_TIMESTAMP();
|
||||
SELECT 1 FROM t1 WHERE col_int0 = @t1_half FOR UPDATE;
|
||||
1
|
||||
1
|
||||
SELECT GET_LOCK('Blocker', 1000) ;
|
||||
GET_LOCK('Blocker', 1000)
|
||||
1
|
||||
RELEASE_LOCK('Blocker')
|
||||
1
|
||||
# pass
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
# TC-13 One session performs ALTER TABLE t1 ADD KEY ... on the fat table t1.
|
||||
# The system MUST survive this.
|
||||
SET @start_time = UNIX_TIMESTAMP();
|
||||
ALTER TABLE t1 ADD KEY idx_col_char4_col_char0 (col_char4,col_char0);
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
# pass
|
||||
# TC-15 One session performs a fat update on the fat table t1.
|
||||
# The system MUST survive this.
|
||||
SET @start_time = UNIX_TIMESTAMP();
|
||||
SET @extra_int = 13;
|
||||
SET @extra_string = f_thread_id(@extra_int);
|
||||
UPDATE t1 SET
|
||||
col_int1 = f_col_int1(col_int0), col_int2 = f_col_int2(col_int0),
|
||||
col_int3 = f_col_int3(col_int0), col_blob = f_col_blob(col_int0),
|
||||
col_char0 = f_col_char0(col_int0), col_char1 = f_col_char1(col_int0),
|
||||
col_char2 = f_col_char2(col_int0), col_char3 = f_col_char3(col_int0),
|
||||
col_char4 = f_col_char4(col_int0)
|
||||
WHERE col_int0 BETWEEN @t1_half - 2500 AND @t1_half + 2500;
|
||||
COMMIT;
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
# pass
|
||||
INSERT INTO my_metrics
|
||||
SELECT NAME, COUNT, MAX_COUNT, MIN_COUNT, AVG_COUNT,
|
||||
COUNT_RESET, MAX_COUNT_RESET, MIN_COUNT_RESET, AVG_COUNT_RESET,
|
||||
TIME_ENABLED, TIME_DISABLED, TIME_ELAPSED, TIME_RESET,
|
||||
STATUS, 'after'
|
||||
FROM information_schema.innodb_metrics
|
||||
WHERE NAME LIKE 'innodb_rwlock_sx_%';
|
||||
# TC-16 The following activities happend after reset in innodb_metrics
|
||||
# - Insert some significant amount of rows into t1.
|
||||
# - Several concurrent users perform excessive updates in t1.
|
||||
# - ALTER TABLE ... ADD KEY <sufficient big enough structure>
|
||||
# - One UPDATE statement modifying a huge slice of t1.
|
||||
# Any of them causes heavy use of SX lock and therefore COUNT_RESET
|
||||
# must have grown for ALL = @sx_count entries.
|
||||
# pass
|
||||
# TC-09 Heavy activity after reset.
|
||||
# COUNT_RESET = MAX_COUNT_RESET for ALL = @sx_count entries
|
||||
# needs to stay valid though he counters will have grown.
|
||||
# pass
|
||||
DELETE FROM my_metrics;
|
||||
INSERT INTO my_metrics
|
||||
SELECT NAME, COUNT, MAX_COUNT, MIN_COUNT, AVG_COUNT,
|
||||
COUNT_RESET, MAX_COUNT_RESET, MIN_COUNT_RESET, AVG_COUNT_RESET,
|
||||
TIME_ENABLED, TIME_DISABLED, TIME_ELAPSED, TIME_RESET,
|
||||
STATUS, 'before'
|
||||
FROM information_schema.innodb_metrics
|
||||
WHERE NAME LIKE 'innodb_rwlock_sx_%';
|
||||
SET GLOBAL innodb_monitor_reset = "innodb_rwlock_sx_%";
|
||||
INSERT INTO my_metrics
|
||||
SELECT NAME, COUNT, MAX_COUNT, MIN_COUNT, AVG_COUNT,
|
||||
COUNT_RESET, MAX_COUNT_RESET, MIN_COUNT_RESET, AVG_COUNT_RESET,
|
||||
TIME_ENABLED, TIME_DISABLED, TIME_ELAPSED, TIME_RESET,
|
||||
STATUS, 'after'
|
||||
FROM information_schema.innodb_metrics
|
||||
WHERE NAME LIKE 'innodb_rwlock_sx_%';
|
||||
# TC-08 There was a reset. COUNT_RESET = MAX_COUNT_RESET for ALL
|
||||
# = @sx_count entries.
|
||||
# pass
|
||||
# TC-17 We had heavy activity causing big counters and after that a reset.
|
||||
# Reset causes COUNT > COUNT_RESET AND MAX_COUNT > MAX_COUNT_RESET
|
||||
# for ALL @sx_count entries.
|
||||
# pass
|
||||
# TC-18 We had some reset but this must not decrease COUNT or MAX_COUNT
|
||||
# after.COUNT >= before.COUNT AND
|
||||
# after.MAX_COUNT >= before.MAX_COUNT for ALL @sx_count entries.
|
||||
# pass
|
||||
# TC-19 We had some reset after heavy activity and this must cause
|
||||
# after.COUNT_RESET < before.COUNT_RESET
|
||||
# AND after.MAX_COUNT_RESET < before.MAX_COUNT_RESET AND
|
||||
# for ALL @sx_count entries.
|
||||
# pass
|
||||
connection con10;
|
||||
disconnect con10;
|
||||
connection con9;
|
||||
disconnect con9;
|
||||
connection con8;
|
||||
disconnect con8;
|
||||
connection con7;
|
||||
disconnect con7;
|
||||
connection con6;
|
||||
disconnect con6;
|
||||
connection con5;
|
||||
disconnect con5;
|
||||
connection con4;
|
||||
disconnect con4;
|
||||
connection con3;
|
||||
disconnect con3;
|
||||
connection con2;
|
||||
disconnect con2;
|
||||
connection con1;
|
||||
disconnect con1;
|
||||
connection default;
|
||||
USE test;
|
||||
DROP SCHEMA my_schema;
|
||||
SET GLOBAL innodb_monitor_disable = all;
|
||||
SET GLOBAL innodb_monitor_reset_all = all;
|
||||
SET GLOBAL innodb_monitor_enable = default;
|
||||
SET GLOBAL innodb_monitor_disable = default;
|
||||
SET GLOBAL innodb_monitor_reset = default;
|
||||
SET GLOBAL innodb_monitor_reset_all = default;
|
||||
SET GLOBAL innodb_monitor_disable = "innodb_rwlock_sx_%";
|
||||
SET GLOBAL innodb_monitor_reset = "innodb_rwlock_sx_%";
|
1
mysql-test/suite/innodb/t/innodb_bug30113362.opt
Normal file
1
mysql-test/suite/innodb/t/innodb_bug30113362.opt
Normal file
|
@ -0,0 +1 @@
|
|||
--innodb-sys-tablestats
|
236
mysql-test/suite/innodb/t/innodb_bug30113362.test
Normal file
236
mysql-test/suite/innodb/t/innodb_bug30113362.test
Normal file
|
@ -0,0 +1,236 @@
|
|||
#
|
||||
# Test for Bug#30113362 : BTR_CUR_WILL_MODIFY_TREE() IS INSUFFICIENT FOR HIGHER TREE LEVEL
|
||||
#
|
||||
|
||||
--source include/have_innodb.inc
|
||||
--source include/have_debug.inc
|
||||
--source include/have_debug_sync.inc
|
||||
--source include/have_innodb_16k.inc
|
||||
|
||||
--disable_query_log
|
||||
SET @old_innodb_limit_optimistic_insert_debug = @@innodb_limit_optimistic_insert_debug;
|
||||
SET @old_innodb_adaptive_hash_index = @@innodb_adaptive_hash_index;
|
||||
SET @old_innodb_stats_persistent = @@innodb_stats_persistent;
|
||||
--enable_query_log
|
||||
|
||||
# Save the initial number of concurrent sessions
|
||||
--source include/count_sessions.inc
|
||||
|
||||
SET GLOBAL innodb_adaptive_hash_index = false;
|
||||
SET GLOBAL innodb_stats_persistent = false;
|
||||
|
||||
connect (purge_control,localhost,root,,);
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
|
||||
--connect (con2,localhost,root,,)
|
||||
|
||||
CREATE TABLE t1 (
|
||||
a00 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a01 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a02 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
b INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY(a00, a01, a02)
|
||||
) charset latin1 ENGINE = InnoDB COMMENT='MERGE_THRESHOLD=45';
|
||||
|
||||
#
|
||||
# Prepare primary key index tree to be used for this test.
|
||||
#
|
||||
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 3;
|
||||
|
||||
delimiter |;
|
||||
CREATE PROCEDURE data_load_t1()
|
||||
BEGIN
|
||||
DECLARE c1 INT DEFAULT 97;
|
||||
DECLARE c2 INT DEFAULT 97;
|
||||
DECLARE c3 INT DEFAULT 97;
|
||||
|
||||
WHILE c1 < 102 DO
|
||||
WHILE c2 < 123 DO
|
||||
WHILE c3 < 123 DO
|
||||
INSERT INTO t1 (a00) VALUES (CHAR(c1,c2,c3));
|
||||
SET c3 = c3 + 1;
|
||||
END WHILE;
|
||||
SET c3 = 97;
|
||||
SET c2 = c2 + 1;
|
||||
END WHILE;
|
||||
SET c2 = 97;
|
||||
SET c1 = c1 + 1;
|
||||
END WHILE;
|
||||
END |
|
||||
delimiter ;|
|
||||
call data_load_t1();
|
||||
DROP PROCEDURE data_load_t1;
|
||||
|
||||
# all node pages are sparse (max 3 node_ptrs)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
connection con2;
|
||||
DELETE FROM t1 WHERE a00 = 'cnm';
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t1 SET a00 = 'cnm';
|
||||
# causes "domino falling" merges to upper level
|
||||
connection purge_control;
|
||||
COMMIT;
|
||||
connection con2;
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 0;
|
||||
ROLLBACK;
|
||||
|
||||
# at this moment, in the tree,
|
||||
# ...
|
||||
# level 4: ...(ast,avw,ayz)(bcc,bff,bii,bll,boo,brr,buu,bxx,cba,ced,cqp,cts)(cwv,czy,ddb)...
|
||||
# ...
|
||||
|
||||
--echo # Test start
|
||||
|
||||
# (1) Similar case to the first reported corefile at bug#30113362
|
||||
# - Deleting 'bii' causes "domino falling" merges and the node_ptr becomes left_most of level 4.
|
||||
# So, the operation needs upper level pages' X-latch, though doesn't cause merge more.
|
||||
|
||||
connection purge_control;
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
connection con2;
|
||||
DELETE FROM t1 WHERE a00 = 'bii';
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t1 SET a00 = 'bii';
|
||||
SET DEBUG_SYNC = 'rollback_undo_pk SIGNAL roll1_wait WAIT_FOR roll2';
|
||||
SET DEBUG_SYNC = 'rollback_purge_clust SIGNAL rollback_waiting WAIT_FOR resume';
|
||||
send ROLLBACK;
|
||||
|
||||
connection purge_control;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR roll1_wait';
|
||||
COMMIT;
|
||||
SET DEBUG_SYNC = 'now SIGNAL roll2';
|
||||
|
||||
connect (con1,localhost,root,,);
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rollback_waiting';
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
||||
send SELECT a00 FROM t1 WHERE a00 = 'bii';
|
||||
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1';
|
||||
# bug#30113362 caused deadlock
|
||||
SET DEBUG_SYNC = 'now SIGNAL resume';
|
||||
|
||||
connection con1;
|
||||
reap;
|
||||
connection con2;
|
||||
reap;
|
||||
connection default;
|
||||
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
# (2) Confirm blocking domain caused by DELETE modify_tree for tall index tree
|
||||
|
||||
# at this moment, in the tree,
|
||||
# ...
|
||||
# level 4: ...(ajk,amn,apq)(ast,avw,ayz,bll,boo,brr,buu,bxx,cba,ced,cqp,cts)(cwv,czy,ddb)(dge,djh,dmk)(dpn,dsq,dvt)(dyw,ebz,efc)...
|
||||
# ...
|
||||
|
||||
# makes >17 records in level4 [(2^(4-1))*2 + 1]. (causes never left_most records)
|
||||
DELETE FROM t1 WHERE a00 = 'dpn';
|
||||
COMMIT;
|
||||
INSERT INTO t1 SET a00 = 'dpn';
|
||||
ROLLBACK;
|
||||
|
||||
# at this moment, in the tree,
|
||||
# (* before "]" and after "[" records are treated as left_most possible records)
|
||||
# ...
|
||||
# level 4: ...(ajk,amn,apq)(ast,avw,ayz,bll,boo,brr,buu,bxx],cba,ced,[cqp,cts,cwv,czy,ddb,dge,dsq,dvt)(dyw,ebz,efc)...
|
||||
# level 3: ...(cba,ccb,cdc)(ced,cfe,cgf,chg],cih,cji,[ckj,clk,con,cpo)(cqp,crq,csr)...
|
||||
# level 2: ...(ckj,cks,clb)(clk,clt],cmc,cml,cmu,cnd,[cnv,coe)(con,cow,cpf)...
|
||||
# level 1: ...(cmu,cmx,cna)(cnd],cng,cnj,cnp,[cns)(cnv,cny,cob)...
|
||||
# level 0: ...(cnd,cne,cnf)(cng,cnh,cni)(cnj,cnk,cnl,cnn,cno)(cnp,cnq,cnr)...
|
||||
|
||||
# deletes just 'ced' node_ptr only from level 4. doesn't cause merge and never left_most.
|
||||
# adjusts MERGE_THRESHOLD to do so.
|
||||
ALTER TABLE t1 COMMENT='MERGE_THRESHOLD=35';
|
||||
|
||||
connection purge_control;
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
|
||||
connection con2;
|
||||
DELETE FROM t1 WHERE a00 = 'cnd';
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t1 SET a00 = 'cnd';
|
||||
SET DEBUG_SYNC = 'rollback_undo_pk SIGNAL roll1_wait WAIT_FOR roll2';
|
||||
SET DEBUG_SYNC = 'rollback_purge_clust SIGNAL rollback_waiting WAIT_FOR resume EXECUTE 2';
|
||||
send ROLLBACK;
|
||||
|
||||
connection purge_control;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR roll1_wait';
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
SET DEBUG_SYNC = 'now SIGNAL roll2';
|
||||
|
||||
connection con1;
|
||||
# FIXME: For some reason, we will not always receive these signals!
|
||||
--disable_warnings
|
||||
# An optimistic row_undo_mod_remove_clust_low() will fail.
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rollback_waiting TIMEOUT 1';
|
||||
SET DEBUG_SYNC = 'now SIGNAL resume';
|
||||
# Wait for the pessimistic row_undo_mod_remove_clust_low() attempt.
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rollback_waiting TIMEOUT 1';
|
||||
--enable_warnings
|
||||
disconnect purge_control;
|
||||
|
||||
# The expectation should be...
|
||||
# level 0: (#cnd#,cne,cnf): causes merge
|
||||
# level 1: (#cnd#],cng,cnj,cnp,[cns): left_most
|
||||
# level 2: (clk,clt],cmc,cml,cmu,#cnd#,[cnv,coe): causes merge
|
||||
# level 3: (ced,cfe,cgf,chg],cih,cji,[ckj,#clk#,con,cpo): left_most possible (not cause merge)
|
||||
# level 4: (ast,avw,ayz,bll,boo,brr,buu,bxx],cba,#ced#,[cqp,cts,cwv,czy,ddb,dge,dsq,dvt): no merge, not left_most possible
|
||||
# So, the top X-latch page is at level4. (ast~dvt)
|
||||
|
||||
# blocking domain based on whether its ancestor is latched or not.
|
||||
# (*[]: ancestor is X-latched)
|
||||
# level 0: ...(asq,asr,ass) [(ast,asu,asv)...(dyt,dyu,dyv)] (dyw,dyx,dyy)...
|
||||
|
||||
# Not blocked searches
|
||||
## In MariaDB, both these will block, because we use different DEBUG_SYNC
|
||||
## instrumentation (in rollback, not purge) and the root page (number 3)
|
||||
## is being latched in row_undo_mod_remove_clust_low().
|
||||
## SELECT a00 FROM t1 WHERE a00 = 'ass';
|
||||
## SELECT a00 FROM t1 WHERE a00 = 'dyx';
|
||||
|
||||
## SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
||||
## send SELECT a00 FROM t1 WHERE a00 = 'ast';
|
||||
|
||||
## connection con2;
|
||||
## SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
||||
## send SELECT a00 FROM t1 WHERE a00 = 'dyw';
|
||||
|
||||
connection default;
|
||||
## SET DEBUG_SYNC = 'now WAIT_FOR lockwait1';
|
||||
## SET DEBUG_SYNC = 'now WAIT_FOR lockwait2';
|
||||
SET DEBUG_SYNC = 'now SIGNAL resume';
|
||||
|
||||
## connection con1;
|
||||
## reap;
|
||||
disconnect con1;
|
||||
|
||||
connection con2;
|
||||
reap;
|
||||
disconnect con2;
|
||||
|
||||
connection default;
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
|
||||
# Cleanup
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--disable_query_log
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = @old_innodb_limit_optimistic_insert_debug;
|
||||
SET GLOBAL innodb_adaptive_hash_index = @old_innodb_adaptive_hash_index;
|
||||
SET GLOBAL innodb_stats_persistent = @old_innodb_stats_persistent;
|
||||
--enable_query_log
|
||||
|
||||
--source include/wait_until_count_sessions.inc
|
1
mysql-test/suite/innodb/t/innodb_wl6326.opt
Normal file
1
mysql-test/suite/innodb/t/innodb_wl6326.opt
Normal file
|
@ -0,0 +1 @@
|
|||
--innodb-sys-tablestats
|
500
mysql-test/suite/innodb/t/innodb_wl6326.test
Normal file
500
mysql-test/suite/innodb/t/innodb_wl6326.test
Normal file
|
@ -0,0 +1,500 @@
|
|||
#
|
||||
# WL#6326: InnoDB: fix index->lock contention
|
||||
#
|
||||
|
||||
--source include/have_innodb.inc
|
||||
--source include/have_debug.inc
|
||||
--source include/have_debug_sync.inc
|
||||
--source include/have_innodb_16k.inc
|
||||
|
||||
--disable_query_log
|
||||
SET @old_innodb_limit_optimistic_insert_debug = @@innodb_limit_optimistic_insert_debug;
|
||||
SET @old_innodb_adaptive_hash_index = @@innodb_adaptive_hash_index;
|
||||
SET @old_innodb_stats_persistent = @@innodb_stats_persistent;
|
||||
--enable_query_log
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
# Save the initial number of concurrent sessions
|
||||
--source include/count_sessions.inc
|
||||
|
||||
SET GLOBAL innodb_adaptive_hash_index = false;
|
||||
SET GLOBAL innodb_stats_persistent = false;
|
||||
|
||||
--connect (con1,localhost,root,,)
|
||||
--connect (con2,localhost,root,,)
|
||||
--connect (con3,localhost,root,,)
|
||||
|
||||
CREATE TABLE t1 (
|
||||
a00 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a01 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a02 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a03 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a04 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a05 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
a06 CHAR(255) NOT NULL DEFAULT 'a',
|
||||
b INT NOT NULL DEFAULT 0
|
||||
) ENGINE = InnoDB;
|
||||
|
||||
ALTER TABLE t1 ADD PRIMARY KEY(
|
||||
a00,
|
||||
a01,
|
||||
a02,
|
||||
a03,
|
||||
a04,
|
||||
a05,
|
||||
a06
|
||||
);
|
||||
|
||||
#
|
||||
# Prepare primary key index tree to be used for this test.
|
||||
#
|
||||
|
||||
# Only root (1)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
# Make the first records sparse artificially,
|
||||
# not to cause modify_tree by single node_ptr insert operation.
|
||||
# * (7 - 2) records should be larger than a half of the page size
|
||||
# * (7 + 2) records should be fit to the page
|
||||
# (above t1 definition is already adjusted)
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 7;
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('aa');
|
||||
INSERT INTO t1 (a00) VALUES ('ab');
|
||||
INSERT INTO t1 (a00) VALUES ('ac');
|
||||
INSERT INTO t1 (a00) VALUES ('ad');
|
||||
INSERT INTO t1 (a00) VALUES ('ae');
|
||||
INSERT INTO t1 (a00) VALUES ('af');
|
||||
INSERT INTO t1 (a00) VALUES ('ag');
|
||||
INSERT INTO t1 (a00) VALUES ('ah');
|
||||
# Raise root (1-2)
|
||||
# (aa,ad)
|
||||
# (aa,ab,ac)(ad,ae,af,ag,ah)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('ai');
|
||||
INSERT INTO t1 (a00) VALUES ('aj');
|
||||
INSERT INTO t1 (a00) VALUES ('ak');
|
||||
# Split leaf (1-3)
|
||||
# (aa,ad,ak)
|
||||
# (aa,ab,ac)(ad,ae,af,ag,ah,ai,aj)(ak)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('al');
|
||||
INSERT INTO t1 (a00) VALUES ('am');
|
||||
INSERT INTO t1 (a00) VALUES ('an');
|
||||
INSERT INTO t1 (a00) VALUES ('ao');
|
||||
INSERT INTO t1 (a00) VALUES ('ap');
|
||||
INSERT INTO t1 (a00) VALUES ('aq');
|
||||
INSERT INTO t1 (a00) VALUES ('ar');
|
||||
# Split leaf (1-4)
|
||||
# (aa,ad,ak,ar)
|
||||
# (aa,ab,ac)(ad,ae,af,ag,ah,ai,aj)(ak,al,am,an,ao,ap,aq)(ar)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('as');
|
||||
INSERT INTO t1 (a00) VALUES ('at');
|
||||
INSERT INTO t1 (a00) VALUES ('au');
|
||||
INSERT INTO t1 (a00) VALUES ('av');
|
||||
INSERT INTO t1 (a00) VALUES ('aw');
|
||||
INSERT INTO t1 (a00) VALUES ('ax');
|
||||
INSERT INTO t1 (a00) VALUES ('ay');
|
||||
# Split leaf (1-5)
|
||||
# (aa,ad,ak,ar,ay)
|
||||
# (aa,ab,ac)(ad,ae,af,ag,ah,ai,aj)(ak,al,am,an,ao,ap,aq)(ar,as,at,au,av,aw,ax)(ay)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('az');
|
||||
INSERT INTO t1 (a00) VALUES ('ba');
|
||||
INSERT INTO t1 (a00) VALUES ('bb');
|
||||
INSERT INTO t1 (a00) VALUES ('bc');
|
||||
INSERT INTO t1 (a00) VALUES ('bd');
|
||||
INSERT INTO t1 (a00) VALUES ('be');
|
||||
INSERT INTO t1 (a00) VALUES ('bf');
|
||||
# Split leaf (1-6)
|
||||
# (aa,ad,ak,ar,ay,bf)
|
||||
# (aa,ab,ac)(ad..)(ak..)(ar,as,at,au,av,aw,ax)(ay,az,ba,bb,bc,bd,be)(bf)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('bg');
|
||||
INSERT INTO t1 (a00) VALUES ('bh');
|
||||
INSERT INTO t1 (a00) VALUES ('bi');
|
||||
INSERT INTO t1 (a00) VALUES ('bj');
|
||||
INSERT INTO t1 (a00) VALUES ('bk');
|
||||
INSERT INTO t1 (a00) VALUES ('bl');
|
||||
INSERT INTO t1 (a00) VALUES ('bm');
|
||||
# Split leaf (1-7)
|
||||
# (aa,ad,ak,ar,ay,bf,bm)
|
||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay,az,ba,bb,bc,bd,be)(bf,bg,bh,bi,bj,bk,bl)(bm)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('bn');
|
||||
INSERT INTO t1 (a00) VALUES ('bo');
|
||||
INSERT INTO t1 (a00) VALUES ('bp');
|
||||
INSERT INTO t1 (a00) VALUES ('bq');
|
||||
INSERT INTO t1 (a00) VALUES ('br');
|
||||
INSERT INTO t1 (a00) VALUES ('bs');
|
||||
INSERT INTO t1 (a00) VALUES ('bt');
|
||||
# Raise root (1-2-8)
|
||||
# (aa,ar)
|
||||
# (aa,ad,ak) (ar,ay,bf,bm,bt)
|
||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay..)(bf..)(bm..)(bt)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('bu');
|
||||
INSERT INTO t1 (a00) VALUES ('bv');
|
||||
INSERT INTO t1 (a00) VALUES ('bw');
|
||||
INSERT INTO t1 (a00) VALUES ('bx');
|
||||
INSERT INTO t1 (a00) VALUES ('by');
|
||||
INSERT INTO t1 (a00) VALUES ('bz');
|
||||
INSERT INTO t1 (a00) VALUES ('ca');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('cb');
|
||||
INSERT INTO t1 (a00) VALUES ('cc');
|
||||
INSERT INTO t1 (a00) VALUES ('cd');
|
||||
INSERT INTO t1 (a00) VALUES ('ce');
|
||||
INSERT INTO t1 (a00) VALUES ('cf');
|
||||
INSERT INTO t1 (a00) VALUES ('cg');
|
||||
INSERT INTO t1 (a00) VALUES ('ch');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('ci');
|
||||
INSERT INTO t1 (a00) VALUES ('cj');
|
||||
INSERT INTO t1 (a00) VALUES ('ck');
|
||||
INSERT INTO t1 (a00) VALUES ('cl');
|
||||
INSERT INTO t1 (a00) VALUES ('cm');
|
||||
INSERT INTO t1 (a00) VALUES ('cn');
|
||||
INSERT INTO t1 (a00) VALUES ('co');
|
||||
# Split also at level 1 (1-3-11)
|
||||
# (aa,ar,co)
|
||||
# (aa,ad,ak) (ar,ay,bf,bm,bt,ca,ch) (co)
|
||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay..)(bf..)(bm..)(bt..)(ca..)(ch..)(co)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('cp');
|
||||
INSERT INTO t1 (a00) VALUES ('cq');
|
||||
INSERT INTO t1 (a00) VALUES ('cr');
|
||||
INSERT INTO t1 (a00) VALUES ('cs');
|
||||
INSERT INTO t1 (a00) VALUES ('ct');
|
||||
INSERT INTO t1 (a00) VALUES ('cu');
|
||||
INSERT INTO t1 (a00) VALUES ('cv');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('cw');
|
||||
INSERT INTO t1 (a00) VALUES ('cx');
|
||||
INSERT INTO t1 (a00) VALUES ('cy');
|
||||
INSERT INTO t1 (a00) VALUES ('cz');
|
||||
INSERT INTO t1 (a00) VALUES ('da');
|
||||
INSERT INTO t1 (a00) VALUES ('db');
|
||||
INSERT INTO t1 (a00) VALUES ('dc');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('dd');
|
||||
INSERT INTO t1 (a00) VALUES ('de');
|
||||
INSERT INTO t1 (a00) VALUES ('df');
|
||||
INSERT INTO t1 (a00) VALUES ('dg');
|
||||
INSERT INTO t1 (a00) VALUES ('dh');
|
||||
INSERT INTO t1 (a00) VALUES ('di');
|
||||
INSERT INTO t1 (a00) VALUES ('dj');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('dk');
|
||||
INSERT INTO t1 (a00) VALUES ('dl');
|
||||
INSERT INTO t1 (a00) VALUES ('dm');
|
||||
INSERT INTO t1 (a00) VALUES ('dn');
|
||||
INSERT INTO t1 (a00) VALUES ('do');
|
||||
INSERT INTO t1 (a00) VALUES ('dp');
|
||||
INSERT INTO t1 (a00) VALUES ('dq');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('dr');
|
||||
INSERT INTO t1 (a00) VALUES ('ds');
|
||||
INSERT INTO t1 (a00) VALUES ('dt');
|
||||
INSERT INTO t1 (a00) VALUES ('du');
|
||||
INSERT INTO t1 (a00) VALUES ('dv');
|
||||
INSERT INTO t1 (a00) VALUES ('dw');
|
||||
INSERT INTO t1 (a00) VALUES ('dx');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('dy');
|
||||
INSERT INTO t1 (a00) VALUES ('dz');
|
||||
INSERT INTO t1 (a00) VALUES ('ea');
|
||||
INSERT INTO t1 (a00) VALUES ('eb');
|
||||
INSERT INTO t1 (a00) VALUES ('ec');
|
||||
INSERT INTO t1 (a00) VALUES ('ed');
|
||||
INSERT INTO t1 (a00) VALUES ('ee');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('ef');
|
||||
INSERT INTO t1 (a00) VALUES ('eg');
|
||||
INSERT INTO t1 (a00) VALUES ('eh');
|
||||
INSERT INTO t1 (a00) VALUES ('ei');
|
||||
INSERT INTO t1 (a00) VALUES ('ej');
|
||||
INSERT INTO t1 (a00) VALUES ('ek');
|
||||
INSERT INTO t1 (a00) VALUES ('el');
|
||||
# Split also at level 1 (1-4-18)
|
||||
# (aa,ar,co,el)
|
||||
# (aa,ad,ak) (ar,ay,bf,bm,bt,ca,ch) (co,cv,dc,dj,dq,dx,ee) (el)
|
||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay..)(bf..)(bm..)(bt..)(ca..)(ch..)(co..)(cv..)(dc..)(dj..)(dq..)(dx..)(ee..)(el)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('em');
|
||||
INSERT INTO t1 (a00) VALUES ('en');
|
||||
INSERT INTO t1 (a00) VALUES ('eo');
|
||||
INSERT INTO t1 (a00) VALUES ('ep');
|
||||
INSERT INTO t1 (a00) VALUES ('eq');
|
||||
INSERT INTO t1 (a00) VALUES ('er');
|
||||
INSERT INTO t1 (a00) VALUES ('es');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('et');
|
||||
INSERT INTO t1 (a00) VALUES ('eu');
|
||||
INSERT INTO t1 (a00) VALUES ('ev');
|
||||
INSERT INTO t1 (a00) VALUES ('ew');
|
||||
INSERT INTO t1 (a00) VALUES ('ex');
|
||||
INSERT INTO t1 (a00) VALUES ('ey');
|
||||
INSERT INTO t1 (a00) VALUES ('ez');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('fa');
|
||||
INSERT INTO t1 (a00) VALUES ('fb');
|
||||
INSERT INTO t1 (a00) VALUES ('fc');
|
||||
INSERT INTO t1 (a00) VALUES ('fd');
|
||||
INSERT INTO t1 (a00) VALUES ('fe');
|
||||
INSERT INTO t1 (a00) VALUES ('ff');
|
||||
INSERT INTO t1 (a00) VALUES ('fg');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('fh');
|
||||
INSERT INTO t1 (a00) VALUES ('fi');
|
||||
INSERT INTO t1 (a00) VALUES ('fj');
|
||||
INSERT INTO t1 (a00) VALUES ('fk');
|
||||
INSERT INTO t1 (a00) VALUES ('fl');
|
||||
INSERT INTO t1 (a00) VALUES ('fm');
|
||||
INSERT INTO t1 (a00) VALUES ('fn');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('fo');
|
||||
INSERT INTO t1 (a00) VALUES ('fp');
|
||||
INSERT INTO t1 (a00) VALUES ('fq');
|
||||
INSERT INTO t1 (a00) VALUES ('fr');
|
||||
INSERT INTO t1 (a00) VALUES ('fs');
|
||||
INSERT INTO t1 (a00) VALUES ('ft');
|
||||
INSERT INTO t1 (a00) VALUES ('fu');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('fv');
|
||||
INSERT INTO t1 (a00) VALUES ('fw');
|
||||
INSERT INTO t1 (a00) VALUES ('fx');
|
||||
INSERT INTO t1 (a00) VALUES ('fy');
|
||||
INSERT INTO t1 (a00) VALUES ('fz');
|
||||
INSERT INTO t1 (a00) VALUES ('ga');
|
||||
INSERT INTO t1 (a00) VALUES ('gb');
|
||||
|
||||
INSERT INTO t1 (a00) VALUES ('gc');
|
||||
INSERT INTO t1 (a00) VALUES ('gd');
|
||||
INSERT INTO t1 (a00) VALUES ('ge');
|
||||
INSERT INTO t1 (a00) VALUES ('gf');
|
||||
INSERT INTO t1 (a00) VALUES ('gg');
|
||||
INSERT INTO t1 (a00) VALUES ('gh');
|
||||
|
||||
|
||||
# Current tree form (1-4-24)
|
||||
# (aa,ar,co,el)
|
||||
# (aa,ad,ak) (ar,ay,bf,bm,bt,ca,ch) (co,cv,dc,dj,dq,dx,ee) (el..,gb)
|
||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay..)(bf..)(bm..)(bt..)(ca..)(ch..)(co..)(cv..)(dc..)(dj..)(dq..)(dx..)(ee..)(el..)..(gb..)
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
|
||||
|
||||
# Insert the rest of records normally
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 0;
|
||||
|
||||
|
||||
--echo # Test start
|
||||
|
||||
# (1) Insert records to leaf page (bf..) and cause modify_page.
|
||||
# - root page is not X latched
|
||||
# - latched from level 1 page (ar,ay,bf,bm,bt,ca,ch)
|
||||
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
|
||||
# Filling leaf page (bf..)
|
||||
INSERT INTO t1 (a00) VALUES ('bfa');
|
||||
|
||||
--connection con1
|
||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
||||
# Cause modify_tree
|
||||
--send
|
||||
INSERT INTO t1 (a00) VALUES ('bfb');
|
||||
|
||||
--connection con2
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
||||
# Not blocked searches
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aq';
|
||||
# "where a00 = 'co'" is blocked because searching from smaller ('co','a','a',..).
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'cp';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
||||
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
||||
# Blocked
|
||||
--send
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'ar';
|
||||
|
||||
--connection con3
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
||||
# Blocked
|
||||
--send
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'cn';
|
||||
|
||||
--connection default
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1';
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2';
|
||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
||||
|
||||
--connection con1
|
||||
--reap
|
||||
|
||||
--connection con2
|
||||
--reap
|
||||
|
||||
--connection con3
|
||||
--reap
|
||||
|
||||
--connection default
|
||||
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
|
||||
|
||||
# (2) Insert records to leaf page (co..) and cause modify_page
|
||||
# - root page is X latched, because node_ptr for 'co'
|
||||
# is 1st record for (co,cv,dc,dj,dq,dx,ee)
|
||||
#
|
||||
# * ordinary pessimitic insert might be done by pessistic update
|
||||
# and we should consider possibility node_ptr to be deleted.
|
||||
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
|
||||
# Filling leaf page (co..)
|
||||
INSERT INTO t1 (a00) VALUES ('coa');
|
||||
|
||||
--connection con1
|
||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
||||
# Cause modify_tree
|
||||
--send
|
||||
INSERT INTO t1 (a00) VALUES ('cob');
|
||||
|
||||
--connection con2
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
||||
# All searches are blocked because root page is X latched
|
||||
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
||||
# Blocked
|
||||
--send
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
||||
|
||||
--connection con3
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
||||
# Blocked
|
||||
--send
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
||||
|
||||
--connection default
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1';
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2';
|
||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
||||
|
||||
--connection con1
|
||||
--reap
|
||||
|
||||
--connection con2
|
||||
--reap
|
||||
|
||||
--connection con3
|
||||
--reap
|
||||
|
||||
--connection default
|
||||
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
|
||||
|
||||
# (3) Insert records to rightmost leaf page (gb..) and cause modify_page
|
||||
# - root page is not X latched, because node_ptr for 'gb' is the last record
|
||||
# of the level 1 though it is last record in the page.
|
||||
# - lathed from level 1 page (el..,gb)
|
||||
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
|
||||
# Filling leaf page (gb..)
|
||||
INSERT INTO t1 (a00) VALUES ('gba');
|
||||
|
||||
--connection con1
|
||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
||||
# Cause modify_tree
|
||||
--send
|
||||
INSERT INTO t1 (a00) VALUES ('gbb');
|
||||
|
||||
--connection con2
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
||||
# Not blocked searches
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'ek';
|
||||
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
||||
# Blocked
|
||||
--send
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
||||
|
||||
--connection con3
|
||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
||||
# Blocked
|
||||
--send
|
||||
SELECT a00,a01 FROM t1 WHERE a00 = 'gb';
|
||||
|
||||
--connection default
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1';
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2';
|
||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
||||
|
||||
--connection con1
|
||||
--reap
|
||||
|
||||
--connection con2
|
||||
--reap
|
||||
|
||||
--connection con3
|
||||
--reap
|
||||
|
||||
--connection default
|
||||
ANALYZE TABLE t1;
|
||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
||||
|
||||
|
||||
|
||||
# Cleanup
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
|
||||
--connection default
|
||||
--disconnect con1
|
||||
--disconnect con2
|
||||
--disconnect con3
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--disable_query_log
|
||||
SET GLOBAL innodb_limit_optimistic_insert_debug = @old_innodb_limit_optimistic_insert_debug;
|
||||
SET GLOBAL innodb_adaptive_hash_index = @old_innodb_adaptive_hash_index;
|
||||
SET GLOBAL innodb_stats_persistent = @old_innodb_stats_persistent;
|
||||
--enable_query_log
|
||||
|
||||
# Wait till all disconnects are completed.
|
||||
--source include/wait_until_count_sessions.inc
|
716
mysql-test/suite/innodb/t/innodb_wl6326_big.test
Normal file
716
mysql-test/suite/innodb/t/innodb_wl6326_big.test
Normal file
|
@ -0,0 +1,716 @@
|
|||
# This is a script for MTR with hybrid use.
|
||||
# a) As regression test
|
||||
# Mostly some brute force attempt to stress the internal sx locks of
|
||||
# InnoDB which were introduced by WL#6326+WL#6363.
|
||||
# The file with expected results fits to this variant.
|
||||
# The impact on code coverage is quite good.
|
||||
# b) As testbed for attempts to extend or improve the RQG test wl6326_sql.yy.
|
||||
# The MTR based test uses
|
||||
# - a table t1 with the same layout
|
||||
# - the same stored functions
|
||||
# - the same stored procedure proc_fill_t1 for inserting a configurable
|
||||
# amount of records into t1
|
||||
# like the RQG test wl6326_sql.yy.
|
||||
# Feel free to modify parameters like $max_row_count, $max_con,
|
||||
# $high_load_duration or switch debugging on (let $test_debug= 1).
|
||||
# But please be aware that MTR will most probably report that the test
|
||||
# failed because it got a difference to expected results.
|
||||
# Reasons:
|
||||
# - In general: The file with expected results fits to a) only.
|
||||
# - The actual results might dependend on $max_row_count.
|
||||
# - Additional result sets might be printed.
|
||||
#
|
||||
|
||||
# WL#6326 is about the sx locks (InnoDB feature only).
|
||||
--source include/have_innodb.inc
|
||||
# Runtime properties:
|
||||
# Notebook i5 dual core with HT, MySQL binaries compiled with debug,
|
||||
# max_row_count=10000 rows
|
||||
# vardir on tmpfs : ~ 375
|
||||
# vardir on disk : ~ 546
|
||||
--source include/big_test.inc
|
||||
# We go with "--send" and "--reap" and that fails with the embedded server.
|
||||
--source include/not_embedded.inc
|
||||
# Its intentional to not take the risk that a run with valgrind times out.
|
||||
--source include/not_valgrind.inc
|
||||
|
||||
# FIXME:
|
||||
# Increase the code coverage provided by the current test by
|
||||
# trying "InnoDB Tablespace Monitor" as soon as some bug is fixed
|
||||
# or wait till the deprecated "InnoDB Tablespace Monitor" is
|
||||
# removed.
|
||||
|
||||
# Setup of some parameters
|
||||
# ------------------------
|
||||
# Number of records within every chunk to be added to t1.
|
||||
let $load_unit= 10000;
|
||||
#
|
||||
# Rough number of records in t1 to achieve.
|
||||
# We add chunks of $load_unit rows till the actual number
|
||||
# of rows in the table t1 exceeds $max_row_count.
|
||||
# let $max_row_count= 1000000;
|
||||
# let $max_row_count= 300000;
|
||||
# let $max_row_count= 100000;
|
||||
# let $max_row_count= 30000;
|
||||
let $max_row_count= 10000; # ~ 322s on tmpfs (NB)
|
||||
#
|
||||
# Determine which variant to run.
|
||||
let $test_debug= 0;
|
||||
#
|
||||
# Number of concurrent sessions to be used in the high load test.
|
||||
let $max_con= 10;
|
||||
# Duration of the high load test in seconds.
|
||||
let $high_load_duration= 60;
|
||||
|
||||
# Putting all objects into the SCHEMA my_schema makes the final cleanup easier.
|
||||
# We simply run than DROP SCHEMA my_schema.
|
||||
CREATE SCHEMA my_schema;
|
||||
USE my_schema;
|
||||
CREATE FUNCTION f_thread_id (i INT) RETURNS CHAR(4) DETERMINISTIC
|
||||
RETURN CONCAT(LPAD(CAST(i AS CHAR),3,'_'),'_') ;
|
||||
SELECT CONCAT('->', f_thread_id( 1), '<-');
|
||||
SELECT CONCAT('->', f_thread_id(12), '<-');
|
||||
|
||||
# Definition of parameters used in functions.
|
||||
# We use here a "1" in order to make the impact on the results of the functions
|
||||
# good visible.
|
||||
SET @extra_int = 1;
|
||||
SET @extra_string = f_thread_id(@extra_int);
|
||||
SELECT @extra_int , @extra_string;
|
||||
|
||||
# The different functions are used later when filling t1 and also during
|
||||
# RQG testing. They serve to generate the difference between column values
|
||||
# in different rows in different areas of the column.
|
||||
# Fictional example:
|
||||
# row 1 col_int0=1 colx='1abcdefgh' coly='abcd1efgh' colz='abcdefgh1'
|
||||
# row 2 col_int0=2 colx='2abcdefgh' coly='abcd2efgh' colz='abcdefgh2'
|
||||
# The function f_<pattern> is for the column with the name <pattern>.
|
||||
# There is a function
|
||||
# - for every column except col_int0
|
||||
# - even if the SQL for generating the value is simple.
|
||||
# The reason for this is the architecture of the RQG test.
|
||||
|
||||
let $part= AS my_result
|
||||
FROM (SELECT 1 AS my_col UNION SELECT 12 UNION SELECT 123
|
||||
UNION SELECT 1234 UNION SELECT 12345) AS tx;
|
||||
|
||||
let $function_name= f_col_int1;
|
||||
eval CREATE FUNCTION $function_name (i INT) RETURNS INT(20) DETERMINISTIC
|
||||
RETURN i * 1000 + @extra_int ;
|
||||
eval SELECT $function_name(my_col) $part;
|
||||
|
||||
let $function_name= f_col_int2;
|
||||
eval CREATE FUNCTION $function_name (i INT) RETURNS INT(20) DETERMINISTIC
|
||||
RETURN @extra_int * 10000000 + i ;
|
||||
eval SELECT $function_name(my_col) $part;
|
||||
|
||||
let $function_name= f_col_int3;
|
||||
eval CREATE FUNCTION $function_name (i INT) RETURNS INT(20) DETERMINISTIC
|
||||
RETURN @extra_int ;
|
||||
eval SELECT $function_name(my_col) $part;
|
||||
|
||||
let $function_name= f_col_blob;
|
||||
eval CREATE FUNCTION $function_name (i INT) RETURNS BLOB DETERMINISTIC
|
||||
RETURN RPAD(@extra_string,(@@innodb_page_size / 2 ) + 1,'a');
|
||||
eval SELECT CONCAT('->', SUBSTR($function_name(my_col) FROM 1 FOR 10),
|
||||
'<-.....->', SUBSTR($function_name(my_col) FROM -10 FOR 10), '<-') $part;
|
||||
|
||||
let $function_name= f_col_char0;
|
||||
eval CREATE FUNCTION $function_name (i INT) RETURNS CHAR(255) DETERMINISTIC
|
||||
RETURN LPAD(CAST(i AS CHAR),255,' ');
|
||||
eval SELECT CONCAT('->', $function_name(my_col), '<-') $part;
|
||||
|
||||
let $function_name= f_col_char1;
|
||||
eval CREATE FUNCTION $function_name (i INT) RETURNS CHAR(26) DETERMINISTIC
|
||||
RETURN
|
||||
CONCAT('B',
|
||||
LPAD(SUBSTR(CAST(i AS CHAR),1,(LENGTH(CAST(i AS CHAR)) DIV 2)),10,' '),
|
||||
@extra_string,
|
||||
RPAD(SUBSTR(CAST(i AS CHAR), -((LENGTH(CAST(i AS CHAR)) + 1) DIV 2)),10,' '),
|
||||
'E') ;
|
||||
eval SELECT CONCAT('->', $function_name(my_col), '<-') $part;
|
||||
|
||||
let $function_name= f_col_char2;
|
||||
eval CREATE FUNCTION $function_name (i INT) RETURNS CHAR(26) DETERMINISTIC
|
||||
RETURN
|
||||
CONCAT('B',
|
||||
RPAD(SUBSTR(CAST(i AS CHAR),1,(LENGTH(CAST(i AS CHAR)) DIV 2)),10,' '),
|
||||
@extra_string,
|
||||
LPAD(SUBSTR(CAST(i AS CHAR), -((LENGTH(CAST(i AS CHAR)) + 1) DIV 2)),10,' '),
|
||||
'E');
|
||||
eval SELECT CONCAT('->', $function_name(my_col), '<-') $part;
|
||||
|
||||
let $function_name= f_col_char3;
|
||||
eval CREATE FUNCTION $function_name (i INT) RETURNS CHAR(26) DETERMINISTIC
|
||||
RETURN
|
||||
CONCAT('B',@extra_string,LPAD(CAST(i AS CHAR),20,' '),'E');
|
||||
eval SELECT CONCAT('->', $function_name(my_col), '<-') $part;
|
||||
|
||||
let $function_name= f_col_char4;
|
||||
eval CREATE FUNCTION $function_name (i INT) RETURNS CHAR(26) DETERMINISTIC
|
||||
RETURN
|
||||
CONCAT('B',RPAD(CAST(i AS CHAR),20,' '),@extra_string,'E');
|
||||
eval SELECT CONCAT('->', $function_name(my_col), '<-') $part;
|
||||
|
||||
# Auxiliary table for figuring out the impact of scenarios on
|
||||
# information_schema.innodb_metrics content.
|
||||
CREATE TABLE my_metrics LIKE information_schema.innodb_metrics;
|
||||
ALTER TABLE my_metrics ADD COLUMN phase ENUM('after', 'before'),
|
||||
DROP COLUMN SUBSYSTEM, DROP COLUMN TYPE, DROP COLUMN COMMENT,
|
||||
ADD PRIMARY KEY (NAME,phase);
|
||||
let $empty_my_metrics= DELETE FROM my_metrics;
|
||||
let $before_my_metrics= INSERT INTO my_metrics
|
||||
SELECT NAME, COUNT, MAX_COUNT, MIN_COUNT, AVG_COUNT,
|
||||
COUNT_RESET, MAX_COUNT_RESET, MIN_COUNT_RESET, AVG_COUNT_RESET,
|
||||
TIME_ENABLED, TIME_DISABLED, TIME_ELAPSED, TIME_RESET,
|
||||
STATUS, 'before'
|
||||
FROM information_schema.innodb_metrics
|
||||
WHERE NAME LIKE 'innodb_rwlock_sx_%';
|
||||
let $after_my_metrics= INSERT INTO my_metrics
|
||||
SELECT NAME, COUNT, MAX_COUNT, MIN_COUNT, AVG_COUNT,
|
||||
COUNT_RESET, MAX_COUNT_RESET, MIN_COUNT_RESET, AVG_COUNT_RESET,
|
||||
TIME_ENABLED, TIME_DISABLED, TIME_ELAPSED, TIME_RESET,
|
||||
STATUS, 'after'
|
||||
FROM information_schema.innodb_metrics
|
||||
WHERE NAME LIKE 'innodb_rwlock_sx_%';
|
||||
let $print_metrics= SELECT NAME, COUNT, MAX_COUNT, MIN_COUNT, AVG_COUNT,
|
||||
COUNT_RESET, MAX_COUNT_RESET, MIN_COUNT_RESET, AVG_COUNT_RESET,
|
||||
TIME_ENABLED, TIME_DISABLED, TIME_ELAPSED, TIME_RESET, STATUS
|
||||
FROM information_schema.innodb_metrics
|
||||
WHERE NAME LIKE 'innodb_rwlock_sx_%'
|
||||
ORDER BY NAME;
|
||||
|
||||
# The main table for testing.
|
||||
CREATE TABLE t1 (
|
||||
col_int0 BIGINT,
|
||||
col_int1 BIGINT,
|
||||
col_int2 BIGINT,
|
||||
col_int3 BIGINT,
|
||||
col_blob BLOB,
|
||||
col_char0 VARCHAR(255),
|
||||
col_char1 VARCHAR(30),
|
||||
col_char2 VARCHAR(30),
|
||||
col_char3 VARCHAR(30),
|
||||
col_char4 VARCHAR(30)
|
||||
) ENGINE = InnoDB;
|
||||
|
||||
# Use many indexes with mostly significant size in order to cause
|
||||
# some heavy use of sx locks during data generation.
|
||||
ALTER TABLE t1 ADD UNIQUE KEY uidx_col_int0 (col_int0),
|
||||
ADD UNIQUE KEY uidx1 (col_int1, col_char0),
|
||||
ADD UNIQUE KEY uidx2 (col_int2, col_char0, col_int1),
|
||||
ADD UNIQUE KEY uidx3 (col_int3, col_int2, col_char0),
|
||||
ADD UNIQUE KEY uidx4 (col_char1, col_char0),
|
||||
ADD UNIQUE KEY uidx5 (col_char2, col_char0, col_char1),
|
||||
ADD UNIQUE KEY uidx6 (col_char3, col_char2, col_char0),
|
||||
ADD UNIQUE KEY uidx7 (col_int1, col_int2, col_int3, col_char4,
|
||||
col_char1, col_char2, col_char3, col_char0),
|
||||
ADD KEY idx8 (col_blob(10), col_char4);
|
||||
|
||||
delimiter |;
|
||||
CREATE PROCEDURE proc_fill_t1 (max_row_count INT, load_unit INT)
|
||||
BEGIN
|
||||
DECLARE my_count INTEGER DEFAULT 0;
|
||||
DECLARE max_load_count INTEGER DEFAULT 0;
|
||||
DROP TABLE IF EXISTS t0;
|
||||
CREATE TEMPORARY TABLE t0 (col_int0 BIGINT, PRIMARY KEY(col_int0));
|
||||
WHILE (my_count < load_unit ) DO
|
||||
SET my_count = my_count + 1;
|
||||
INSERT INTO t0 SET col_int0 = my_count;
|
||||
END WHILE;
|
||||
SET max_load_count = (SELECT (max_row_count DIV load_unit) + 1 );
|
||||
SELECT COUNT(col_int0) INTO @val FROM t1;
|
||||
SET my_count = 0;
|
||||
REPEAT
|
||||
INSERT INTO t1 (col_int0, col_int1, col_int2, col_int3, col_blob,
|
||||
col_char0, col_char1, col_char2,col_char3,col_char4)
|
||||
SELECT col_int0 + @val,
|
||||
f_col_int1(col_int0 + @val),
|
||||
f_col_int2(col_int0 + @val),
|
||||
f_col_int3(col_int0 + @val),
|
||||
f_col_blob(col_int0 + @val),
|
||||
f_col_char0(col_int0 + @val),
|
||||
f_col_char1(col_int0 + @val),
|
||||
f_col_char2(col_int0 + @val),
|
||||
f_col_char3(col_int0 + @val),
|
||||
f_col_char4(col_int0 + @val)
|
||||
FROM t0;
|
||||
COMMIT;
|
||||
SELECT MAX(col_int0) INTO @val FROM t1;
|
||||
SET my_count = my_count + 1;
|
||||
UNTIL( my_count > max_load_count OR @val >= max_row_count )
|
||||
END REPEAT;
|
||||
DROP TEMPORARY TABLE t0;
|
||||
END|
|
||||
delimiter ;|
|
||||
|
||||
delimiter |;
|
||||
CREATE PROCEDURE proc_dml (max_duration INT, t1_stripe_half INT)
|
||||
BEGIN
|
||||
DECLARE aux INTEGER DEFAULT 0;
|
||||
DECLARE start_time INT;
|
||||
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND BEGIN END;
|
||||
|
||||
SET @extra_int = CONNECTION_ID();
|
||||
SET @extra_string = f_thread_id(@extra_int);
|
||||
SELECT ROUND(MAX(col_int0) / 2 ) INTO @t1_half FROM t1;
|
||||
# The user lock 'Blocker' should be already set by some other session S1.
|
||||
# S1 starts the race by releasing that lock.
|
||||
# Wait till the lock is released and the lock can be obtained.
|
||||
# In order to prevent endless waiting in case of non foreseen problems
|
||||
# limit the timespan to 30 seconds.
|
||||
SELECT GET_LOCK('Blocker', 30) INTO @aux;
|
||||
# Release the lock immediate so that the other "runner" sessions start too.
|
||||
SELECT RELEASE_LOCK('Blocker') INTO @aux;
|
||||
SET start_time = UNIX_TIMESTAMP();
|
||||
|
||||
WHILE (UNIX_TIMESTAMP() - start_time < max_duration) DO
|
||||
SET @aux = @t1_half - t1_stripe_half + ROUND(RAND() * t1_stripe_half * 2);
|
||||
UPDATE t1 SET
|
||||
col_int1 = f_col_int1(col_int0),
|
||||
col_int2 = f_col_int2(col_int0),
|
||||
col_int3 = f_col_int3(col_int0),
|
||||
col_blob = f_col_blob(col_int0),
|
||||
col_char0 = f_col_char0(col_int0),
|
||||
col_char1 = f_col_char1(col_int0),
|
||||
col_char2 = f_col_char2(col_int0),
|
||||
col_char3 = f_col_char3(col_int0),
|
||||
col_char4 = f_col_char4(col_int0)
|
||||
WHERE col_int0 = @aux;
|
||||
COMMIT;
|
||||
END WHILE;
|
||||
END|
|
||||
delimiter ;|
|
||||
|
||||
SET GLOBAL innodb_monitor_disable = "innodb_rwlock_sx_%";
|
||||
SET @pre_reset_ts = NOW();
|
||||
--sleep 1.1
|
||||
SET GLOBAL innodb_monitor_reset = "innodb_rwlock_sx_%";
|
||||
SET @pre_enable_ts = NOW();
|
||||
--sleep 1.1
|
||||
SET GLOBAL innodb_monitor_enable = "innodb_rwlock_sx_%";
|
||||
--sleep 1.1
|
||||
SET @pre_collect_ts = NOW();
|
||||
eval $empty_my_metrics;
|
||||
eval $before_my_metrics;
|
||||
--echo # TC-01 There are exact three entries "innodb_rwlock_sx_%" with the
|
||||
--echo # with the name which follow in innodb_metrics.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> 3 FROM my_metrics
|
||||
WHERE NAME IN ('innodb_rwlock_sx_spin_waits',
|
||||
'innodb_rwlock_sx_spin_rounds',
|
||||
'innodb_rwlock_sx_os_waits');
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT NAME FROM my_metrics
|
||||
ORDER BY NAME;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
SELECT COUNT(*) INTO @sx_count FROM my_metrics;
|
||||
|
||||
--echo # TC-02 Counting is now enabled. ALL = @sx_count entries show that.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics
|
||||
WHERE STATUS = 'enabled';
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT NAME, STATUS FROM my_metrics
|
||||
ORDER BY NAME;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
--echo # TC-03 @pre_reset_ts < TIME_RESET. ALL = @sx_count entries show that.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics
|
||||
WHERE @pre_reset_ts < TIME_RESET;
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT NAME, @pre_reset_ts, TIME_RESET FROM my_metrics
|
||||
ORDER BY NAME;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
--echo # TC-04 @pre_enable_ts < TIME_ENABLED. ALL = @sx_count entries show that.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics
|
||||
WHERE @pre_enable_ts < TIME_ENABLED;
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT NAME, @pre_enable_ts, TIME_ENABLED FROM my_metrics
|
||||
ORDER BY NAME;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
--echo # TC-05 TIME_RESET < TIME_ENABLED AND TIME_ENABLED < @pre_collect_ts
|
||||
--echo # AND TIME_ELAPSED > 0. ALL = @sx_count entries show that.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics
|
||||
WHERE TIME_RESET < TIME_ENABLED AND TIME_ENABLED < @pre_collect_ts
|
||||
AND TIME_ELAPSED > 0;
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT NAME, @pre_collect_ts, TIME_RESET, TIME_ENABLED, TIME_ELAPSED
|
||||
FROM my_metrics
|
||||
ORDER BY NAME;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
--echo # TC-06 COUNT_RESET = MAX_COUNT_RESET. ALL = @sx_count entries show that.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics
|
||||
WHERE COUNT_RESET = MAX_COUNT_RESET;
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT NAME, COUNT_RESET, MAX_COUNT_RESET FROM my_metrics
|
||||
ORDER BY NAME;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
SET GLOBAL innodb_monitor_reset = "innodb_rwlock_sx_%";
|
||||
--disable_result_log
|
||||
if($test_debug)
|
||||
{
|
||||
--enable_result_log
|
||||
eval $print_metrics;
|
||||
}
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
--enable_result_log
|
||||
|
||||
eval $empty_my_metrics;
|
||||
eval $before_my_metrics;
|
||||
# These values (the "0") help to identify later if some record is in its
|
||||
# initial state or already modified.
|
||||
SET @extra_string = '__0_';
|
||||
SET @extra_int = 0;
|
||||
|
||||
--echo # TC-07 One session inserts some significant amount of rows into t1.
|
||||
--echo # The system MUST survive that.
|
||||
--replace_result $max_row_count <max_row_count>
|
||||
eval SET @max_row_count = $max_row_count;
|
||||
--replace_result $load_unit <load_unit>
|
||||
eval SET @load_unit = $load_unit;
|
||||
SET @start_time = UNIX_TIMESTAMP();
|
||||
SET AUTOCOMMIT = OFF;
|
||||
CALL proc_fill_t1 (@max_row_count, @load_unit);
|
||||
--echo # pass
|
||||
SET AUTOCOMMIT = ON;
|
||||
SELECT col_int0 INTO @t1_half FROM t1
|
||||
WHERE col_int0 >= (@val DIV 2) ORDER BY col_int0 LIMIT 1;
|
||||
|
||||
--disable_result_log
|
||||
if($test_debug)
|
||||
{
|
||||
--enable_result_log
|
||||
SELECT COUNT(*) AS table_row_count,
|
||||
UNIX_TIMESTAMP() - @start_time AS fill_run_time
|
||||
FROM t1;
|
||||
eval $print_metrics;
|
||||
}
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
--enable_result_log
|
||||
|
||||
# Show that the value distribution is according to the plan.
|
||||
--vertical_results
|
||||
SELECT col_int0, col_int1, col_int2, col_int3,
|
||||
CONCAT('->', SUBSTR(col_blob FROM 1 FOR 10),
|
||||
'<-.....->', SUBSTR(col_blob FROM -10 FOR 10), '<-') AS col_blobx,
|
||||
CONCAT('->',col_char0,'<-') AS col_char0x,
|
||||
CONCAT('->',col_char1,'<-') AS col_char1x,
|
||||
CONCAT('->',col_char2,'<-') AS col_char2x,
|
||||
CONCAT('->',col_char3,'<-') AS col_char3x,
|
||||
CONCAT('->',col_char4,'<-') AS col_char4x
|
||||
FROM t1 WHERE col_int0 between 98 AND 102;
|
||||
--horizontal_results
|
||||
|
||||
# For experiments/interest only. Please do not remove that.
|
||||
if (0)
|
||||
{
|
||||
ANALYZE TABLE t1;
|
||||
SELECT n_rows, clustered_index_size, sum_of_other_index_sizes
|
||||
FROM mysql.innodb_table_stats;
|
||||
|
||||
# SELECT * FROM mysql.innodb_index_stats;
|
||||
# idx_col_int3_int0 n_diff_pfx01 1 col_int3
|
||||
# idx_col_int3_int0 n_diff_pfx02 10000 col_int3,col_int0
|
||||
# idx_col_int3_int0 n_diff_pfx03 10000 col_int3,col_int0,DB_ROW_ID
|
||||
# idx_col_int3_int0 n_leaf_pages 19 Number of leaf pages in the index
|
||||
# idx_col_int3_int0 size 20 Number of pages in the index
|
||||
|
||||
--vertical_results
|
||||
SELECT t1.index_name, t1.stat_value AS idx_pages, t2.stat_value AS idx_leaf_pages,
|
||||
(t1.stat_value - t2.stat_value - 1) / t1.stat_value AS sx_page_ratio
|
||||
FROM mysql.innodb_index_stats t1, mysql.innodb_index_stats t2
|
||||
WHERE t1.index_name = t2.index_name
|
||||
AND t1.stat_name = 'size' AND t2.stat_name = 'n_leaf_pages'
|
||||
ORDER BY t1.index_name;
|
||||
--horizontal_results
|
||||
}
|
||||
|
||||
--echo # TC-11 Several concurrent sessions perform updates in t1 like mad.
|
||||
--echo # The system MUST survive this.
|
||||
--echo # Printing of statements is partially suppressed.
|
||||
SET @start_time = UNIX_TIMESTAMP();
|
||||
SELECT 1 FROM t1 WHERE col_int0 = @t1_half FOR UPDATE;
|
||||
SELECT GET_LOCK('Blocker', 1000) ;
|
||||
--disable_query_log
|
||||
let $num= $max_con;
|
||||
while ($num)
|
||||
{
|
||||
--connect (con$num,localhost,root,,)
|
||||
USE my_schema;
|
||||
# The second parameter of the procedure is size of the affected stripe / 2.
|
||||
# A smaller stripe causes some smaller counter growth but most probably
|
||||
# also more stress around locking in general.
|
||||
# Example # (nnnn) = half stripe size
|
||||
# NAME | COUNT_RESET (5000) | COUNT_RESET (100)
|
||||
# -----------------------------+--------------------+----------------
|
||||
# innodb_rwlock_sx_os_waits | 1412 | 486
|
||||
# innodb_rwlock_sx_spin_rounds | 44061 | 17031
|
||||
# innodb_rwlock_sx_spin_waits | 996 | 515
|
||||
--send
|
||||
eval CALL proc_dml($high_load_duration,@t1_half);
|
||||
dec $num;
|
||||
}
|
||||
--connection default
|
||||
SELECT RELEASE_LOCK('Blocker') ;
|
||||
--sleep 3
|
||||
COMMIT;
|
||||
let $num= $max_con;
|
||||
while ($num)
|
||||
{
|
||||
--connection con$num
|
||||
--reap
|
||||
dec $num;
|
||||
}
|
||||
--echo # pass
|
||||
--connection default
|
||||
--enable_query_log
|
||||
|
||||
# let $wait_timeout= 181;
|
||||
# --source include/wait_condition.inc
|
||||
# eval $after_my_metrics;
|
||||
--disable_result_log
|
||||
if($test_debug)
|
||||
{
|
||||
--enable_result_log
|
||||
SELECT UNIX_TIMESTAMP() - @start_time AS update_battle_run_time;
|
||||
eval $print_metrics;
|
||||
}
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
--enable_result_log
|
||||
|
||||
--echo # TC-13 One session performs ALTER TABLE t1 ADD KEY ... on the fat table t1.
|
||||
--echo # The system MUST survive this.
|
||||
SET @start_time = UNIX_TIMESTAMP();
|
||||
ALTER TABLE t1 ADD KEY idx_col_char4_col_char0 (col_char4,col_char0);
|
||||
--disable_result_log
|
||||
if($test_debug)
|
||||
{
|
||||
--enable_result_log
|
||||
SELECT UNIX_TIMESTAMP() - @start_time AS add_key_run_time;
|
||||
eval $print_metrics;
|
||||
}
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
--enable_result_log
|
||||
--echo # pass
|
||||
|
||||
--echo # TC-15 One session performs a fat update on the fat table t1.
|
||||
--echo # The system MUST survive this.
|
||||
SET @start_time = UNIX_TIMESTAMP();
|
||||
SET @extra_int = 13;
|
||||
SET @extra_string = f_thread_id(@extra_int);
|
||||
eval UPDATE t1 SET
|
||||
col_int1 = f_col_int1(col_int0), col_int2 = f_col_int2(col_int0),
|
||||
col_int3 = f_col_int3(col_int0), col_blob = f_col_blob(col_int0),
|
||||
col_char0 = f_col_char0(col_int0), col_char1 = f_col_char1(col_int0),
|
||||
col_char2 = f_col_char2(col_int0), col_char3 = f_col_char3(col_int0),
|
||||
col_char4 = f_col_char4(col_int0)
|
||||
WHERE col_int0 BETWEEN @t1_half - 2500 AND @t1_half + 2500;
|
||||
COMMIT;
|
||||
--disable_result_log
|
||||
if($test_debug)
|
||||
{
|
||||
--enable_result_log
|
||||
SELECT UNIX_TIMESTAMP() - @start_time AS total_update_run_time;
|
||||
eval $print_metrics;
|
||||
}
|
||||
SHOW ENGINE INNODB STATUS;
|
||||
--enable_result_log
|
||||
--echo # pass
|
||||
|
||||
# Basically every of the big activities causes some counter growth.
|
||||
# But caused by
|
||||
# - the architecture of InnoDB (certain things happen asynchronous)
|
||||
# - the actual test configuration (server/InnoDB options)
|
||||
# - conditions like parallel (./mtr --parallel=auto?) load on the testing box
|
||||
# this might be not fulfilled per single big activity every time except
|
||||
# we go with huge waits or similar.
|
||||
# Observation:
|
||||
# - non debug binaries: expectation frequent not fulfilled
|
||||
# - debug binaries: expectation rare not fulfilled
|
||||
#
|
||||
let $wait_timeout= 121;
|
||||
let $wait_condition=
|
||||
SELECT COUNT(*) = @sx_count
|
||||
FROM information_schema.innodb_metrics t_after
|
||||
JOIN my_metrics t_before
|
||||
ON t_after.COUNT_RESET > t_before.COUNT_RESET AND t_after.NAME = t_before.NAME;
|
||||
--source include/wait_condition.inc
|
||||
eval $after_my_metrics;
|
||||
|
||||
--echo # TC-16 The following activities happend after reset in innodb_metrics
|
||||
--echo # - Insert some significant amount of rows into t1.
|
||||
--echo # - Several concurrent users perform excessive updates in t1.
|
||||
--echo # - ALTER TABLE ... ADD KEY <sufficient big enough structure>
|
||||
--echo # - One UPDATE statement modifying a huge slice of t1.
|
||||
--echo # Any of them causes heavy use of SX lock and therefore COUNT_RESET
|
||||
--echo # must have grown for ALL = @sx_count entries.
|
||||
# The former testcases TC-10 and TC12 had to be made a part of this testcase
|
||||
# because their results were unstable.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics t_after JOIN my_metrics t_before
|
||||
ON t_after.COUNT_RESET > t_before.COUNT_RESET AND t_after.NAME = t_before.NAME
|
||||
WHERE t_after.phase = 'after' AND t_before.phase = 'before';
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT * FROM my_metrics
|
||||
ORDER BY NAME, phase;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
--echo # TC-09 Heavy activity after reset.
|
||||
--echo # COUNT_RESET = MAX_COUNT_RESET for ALL = @sx_count entries
|
||||
--echo # needs to stay valid though he counters will have grown.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics
|
||||
WHERE phase = 'after' AND COUNT_RESET = MAX_COUNT_RESET;
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT * FROM my_metrics
|
||||
ORDER BY NAME, phase;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
eval $empty_my_metrics;
|
||||
eval $before_my_metrics;
|
||||
SET GLOBAL innodb_monitor_reset = "innodb_rwlock_sx_%";
|
||||
eval $after_my_metrics;
|
||||
--echo # TC-08 There was a reset. COUNT_RESET = MAX_COUNT_RESET for ALL
|
||||
--echo # = @sx_count entries.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics
|
||||
WHERE phase = 'before' AND COUNT_RESET = MAX_COUNT_RESET;
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT * FROM my_metrics
|
||||
ORDER BY NAME, phase;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
--echo # TC-17 We had heavy activity causing big counters and after that a reset.
|
||||
--echo # Reset causes COUNT > COUNT_RESET AND MAX_COUNT > MAX_COUNT_RESET
|
||||
--echo # for ALL @sx_count entries.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics
|
||||
WHERE phase = 'after'
|
||||
AND COUNT > COUNT_RESET
|
||||
AND MAX_COUNT > MAX_COUNT_RESET;
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT * FROM my_metrics
|
||||
ORDER BY NAME, phase;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
--echo # TC-18 We had some reset but this must not decrease COUNT or MAX_COUNT
|
||||
--echo # after.COUNT >= before.COUNT AND
|
||||
--echo # after.MAX_COUNT >= before.MAX_COUNT for ALL @sx_count entries.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics t_after JOIN my_metrics t_before
|
||||
ON t_after.COUNT >= t_before.COUNT AND t_after.MAX_COUNT >= t_before.MAX_COUNT
|
||||
AND t_after.NAME = t_before.NAME
|
||||
WHERE t_after.phase = 'after' AND t_before.phase = 'before';
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT * FROM my_metrics
|
||||
ORDER BY NAME, phase;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
--echo # TC-19 We had some reset after heavy activity and this must cause
|
||||
--echo # after.COUNT_RESET < before.COUNT_RESET
|
||||
--echo # AND after.MAX_COUNT_RESET < before.MAX_COUNT_RESET AND
|
||||
--echo # for ALL @sx_count entries.
|
||||
let $check_statement=
|
||||
SELECT COUNT(*) <> @sx_count FROM my_metrics t_after JOIN my_metrics t_before
|
||||
ON t_after.COUNT_RESET < t_before.COUNT_RESET
|
||||
AND t_after.MAX_COUNT_RESET < t_before.MAX_COUNT_RESET
|
||||
AND t_after.NAME = t_before.NAME
|
||||
WHERE t_after.phase = 'after' AND t_before.phase = 'before';
|
||||
if(`$check_statement`)
|
||||
{
|
||||
--echo # fail
|
||||
eval $check_statement;
|
||||
SELECT * FROM my_metrics
|
||||
ORDER BY NAME, phase;
|
||||
exit;
|
||||
}
|
||||
--echo # pass
|
||||
|
||||
# Cleanup
|
||||
let $num= $max_con;
|
||||
while ($num)
|
||||
{
|
||||
--connection con$num
|
||||
--disconnect con$num
|
||||
--source include/wait_until_disconnected.inc
|
||||
dec $num;
|
||||
}
|
||||
--connection default
|
||||
USE test;
|
||||
DROP SCHEMA my_schema;
|
||||
SET GLOBAL innodb_monitor_disable = all;
|
||||
SET GLOBAL innodb_monitor_reset_all = all;
|
||||
--disable_warnings
|
||||
SET GLOBAL innodb_monitor_enable = default;
|
||||
SET GLOBAL innodb_monitor_disable = default;
|
||||
SET GLOBAL innodb_monitor_reset = default;
|
||||
SET GLOBAL innodb_monitor_reset_all = default;
|
||||
--enable_warnings
|
||||
SET GLOBAL innodb_monitor_disable = "innodb_rwlock_sx_%";
|
||||
SET GLOBAL innodb_monitor_reset = "innodb_rwlock_sx_%";
|
||||
|
|
@ -14554,7 +14554,7 @@ static int compare_fields_by_table_order(Item *field1,
|
|||
Item_field *f2= (Item_field *) field2_real;
|
||||
if (f1->used_tables() & OUTER_REF_TABLE_BIT)
|
||||
{
|
||||
outer_ref= -1;
|
||||
outer_ref= 1;
|
||||
cmp= -1;
|
||||
}
|
||||
if (f2->used_tables() & OUTER_REF_TABLE_BIT)
|
||||
|
|
|
@ -415,29 +415,46 @@ static void wsrep_replication_process(THD *thd)
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
static bool create_wsrep_THD(wsrep_thread_args* args)
|
||||
static bool create_wsrep_THD(wsrep_thread_args* args, bool thread_count_lock)
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_thread_count);
|
||||
if (!thread_count_lock)
|
||||
mysql_mutex_lock(&LOCK_thread_count);
|
||||
|
||||
ulong old_wsrep_running_threads= wsrep_running_threads;
|
||||
|
||||
DBUG_ASSERT(args->thread_type == WSREP_APPLIER_THREAD ||
|
||||
args->thread_type == WSREP_ROLLBACKER_THREAD);
|
||||
|
||||
bool res= mysql_thread_create(args->thread_type == WSREP_APPLIER_THREAD
|
||||
? key_wsrep_applier : key_wsrep_rollbacker,
|
||||
&args->thread_id, &connection_attrib,
|
||||
start_wsrep_THD, (void*)args);
|
||||
|
||||
if (res)
|
||||
{
|
||||
WSREP_ERROR("Can't create wsrep thread");
|
||||
}
|
||||
|
||||
/*
|
||||
if starting a thread on server startup, wait until the this thread's THD
|
||||
is fully initialized (otherwise a THD initialization code might
|
||||
try to access a partially initialized server data structure - MDEV-8208).
|
||||
*/
|
||||
if (!mysqld_server_initialized)
|
||||
{
|
||||
while (old_wsrep_running_threads == wsrep_running_threads)
|
||||
{
|
||||
mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
|
||||
mysql_mutex_unlock(&LOCK_thread_count);
|
||||
}
|
||||
}
|
||||
|
||||
if (!thread_count_lock)
|
||||
mysql_mutex_unlock(&LOCK_thread_count);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void wsrep_create_appliers(long threads)
|
||||
bool wsrep_create_appliers(long threads, bool thread_count_lock)
|
||||
{
|
||||
if (!wsrep_connected)
|
||||
{
|
||||
|
@ -449,26 +466,32 @@ void wsrep_create_appliers(long threads)
|
|||
"connection at '%s'", wsrep_cluster_address);
|
||||
assert(0);
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
long wsrep_threads=0;
|
||||
long wsrep_threads= 0;
|
||||
|
||||
while (wsrep_threads++ < threads) {
|
||||
wsrep_thread_args* arg;
|
||||
if((arg = (wsrep_thread_args*)my_malloc(sizeof(wsrep_thread_args), MYF(0))) == NULL) {
|
||||
|
||||
if((arg= (wsrep_thread_args*)my_malloc(sizeof(wsrep_thread_args), MYF(0))) == NULL)
|
||||
{
|
||||
WSREP_ERROR("Can't allocate memory for wsrep replication thread %ld\n", wsrep_threads);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
arg->thread_type = WSREP_APPLIER_THREAD;
|
||||
arg->processor = wsrep_replication_process;
|
||||
arg->thread_type= WSREP_APPLIER_THREAD;
|
||||
arg->processor= wsrep_replication_process;
|
||||
|
||||
if (create_wsrep_THD(arg)) {
|
||||
WSREP_WARN("Can't create thread to manage wsrep replication");
|
||||
if (create_wsrep_THD(arg, thread_count_lock))
|
||||
{
|
||||
WSREP_ERROR("Can't create thread to manage wsrep replication");
|
||||
my_free(arg);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void wsrep_rollback_process(THD *thd)
|
||||
|
@ -564,7 +587,7 @@ void wsrep_create_rollbacker()
|
|||
arg->processor = wsrep_rollback_process;
|
||||
|
||||
/* create rollbacker */
|
||||
if (create_wsrep_THD(arg)) {
|
||||
if (create_wsrep_THD(arg, false)) {
|
||||
WSREP_WARN("Can't create thread to manage wsrep rollback");
|
||||
my_free(arg);
|
||||
return;
|
||||
|
|
|
@ -26,7 +26,7 @@ int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff,
|
|||
enum enum_var_type scope);
|
||||
void wsrep_client_rollback(THD *thd);
|
||||
void wsrep_replay_transaction(THD *thd);
|
||||
void wsrep_create_appliers(long threads);
|
||||
bool wsrep_create_appliers(long threads, bool thread_count_lock=false);
|
||||
void wsrep_create_rollbacker();
|
||||
|
||||
int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr,
|
||||
|
|
|
@ -602,16 +602,22 @@ static void wsrep_slave_count_change_update ()
|
|||
|
||||
bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type)
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_thread_count);
|
||||
bool res= false;
|
||||
|
||||
wsrep_slave_count_change_update();
|
||||
|
||||
if (wsrep_slave_count_change > 0)
|
||||
{
|
||||
WSREP_DEBUG("Creating %d applier threads, total %ld", wsrep_slave_count_change, wsrep_slave_threads);
|
||||
wsrep_create_appliers(wsrep_slave_count_change);
|
||||
res= wsrep_create_appliers(wsrep_slave_count_change, true);
|
||||
WSREP_DEBUG("Running %lu applier threads", wsrep_running_applier_threads);
|
||||
wsrep_slave_count_change = 0;
|
||||
}
|
||||
return false;
|
||||
|
||||
mysql_mutex_unlock(&LOCK_thread_count);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2015, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2020, MariaDB Corporation.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
Google, Inc. Those modifications are gratefully acknowledged and are described
|
||||
|
@ -804,46 +804,66 @@ btr_cur_will_modify_tree(
|
|||
const ulint n_recs = page_get_n_recs(page);
|
||||
|
||||
if (lock_intention <= BTR_INTENTION_BOTH) {
|
||||
ulint margin;
|
||||
compile_time_assert(BTR_INTENTION_DELETE < BTR_INTENTION_BOTH);
|
||||
compile_time_assert(BTR_INTENTION_BOTH < BTR_INTENTION_INSERT);
|
||||
|
||||
/* check delete will cause. (BTR_INTENTION_BOTH
|
||||
or BTR_INTENTION_DELETE) */
|
||||
/* first, 2nd, 2nd-last and last records are 4 records */
|
||||
if (n_recs < 5) {
|
||||
return(true);
|
||||
if (!page_has_siblings(page)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* is first, 2nd or last record */
|
||||
if (page_rec_is_first(rec, page)
|
||||
|| (page_has_next(page)
|
||||
&& (page_rec_is_last(rec, page)
|
||||
|| page_rec_is_second_last(rec, page)))
|
||||
|| (page_has_prev(page)
|
||||
&& page_rec_is_second(rec, page))) {
|
||||
return(true);
|
||||
}
|
||||
ulint margin = rec_size;
|
||||
|
||||
if (lock_intention == BTR_INTENTION_BOTH) {
|
||||
ulint level = btr_page_get_level(page);
|
||||
|
||||
/* This value is the worst expectation for the node_ptr
|
||||
records to be deleted from this page. It is used to
|
||||
expect whether the cursor position can be the left_most
|
||||
record in this page or not. */
|
||||
ulint max_nodes_deleted = 0;
|
||||
|
||||
/* By modifying tree operations from the under of this
|
||||
level, logically (2 ^ (level - 1)) opportunities to
|
||||
deleting records in maximum even unreally rare case. */
|
||||
if (level > 7) {
|
||||
/* TODO: adjust this practical limit. */
|
||||
max_nodes_deleted = 64;
|
||||
} else if (level > 0) {
|
||||
max_nodes_deleted = (ulint)1 << (level - 1);
|
||||
}
|
||||
/* check delete will cause. (BTR_INTENTION_BOTH
|
||||
or BTR_INTENTION_DELETE) */
|
||||
if (n_recs <= max_nodes_deleted * 2
|
||||
|| page_rec_is_first(rec, page)) {
|
||||
/* The cursor record can be the left most record
|
||||
in this page. */
|
||||
return true;
|
||||
}
|
||||
|
||||
if (page_has_prev(page)
|
||||
&& page_rec_distance_is_at_most(
|
||||
page_get_infimum_rec(page), rec,
|
||||
max_nodes_deleted)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (page_has_next(page)
|
||||
&& page_rec_distance_is_at_most(
|
||||
rec, page_get_supremum_rec(page),
|
||||
max_nodes_deleted)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Delete at leftmost record in a page causes delete
|
||||
& insert at its parent page. After that, the delete
|
||||
might cause btr_compress() and delete record at its
|
||||
parent page. Thus we should consider max 2 deletes. */
|
||||
|
||||
margin = rec_size * 2;
|
||||
} else {
|
||||
ut_ad(lock_intention == BTR_INTENTION_DELETE);
|
||||
|
||||
margin = rec_size;
|
||||
parent page. Thus we should consider max deletes. */
|
||||
margin *= max_nodes_deleted;
|
||||
}
|
||||
/* NOTE: call mach_read_from_4() directly to avoid assertion
|
||||
failure. It is safe because we already have SX latch of the
|
||||
index tree */
|
||||
|
||||
/* Safe because we already have SX latch of the index tree */
|
||||
if (page_get_data_size(page)
|
||||
< margin + BTR_CUR_PAGE_COMPRESS_LIMIT(index)
|
||||
|| (mach_read_from_4(page + FIL_PAGE_NEXT)
|
||||
== FIL_NULL
|
||||
&& mach_read_from_4(page + FIL_PAGE_PREV)
|
||||
== FIL_NULL)) {
|
||||
< margin + BTR_CUR_PAGE_COMPRESS_LIMIT(index)) {
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
@ -2025,9 +2045,9 @@ need_opposite_intention:
|
|||
offsets2 = rec_get_offsets(
|
||||
first_rec, index, offsets2,
|
||||
false, ULINT_UNDEFINED, &heap);
|
||||
cmp_rec_rec_with_match(node_ptr, first_rec,
|
||||
offsets, offsets2, index, FALSE,
|
||||
&matched_fields);
|
||||
cmp_rec_rec(node_ptr, first_rec,
|
||||
offsets, offsets2, index, false,
|
||||
&matched_fields);
|
||||
|
||||
if (matched_fields
|
||||
>= rec_offs_n_fields(offsets) - 1) {
|
||||
|
@ -2043,10 +2063,10 @@ need_opposite_intention:
|
|||
offsets2 = rec_get_offsets(
|
||||
last_rec, index, offsets2,
|
||||
false, ULINT_UNDEFINED, &heap);
|
||||
cmp_rec_rec_with_match(
|
||||
cmp_rec_rec(
|
||||
node_ptr, last_rec,
|
||||
offsets, offsets2, index,
|
||||
FALSE, &matched_fields);
|
||||
false, &matched_fields);
|
||||
if (matched_fields
|
||||
>= rec_offs_n_fields(offsets) - 1) {
|
||||
detected_same_key_root = true;
|
||||
|
@ -4242,7 +4262,6 @@ btr_cur_optimistic_update(
|
|||
dtuple_t* new_entry;
|
||||
roll_ptr_t roll_ptr;
|
||||
ulint i;
|
||||
ulint n_ext;
|
||||
|
||||
block = btr_cur_get_block(cursor);
|
||||
page = buf_block_get_frame(block);
|
||||
|
@ -4319,10 +4338,8 @@ any_extern:
|
|||
+ DTUPLE_EST_ALLOC(rec_offs_n_fields(*offsets)));
|
||||
}
|
||||
|
||||
new_entry = row_rec_to_index_entry(rec, index, *offsets,
|
||||
&n_ext, *heap);
|
||||
/* We checked above that there are no externally stored fields. */
|
||||
ut_a(!n_ext);
|
||||
new_entry = row_rec_to_index_entry(rec, index, *offsets, *heap);
|
||||
ut_ad(!dtuple_get_n_ext(new_entry));
|
||||
|
||||
/* The page containing the clustered index record
|
||||
corresponding to new_entry is latched in mtr.
|
||||
|
@ -4586,7 +4603,6 @@ btr_cur_pessimistic_update(
|
|||
roll_ptr_t roll_ptr;
|
||||
ibool was_first;
|
||||
ulint n_reserved = 0;
|
||||
ulint n_ext;
|
||||
ulint max_ins_size = 0;
|
||||
|
||||
*offsets = NULL;
|
||||
|
@ -4651,7 +4667,7 @@ btr_cur_pessimistic_update(
|
|||
ut_ad(rec_offs_validate(rec, index, *offsets));
|
||||
|
||||
dtuple_t* new_entry = row_rec_to_index_entry(
|
||||
rec, index, *offsets, &n_ext, entry_heap);
|
||||
rec, index, *offsets, entry_heap);
|
||||
|
||||
/* The page containing the clustered index record
|
||||
corresponding to new_entry is latched in mtr. If the
|
||||
|
@ -4671,7 +4687,6 @@ btr_cur_pessimistic_update(
|
|||
|
||||
ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec));
|
||||
ut_ad(rec_offs_validate(rec, index, *offsets));
|
||||
n_ext += btr_push_update_extern_fields(new_entry, update, entry_heap);
|
||||
|
||||
if ((flags & BTR_NO_UNDO_LOG_FLAG)
|
||||
&& rec_offs_any_extern(*offsets)) {
|
||||
|
@ -4692,6 +4707,8 @@ btr_cur_pessimistic_update(
|
|||
index, rec, page_zip, *offsets, update, true, mtr);
|
||||
}
|
||||
|
||||
ulint n_ext = dtuple_get_n_ext(new_entry);
|
||||
|
||||
if (page_zip_rec_needs_ext(
|
||||
rec_get_converted_size(index, new_entry, n_ext),
|
||||
page_is_comp(page),
|
||||
|
@ -6722,10 +6739,10 @@ btr_estimate_number_of_different_key_vals(
|
|||
ULINT_UNDEFINED,
|
||||
&heap);
|
||||
|
||||
cmp_rec_rec_with_match(rec, next_rec,
|
||||
offsets_rec, offsets_next_rec,
|
||||
index, stats_null_not_equal,
|
||||
&matched_fields);
|
||||
cmp_rec_rec(rec, next_rec,
|
||||
offsets_rec, offsets_next_rec,
|
||||
index, stats_null_not_equal,
|
||||
&matched_fields);
|
||||
|
||||
for (j = matched_fields; j < n_cols; j++) {
|
||||
/* We add one if this index record has
|
||||
|
@ -7005,84 +7022,6 @@ btr_cur_unmark_extern_fields(
|
|||
}
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Flags the data tuple fields that are marked as extern storage in the
|
||||
update vector. We use this function to remember which fields we must
|
||||
mark as extern storage in a record inserted for an update.
|
||||
@return number of flagged external columns */
|
||||
ulint
|
||||
btr_push_update_extern_fields(
|
||||
/*==========================*/
|
||||
dtuple_t* tuple, /*!< in/out: data tuple */
|
||||
const upd_t* update, /*!< in: update vector */
|
||||
mem_heap_t* heap) /*!< in: memory heap */
|
||||
{
|
||||
ulint n_pushed = 0;
|
||||
ulint n;
|
||||
const upd_field_t* uf;
|
||||
|
||||
uf = update->fields;
|
||||
n = upd_get_n_fields(update);
|
||||
|
||||
for (; n--; uf++) {
|
||||
if (dfield_is_ext(&uf->new_val)) {
|
||||
dfield_t* field
|
||||
= dtuple_get_nth_field(tuple, uf->field_no);
|
||||
|
||||
if (!dfield_is_ext(field)) {
|
||||
dfield_set_ext(field);
|
||||
n_pushed++;
|
||||
}
|
||||
|
||||
switch (uf->orig_len) {
|
||||
byte* data;
|
||||
ulint len;
|
||||
byte* buf;
|
||||
case 0:
|
||||
break;
|
||||
case BTR_EXTERN_FIELD_REF_SIZE:
|
||||
/* Restore the original locally stored
|
||||
part of the column. In the undo log,
|
||||
InnoDB writes a longer prefix of externally
|
||||
stored columns, so that column prefixes
|
||||
in secondary indexes can be reconstructed. */
|
||||
dfield_set_data(field,
|
||||
(byte*) dfield_get_data(field)
|
||||
+ dfield_get_len(field)
|
||||
- BTR_EXTERN_FIELD_REF_SIZE,
|
||||
BTR_EXTERN_FIELD_REF_SIZE);
|
||||
dfield_set_ext(field);
|
||||
break;
|
||||
default:
|
||||
/* Reconstruct the original locally
|
||||
stored part of the column. The data
|
||||
will have to be copied. */
|
||||
ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
|
||||
|
||||
data = (byte*) dfield_get_data(field);
|
||||
len = dfield_get_len(field);
|
||||
|
||||
buf = (byte*) mem_heap_alloc(heap,
|
||||
uf->orig_len);
|
||||
/* Copy the locally stored prefix. */
|
||||
memcpy(buf, data,
|
||||
unsigned(uf->orig_len)
|
||||
- BTR_EXTERN_FIELD_REF_SIZE);
|
||||
/* Copy the BLOB pointer. */
|
||||
memcpy(buf + unsigned(uf->orig_len)
|
||||
- BTR_EXTERN_FIELD_REF_SIZE,
|
||||
data + len - BTR_EXTERN_FIELD_REF_SIZE,
|
||||
BTR_EXTERN_FIELD_REF_SIZE);
|
||||
|
||||
dfield_set_data(field, buf, uf->orig_len);
|
||||
dfield_set_ext(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(n_pushed);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Returns the length of a BLOB part stored on the header page.
|
||||
@return part length */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2009, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2015, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1169,13 +1169,9 @@ dict_stats_analyze_index_level(
|
|||
prev_rec, index, prev_rec_offsets, !level,
|
||||
n_uniq, &heap);
|
||||
|
||||
cmp_rec_rec_with_match(rec,
|
||||
prev_rec,
|
||||
rec_offsets,
|
||||
prev_rec_offsets,
|
||||
index,
|
||||
FALSE,
|
||||
&matched_fields);
|
||||
cmp_rec_rec(prev_rec, rec,
|
||||
prev_rec_offsets, rec_offsets, index,
|
||||
false, &matched_fields);
|
||||
|
||||
for (i = matched_fields; i < n_uniq; i++) {
|
||||
|
||||
|
@ -1395,9 +1391,8 @@ dict_stats_scan_page(
|
|||
|
||||
/* check whether rec != next_rec when looking at
|
||||
the first n_prefix fields */
|
||||
cmp_rec_rec_with_match(rec, next_rec,
|
||||
offsets_rec, offsets_next_rec,
|
||||
index, FALSE, &matched_fields);
|
||||
cmp_rec_rec(rec, next_rec, offsets_rec, offsets_next_rec,
|
||||
index, false, &matched_fields);
|
||||
|
||||
if (matched_fields < n_prefix) {
|
||||
/* rec != next_rec, => rec is non-boring */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2018, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2018, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1436,10 +1436,9 @@ rtr_page_copy_rec_list_end_no_locks(
|
|||
offsets2 = rec_get_offsets(cur_rec, index, offsets2,
|
||||
is_leaf,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec,
|
||||
offsets1, offsets2,
|
||||
index, FALSE,
|
||||
&cur_matched_fields);
|
||||
cmp = cmp_rec_rec(cur1_rec, cur_rec,
|
||||
offsets1, offsets2, index, false,
|
||||
&cur_matched_fields);
|
||||
if (cmp < 0) {
|
||||
page_cur_move_to_prev(&page_cur);
|
||||
break;
|
||||
|
@ -1551,15 +1550,13 @@ rtr_page_copy_rec_list_start_no_locks(
|
|||
|
||||
while (!page_rec_is_supremum(cur_rec)) {
|
||||
ulint cur_matched_fields = 0;
|
||||
int cmp;
|
||||
|
||||
offsets2 = rec_get_offsets(cur_rec, index, offsets2,
|
||||
is_leaf,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec,
|
||||
offsets1, offsets2,
|
||||
index, FALSE,
|
||||
&cur_matched_fields);
|
||||
int cmp = cmp_rec_rec(cur1_rec, cur_rec,
|
||||
offsets1, offsets2, index, false,
|
||||
&cur_matched_fields);
|
||||
if (cmp < 0) {
|
||||
page_cur_move_to_prev(&page_cur);
|
||||
cur_rec = page_cur_get_rec(&page_cur);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2019, MariaDB Corporation.
|
||||
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -784,18 +784,6 @@ btr_rec_copy_externally_stored_field(
|
|||
ulint* len,
|
||||
mem_heap_t* heap);
|
||||
|
||||
/*******************************************************************//**
|
||||
Flags the data tuple fields that are marked as extern storage in the
|
||||
update vector. We use this function to remember which fields we must
|
||||
mark as extern storage in a record inserted for an update.
|
||||
@return number of flagged external columns */
|
||||
ulint
|
||||
btr_push_update_extern_fields(
|
||||
/*==========================*/
|
||||
dtuple_t* tuple, /*!< in/out: data tuple */
|
||||
const upd_t* update, /*!< in: update vector */
|
||||
mem_heap_t* heap) /*!< in: memory heap */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
/***********************************************************//**
|
||||
Sets a secondary index record's delete mark to the given value. This
|
||||
function is only used by the insert buffer merge mechanism. */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2013, 2019, MariaDB Corporation.
|
||||
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2013, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -857,6 +857,22 @@ page_rec_is_last(
|
|||
const page_t* page) /*!< in: page */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
||||
/************************************************************//**
|
||||
true if distance between the records (measured in number of times we have to
|
||||
move to the next record) is at most the specified value
|
||||
@param[in] left_rec lefter record
|
||||
@param[in] right_rec righter record
|
||||
@param[in] val specified value to compare
|
||||
@return true if the distance is smaller than the value */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
page_rec_distance_is_at_most(
|
||||
/*=========================*/
|
||||
const rec_t* left_rec,
|
||||
const rec_t* right_rec,
|
||||
ulint val)
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
||||
/************************************************************//**
|
||||
true if the record is the second last user record on a page.
|
||||
@return true if the second last user record */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2016, 2019, MariaDB Corporation.
|
||||
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2016, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -358,6 +358,26 @@ page_rec_is_last(
|
|||
return(page_rec_get_next_const(rec) == page_get_supremum_rec(page));
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
true if distance between the records (measured in number of times we have to
|
||||
move to the next record) is at most the specified value */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
page_rec_distance_is_at_most(
|
||||
/*=========================*/
|
||||
const rec_t* left_rec,
|
||||
const rec_t* right_rec,
|
||||
ulint val)
|
||||
{
|
||||
for (ulint i = 0; i <= val; i++) {
|
||||
if (left_rec == right_rec) {
|
||||
return (true);
|
||||
}
|
||||
left_rec = page_rec_get_next_const(left_rec);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
true if the record is the second last user record on a page.
|
||||
@return true if the second last user record */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -80,7 +80,7 @@ cmp_dfield_dfield(
|
|||
|
||||
/** Compare a GIS data tuple to a physical record.
|
||||
@param[in] dtuple data tuple
|
||||
@param[in] rec B-tree record
|
||||
@param[in] rec R-tree record
|
||||
@param[in] offsets rec_get_offsets(rec)
|
||||
@param[in] mode compare mode
|
||||
@retval negative if dtuple is less than rec */
|
||||
|
@ -190,43 +190,23 @@ cmp_rec_rec_simple(
|
|||
duplicate key value if applicable,
|
||||
or NULL */
|
||||
MY_ATTRIBUTE((nonnull(1,2,3,4), warn_unused_result));
|
||||
/** Compare two B-tree records.
|
||||
@param[in] rec1 B-tree record
|
||||
@param[in] rec2 B-tree record
|
||||
@param[in] offsets1 rec_get_offsets(rec1, index)
|
||||
@param[in] offsets2 rec_get_offsets(rec2, index)
|
||||
@param[in] index B-tree index
|
||||
@param[in] nulls_unequal true if this is for index cardinality
|
||||
statistics estimation, and innodb_stats_method=nulls_unequal
|
||||
or innodb_stats_method=nulls_ignored
|
||||
@param[out] matched_fields number of completely matched fields
|
||||
within the first field not completely matched
|
||||
@return the comparison result
|
||||
@retval 0 if rec1 is equal to rec2
|
||||
@retval negative if rec1 is less than rec2
|
||||
@retval positive if rec2 is greater than rec2 */
|
||||
int
|
||||
cmp_rec_rec_with_match(
|
||||
const rec_t* rec1,
|
||||
const rec_t* rec2,
|
||||
const offset_t* offsets1,
|
||||
const offset_t* offsets2,
|
||||
const dict_index_t* index,
|
||||
bool nulls_unequal,
|
||||
ulint* matched_fields);
|
||||
|
||||
/** Compare two B-tree records.
|
||||
/** Compare two B-tree or R-tree records.
|
||||
Only the common first fields are compared, and externally stored field
|
||||
are treated as equal.
|
||||
@param[in] rec1 B-tree record
|
||||
@param[in] rec2 B-tree record
|
||||
@param[in] rec1 record (possibly not on an index page)
|
||||
@param[in] rec2 B-tree or R-tree record in an index page
|
||||
@param[in] offsets1 rec_get_offsets(rec1, index)
|
||||
@param[in] offsets2 rec_get_offsets(rec2, index)
|
||||
@param[in] nulls_unequal true if this is for index cardinality
|
||||
statistics estimation with
|
||||
innodb_stats_method=nulls_unequal
|
||||
or innodb_stats_method=nulls_ignored
|
||||
@param[out] matched_fields number of completely matched fields
|
||||
within the first field not completely matched
|
||||
@return positive, 0, negative if rec1 is greater, equal, less, than rec2,
|
||||
respectively */
|
||||
UNIV_INLINE
|
||||
@retval 0 if rec1 is equal to rec2
|
||||
@retval negative if rec1 is less than rec2
|
||||
@retval positive if rec1 is greater than rec2 */
|
||||
int
|
||||
cmp_rec_rec(
|
||||
const rec_t* rec1,
|
||||
|
@ -234,7 +214,9 @@ cmp_rec_rec(
|
|||
const offset_t* offsets1,
|
||||
const offset_t* offsets2,
|
||||
const dict_index_t* index,
|
||||
ulint* matched_fields = NULL);
|
||||
bool nulls_unequal = false,
|
||||
ulint* matched_fields = NULL)
|
||||
MY_ATTRIBUTE((nonnull(1,2,3,4,5)));
|
||||
|
||||
/** Compare two data fields.
|
||||
@param[in] dfield1 data field
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -52,40 +53,6 @@ cmp_dfield_dfield(
|
|||
dfield_get_len(dfield2)));
|
||||
}
|
||||
|
||||
/** Compare two B-tree records.
|
||||
Only the common first fields are compared, and externally stored field
|
||||
are treated as equal.
|
||||
@param[in] rec1 B-tree record
|
||||
@param[in] rec2 B-tree record
|
||||
@param[in] offsets1 rec_get_offsets(rec1, index)
|
||||
@param[in] offsets2 rec_get_offsets(rec2, index)
|
||||
@param[out] matched_fields number of completely matched fields
|
||||
within the first field not completely matched
|
||||
@return positive, 0, negative if rec1 is greater, equal, less, than rec2,
|
||||
respectively */
|
||||
UNIV_INLINE
|
||||
int
|
||||
cmp_rec_rec(
|
||||
const rec_t* rec1,
|
||||
const rec_t* rec2,
|
||||
const offset_t* offsets1,
|
||||
const offset_t* offsets2,
|
||||
const dict_index_t* index,
|
||||
ulint* matched_fields)
|
||||
{
|
||||
ulint match_f;
|
||||
int ret;
|
||||
|
||||
ret = cmp_rec_rec_with_match(
|
||||
rec1, rec2, offsets1, offsets2, index, false, &match_f);
|
||||
|
||||
if (matched_fields != NULL) {
|
||||
*matched_fields = match_f;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/** Compare two data fields.
|
||||
@param[in] dfield1 data field
|
||||
@param[in] dfield2 data field
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2019, MariaDB Corporation.
|
||||
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1410,6 +1410,7 @@ rec_get_converted_size(
|
|||
|
||||
data_size = dtuple_get_data_size(dtuple, 0);
|
||||
|
||||
ut_ad(n_ext == dtuple_get_n_ext(dtuple));
|
||||
extra_size = rec_get_converted_extra_size(
|
||||
data_size, dtuple_get_n_fields(dtuple), n_ext);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2016, 2017, MariaDB Corporation.
|
||||
Copyright (c) 2016, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -207,8 +207,6 @@ row_rec_to_index_entry_low(
|
|||
const rec_t* rec, /*!< in: record in the index */
|
||||
const dict_index_t* index, /*!< in: index */
|
||||
const offset_t* offsets,/*!< in: rec_get_offsets(rec, index) */
|
||||
ulint* n_ext, /*!< out: number of externally
|
||||
stored columns */
|
||||
mem_heap_t* heap) /*!< in: memory heap from which
|
||||
the memory needed is allocated */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
@ -222,8 +220,6 @@ row_rec_to_index_entry(
|
|||
const rec_t* rec, /*!< in: record in the index */
|
||||
const dict_index_t* index, /*!< in: index */
|
||||
const offset_t* offsets,/*!< in/out: rec_get_offsets(rec) */
|
||||
ulint* n_ext, /*!< out: number of externally
|
||||
stored columns */
|
||||
mem_heap_t* heap) /*!< in: memory heap from which
|
||||
the memory needed is allocated */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2013, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2013, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/***********************************************************************
|
||||
|
||||
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2009, Percona Inc.
|
||||
Copyright (c) 2013, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2013, 2020, MariaDB Corporation.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted
|
||||
by Percona Inc.. Those modifications are
|
||||
|
@ -1470,6 +1470,12 @@ os_file_get_parent_dir(
|
|||
return(NULL);
|
||||
}
|
||||
|
||||
if (last_slash - path < 0) {
|
||||
/* Sanity check, it prevents gcc from trying to handle this case which
|
||||
* results in warnings for some optimized builds */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Non-trivial directory component */
|
||||
|
||||
return(mem_strdupl(path, ulint(last_slash - path)));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -534,7 +535,7 @@ cmp_data(
|
|||
|
||||
/** Compare a GIS data tuple to a physical record.
|
||||
@param[in] dtuple data tuple
|
||||
@param[in] rec B-tree record
|
||||
@param[in] rec R-tree record
|
||||
@param[in] offsets rec_get_offsets(rec)
|
||||
@param[in] mode compare mode
|
||||
@retval negative if dtuple is less than rec */
|
||||
|
@ -1096,23 +1097,24 @@ cmp_rec_rec_simple(
|
|||
return(0);
|
||||
}
|
||||
|
||||
/** Compare two B-tree records.
|
||||
@param[in] rec1 B-tree record
|
||||
@param[in] rec2 B-tree record
|
||||
@param[in] offsets1 rec_get_offsets(rec1, index)
|
||||
@param[in] offsets2 rec_get_offsets(rec2, index)
|
||||
@param[in] index B-tree index
|
||||
@param[in] nulls_unequal true if this is for index cardinality
|
||||
statistics estimation, and innodb_stats_method=nulls_unequal
|
||||
or innodb_stats_method=nulls_ignored
|
||||
@param[out] matched_fields number of completely matched fields
|
||||
within the first field not completely matched
|
||||
@return the comparison result
|
||||
/** Compare two B-tree or R-tree records.
|
||||
Only the common first fields are compared, and externally stored field
|
||||
are treated as equal.
|
||||
@param[in] rec1 record (possibly not on an index page)
|
||||
@param[in] rec2 B-tree or R-tree record in an index page
|
||||
@param[in] offsets1 rec_get_offsets(rec1, index)
|
||||
@param[in] offsets2 rec_get_offsets(rec2, index)
|
||||
@param[in] nulls_unequal true if this is for index cardinality
|
||||
statistics estimation with
|
||||
innodb_stats_method=nulls_unequal
|
||||
or innodb_stats_method=nulls_ignored
|
||||
@param[out] matched_fields number of completely matched fields
|
||||
within the first field not completely matched
|
||||
@retval 0 if rec1 is equal to rec2
|
||||
@retval negative if rec1 is less than rec2
|
||||
@retval positive if rec2 is greater than rec2 */
|
||||
@retval positive if rec1 is greater than rec2 */
|
||||
int
|
||||
cmp_rec_rec_with_match(
|
||||
cmp_rec_rec(
|
||||
const rec_t* rec1,
|
||||
const rec_t* rec2,
|
||||
const offset_t* offsets1,
|
||||
|
@ -1121,17 +1123,14 @@ cmp_rec_rec_with_match(
|
|||
bool nulls_unequal,
|
||||
ulint* matched_fields)
|
||||
{
|
||||
ulint rec1_n_fields; /* the number of fields in rec */
|
||||
ulint rec1_f_len; /* length of current field in rec */
|
||||
const byte* rec1_b_ptr; /* pointer to the current byte
|
||||
in rec field */
|
||||
ulint rec2_n_fields; /* the number of fields in rec */
|
||||
ulint rec2_f_len; /* length of current field in rec */
|
||||
const byte* rec2_b_ptr; /* pointer to the current byte
|
||||
in rec field */
|
||||
ulint cur_field = 0; /* current field number */
|
||||
int ret = 0; /* return value */
|
||||
ulint comp;
|
||||
|
||||
ut_ad(rec1 != NULL);
|
||||
ut_ad(rec2 != NULL);
|
||||
|
@ -1139,10 +1138,12 @@ cmp_rec_rec_with_match(
|
|||
ut_ad(rec_offs_validate(rec1, index, offsets1));
|
||||
ut_ad(rec_offs_validate(rec2, index, offsets2));
|
||||
ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2));
|
||||
ut_ad(fil_page_index_page_check(page_align(rec2)));
|
||||
ut_ad(!!dict_index_is_spatial(index)
|
||||
== (fil_page_get_type(page_align(rec2)) == FIL_PAGE_RTREE));
|
||||
|
||||
comp = rec_offs_comp(offsets1);
|
||||
rec1_n_fields = rec_offs_n_fields(offsets1);
|
||||
rec2_n_fields = rec_offs_n_fields(offsets2);
|
||||
ulint comp = rec_offs_comp(offsets1);
|
||||
ulint n_fields;
|
||||
|
||||
/* Test if rec is the predefined minimum record */
|
||||
if (UNIV_UNLIKELY(rec_get_info_bits(rec1, comp)
|
||||
|
@ -1158,37 +1159,41 @@ cmp_rec_rec_with_match(
|
|||
goto order_resolved;
|
||||
}
|
||||
|
||||
/* Match fields in a loop */
|
||||
/* For non-leaf spatial index records, the
|
||||
dict_index_get_n_unique_in_tree() does include the child page
|
||||
number, because spatial index node pointers only contain
|
||||
the MBR (minimum bounding rectangle) and the child page number.
|
||||
|
||||
for (; cur_field < rec1_n_fields && cur_field < rec2_n_fields;
|
||||
cur_field++) {
|
||||
For B-tree node pointers, the key alone (secondary index
|
||||
columns and PRIMARY KEY columns) must be unique, and there is
|
||||
no need to compare the child page number. */
|
||||
n_fields = std::min(rec_offs_n_fields(offsets1),
|
||||
rec_offs_n_fields(offsets2));
|
||||
n_fields = std::min(n_fields, dict_index_get_n_unique_in_tree(index));
|
||||
|
||||
for (; cur_field < n_fields; cur_field++) {
|
||||
ulint mtype;
|
||||
ulint prtype;
|
||||
|
||||
/* If this is node-ptr records then avoid comparing node-ptr
|
||||
field. Only key field needs to be compared. */
|
||||
if (cur_field == dict_index_get_n_unique_in_tree(index)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (dict_index_is_ibuf(index)) {
|
||||
if (UNIV_UNLIKELY(dict_index_is_ibuf(index))) {
|
||||
/* This is for the insert buffer B-tree. */
|
||||
mtype = DATA_BINARY;
|
||||
prtype = 0;
|
||||
} else {
|
||||
const dict_col_t* col;
|
||||
|
||||
col = dict_index_get_nth_col(index, cur_field);
|
||||
|
||||
const dict_col_t* col = dict_index_get_nth_col(
|
||||
index, cur_field);
|
||||
mtype = col->mtype;
|
||||
prtype = col->prtype;
|
||||
|
||||
/* If the index is spatial index, we mark the
|
||||
prtype of the first field as MBR field. */
|
||||
if (cur_field == 0 && dict_index_is_spatial(index)) {
|
||||
if (UNIV_LIKELY(!dict_index_is_spatial(index))) {
|
||||
} else if (cur_field == 0) {
|
||||
ut_ad(DATA_GEOMETRY_MTYPE(mtype));
|
||||
prtype |= DATA_GIS_MBR;
|
||||
} else if (!page_rec_is_leaf(rec2)) {
|
||||
/* Compare the child page number. */
|
||||
ut_ad(cur_field == 1);
|
||||
mtype = DATA_SYS_CHILD;
|
||||
prtype = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1226,8 +1231,10 @@ cmp_rec_rec_with_match(
|
|||
to the common fields */
|
||||
ut_ad(ret == 0);
|
||||
order_resolved:
|
||||
*matched_fields = cur_field;
|
||||
return(ret);
|
||||
if (matched_fields) {
|
||||
*matched_fields = cur_field;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef UNIV_COMPILE_TEST_FUNCS
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2010, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2015, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1722,7 +1722,6 @@ row_fts_merge_insert(
|
|||
corresponding FTS index auxiliary tables */
|
||||
for (;;) {
|
||||
dtuple_t* dtuple;
|
||||
ulint n_ext;
|
||||
int min_rec = 0;
|
||||
|
||||
if (fts_sort_pll_degree <= 2) {
|
||||
|
@ -1765,7 +1764,7 @@ row_fts_merge_insert(
|
|||
}
|
||||
|
||||
dtuple = row_rec_to_index_entry_low(
|
||||
mrec[min_rec], index, offsets[min_rec], &n_ext,
|
||||
mrec[min_rec], index, offsets[min_rec],
|
||||
tuple_heap);
|
||||
|
||||
row_fts_insert_tuple(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2015, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1526,13 +1526,70 @@ IndexPurge::next() UNIV_NOTHROW
|
|||
mtr_set_log_mode(&m_mtr, MTR_LOG_NO_REDO);
|
||||
|
||||
btr_pcur_restore_position(BTR_MODIFY_LEAF, &m_pcur, &m_mtr);
|
||||
/* The following is based on btr_pcur_move_to_next_user_rec(). */
|
||||
m_pcur.old_stored = false;
|
||||
ut_ad(m_pcur.latch_mode == BTR_MODIFY_LEAF);
|
||||
do {
|
||||
if (btr_pcur_is_after_last_on_page(&m_pcur)) {
|
||||
if (btr_pcur_is_after_last_in_tree(&m_pcur)) {
|
||||
return DB_END_OF_INDEX;
|
||||
}
|
||||
|
||||
if (!btr_pcur_move_to_next_user_rec(&m_pcur, &m_mtr)) {
|
||||
buf_block_t* block = btr_pcur_get_block(&m_pcur);
|
||||
uint32_t next_page = btr_page_get_next(block->frame);
|
||||
|
||||
return(DB_END_OF_INDEX);
|
||||
}
|
||||
/* MDEV-13542 FIXME: Make these checks part of
|
||||
btr_pcur_move_to_next_page(), and introduce a
|
||||
return status that will be checked in all callers! */
|
||||
switch (next_page) {
|
||||
default:
|
||||
if (next_page != block->page.id.page_no()) {
|
||||
break;
|
||||
}
|
||||
/* MDEV-20931 FIXME: Check that
|
||||
next_page is within the tablespace
|
||||
bounds! Also check that it is not a
|
||||
change buffer bitmap page. */
|
||||
/* fall through */
|
||||
case 0:
|
||||
case 1:
|
||||
case FIL_NULL:
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
dict_index_t* index = m_pcur.btr_cur.index;
|
||||
buf_block_t* next_block = btr_block_get(
|
||||
page_id_t(block->page.id.space(), next_page),
|
||||
block->page.size, BTR_MODIFY_LEAF, index,
|
||||
&m_mtr);
|
||||
|
||||
if (UNIV_UNLIKELY(!next_block
|
||||
|| !fil_page_index_page_check(
|
||||
next_block->frame)
|
||||
|| !!dict_index_is_spatial(index)
|
||||
!= (fil_page_get_type(
|
||||
next_block->frame)
|
||||
== FIL_PAGE_RTREE)
|
||||
|| page_is_comp(next_block->frame)
|
||||
!= page_is_comp(block->frame)
|
||||
|| btr_page_get_prev(
|
||||
next_block->frame)
|
||||
!= block->page.id.page_no())) {
|
||||
return DB_CORRUPTION;
|
||||
}
|
||||
|
||||
btr_leaf_page_release(block, BTR_MODIFY_LEAF, &m_mtr);
|
||||
|
||||
page_cur_set_before_first(next_block,
|
||||
&m_pcur.btr_cur.page_cur);
|
||||
|
||||
ut_d(page_check_dir(next_block->frame));
|
||||
} else {
|
||||
btr_pcur_move_to_next_on_page(&m_pcur);
|
||||
}
|
||||
} while (!btr_pcur_is_on_user_rec(&m_pcur));
|
||||
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -3559,7 +3559,6 @@ row_log_apply_op(
|
|||
enum row_op op;
|
||||
ulint extra_size;
|
||||
ulint data_size;
|
||||
ulint n_ext;
|
||||
dtuple_t* entry;
|
||||
trx_id_t trx_id;
|
||||
|
||||
|
@ -3637,10 +3636,10 @@ corrupted:
|
|||
}
|
||||
|
||||
entry = row_rec_to_index_entry_low(
|
||||
mrec - data_size, index, offsets, &n_ext, heap);
|
||||
mrec - data_size, index, offsets, heap);
|
||||
/* Online index creation is only implemented for secondary
|
||||
indexes, which never contain off-page columns. */
|
||||
ut_ad(n_ext == 0);
|
||||
ut_ad(dtuple_get_n_ext(entry) == 0);
|
||||
|
||||
row_log_apply_op_low(index, dup, error, offsets_heap,
|
||||
has_index_lock, op, trx_id, entry);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2014, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2014, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -3535,7 +3535,6 @@ row_merge_insert_index_tuples(
|
|||
double curr_progress = 0;
|
||||
dict_index_t* old_index = NULL;
|
||||
const mrec_t* mrec = NULL;
|
||||
ulint n_ext = 0;
|
||||
mtr_t mtr;
|
||||
|
||||
|
||||
|
@ -3601,8 +3600,6 @@ row_merge_insert_index_tuples(
|
|||
row buffer to data tuple record */
|
||||
row_merge_mtuple_to_dtuple(
|
||||
index, dtuple, &row_buf->tuples[n_rows]);
|
||||
|
||||
n_ext = dtuple_get_n_ext(dtuple);
|
||||
n_rows++;
|
||||
/* BLOB pointers must be copied from dtuple */
|
||||
mrec = NULL;
|
||||
|
@ -3621,7 +3618,7 @@ row_merge_insert_index_tuples(
|
|||
}
|
||||
|
||||
dtuple = row_rec_to_index_entry_low(
|
||||
mrec, index, offsets, &n_ext, tuple_heap);
|
||||
mrec, index, offsets, tuple_heap);
|
||||
}
|
||||
|
||||
old_index = dict_table_get_first_index(old_table);
|
||||
|
@ -3634,10 +3631,7 @@ row_merge_insert_index_tuples(
|
|||
}
|
||||
}
|
||||
|
||||
if (!n_ext) {
|
||||
/* There are no externally stored columns. */
|
||||
} else {
|
||||
ut_ad(dict_index_is_clust(index));
|
||||
if (dict_index_is_clust(index) && dtuple_get_n_ext(dtuple)) {
|
||||
/* Off-page columns can be fetched safely
|
||||
when concurrent modifications to the table
|
||||
are disabled. (Purge can process delete-marked
|
||||
|
|
|
@ -4681,7 +4681,6 @@ row_scan_index_for_mysql(
|
|||
ulint i;
|
||||
ulint cnt;
|
||||
mem_heap_t* heap = NULL;
|
||||
ulint n_ext;
|
||||
offset_t offsets_[REC_OFFS_NORMAL_SIZE];
|
||||
offset_t* offsets;
|
||||
rec_offs_init(offsets_);
|
||||
|
@ -4823,7 +4822,7 @@ not_ok:
|
|||
mem_heap_empty(heap);
|
||||
|
||||
prev_entry = row_rec_to_index_entry(
|
||||
rec, index, offsets, &n_ext, heap);
|
||||
rec, index, offsets, heap);
|
||||
|
||||
if (UNIV_LIKELY_NULL(tmp_heap)) {
|
||||
mem_heap_free(tmp_heap);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2018, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2018, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -685,7 +685,6 @@ row_rec_to_index_entry_impl(
|
|||
const rec_t* rec,
|
||||
const dict_index_t* index,
|
||||
const offset_t* offsets,
|
||||
ulint* n_ext,
|
||||
mem_heap_t* heap)
|
||||
{
|
||||
dtuple_t* entry;
|
||||
|
@ -703,8 +702,6 @@ row_rec_to_index_entry_impl(
|
|||
/* Because this function may be invoked by row0merge.cc
|
||||
on a record whose header is in different format, the check
|
||||
rec_offs_validate(rec, index, offsets) must be avoided here. */
|
||||
ut_ad(n_ext);
|
||||
*n_ext = 0;
|
||||
|
||||
rec_len = rec_offs_n_fields(offsets);
|
||||
|
||||
|
@ -731,7 +728,6 @@ row_rec_to_index_entry_impl(
|
|||
|
||||
if (rec_offs_nth_extern(offsets, i)) {
|
||||
dfield_set_ext(dfield);
|
||||
(*n_ext)++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -743,18 +739,15 @@ row_rec_to_index_entry_impl(
|
|||
@param[in] rec index record
|
||||
@param[in] index index
|
||||
@param[in] offsets rec_get_offsets(rec, index)
|
||||
@param[out] n_ext number of externally stored columns
|
||||
@param[in,out] heap memory heap for allocations */
|
||||
dtuple_t*
|
||||
row_rec_to_index_entry_low(
|
||||
const rec_t* rec,
|
||||
const dict_index_t* index,
|
||||
const offset_t* offsets,
|
||||
ulint* n_ext,
|
||||
mem_heap_t* heap)
|
||||
{
|
||||
return row_rec_to_index_entry_impl<false>(
|
||||
rec, index, offsets, n_ext, heap);
|
||||
return row_rec_to_index_entry_impl<false>(rec, index, offsets, heap);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
|
@ -767,8 +760,6 @@ row_rec_to_index_entry(
|
|||
const rec_t* rec, /*!< in: record in the index */
|
||||
const dict_index_t* index, /*!< in: index */
|
||||
const offset_t* offsets,/*!< in: rec_get_offsets(rec) */
|
||||
ulint* n_ext, /*!< out: number of externally
|
||||
stored columns */
|
||||
mem_heap_t* heap) /*!< in: memory heap from which
|
||||
the memory needed is allocated */
|
||||
{
|
||||
|
@ -790,7 +781,7 @@ row_rec_to_index_entry(
|
|||
rec_offs_make_valid(copy_rec, index, true,
|
||||
const_cast<offset_t*>(offsets));
|
||||
entry = row_rec_to_index_entry_impl<true>(
|
||||
copy_rec, index, offsets, n_ext, heap);
|
||||
copy_rec, index, offsets, heap);
|
||||
rec_offs_make_valid(rec, index, true,
|
||||
const_cast<offset_t*>(offsets));
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -186,6 +186,7 @@ static bool row_undo_mod_must_purge(undo_node_t* node, mtr_t* mtr)
|
|||
|
||||
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&node->pcur);
|
||||
ut_ad(btr_cur->index->is_primary());
|
||||
DEBUG_SYNC_C("rollback_purge_clust");
|
||||
|
||||
mtr->s_lock(&purge_sys.latch, __FILE__, __LINE__);
|
||||
|
||||
|
@ -319,6 +320,7 @@ row_undo_mod_clust(
|
|||
== node->new_trx_id);
|
||||
|
||||
btr_pcur_commit_specify_mtr(pcur, &mtr);
|
||||
DEBUG_SYNC_C("rollback_undo_pk");
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
goto func_exit;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2015, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -223,7 +223,6 @@ row_upd_check_references_constraints(
|
|||
dtuple_t* entry;
|
||||
trx_t* trx;
|
||||
const rec_t* rec;
|
||||
ulint n_ext;
|
||||
dberr_t err;
|
||||
ibool got_s_lock = FALSE;
|
||||
|
||||
|
@ -240,7 +239,7 @@ row_upd_check_references_constraints(
|
|||
|
||||
heap = mem_heap_create(500);
|
||||
|
||||
entry = row_rec_to_index_entry(rec, index, offsets, &n_ext, heap);
|
||||
entry = row_rec_to_index_entry(rec, index, offsets, heap);
|
||||
|
||||
mtr_commit(mtr);
|
||||
|
||||
|
@ -341,7 +340,6 @@ wsrep_row_upd_check_foreign_constraints(
|
|||
dtuple_t* entry;
|
||||
trx_t* trx;
|
||||
const rec_t* rec;
|
||||
ulint n_ext;
|
||||
dberr_t err;
|
||||
ibool got_s_lock = FALSE;
|
||||
ibool opened = FALSE;
|
||||
|
@ -359,8 +357,7 @@ wsrep_row_upd_check_foreign_constraints(
|
|||
|
||||
heap = mem_heap_create(500);
|
||||
|
||||
entry = row_rec_to_index_entry(rec, index, offsets,
|
||||
&n_ext, heap);
|
||||
entry = row_rec_to_index_entry(rec, index, offsets, heap);
|
||||
|
||||
mtr_commit(mtr);
|
||||
|
||||
|
@ -2812,9 +2809,9 @@ check_fk:
|
|||
|
||||
mtr_commit(mtr);
|
||||
|
||||
err = row_ins_clust_index_entry(
|
||||
index, entry, thr,
|
||||
node->upd_ext ? node->upd_ext->n_ext : 0);
|
||||
err = row_ins_clust_index_entry(index, entry, thr, node->upd_ext
|
||||
? node->upd_ext->n_ext
|
||||
: dtuple_get_n_ext(entry));
|
||||
node->state = UPD_NODE_INSERT_CLUSTERED;
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2019, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -153,15 +153,13 @@ row_vers_impl_x_locked_low(
|
|||
const ulint rec_del = rec_get_deleted_flag(rec, comp);
|
||||
|
||||
if (dict_index_has_virtual(index)) {
|
||||
ulint n_ext;
|
||||
ulint est_size = DTUPLE_EST_ALLOC(index->n_fields);
|
||||
|
||||
/* Allocate the dtuple for virtual columns extracted from undo
|
||||
log with its own heap, so to avoid it being freed as we
|
||||
iterating in the version loop below. */
|
||||
v_heap = mem_heap_create(est_size);
|
||||
ientry = row_rec_to_index_entry(
|
||||
rec, index, offsets, &n_ext, v_heap);
|
||||
ientry = row_rec_to_index_entry(rec, index, offsets, v_heap);
|
||||
}
|
||||
|
||||
/* We look up if some earlier version, which was modified by
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2019, MariaDB Corporation.
|
||||
Copyright (c) 1996, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -2335,8 +2335,6 @@ trx_undo_prev_version_build(
|
|||
ut_a(ptr);
|
||||
|
||||
if (row_upd_changes_field_size_or_external(index, offsets, update)) {
|
||||
ulint n_ext;
|
||||
|
||||
/* We should confirm the existence of disowned external data,
|
||||
if the previous version record is delete marked. If the trx_id
|
||||
of the previous record is seen by purge view, we should treat
|
||||
|
@ -2377,14 +2375,15 @@ trx_undo_prev_version_build(
|
|||
those fields that update updates to become externally stored
|
||||
fields. Store the info: */
|
||||
|
||||
entry = row_rec_to_index_entry(
|
||||
rec, index, offsets, &n_ext, heap);
|
||||
n_ext += btr_push_update_extern_fields(entry, update, heap);
|
||||
entry = row_rec_to_index_entry(rec, index, offsets, heap);
|
||||
/* The page containing the clustered index record
|
||||
corresponding to entry is latched in mtr. Thus the
|
||||
following call is safe. */
|
||||
row_upd_index_replace_new_col_vals(entry, index, update, heap);
|
||||
|
||||
/* Get number of externally stored columns in updated record */
|
||||
const ulint n_ext = dtuple_get_n_ext(entry);
|
||||
|
||||
buf = static_cast<byte*>(mem_heap_alloc(
|
||||
heap, rec_get_converted_size(index, entry, n_ext)));
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue