summaryrefslogtreecommitdiff
path: root/mysql-test/suite/innodb/t/innodb_wl6326_big.test
blob: 27d02591b847738893570fd1a376967384933248 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
# 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
# Possibly related to MDEV-16678, the test seems to deterministically fail on
# non-debug builds. innodb_force_recovery=2 (disabling the purge of history)
# would seem to help a little.
--source include/have_debug.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,
ENABLED, '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,
ENABLED, '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, ENABLED
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 ENABLED;
if(`$check_statement`)
{
   --echo #    fail
   eval $check_statement;
   SELECT NAME, ENABLED 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_%";