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
|
use strict;
use lib 'lib';
use lib '../lib';
use DBI;
use GenTest;
use GenTest::Constants;
use GenTest::Grammar;
use GenTest::Simplifier::Grammar;
use Time::HiRes;
#
# This script is used to simplify grammar files to the smallest form that will still reproduce the desired outcome
# For the purpose, the GenTest::Simplifier::Grammar module provides progressively simple grammars, and we
# define an oracle() function that runs those grammars with the RQG and reports if the RQG returns the desired
# status code (usually something like STATUS_SERVER_CRASHED
#
# For more information, please see:
#
# http://forge.mysql.com/wiki/RandomQueryGeneratorSimplification
#
#
# Please modify those settings to fit your environment before you run this script
#
my @rqg_options =(
'--basedir=/build/bzr/mysql-next-bugfixing',
'--gendata=conf/WL5004_data.zz --threads=40 --rpl_mode=row --queries=10K --duration=40 --reporter=Deadlock,Shutdown'
);
my $initial_grammar_file = 'conf/WL5004_sql.yy';
# Status codes are described in lib/GenTest/Constants.pm
# STATUS_ANY_ERROR means that any RQG error would cause the simplification to continue,
# e.g. both deadlocks and crashes will be considered together
my @desired_status_codes = (STATUS_REPLICATION_FAILURE);
# This is the number of times the oracle() will run the RQG in order to get to the
# desired error code. If the error is sporadic, several runs may be required to know
# if the bug is still present in the simplified grammar or not.
my $trials = 1;
# Set $grammar_flags to GRAMMAR_FLAG_COMPACT_RULES so that rules such as rule: a | a | a | a | a | a | b
# are compressed to rule: a | b before simplification. This will speed up the process as each instance of
# "a" will not be removed separately until they are all gone.
my $grammar_flags = GRAMMAR_FLAG_COMPACT_RULES;
# End of user-modifiable settings
my $run_id = time();
say("The ID of this run is $run_id.");
open(INITIAL_GRAMMAR, $initial_grammar_file) or die "Umable to open '$initial_grammar_file': $!";;
read(INITIAL_GRAMMAR, my $initial_grammar , -s $initial_grammar_file);
close(INITIAL_GRAMMAR);
my $iteration;
my $simplifier = GenTest::Simplifier::Grammar->new(
grammar_flags => $grammar_flags,
oracle => sub {
my $oracle_grammar = shift;
foreach my $trial (1..$trials) {
$iteration++;
say("run_id = $run_id; iteration = $iteration; trial = $trial");
my $tmpfile = tmpdir().$run_id.'-'.$iteration.'-'.$trial.'.yy';
my $logfile = tmpdir().$run_id.'-'.$iteration.'-'.$trial.'.log';
my $vardir = tmpdir().$run_id.'-'.$iteration.'-'.$trial.'-var';
open (GRAMMAR, ">$tmpfile") or die "unable to create $tmpfile: $!";
print GRAMMAR $oracle_grammar;
close (GRAMMAR);
my $start_time = Time::HiRes::time();
mkdir ($vardir);
my $rqg_status = system("perl runall.pl ".join(' ', @rqg_options)." --grammar=$tmpfile --vardir=$vardir 2>&1 >$logfile");
$rqg_status = $rqg_status >> 8;
my $end_time = Time::HiRes::time();
my $duration = $end_time - $start_time;
say("rqg_status = $rqg_status; duration = $duration");
return ORACLE_ISSUE_NO_LONGER_REPEATABLE if $rqg_status == STATUS_ENVIRONMENT_FAILURE;
foreach my $desired_status_code (@desired_status_codes) {
if (
($rqg_status == $desired_status_code) ||
(($rqg_status != 0) && ($desired_status_code == STATUS_ANY_ERROR))
) {
return ORACLE_ISSUE_STILL_REPEATABLE;
}
}
}
return ORACLE_ISSUE_NO_LONGER_REPEATABLE;
}
);
my $simplified_grammar = $simplifier->simplify($initial_grammar);
print "Simplified grammar:\n\n$simplified_grammar;\n\n" if defined $simplified_grammar;
|