503.6.1
by Daniel Nichter
s/Percona Inc/Percona Ireland Ltd/g |
1 |
# This program is copyright 2010-2011 Percona Ireland Ltd.
|
2
by Daniel Nichter
Add lib/, t/lib/, and sandbox/. All modules are updated and passing on MySQL 5.1. |
2 |
# Feedback and improvements are welcome.
|
3 |
#
|
|
4 |
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
5 |
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
6 |
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
7 |
#
|
|
8 |
# This program is free software; you can redistribute it and/or modify it under
|
|
9 |
# the terms of the GNU General Public License as published by the Free Software
|
|
10 |
# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
|
|
11 |
# systems, you can issue `man perlgpl' or `man perlartistic' to read these
|
|
12 |
# licenses.
|
|
13 |
#
|
|
14 |
# You should have received a copy of the GNU General Public License along with
|
|
15 |
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
16 |
# Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
17 |
# ###########################################################################
|
|
18
by Daniel Nichter
Remove $Revision$ and finish re-branding modules. Rename MaatkitTest.pm to PerconaTest.pm. Put copyrights on one line. |
18 |
# Advisor package
|
2
by Daniel Nichter
Add lib/, t/lib/, and sandbox/. All modules are updated and passing on MySQL 5.1. |
19 |
# ###########################################################################
|
9
by Daniel Nichter
Move module docu to work for NaturalDocs. |
20 |
{
|
2
by Daniel Nichter
Add lib/, t/lib/, and sandbox/. All modules are updated and passing on MySQL 5.1. |
21 |
# Package: Advisor
|
22 |
# Advisor loads, checks, and runs rules for the various mk-*-advisor tools.
|
|
23 |
package Advisor; |
|
24 |
||
25 |
use strict; |
|
26 |
use warnings FATAL => 'all'; |
|
27 |
use English qw(-no_match_vars); |
|
134
by Daniel Nichter
Replace MKDEBUG with PTDEBUG in modules. |
28 |
use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
2
by Daniel Nichter
Add lib/, t/lib/, and sandbox/. All modules are updated and passing on MySQL 5.1. |
29 |
|
30 |
# Sub: new
|
|
31 |
#
|
|
32 |
# Parameters:
|
|
33 |
# %args - Arguments
|
|
34 |
#
|
|
35 |
# Required Arguments:
|
|
36 |
# match_type - How rules match: "bool" or "pos"
|
|
37 |
# ignore_rules - Hashref with rule IDs to ignore
|
|
38 |
#
|
|
39 |
# Returns:
|
|
40 |
# Advisor object
|
|
41 |
sub new { |
|
42 |
my ( $class, %args ) = @_; |
|
43 |
foreach my $arg ( qw(match_type) ) { |
|
44 |
die "I need a $arg argument" unless $args{$arg}; |
|
45 |
}
|
|
46 |
||
47 |
my $self = { |
|
48 |
%args, |
|
49 |
rules => [], # Rules from all advisor modules. |
|
50 |
rule_index_for => {}, # Maps rules by ID to their array index in $rules. |
|
51 |
rule_info => {}, # ID, severity, description, etc. for each rule. |
|
52 |
};
|
|
53 |
||
54 |
return bless $self, $class; |
|
55 |
}
|
|
56 |
||
57 |
# Sub: load_rules
|
|
58 |
# Load rules from the given advisor module. Will die on duplicate
|
|
59 |
# rule IDs.
|
|
60 |
#
|
|
61 |
# Parameters:
|
|
62 |
# $advisor - An *AdvisorRules module, like <QueryAdvisorRules>
|
|
63 |
sub load_rules { |
|
64 |
my ( $self, $advisor ) = @_; |
|
65 |
return unless $advisor; |
|
134
by Daniel Nichter
Replace MKDEBUG with PTDEBUG in modules. |
66 |
PTDEBUG && _d('Loading rules from', ref $advisor); |
2
by Daniel Nichter
Add lib/, t/lib/, and sandbox/. All modules are updated and passing on MySQL 5.1. |
67 |
|
68 |
# Starting index value in rules arrayref for these rules.
|
|
69 |
# This is >0 if rules from other advisor modules have
|
|
70 |
# already been loaded.
|
|
71 |
my $i = scalar @{$self->{rules}}; |
|
72 |
||
73 |
RULE:
|
|
74 |
foreach my $rule ( $advisor->get_rules() ) { |
|
75 |
my $id = $rule->{id}; |
|
76 |
if ( $self->{ignore_rules}->{"$id"} ) { |
|
134
by Daniel Nichter
Replace MKDEBUG with PTDEBUG in modules. |
77 |
PTDEBUG && _d("Ignoring rule", $id); |
2
by Daniel Nichter
Add lib/, t/lib/, and sandbox/. All modules are updated and passing on MySQL 5.1. |
78 |
next RULE; |
79 |
}
|
|
80 |
die "Rule $id already exists and cannot be redefined" |
|
81 |
if defined $self->{rule_index_for}->{$id}; |
|
82 |
push @{$self->{rules}}, $rule; |
|
83 |
$self->{rule_index_for}->{$id} = $i++; |
|
84 |
}
|
|
85 |
||
86 |
return; |
|
87 |
}
|
|
88 |
||
89 |
# Sub: load_rule_info
|
|
90 |
# Load rule information (severity and description) from the given advisor
|
|
91 |
# module.
|
|
92 |
#
|
|
93 |
# Parameters:
|
|
94 |
# $advisor - An *AdvisorRules module, like <QueryAdvisorRules>
|
|
95 |
sub load_rule_info { |
|
96 |
my ( $self, $advisor ) = @_; |
|
97 |
return unless $advisor; |
|
134
by Daniel Nichter
Replace MKDEBUG with PTDEBUG in modules. |
98 |
PTDEBUG && _d('Loading rule info from', ref $advisor); |
2
by Daniel Nichter
Add lib/, t/lib/, and sandbox/. All modules are updated and passing on MySQL 5.1. |
99 |
my $rules = $self->{rules}; |
100 |
foreach my $rule ( @$rules ) { |
|
101 |
my $id = $rule->{id}; |
|
102 |
if ( $self->{ignore_rules}->{"$id"} ) { |
|
103 |
# This shouldn't happen. load_rules() should keep any ignored
|
|
104 |
# rules out of $self->{rules}.
|
|
105 |
die "Rule $id was loaded but should be ignored"; |
|
106 |
}
|
|
107 |
my $rule_info = $advisor->get_rule_info($id); |
|
108 |
next unless $rule_info; |
|
109 |
die "Info for rule $id already exists and cannot be redefined" |
|
110 |
if $self->{rule_info}->{$id}; |
|
111 |
$self->{rule_info}->{$id} = $rule_info; |
|
112 |
}
|
|
113 |
return; |
|
114 |
}
|
|
115 |
||
116 |
||
117 |
# Sub: run_rules
|
|
118 |
# Run all rules from all advisors loaded ealier.
|
|
119 |
#
|
|
120 |
# Parameters:
|
|
121 |
# %args - Arguments passed through to each rule's coderef
|
|
122 |
#
|
|
123 |
# Returns:
|
|
124 |
# An arrayref of rule IDs that matched and arrayref of pos
|
|
125 |
# where those rules matched (if <new()> match_type is "bool").
|
|
126 |
sub run_rules { |
|
127 |
my ( $self, %args ) = @_; |
|
128 |
my @matched_rules; |
|
129 |
my @matched_pos; |
|
130 |
my $rules = $self->{rules}; |
|
131 |
my $match_type = lc $self->{match_type}; |
|
132 |
foreach my $rule ( @$rules ) { |
|
133 |
eval { |
|
134 |
my $match = $rule->{code}->(%args); |
|
135 |
if ( $match_type eq 'pos' ) { |
|
136 |
if ( defined $match ) { |
|
134
by Daniel Nichter
Replace MKDEBUG with PTDEBUG in modules. |
137 |
PTDEBUG && _d('Matches rule', $rule->{id}, 'near pos', $match); |
2
by Daniel Nichter
Add lib/, t/lib/, and sandbox/. All modules are updated and passing on MySQL 5.1. |
138 |
push @matched_rules, $rule->{id}; |
139 |
push @matched_pos, $match; |
|
140 |
}
|
|
141 |
}
|
|
142 |
elsif ( $match_type eq 'bool' ) { |
|
143 |
if ( $match ) { |
|
134
by Daniel Nichter
Replace MKDEBUG with PTDEBUG in modules. |
144 |
PTDEBUG && _d("Matches rule", $rule->{id}); |
2
by Daniel Nichter
Add lib/, t/lib/, and sandbox/. All modules are updated and passing on MySQL 5.1. |
145 |
push @matched_rules, $rule->{id}; |
146 |
}
|
|
147 |
}
|
|
148 |
};
|
|
149 |
if ( $EVAL_ERROR ) { |
|
150 |
warn "Code for rule $rule->{id} caused an error: $EVAL_ERROR"; |
|
151 |
}
|
|
152 |
}
|
|
153 |
return \@matched_rules, \@matched_pos; |
|
154 |
};
|
|
155 |
||
156 |
||
157 |
# Sub: get_rule_info
|
|
158 |
# Get the information for a rule by ID.
|
|
159 |
#
|
|
160 |
# Parameters:
|
|
161 |
# $id - Rule ID
|
|
162 |
#
|
|
163 |
# Returns:
|
|
164 |
# Hashref with the rule's information (id, severity, description)
|
|
165 |
sub get_rule_info { |
|
166 |
my ( $self, $id ) = @_; |
|
167 |
return unless $id; |
|
168 |
return $self->{rule_info}->{$id}; |
|
169 |
}
|
|
170 |
||
171 |
sub _d { |
|
172 |
my ($package, undef, $line) = caller 0; |
|
173 |
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
|
174 |
map { defined $_ ? $_ : 'undef' } |
|
175 |
@_; |
|
176 |
print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
|
177 |
}
|
|
178 |
||
179 |
1; |
|
180 |
}
|
|
181 |
# ###########################################################################
|
|
182 |
# End Advisor package
|
|
183 |
# ###########################################################################
|