mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-10-19 08:56:34 +00:00
Split --review and --history
This commit is contained in:
@@ -37,6 +37,7 @@ BEGIN {
|
|||||||
QueryParser
|
QueryParser
|
||||||
TableParser
|
TableParser
|
||||||
QueryReview
|
QueryReview
|
||||||
|
QueryHistory
|
||||||
Daemon
|
Daemon
|
||||||
BinaryLogParser
|
BinaryLogParser
|
||||||
GeneralLogParser
|
GeneralLogParser
|
||||||
@@ -3531,6 +3532,8 @@ $Data::Dumper::Indent = 1;
|
|||||||
$Data::Dumper::Sortkeys = 1;
|
$Data::Dumper::Sortkeys = 1;
|
||||||
$Data::Dumper::Quotekeys = 0;
|
$Data::Dumper::Quotekeys = 0;
|
||||||
|
|
||||||
|
BEGIN { our @ISA = 'ProtocolParser'; }
|
||||||
|
|
||||||
use constant {
|
use constant {
|
||||||
COM_SLEEP => '00',
|
COM_SLEEP => '00',
|
||||||
COM_QUIT => '01',
|
COM_QUIT => '01',
|
||||||
@@ -4743,45 +4746,6 @@ sub remove_mysql_header {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _get_errors_fh {
|
|
||||||
my ( $self ) = @_;
|
|
||||||
my $errors_fh = $self->{errors_fh};
|
|
||||||
return $errors_fh if $errors_fh;
|
|
||||||
|
|
||||||
my $o = $self->{o};
|
|
||||||
if ( $o && $o->has('tcpdump-errors') && $o->got('tcpdump-errors') ) {
|
|
||||||
my $errors_file = $o->get('tcpdump-errors');
|
|
||||||
PTDEBUG && _d('tcpdump-errors file:', $errors_file);
|
|
||||||
open $errors_fh, '>>', $errors_file
|
|
||||||
or die "Cannot open tcpdump-errors file $errors_file: $OS_ERROR";
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{errors_fh} = $errors_fh;
|
|
||||||
return $errors_fh;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub fail_session {
|
|
||||||
my ( $self, $session, $reason ) = @_;
|
|
||||||
PTDEBUG && _d('Client', $session->{client}, 'failed because', $reason);
|
|
||||||
my $errors_fh = $self->_get_errors_fh();
|
|
||||||
if ( $errors_fh ) {
|
|
||||||
my $raw_packets = $session->{raw_packets};
|
|
||||||
delete $session->{raw_packets}; # Don't dump, it's printed below.
|
|
||||||
$session->{reason_for_failure} = $reason;
|
|
||||||
my $session_dump = '# ' . Dumper($session);
|
|
||||||
chomp $session_dump;
|
|
||||||
$session_dump =~ s/\n/\n# /g;
|
|
||||||
print $errors_fh "$session_dump\n";
|
|
||||||
{
|
|
||||||
local $LIST_SEPARATOR = "\n";
|
|
||||||
print $errors_fh "@$raw_packets";
|
|
||||||
print $errors_fh "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete $self->{sessions}->{$session->{client}};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _delete_buff {
|
sub _delete_buff {
|
||||||
my ( $self, $session ) = @_;
|
my ( $self, $session ) = @_;
|
||||||
map { delete $session->{$_} } qw(buff buff_left mysql_data_len);
|
map { delete $session->{$_} } qw(buff buff_left mysql_data_len);
|
||||||
@@ -8751,60 +8715,6 @@ sub new {
|
|||||||
return bless $self, $class;
|
return bless $self, $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub set_history_options {
|
|
||||||
my ( $self, %args ) = @_;
|
|
||||||
foreach my $arg ( qw(table tbl_struct col_pat) ) {
|
|
||||||
die "I need a $arg argument" unless $args{$arg};
|
|
||||||
}
|
|
||||||
|
|
||||||
my @cols;
|
|
||||||
my @metrics;
|
|
||||||
foreach my $col ( @{$args{tbl_struct}->{cols}} ) {
|
|
||||||
my ( $attr, $metric ) = $col =~ m/$args{col_pat}/;
|
|
||||||
next unless $attr && $metric;
|
|
||||||
|
|
||||||
|
|
||||||
$attr = ucfirst $attr if $attr =~ m/_/;
|
|
||||||
$attr = 'Filesort' if $attr eq 'filesort';
|
|
||||||
|
|
||||||
$attr =~ s/^Qc_hit/QC_Hit/; # Qc_hit is really QC_Hit
|
|
||||||
$attr =~ s/^Innodb/InnoDB/g; # Innodb is really InnoDB
|
|
||||||
$attr =~ s/_io_/_IO_/g; # io is really IO
|
|
||||||
|
|
||||||
push @cols, $col;
|
|
||||||
push @metrics, [$attr, $metric];
|
|
||||||
}
|
|
||||||
|
|
||||||
my $sql = "REPLACE INTO $args{table}("
|
|
||||||
. join(', ',
|
|
||||||
map { $self->{quoter}->quote($_) } ('checksum', 'sample', @cols))
|
|
||||||
. ') VALUES (CONV(?, 16, 10), ?'
|
|
||||||
. (@cols ? ', ' : '') # issue 1265
|
|
||||||
. join(', ', map {
|
|
||||||
$_ eq 'ts_min' || $_ eq 'ts_max'
|
|
||||||
? "COALESCE(?, $self->{ts_default})"
|
|
||||||
: '?'
|
|
||||||
} @cols) . ')';
|
|
||||||
PTDEBUG && _d($sql);
|
|
||||||
|
|
||||||
$self->{history_sth} = $self->{dbh}->prepare($sql);
|
|
||||||
$self->{history_metrics} = \@metrics;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_review_history {
|
|
||||||
my ( $self, $id, $sample, %data ) = @_;
|
|
||||||
foreach my $thing ( qw(min max) ) {
|
|
||||||
next unless defined $data{ts} && defined $data{ts}->{$thing};
|
|
||||||
$data{ts}->{$thing} = parse_timestamp($data{ts}->{$thing});
|
|
||||||
}
|
|
||||||
$self->{history_sth}->execute(
|
|
||||||
make_checksum($id),
|
|
||||||
$sample,
|
|
||||||
map { $data{$_->[0]}->{$_->[1]} } @{$self->{history_metrics}});
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_review_info {
|
sub get_review_info {
|
||||||
my ( $self, $id ) = @_;
|
my ( $self, $id ) = @_;
|
||||||
$self->{select_sth}->execute(make_checksum($id));
|
$self->{select_sth}->execute(make_checksum($id));
|
||||||
@@ -8843,6 +8753,113 @@ sub _d {
|
|||||||
# End QueryReview package
|
# End QueryReview package
|
||||||
# ###########################################################################
|
# ###########################################################################
|
||||||
|
|
||||||
|
# ###########################################################################
|
||||||
|
# QueryHistory package
|
||||||
|
# This package is a copy without comments from the original. The original
|
||||||
|
# with comments and its test file can be found in the Bazaar repository at,
|
||||||
|
# lib/QueryHistory.pm
|
||||||
|
# t/lib/QueryHistory.t
|
||||||
|
# See https://launchpad.net/percona-toolkit for more information.
|
||||||
|
# ###########################################################################
|
||||||
|
{
|
||||||
|
package QueryHistory;
|
||||||
|
|
||||||
|
use English qw(-no_match_vars);
|
||||||
|
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
|
||||||
|
|
||||||
|
use Lmo;
|
||||||
|
|
||||||
|
use Quoter;
|
||||||
|
use Transformers qw(make_checksum parse_timestamp);
|
||||||
|
|
||||||
|
has history_dbh => (
|
||||||
|
is => 'ro',
|
||||||
|
required => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
has history_sth => (
|
||||||
|
is => 'rw',
|
||||||
|
);
|
||||||
|
|
||||||
|
has history_metrics => (
|
||||||
|
is => 'rw',
|
||||||
|
isa => 'ArrayRef',
|
||||||
|
);
|
||||||
|
|
||||||
|
has column_pattern => (
|
||||||
|
is => 'ro',
|
||||||
|
isa => 'Regexp',
|
||||||
|
required => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
has ts_default => (
|
||||||
|
is => 'ro',
|
||||||
|
isa => 'Str',
|
||||||
|
default => sub { 'NOW()' },
|
||||||
|
);
|
||||||
|
|
||||||
|
sub set_history_options {
|
||||||
|
my ( $self, %args ) = @_;
|
||||||
|
foreach my $arg ( qw(table tbl_struct) ) {
|
||||||
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
|
}
|
||||||
|
|
||||||
|
my $col_pat = $self->column_pattern();
|
||||||
|
|
||||||
|
my @cols;
|
||||||
|
my @metrics;
|
||||||
|
foreach my $col ( @{$args{tbl_struct}->{cols}} ) {
|
||||||
|
my ( $attr, $metric ) = $col =~ m/$col_pat/;
|
||||||
|
next unless $attr && $metric;
|
||||||
|
|
||||||
|
|
||||||
|
$attr = ucfirst $attr if $attr =~ m/_/;
|
||||||
|
$attr = 'Filesort' if $attr eq 'filesort';
|
||||||
|
|
||||||
|
$attr =~ s/^Qc_hit/QC_Hit/; # Qc_hit is really QC_Hit
|
||||||
|
$attr =~ s/^Innodb/InnoDB/g; # Innodb is really InnoDB
|
||||||
|
$attr =~ s/_io_/_IO_/g; # io is really IO
|
||||||
|
|
||||||
|
push @cols, $col;
|
||||||
|
push @metrics, [$attr, $metric];
|
||||||
|
}
|
||||||
|
|
||||||
|
my $ts_default = $self->ts_default;
|
||||||
|
|
||||||
|
my $sql = "REPLACE INTO $args{table}("
|
||||||
|
. join(', ',
|
||||||
|
map { Quoter->quote($_) } ('checksum', 'sample', @cols))
|
||||||
|
. ') VALUES (CONV(?, 16, 10), ?'
|
||||||
|
. (@cols ? ', ' : '') # issue 1265
|
||||||
|
. join(', ', map {
|
||||||
|
$_ eq 'ts_min' || $_ eq 'ts_max'
|
||||||
|
? "COALESCE(?, $ts_default)"
|
||||||
|
: '?'
|
||||||
|
} @cols) . ')';
|
||||||
|
PTDEBUG && _d($sql);
|
||||||
|
|
||||||
|
$self->history_sth($self->history_dbh->prepare($sql));
|
||||||
|
$self->history_metrics(\@metrics);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_review_history {
|
||||||
|
my ( $self, $id, $sample, %data ) = @_;
|
||||||
|
foreach my $thing ( qw(min max) ) {
|
||||||
|
next unless defined $data{ts} && defined $data{ts}->{$thing};
|
||||||
|
$data{ts}->{$thing} = parse_timestamp($data{ts}->{$thing});
|
||||||
|
}
|
||||||
|
$self->history_sth->execute(
|
||||||
|
make_checksum($id),
|
||||||
|
$sample,
|
||||||
|
map { $data{$_->[0]}->{$_->[1]} } @{$self->history_metrics});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# ###########################################################################
|
||||||
|
# End QueryHistory package
|
||||||
|
# ###########################################################################
|
||||||
|
|
||||||
# ###########################################################################
|
# ###########################################################################
|
||||||
# Daemon package
|
# Daemon package
|
||||||
# This package is a copy without comments from the original. The original
|
# This package is a copy without comments from the original. The original
|
||||||
@@ -9506,6 +9523,9 @@ use warnings FATAL => 'all';
|
|||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
|
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
|
||||||
|
|
||||||
|
use File::Basename qw(basename);
|
||||||
|
use File::Temp qw(tempfile);
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
require IO::Uncompress::Inflate; # yum: perl-IO-Compress-Zlib
|
require IO::Uncompress::Inflate; # yum: perl-IO-Compress-Zlib
|
||||||
IO::Uncompress::Inflate->import(qw(inflate $InflateError));
|
IO::Uncompress::Inflate->import(qw(inflate $InflateError));
|
||||||
@@ -9707,38 +9727,33 @@ sub make_event {
|
|||||||
|
|
||||||
sub _get_errors_fh {
|
sub _get_errors_fh {
|
||||||
my ( $self ) = @_;
|
my ( $self ) = @_;
|
||||||
my $errors_fh = $self->{errors_fh};
|
return $self->{errors_fh} if $self->{errors_fh};
|
||||||
return $errors_fh if $errors_fh;
|
|
||||||
|
|
||||||
my $o = $self->{o};
|
my $exec = basename($0);
|
||||||
if ( $o && $o->has('tcpdump-errors') && $o->got('tcpdump-errors') ) {
|
my ($errors_fh, $filename) = tempfile("/tmp/$exec-errors.XXXXXXX", UNLINK => 0);
|
||||||
my $errors_file = $o->get('tcpdump-errors');
|
|
||||||
PTDEBUG && _d('tcpdump-errors file:', $errors_file);
|
|
||||||
open $errors_fh, '>>', $errors_file
|
|
||||||
or die "Cannot open tcpdump-errors file $errors_file: $OS_ERROR";
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{errors_fh} = $errors_fh;
|
$self->{errors_file} = $filename;
|
||||||
|
$self->{errors_fh} = $errors_fh;
|
||||||
return $errors_fh;
|
return $errors_fh;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub fail_session {
|
sub fail_session {
|
||||||
my ( $self, $session, $reason ) = @_;
|
my ( $self, $session, $reason ) = @_;
|
||||||
my $errors_fh = $self->_get_errors_fh();
|
|
||||||
if ( $errors_fh ) {
|
|
||||||
$session->{reason_for_failure} = $reason;
|
|
||||||
my $session_dump = '# ' . Dumper($session);
|
|
||||||
chomp $session_dump;
|
|
||||||
$session_dump =~ s/\n/\n# /g;
|
|
||||||
print $errors_fh "$session_dump\n";
|
|
||||||
{
|
|
||||||
local $LIST_SEPARATOR = "\n";
|
|
||||||
print $errors_fh "@{$session->{raw_packets}}";
|
|
||||||
print $errors_fh "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PTDEBUG && _d('Failed session', $session->{client}, 'because', $reason);
|
PTDEBUG && _d('Failed session', $session->{client}, 'because', $reason);
|
||||||
delete $self->{sessions}->{$session->{client}};
|
delete $self->{sessions}->{$session->{client}};
|
||||||
|
|
||||||
|
return if $self->{_no_save_error};
|
||||||
|
|
||||||
|
my $errors_fh = $self->_get_errors_fh();
|
||||||
|
|
||||||
|
print "Session $session->{client} had errors, will save them in $self->{errors_file}\n";
|
||||||
|
|
||||||
|
my $raw_packets = delete $session->{raw_packets};
|
||||||
|
$session->{reason_for_failure} = $reason;
|
||||||
|
my $session_dump = '# ' . Dumper($session);
|
||||||
|
chomp $session_dump;
|
||||||
|
$session_dump =~ s/\n/\n# /g;
|
||||||
|
print $errors_fh join("\n", $session_dump, @$raw_packets), "\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12365,7 +12380,9 @@ sub main {
|
|||||||
$dp->prop('set-vars', $o->get('set-vars'));
|
$dp->prop('set-vars', $o->get('set-vars'));
|
||||||
|
|
||||||
# Frequently used options.
|
# Frequently used options.
|
||||||
my $review_dsn = $o->get('review');
|
my $review_dsn = handle_special_defaults($o, 'review');
|
||||||
|
my $history_dsn = handle_special_defaults($o, 'history');
|
||||||
|
|
||||||
my @groupby = @{$o->get('group-by')};
|
my @groupby = @{$o->get('group-by')};
|
||||||
my @orderby;
|
my @orderby;
|
||||||
if ( (grep { $_ =~ m/genlog|GeneralLogParser|rawlog|RawLogParser/ } @{$o->get('type')})
|
if ( (grep { $_ =~ m/genlog|GeneralLogParser|rawlog|RawLogParser/ } @{$o->get('type')})
|
||||||
@@ -12390,20 +12407,6 @@ sub main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( my $review_dsn = $o->get('review') ) {
|
|
||||||
$o->save_error('--review does not accept a t option. Perhaps you meant '
|
|
||||||
. 'to use --review-table or --history-table?')
|
|
||||||
if defined $review_dsn->{t};
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $tables ('review-table', 'history-table') {
|
|
||||||
my $got = $o->get($tables);
|
|
||||||
if ( grep !defined, Quoter->split_unquote($got) ) {
|
|
||||||
$o->save_error("--$tables should be passed a "
|
|
||||||
. "fully-qualified table name, got $got");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( my $patterns = $o->get('embedded-attributes') ) {
|
if ( my $patterns = $o->get('embedded-attributes') ) {
|
||||||
$o->save_error("--embedded-attributes should be passed two "
|
$o->save_error("--embedded-attributes should be passed two "
|
||||||
. "comma-separated patterns, got " . scalar(@$patterns) )
|
. "comma-separated patterns, got " . scalar(@$patterns) )
|
||||||
@@ -12474,44 +12477,37 @@ sub main {
|
|||||||
# ########################################################################
|
# ########################################################################
|
||||||
my $qv; # QueryReview
|
my $qv; # QueryReview
|
||||||
my $qv_dbh; # For QueryReview
|
my $qv_dbh; # For QueryReview
|
||||||
|
|
||||||
|
my $tp = new TableParser(Quoter => $q);
|
||||||
if ( $review_dsn ) {
|
if ( $review_dsn ) {
|
||||||
my $tp = new TableParser(Quoter => $q);
|
my %dsn_without_Dt = %$review_dsn;
|
||||||
|
delete $dsn_without_Dt{D};
|
||||||
|
delete $dsn_without_Dt{t};
|
||||||
|
|
||||||
$qv_dbh = get_cxn(
|
$qv_dbh = get_cxn(
|
||||||
for => '--review',
|
for => '--review',
|
||||||
dsn => $review_dsn,
|
dsn => \%dsn_without_Dt,
|
||||||
OptionParser => $o,
|
OptionParser => $o,
|
||||||
DSNParser => $dp,
|
DSNParser => $dp,
|
||||||
opts => { AutoCommit => 1 },
|
opts => { AutoCommit => 1 },
|
||||||
);
|
);
|
||||||
$qv_dbh->{InactiveDestroy} = 1; # Don't die on fork().
|
$qv_dbh->{InactiveDestroy} = 1; # Don't die on fork().
|
||||||
|
|
||||||
my @db_tbl = Quoter->split_unquote($o->get('review-table'));
|
my @db_tbl = @{$review_dsn}{qw(D t)};
|
||||||
my @hdb_tbl = Quoter->split_unquote($o->get('history-table'));
|
my $db_tbl = $q->quote(@db_tbl);
|
||||||
|
|
||||||
my $db_tbl = $q->quote(@db_tbl);
|
|
||||||
my $hdb_tbl = $q->quote(@hdb_tbl);
|
|
||||||
|
|
||||||
my $create_review_sql = $o->read_para_after(
|
my $create_review_sql = $o->read_para_after(
|
||||||
__FILE__, qr/MAGIC_create_review/);
|
__FILE__, qr/\bMAGIC_create_review\b/);
|
||||||
$create_review_sql =~ s/query_review/IF NOT EXISTS $db_tbl/;
|
$create_review_sql =~ s/\bquery_review\b/$db_tbl/;
|
||||||
|
|
||||||
my $create_history_sql = $o->read_para_after(
|
create_review_tables(
|
||||||
__FILE__, qr/MAGIC_create_review_history/);
|
type => 'review',
|
||||||
$create_history_sql =~ s/query_review_history/IF NOT EXISTS $hdb_tbl/;
|
dbh => $qv_dbh,
|
||||||
|
full_table => $db_tbl,
|
||||||
for my $create (
|
create_table_sql => $create_review_sql,
|
||||||
[ $db_tbl, $create_review_sql ],
|
create_table => $o->get('create-review-table'),
|
||||||
[ $hdb_tbl, $create_history_sql ],
|
TableParser => $tp,
|
||||||
) {
|
);
|
||||||
my ($tbl_name, $sql) = @$create;
|
|
||||||
create_review_tables(
|
|
||||||
dbh => $qv_dbh,
|
|
||||||
full_table => $tbl_name,
|
|
||||||
create_table_sql => $sql,
|
|
||||||
create_table => $o->get('create-review-tables'),
|
|
||||||
TableParser => $tp,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set up the new QueryReview object.
|
# Set up the new QueryReview object.
|
||||||
my $struct = $tp->parse($tp->get_create_table($qv_dbh, @db_tbl));
|
my $struct = $tp->parse($tp->get_create_table($qv_dbh, @db_tbl));
|
||||||
@@ -12521,24 +12517,55 @@ sub main {
|
|||||||
tbl_struct => $struct,
|
tbl_struct => $struct,
|
||||||
quoter => $q,
|
quoter => $q,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
# Inspect for MAGIC_history_cols. Add them to the --select list
|
# ########################################################################
|
||||||
# only if an explicit --select list was given. Otherwise, leave
|
# Set up for --history.
|
||||||
# --select undef which will cause EventAggregator to aggregate every
|
# ########################################################################
|
||||||
# attribute available which will include the history columns.
|
my $qh; # QueryHistory
|
||||||
# If no --select list was given and we make one by adding the history
|
my $qh_dbh;
|
||||||
# columsn to it, then EventAggregator will only aggregate the
|
if ( $history_dsn ) {
|
||||||
# history columns and nothing else--we don't want this.
|
my %dsn_without_Dt = %$history_dsn;
|
||||||
my $tbl = $tp->parse($tp->get_create_table($qv_dbh, @hdb_tbl));
|
delete $dsn_without_Dt{D};
|
||||||
my $pat = $o->read_para_after(__FILE__, qr/MAGIC_history_cols/);
|
delete $dsn_without_Dt{t};
|
||||||
|
my $qh_dbh = get_cxn(
|
||||||
|
for => '--history',
|
||||||
|
dsn => \%dsn_without_Dt,
|
||||||
|
OptionParser => $o,
|
||||||
|
DSNParser => $dp,
|
||||||
|
opts => { AutoCommit => 1 },
|
||||||
|
);
|
||||||
|
$qh_dbh->{InactiveDestroy} = 1; # Don't die on fork().
|
||||||
|
|
||||||
|
my @hdb_tbl = @{$history_dsn}{qw(D t)};
|
||||||
|
my $hdb_tbl = $q->quote(@hdb_tbl);
|
||||||
|
|
||||||
|
my $create_history_sql = $o->read_para_after(
|
||||||
|
__FILE__, qr/\bMAGIC_create_review_history\b/);
|
||||||
|
$create_history_sql =~ s/\bquery_history\b/$hdb_tbl/;
|
||||||
|
|
||||||
|
create_review_tables(
|
||||||
|
type => 'history',
|
||||||
|
dbh => $qh_dbh,
|
||||||
|
full_table => $hdb_tbl,
|
||||||
|
create_table_sql => $create_history_sql,
|
||||||
|
create_table => $o->get('create-history-table'),
|
||||||
|
TableParser => $tp,
|
||||||
|
);
|
||||||
|
|
||||||
|
my $tbl = $tp->parse($tp->get_create_table($qh_dbh, @hdb_tbl));
|
||||||
|
my $pat = $o->read_para_after(__FILE__, qr/\bMAGIC_history_cols\b/);
|
||||||
$pat =~ s/\s+//g;
|
$pat =~ s/\s+//g;
|
||||||
$pat = qr/^(.*?)_($pat)$/;
|
$pat = qr/^(.*?)_($pat)$/;
|
||||||
|
|
||||||
|
$qh = QueryHistory->new(
|
||||||
|
history_dbh => $qh_dbh,
|
||||||
|
column_pattern => $pat,
|
||||||
|
);
|
||||||
# And tell the QueryReview that it has more work to do.
|
# And tell the QueryReview that it has more work to do.
|
||||||
$qv->set_history_options(
|
$qh->set_history_options(
|
||||||
table => $hdb_tbl,
|
table => $hdb_tbl,
|
||||||
tbl_struct => $tbl,
|
tbl_struct => $tbl,
|
||||||
col_pat => $pat,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12926,7 +12953,7 @@ sub main {
|
|||||||
);
|
);
|
||||||
$aux_dbh->{InactiveDestroy} = 1; # Don't die on fork().
|
$aux_dbh->{InactiveDestroy} = 1; # Don't die on fork().
|
||||||
}
|
}
|
||||||
$aux_dbh ||= $qv_dbh || $ps_dbh || $ep_dbh;
|
$aux_dbh ||= $qv_dbh || $qh_dbh || $ps_dbh || $ep_dbh;
|
||||||
PTDEBUG && _d('aux dbh:', $aux_dbh);
|
PTDEBUG && _d('aux dbh:', $aux_dbh);
|
||||||
|
|
||||||
my $time_callback = sub {
|
my $time_callback = sub {
|
||||||
@@ -13058,6 +13085,7 @@ sub main {
|
|||||||
files => \@read_files,
|
files => \@read_files,
|
||||||
Pipeline => $pipeline,
|
Pipeline => $pipeline,
|
||||||
QueryReview => $qv,
|
QueryReview => $qv,
|
||||||
|
QueryHistory => $qh,
|
||||||
%common_modules,
|
%common_modules,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -13459,8 +13487,9 @@ sub main {
|
|||||||
VersionCheck::version_check(
|
VersionCheck::version_check(
|
||||||
force => $o->got('version-check'),
|
force => $o->got('version-check'),
|
||||||
instances => [
|
instances => [
|
||||||
($qv_dbh ? { dbh => $qv_dbh, dsn => $review_dsn } : ()),
|
($qv_dbh ? { dbh => $qv_dbh, dsn => $review_dsn } : ()),
|
||||||
($ps_dbh ? { dbh => $ps_dbh, dsn => $ps_dsn } : ()),
|
($qh_dbh ? { dbh => $qh_dbh, dsn => $history_dsn } : ()),
|
||||||
|
($ps_dbh ? { dbh => $ps_dbh, dsn => $ps_dsn } : ()),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -13492,7 +13521,7 @@ sub main {
|
|||||||
PTDEBUG && _d('Disconnected dbh', $_);
|
PTDEBUG && _d('Disconnected dbh', $_);
|
||||||
}
|
}
|
||||||
grep { $_ }
|
grep { $_ }
|
||||||
($qv_dbh, $ps_dbh, $ep_dbh, $aux_dbh);
|
($qv_dbh, $qh_dbh, $ps_dbh, $ep_dbh, $aux_dbh);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} # End main()
|
} # End main()
|
||||||
@@ -13503,12 +13532,12 @@ sub main {
|
|||||||
|
|
||||||
sub create_review_tables {
|
sub create_review_tables {
|
||||||
my ( %args ) = @_;
|
my ( %args ) = @_;
|
||||||
my @required_args = qw(dbh full_table TableParser);
|
my @required_args = qw(dbh full_table TableParser type);
|
||||||
foreach my $arg ( @required_args ) {
|
foreach my $arg ( @required_args ) {
|
||||||
die "I need a $arg argument" unless $args{$arg};
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
}
|
}
|
||||||
my $create_table_sql = $args{create_table_sql};
|
my $create_table_sql = $args{create_table_sql};
|
||||||
my ($dbh, $full_table, $tp) = @args{@required_args};
|
my ($dbh, $full_table, $tp, $type) = @args{@required_args};
|
||||||
|
|
||||||
PTDEBUG && _d('Checking --review table', $full_table);
|
PTDEBUG && _d('Checking --review table', $full_table);
|
||||||
|
|
||||||
@@ -13518,8 +13547,8 @@ sub create_review_tables {
|
|||||||
PTDEBUG && _d($show_db_sql);
|
PTDEBUG && _d($show_db_sql);
|
||||||
my @db_exists = $dbh->selectrow_array($show_db_sql);
|
my @db_exists = $dbh->selectrow_array($show_db_sql);
|
||||||
if ( !@db_exists && !$args{create_table} ) {
|
if ( !@db_exists && !$args{create_table} ) {
|
||||||
die "--review database $db does not exist and "
|
die "--$type database $db does not exist and "
|
||||||
. "--no-create-review-tables was specified. You need "
|
. "--no-create-$type-table was specified. You need "
|
||||||
. "to create the database.\n";
|
. "to create the database.\n";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -13535,7 +13564,7 @@ sub create_review_tables {
|
|||||||
};
|
};
|
||||||
if ( $EVAL_ERROR && !@db_exists ) {
|
if ( $EVAL_ERROR && !@db_exists ) {
|
||||||
warn $EVAL_ERROR;
|
warn $EVAL_ERROR;
|
||||||
die "--review database $db does not exist and it cannot be "
|
die "--$type database $db does not exist and it cannot be "
|
||||||
. "created automatically. You need to create the database.\n";
|
. "created automatically. You need to create the database.\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13556,7 +13585,7 @@ sub create_review_tables {
|
|||||||
|
|
||||||
if ( !$tbl_exists && !$args{create_table} ) {
|
if ( !$tbl_exists && !$args{create_table} ) {
|
||||||
die "Table $full_table does not exist and "
|
die "Table $full_table does not exist and "
|
||||||
. "--no-create-review-tables was specified. "
|
. "--no-create-$type-table was specified. "
|
||||||
. "You need to create the table.\n";
|
. "You need to create the table.\n";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -13566,7 +13595,7 @@ sub create_review_tables {
|
|||||||
};
|
};
|
||||||
if ( $EVAL_ERROR && !$args{create_table} ) {
|
if ( $EVAL_ERROR && !$args{create_table} ) {
|
||||||
warn $EVAL_ERROR;
|
warn $EVAL_ERROR;
|
||||||
die "--review history table $full_table does not exist and it cannot be "
|
die "--$type history table $full_table does not exist and it cannot be "
|
||||||
. "created automatically. You need to create the table.\n"
|
. "created automatically. You need to create the table.\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13583,6 +13612,7 @@ sub print_reports {
|
|||||||
|
|
||||||
my ($o, $qv, $pipeline) = @args{qw(OptionParser QueryReview Pipeline)};
|
my ($o, $qv, $pipeline) = @args{qw(OptionParser QueryReview Pipeline)};
|
||||||
my ($eas, $tls, $stats) = @args{qw(eas tls stats)};
|
my ($eas, $tls, $stats) = @args{qw(eas tls stats)};
|
||||||
|
my $qh = $args{QueryHistory};
|
||||||
|
|
||||||
my @reports = @{$o->get('report-format')};
|
my @reports = @{$o->get('report-format')};
|
||||||
my @groupby = @{$args{groupby}};
|
my @groupby = @{$args{groupby}};
|
||||||
@@ -13657,13 +13687,19 @@ sub print_reports {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( $qv ) { # query review
|
if ( $qv ) { # query review
|
||||||
update_query_review_tables(
|
update_query_review_table(
|
||||||
ea => $eas->[$i],
|
ea => $eas->[$i],
|
||||||
worst => $worst,
|
worst => $worst,
|
||||||
QueryReview => $qv,
|
QueryReview => $qv,
|
||||||
OptionParser => $o,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if ( $qh ) { # query history
|
||||||
|
update_query_history_table(
|
||||||
|
ea => $eas->[$i],
|
||||||
|
worst => $worst,
|
||||||
|
QueryHistory => $qh,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if ( $o->get('timeline') ) { # --timeline
|
if ( $o->get('timeline') ) { # --timeline
|
||||||
$tls->[$i]->report($tls->[$i]->results(), sub { print @_ });
|
$tls->[$i]->report($tls->[$i]->results(), sub { print @_ });
|
||||||
@@ -13721,6 +13757,22 @@ sub sig_int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Handle the special defaults for --review & --history
|
||||||
|
sub handle_special_defaults {
|
||||||
|
my ($o, $opt) = @_;
|
||||||
|
my $dsn = $o->get($opt);
|
||||||
|
return unless $dsn;
|
||||||
|
|
||||||
|
my $default_table = $o->read_para_after(
|
||||||
|
__FILE__, qr/MAGIC_${opt}_table/);
|
||||||
|
$default_table =~ s/.+\s(\S+)$/$1/;
|
||||||
|
my ($D, $t) = Quoter->split_unquote($default_table);
|
||||||
|
$dsn->{D} ||= $D;
|
||||||
|
$dsn->{t} ||= $t;
|
||||||
|
|
||||||
|
return $dsn;
|
||||||
|
}
|
||||||
|
|
||||||
sub make_alt_attrib {
|
sub make_alt_attrib {
|
||||||
my ( $alt_attrib ) = @_;
|
my ( $alt_attrib ) = @_;
|
||||||
my @alts = split('\|', $alt_attrib);
|
my @alts = split('\|', $alt_attrib);
|
||||||
@@ -13856,15 +13908,14 @@ sub get_worst_queries {
|
|||||||
return $ea->top_events(%top_spec);
|
return $ea->top_events(%top_spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub update_query_review_tables {
|
sub update_query_review_table {
|
||||||
my ( %args ) = @_;
|
my ( %args ) = @_;
|
||||||
foreach my $arg ( qw(ea worst QueryReview OptionParser) ) {
|
foreach my $arg ( qw(ea worst QueryReview) ) {
|
||||||
die "I need a $arg argument" unless $args{$arg};
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
}
|
}
|
||||||
my $ea = $args{ea};
|
my $ea = $args{ea};
|
||||||
my $worst = $args{worst};
|
my $worst = $args{worst};
|
||||||
my $qv = $args{QueryReview};
|
my $qv = $args{QueryReview};
|
||||||
my $o = $args{OptionParser};
|
|
||||||
|
|
||||||
my $attribs = $ea->get_attributes();
|
my $attribs = $ea->get_attributes();
|
||||||
|
|
||||||
@@ -13881,6 +13932,28 @@ sub update_query_review_tables {
|
|||||||
first_seen => $stats->{ts}->{min},
|
first_seen => $stats->{ts}->{min},
|
||||||
last_seen => $stats->{ts}->{max}
|
last_seen => $stats->{ts}->{max}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub update_query_history_table {
|
||||||
|
my ( %args ) = @_;
|
||||||
|
foreach my $arg ( qw(ea worst QueryHistory) ) {
|
||||||
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
|
}
|
||||||
|
my $ea = $args{ea};
|
||||||
|
my $worst = $args{worst};
|
||||||
|
my $qh = $args{QueryHistory};
|
||||||
|
|
||||||
|
my $attribs = $ea->get_attributes();
|
||||||
|
|
||||||
|
PTDEBUG && _d('Updating query review tables');
|
||||||
|
|
||||||
|
foreach my $worst_info ( @$worst ) {
|
||||||
|
my $item = $worst_info->[0];
|
||||||
|
my $sample = $ea->results->{samples}->{$item};
|
||||||
|
|
||||||
my %history;
|
my %history;
|
||||||
foreach my $attrib ( @$attribs ) {
|
foreach my $attrib ( @$attribs ) {
|
||||||
$history{$attrib} = $ea->metrics(
|
$history{$attrib} = $ea->metrics(
|
||||||
@@ -13888,13 +13961,14 @@ sub update_query_review_tables {
|
|||||||
where => $item,
|
where => $item,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$qv->set_review_history(
|
$qh->set_review_history(
|
||||||
$item, $sample->{arg} || '', %history);
|
$item, $sample->{arg} || '', %history);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Sub: verify_run_time
|
# Sub: verify_run_time
|
||||||
# Verify that the given run mode and run time are valid. If the run mode
|
# Verify that the given run mode and run time are valid. If the run mode
|
||||||
# is "interval", the time boundary (in seconds) for the run time is returned
|
# is "interval", the time boundary (in seconds) for the run time is returned
|
||||||
@@ -14320,9 +14394,9 @@ example,
|
|||||||
You can see how useful this meta-data is -- as you analyze your queries, you get
|
You can see how useful this meta-data is -- as you analyze your queries, you get
|
||||||
your comments integrated right into the report.
|
your comments integrated right into the report.
|
||||||
|
|
||||||
The tool will also store information into a separate database table specified
|
If you add the L<"--history"> option, it will also store information into
|
||||||
by the L<"--history-table"> option, so you can keep historical trending information
|
a separate database table, so you can keep historical trending information on
|
||||||
on classes of queries.
|
classes of queries.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
@@ -14483,15 +14557,23 @@ Continue parsing even if there is an error. The tool will not continue
|
|||||||
forever: it stops once any process causes 100 errors, in which case there
|
forever: it stops once any process causes 100 errors, in which case there
|
||||||
is probably a bug in the tool or the input is invalid.
|
is probably a bug in the tool or the input is invalid.
|
||||||
|
|
||||||
=item --[no]create-review-tables
|
=item --[no]create-history-table
|
||||||
|
|
||||||
default: yes
|
default: yes
|
||||||
|
|
||||||
Create the L<"--review"> tables if they do not exist.
|
Create the L<"--history"> table if it does not exist.
|
||||||
|
|
||||||
This option causes the tables specified by L<"--review-table"> and
|
This option causes the table specified by L<"--history"> to be created
|
||||||
L<"--history-table"> to be created with the default structures shown
|
with the default structure shown in the documentation for L<"--history">.
|
||||||
in the documentation for L<"--review">.
|
|
||||||
|
=item --[no]create-review-table
|
||||||
|
|
||||||
|
default: yes
|
||||||
|
|
||||||
|
Create the L<"--review"> table if it does not exist.
|
||||||
|
|
||||||
|
This option causes the table specified by L<"--review"> to be created
|
||||||
|
with the default structure shown in the documentation for L<"--review">.
|
||||||
|
|
||||||
=item --daemonize
|
=item --daemonize
|
||||||
|
|
||||||
@@ -14704,12 +14786,6 @@ into a suggestion of what they do, such as C<INSERT SELECT table1 table2>.
|
|||||||
|
|
||||||
Show help and exit.
|
Show help and exit.
|
||||||
|
|
||||||
=item --history-table
|
|
||||||
|
|
||||||
type: string; default: percona_schema.query_history
|
|
||||||
|
|
||||||
Where to save the historical data produced by L<"--review">.
|
|
||||||
|
|
||||||
=item --host
|
=item --host
|
||||||
|
|
||||||
short form: -h; type: string
|
short form: -h; type: string
|
||||||
@@ -14968,6 +15044,11 @@ type: DSN
|
|||||||
|
|
||||||
Save query classes and historical values for later review and trend analysis.
|
Save query classes and historical values for later review and trend analysis.
|
||||||
|
|
||||||
|
=for comment ignore-pt-internal-value
|
||||||
|
MAGIC_review_table
|
||||||
|
|
||||||
|
Defaults to percona_schema.query_review
|
||||||
|
|
||||||
The argument specifies a host to store all unique query fingerprints in; the
|
The argument specifies a host to store all unique query fingerprints in; the
|
||||||
databases and tables were this data is stored can be specified with the
|
databases and tables were this data is stored can be specified with the
|
||||||
L<"--review-table"> and L<"--history-table"> options.
|
L<"--review-table"> and L<"--history-table"> options.
|
||||||
@@ -14980,7 +15061,7 @@ by pt-query-digest. The following CREATE TABLE definition is also used:
|
|||||||
=for comment ignore-pt-internal-value
|
=for comment ignore-pt-internal-value
|
||||||
MAGIC_create_review:
|
MAGIC_create_review:
|
||||||
|
|
||||||
CREATE TABLE query_review (
|
CREATE TABLE IF NOT EXISTS query_review (
|
||||||
checksum BIGINT UNSIGNED NOT NULL PRIMARY KEY,
|
checksum BIGINT UNSIGNED NOT NULL PRIMARY KEY,
|
||||||
fingerprint TEXT NOT NULL,
|
fingerprint TEXT NOT NULL,
|
||||||
sample TEXT NOT NULL,
|
sample TEXT NOT NULL,
|
||||||
@@ -15012,9 +15093,26 @@ After parsing and aggregating events, your table should contain a row for each
|
|||||||
fingerprint. This option depends on C<--group-by fingerprint> (which is the
|
fingerprint. This option depends on C<--group-by fingerprint> (which is the
|
||||||
default). It will not work otherwise.
|
default). It will not work otherwise.
|
||||||
|
|
||||||
Additionally, pt-query-digest will save historical information in the
|
=item --history
|
||||||
L<"--history-table"> so you can see how classes of queries have changed
|
|
||||||
over time. The table must have at least the following columns:
|
type: DSN
|
||||||
|
|
||||||
|
The table in which to store historical values for review trend analysis.
|
||||||
|
|
||||||
|
=for comment ignore-pt-internal-value
|
||||||
|
MAGIC_history_table
|
||||||
|
|
||||||
|
Defaults to percona_schema.query_history
|
||||||
|
|
||||||
|
Each time you review queries with L<"--review">, pt-query-digest will save
|
||||||
|
information into this table so you can see how classes of queries have changed
|
||||||
|
over time.
|
||||||
|
|
||||||
|
This DSN should mention a table in which to store statistics about each
|
||||||
|
class of queries. pt-query-digest verifies the existence of the table.
|
||||||
|
|
||||||
|
pt-query-digest then inspects the columns in the table. The table must have at
|
||||||
|
least the following columns:
|
||||||
|
|
||||||
CREATE TABLE query_review_history (
|
CREATE TABLE query_review_history (
|
||||||
checksum BIGINT UNSIGNED NOT NULL,
|
checksum BIGINT UNSIGNED NOT NULL,
|
||||||
@@ -15033,7 +15131,8 @@ MAGIC_history_cols
|
|||||||
If the column ends with one of those values, then the prefix is interpreted as
|
If the column ends with one of those values, then the prefix is interpreted as
|
||||||
the event attribute to store in that column, and the suffix is interpreted as
|
the event attribute to store in that column, and the suffix is interpreted as
|
||||||
the metric to be stored. For example, a column named Query_time_min will be
|
the metric to be stored. For example, a column named Query_time_min will be
|
||||||
used to store the minimum Query_time for the class of events.
|
used to store the minimum Query_time for the class of events. The presence of
|
||||||
|
this column will also add Query_time to the L<"--select"> list.
|
||||||
|
|
||||||
The table should also have a primary key, but that is up to you, depending on
|
The table should also have a primary key, but that is up to you, depending on
|
||||||
how you want to store the historical data. We suggest adding ts_min and ts_max
|
how you want to store the historical data. We suggest adding ts_min and ts_max
|
||||||
@@ -15041,13 +15140,13 @@ columns and making them part of the primary key along with the checksum. But
|
|||||||
you could also just add a ts_min column and make it a DATE type, so you'd get
|
you could also just add a ts_min column and make it a DATE type, so you'd get
|
||||||
one row per class of queries per day.
|
one row per class of queries per day.
|
||||||
|
|
||||||
The default table structure follows. The following table definition is used
|
The default table structure follows. The following
|
||||||
for L<"--[no]create-review-tables">:
|
table definition is used for L<"--create-history-table">:
|
||||||
|
|
||||||
=for comment ignore-pt-internal-value
|
=for comment ignore-pt-internal-value
|
||||||
MAGIC_create_review_history
|
MAGIC_create_review_history
|
||||||
|
|
||||||
CREATE TABLE query_review_history (
|
CREATE TABLE IF NOT EXISTS query_history (
|
||||||
checksum BIGINT UNSIGNED NOT NULL,
|
checksum BIGINT UNSIGNED NOT NULL,
|
||||||
sample TEXT NOT NULL,
|
sample TEXT NOT NULL,
|
||||||
ts_min DATETIME,
|
ts_min DATETIME,
|
||||||
@@ -15151,12 +15250,6 @@ MAGIC_create_review_history
|
|||||||
Note that we store the count (cnt) for the ts attribute only; it will be
|
Note that we store the count (cnt) for the ts attribute only; it will be
|
||||||
redundant to store this for other attributes.
|
redundant to store this for other attributes.
|
||||||
|
|
||||||
=item --review-table
|
|
||||||
|
|
||||||
type: string; default: percona_schema.query_review
|
|
||||||
|
|
||||||
Where to save the samples produced by L<"--review">.
|
|
||||||
|
|
||||||
=item --run-time
|
=item --run-time
|
||||||
|
|
||||||
type: time
|
type: time
|
||||||
|
@@ -51,7 +51,7 @@ $Data::Dumper::Indent = 1;
|
|||||||
$Data::Dumper::Sortkeys = 1;
|
$Data::Dumper::Sortkeys = 1;
|
||||||
$Data::Dumper::Quotekeys = 0;
|
$Data::Dumper::Quotekeys = 0;
|
||||||
|
|
||||||
use base 'ProtocolParser';
|
BEGIN { our @ISA = 'ProtocolParser'; }
|
||||||
|
|
||||||
use constant {
|
use constant {
|
||||||
COM_SLEEP => '00',
|
COM_SLEEP => '00',
|
||||||
|
132
lib/QueryHistory.pm
Normal file
132
lib/QueryHistory.pm
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# This program is copyright 2008-2011 Percona Ireland Ltd.
|
||||||
|
# Feedback and improvements are welcome.
|
||||||
|
#
|
||||||
|
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||||
|
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
|
||||||
|
# systems, you can issue `man perlgpl' or `man perlartistic' to read these
|
||||||
|
# licenses.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
# Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
# ###########################################################################
|
||||||
|
# QueryHistory package
|
||||||
|
# ###########################################################################
|
||||||
|
{
|
||||||
|
# Package: QueryHistory
|
||||||
|
package QueryHistory;
|
||||||
|
|
||||||
|
use English qw(-no_match_vars);
|
||||||
|
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
|
||||||
|
|
||||||
|
use Lmo;
|
||||||
|
|
||||||
|
use Quoter;
|
||||||
|
use Transformers qw(make_checksum parse_timestamp);
|
||||||
|
|
||||||
|
has history_dbh => (
|
||||||
|
is => 'ro',
|
||||||
|
required => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
has history_sth => (
|
||||||
|
is => 'rw',
|
||||||
|
);
|
||||||
|
|
||||||
|
has history_metrics => (
|
||||||
|
is => 'rw',
|
||||||
|
isa => 'ArrayRef',
|
||||||
|
);
|
||||||
|
|
||||||
|
has column_pattern => (
|
||||||
|
is => 'ro',
|
||||||
|
isa => 'Regexp',
|
||||||
|
required => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
has ts_default => (
|
||||||
|
is => 'ro',
|
||||||
|
isa => 'Str',
|
||||||
|
default => sub { 'NOW()' },
|
||||||
|
);
|
||||||
|
|
||||||
|
# Tell QueryReview object to also prepare to save values in the review history
|
||||||
|
# table.
|
||||||
|
sub set_history_options {
|
||||||
|
my ( $self, %args ) = @_;
|
||||||
|
foreach my $arg ( qw(table tbl_struct) ) {
|
||||||
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
|
}
|
||||||
|
|
||||||
|
my $col_pat = $self->column_pattern();
|
||||||
|
|
||||||
|
# Pick out columns, attributes and metrics that need to be stored in the
|
||||||
|
# table.
|
||||||
|
my @cols;
|
||||||
|
my @metrics;
|
||||||
|
foreach my $col ( @{$args{tbl_struct}->{cols}} ) {
|
||||||
|
my ( $attr, $metric ) = $col =~ m/$col_pat/;
|
||||||
|
next unless $attr && $metric;
|
||||||
|
|
||||||
|
# TableParser lowercases the column names so, e.g., Query_time
|
||||||
|
# becomes query_time. We have to fix this so attribs in the event
|
||||||
|
# match keys in $self->{history_metrics}...
|
||||||
|
|
||||||
|
# If the attrib name has at least one _ then it's a multi-word
|
||||||
|
# attrib like Query_time or Lock_time, so the first letter should
|
||||||
|
# be uppercase. Else, it's a one-word attrib like ts, checksum
|
||||||
|
# or sample, so we leave it alone. Except Filesort which is yet
|
||||||
|
# another exception.
|
||||||
|
$attr = ucfirst $attr if $attr =~ m/_/;
|
||||||
|
$attr = 'Filesort' if $attr eq 'filesort';
|
||||||
|
|
||||||
|
$attr =~ s/^Qc_hit/QC_Hit/; # Qc_hit is really QC_Hit
|
||||||
|
$attr =~ s/^Innodb/InnoDB/g; # Innodb is really InnoDB
|
||||||
|
$attr =~ s/_io_/_IO_/g; # io is really IO
|
||||||
|
|
||||||
|
push @cols, $col;
|
||||||
|
push @metrics, [$attr, $metric];
|
||||||
|
}
|
||||||
|
|
||||||
|
my $ts_default = $self->ts_default;
|
||||||
|
|
||||||
|
my $sql = "REPLACE INTO $args{table}("
|
||||||
|
. join(', ',
|
||||||
|
map { Quoter->quote($_) } ('checksum', 'sample', @cols))
|
||||||
|
. ') VALUES (CONV(?, 16, 10), ?'
|
||||||
|
. (@cols ? ', ' : '') # issue 1265
|
||||||
|
. join(', ', map {
|
||||||
|
# ts_min and ts_max might be part of the PK, in which case they must
|
||||||
|
# not be NULL.
|
||||||
|
$_ eq 'ts_min' || $_ eq 'ts_max'
|
||||||
|
? "COALESCE(?, $ts_default)"
|
||||||
|
: '?'
|
||||||
|
} @cols) . ')';
|
||||||
|
PTDEBUG && _d($sql);
|
||||||
|
|
||||||
|
$self->history_sth($self->history_dbh->prepare($sql));
|
||||||
|
$self->history_metrics(\@metrics);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Save review history for a class of queries. The incoming data is a bunch
|
||||||
|
# of hashes. Each top-level key is an attribute name, and each second-level key
|
||||||
|
# is a metric name. Look at the test for more examples.
|
||||||
|
sub set_review_history {
|
||||||
|
my ( $self, $id, $sample, %data ) = @_;
|
||||||
|
# Need to transform ts->min/max into timestamps
|
||||||
|
foreach my $thing ( qw(min max) ) {
|
||||||
|
next unless defined $data{ts} && defined $data{ts}->{$thing};
|
||||||
|
$data{ts}->{$thing} = parse_timestamp($data{ts}->{$thing});
|
||||||
|
}
|
||||||
|
$self->history_sth->execute(
|
||||||
|
make_checksum($id),
|
||||||
|
$sample,
|
||||||
|
map { $data{$_->[0]}->{$_->[1]} } @{$self->history_metrics});
|
||||||
|
}
|
@@ -107,78 +107,6 @@ sub new {
|
|||||||
return bless $self, $class;
|
return bless $self, $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Tell QueryReview object to also prepare to save values in the review history
|
|
||||||
# table.
|
|
||||||
sub set_history_options {
|
|
||||||
my ( $self, %args ) = @_;
|
|
||||||
foreach my $arg ( qw(table tbl_struct col_pat) ) {
|
|
||||||
die "I need a $arg argument" unless $args{$arg};
|
|
||||||
}
|
|
||||||
|
|
||||||
# Pick out columns, attributes and metrics that need to be stored in the
|
|
||||||
# table.
|
|
||||||
my @cols;
|
|
||||||
my @metrics;
|
|
||||||
foreach my $col ( @{$args{tbl_struct}->{cols}} ) {
|
|
||||||
my ( $attr, $metric ) = $col =~ m/$args{col_pat}/;
|
|
||||||
next unless $attr && $metric;
|
|
||||||
|
|
||||||
# TableParser lowercases the column names so, e.g., Query_time
|
|
||||||
# becomes query_time. We have to fix this so attribs in the event
|
|
||||||
# match keys in $self->{history_metrics}...
|
|
||||||
|
|
||||||
# If the attrib name has at least one _ then it's a multi-word
|
|
||||||
# attrib like Query_time or Lock_time, so the first letter should
|
|
||||||
# be uppercase. Else, it's a one-word attrib like ts, checksum
|
|
||||||
# or sample, so we leave it alone. Except Filesort which is yet
|
|
||||||
# another exception.
|
|
||||||
$attr = ucfirst $attr if $attr =~ m/_/;
|
|
||||||
$attr = 'Filesort' if $attr eq 'filesort';
|
|
||||||
|
|
||||||
$attr =~ s/^Qc_hit/QC_Hit/; # Qc_hit is really QC_Hit
|
|
||||||
$attr =~ s/^Innodb/InnoDB/g; # Innodb is really InnoDB
|
|
||||||
$attr =~ s/_io_/_IO_/g; # io is really IO
|
|
||||||
|
|
||||||
push @cols, $col;
|
|
||||||
push @metrics, [$attr, $metric];
|
|
||||||
}
|
|
||||||
|
|
||||||
my $sql = "REPLACE INTO $args{table}("
|
|
||||||
. join(', ',
|
|
||||||
map { $self->{quoter}->quote($_) } ('checksum', 'sample', @cols))
|
|
||||||
. ') VALUES (CONV(?, 16, 10), ?'
|
|
||||||
. (@cols ? ', ' : '') # issue 1265
|
|
||||||
. join(', ', map {
|
|
||||||
# ts_min and ts_max might be part of the PK, in which case they must
|
|
||||||
# not be NULL.
|
|
||||||
$_ eq 'ts_min' || $_ eq 'ts_max'
|
|
||||||
? "COALESCE(?, $self->{ts_default})"
|
|
||||||
: '?'
|
|
||||||
} @cols) . ')';
|
|
||||||
PTDEBUG && _d($sql);
|
|
||||||
|
|
||||||
$self->{history_sth} = $self->{dbh}->prepare($sql);
|
|
||||||
$self->{history_metrics} = \@metrics;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Save review history for a class of queries. The incoming data is a bunch
|
|
||||||
# of hashes. Each top-level key is an attribute name, and each second-level key
|
|
||||||
# is a metric name. Look at the test for more examples.
|
|
||||||
sub set_review_history {
|
|
||||||
my ( $self, $id, $sample, %data ) = @_;
|
|
||||||
# Need to transform ts->min/max into timestamps
|
|
||||||
foreach my $thing ( qw(min max) ) {
|
|
||||||
next unless defined $data{ts} && defined $data{ts}->{$thing};
|
|
||||||
$data{ts}->{$thing} = parse_timestamp($data{ts}->{$thing});
|
|
||||||
}
|
|
||||||
$self->{history_sth}->execute(
|
|
||||||
make_checksum($id),
|
|
||||||
$sample,
|
|
||||||
map { $data{$_->[0]}->{$_->[1]} } @{$self->{history_metrics}});
|
|
||||||
}
|
|
||||||
|
|
||||||
# Fetch information from the database about a query that's been reviewed.
|
# Fetch information from the database about a query that's been reviewed.
|
||||||
sub get_review_info {
|
sub get_review_info {
|
||||||
my ( $self, $id ) = @_;
|
my ( $self, $id ) = @_;
|
||||||
|
@@ -11,6 +11,7 @@ use warnings FATAL => 'all';
|
|||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
use Test::More;
|
use Test::More;
|
||||||
|
|
||||||
|
use ProtocolParser;
|
||||||
use MySQLProtocolParser;
|
use MySQLProtocolParser;
|
||||||
use TcpdumpParser;
|
use TcpdumpParser;
|
||||||
use PerconaTest;
|
use PerconaTest;
|
||||||
@@ -1777,4 +1778,7 @@ like(
|
|||||||
# #############################################################################
|
# #############################################################################
|
||||||
# Done.
|
# Done.
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
|
|
||||||
|
# Get rid of error files
|
||||||
|
`rm /tmp/MySQLProtocolParser.t-errors.*`;
|
||||||
done_testing;
|
done_testing;
|
||||||
|
@@ -38,7 +38,7 @@ $sb->create_dbs($dbh, [qw(test percona_schema)]);
|
|||||||
|
|
||||||
# Run pt-query-digest in the background for 2s,
|
# Run pt-query-digest in the background for 2s,
|
||||||
# saving queries to test.query_review.
|
# saving queries to test.query_review.
|
||||||
diag(`$trunk/bin/pt-query-digest --processlist h=127.1,P=12345,u=msandbox,p=msandbox --interval 0.01 --create-review-table --review h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review --daemonize --pid $pid_file --log /dev/null --run-time 2`);
|
diag(`$trunk/bin/pt-query-digest --processlist h=127.1,P=12345,u=msandbox,p=msandbox --interval 0.01 --create-review-table --review h=127.1,P=12345,u=msandbox,p=msandbox,D=test,t=query_review --daemonize --pid $pid_file --log /dev/null --run-time 2`);
|
||||||
|
|
||||||
# Wait until its running.
|
# Wait until its running.
|
||||||
PerconaTest::wait_for_files($pid_file);
|
PerconaTest::wait_for_files($pid_file);
|
||||||
|
@@ -18,29 +18,6 @@ my $help = qx{$cmd --help};
|
|||||||
|
|
||||||
my $output;
|
my $output;
|
||||||
|
|
||||||
# #############################################################################
|
|
||||||
# Test cmd line op sanity.
|
|
||||||
# #############################################################################
|
|
||||||
for my $opt (qw(review-table history-table)) {
|
|
||||||
$output = `$cmd --review h=127.1,P=12345,u=msandbox,p=msandbox --$opt test`;
|
|
||||||
like($output, qr/--$opt should be passed a/, "Dies if no database part in --$opt");
|
|
||||||
}
|
|
||||||
|
|
||||||
$output = `$cmd --review h=127.1,P=12345,u=msandbox,p=msandbox,D=test,t=test`;
|
|
||||||
like($output, qr/--review does not accept a t option/, 'Dies if t part in --review DSN');
|
|
||||||
|
|
||||||
like(
|
|
||||||
$help,
|
|
||||||
qr/review-table\s+\Qpercona_schema.query_review\E/,
|
|
||||||
"--review-table has a sane default"
|
|
||||||
);
|
|
||||||
|
|
||||||
like(
|
|
||||||
$help,
|
|
||||||
qr/history-table\s+\Qpercona_schema.query_history\E/,
|
|
||||||
"--history-table has a sane default"
|
|
||||||
);
|
|
||||||
|
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
# https://bugs.launchpad.net/percona-toolkit/+bug/885382
|
# https://bugs.launchpad.net/percona-toolkit/+bug/885382
|
||||||
# pt-query-digest --embedded-attributes doesn't check cardinality
|
# pt-query-digest --embedded-attributes doesn't check cardinality
|
||||||
|
@@ -31,6 +31,7 @@ sub normalize_numbers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox';
|
||||||
my $run_with = "$trunk/bin/pt-query-digest --report-format=query_report --limit 10 $trunk/t/lib/samples/slowlogs/";
|
my $run_with = "$trunk/bin/pt-query-digest --report-format=query_report --limit 10 $trunk/t/lib/samples/slowlogs/";
|
||||||
my $output;
|
my $output;
|
||||||
my $cmd;
|
my $cmd;
|
||||||
@@ -40,21 +41,21 @@ $sb->load_file('master', 't/pt-query-digest/samples/query_review.sql');
|
|||||||
|
|
||||||
# Test --create-review and --create-review-history-table
|
# Test --create-review and --create-review-history-table
|
||||||
$output = 'foo'; # clear previous test results
|
$output = 'foo'; # clear previous test results
|
||||||
$cmd = "${run_with}slow006.txt --create-review-tables --review "
|
$cmd = "${run_with}slow006.txt --create-review-table --create-history-table --review "
|
||||||
. "h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review "
|
. "$dsn,D=test,t=query_review "
|
||||||
. "--history-table test.query_review_history";
|
. "--history $dsn,D=test,t=query_review_history";
|
||||||
$output = `$cmd >/dev/null 2>&1`;
|
$output = `$cmd >/dev/null 2>&1`;
|
||||||
|
|
||||||
my ($table) = $dbh->selectrow_array(
|
my ($table) = $dbh->selectrow_array(
|
||||||
"show tables from test like 'query_review'");
|
"show tables from test like 'query_review'");
|
||||||
is($table, 'query_review', '--create-review-tables');
|
is($table, 'query_review', '--create-review-table');
|
||||||
($table) = $dbh->selectrow_array(
|
($table) = $dbh->selectrow_array(
|
||||||
"show tables from test like 'query_review_history'");
|
"show tables from test like 'query_review_history'");
|
||||||
is($table, 'query_review_history', '--create-review-tables');
|
is($table, 'query_review_history', '--create-history-table');
|
||||||
|
|
||||||
$output = 'foo'; # clear previous test results
|
$output = 'foo'; # clear previous test results
|
||||||
$cmd = "${run_with}slow006.txt --review h=127.1,u=msandbox,p=msandbox,P=12345 --review-table test.query_review "
|
$cmd = "${run_with}slow006.txt --review $dsn,D=test,t=query_review "
|
||||||
. "--history-table test.query_review_history";
|
. "--history $dsn,D=test,t=query_review_history";
|
||||||
$output = `$cmd`;
|
$output = `$cmd`;
|
||||||
my $res = $dbh->selectall_arrayref( 'SELECT * FROM test.query_review',
|
my $res = $dbh->selectall_arrayref( 'SELECT * FROM test.query_review',
|
||||||
{ Slice => {} } );
|
{ Slice => {} } );
|
||||||
@@ -178,13 +179,13 @@ is_deeply(
|
|||||||
# have been reviewed, the report should include both of them with
|
# have been reviewed, the report should include both of them with
|
||||||
# their respective query review info added to the report.
|
# their respective query review info added to the report.
|
||||||
ok(
|
ok(
|
||||||
no_diff($run_with.'slow006.txt --review h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review --create-review-tables', "t/pt-query-digest/samples/slow006_AR_1.txt"),
|
no_diff($run_with."slow006.txt --history $dsn --review $dsn,D=test,t=query_review", "t/pt-query-digest/samples/slow006_AR_1.txt"),
|
||||||
'Analyze-review pass 1 reports not-reviewed queries'
|
'Analyze-review pass 1 reports not-reviewed queries'
|
||||||
);
|
);
|
||||||
|
|
||||||
($table) = $dbh->selectrow_array(
|
($table) = $dbh->selectrow_array(
|
||||||
"show tables from percona_schema like 'query_history'");
|
"show tables from percona_schema like 'query_history'");
|
||||||
is($table, 'query_history', '--create-review-tables creates both percona_schema and query_review_history');
|
is($table, 'query_history', '--create-history-table creates both percona_schema and query_history');
|
||||||
|
|
||||||
# Mark a query as reviewed and run --report again and that query should
|
# Mark a query as reviewed and run --report again and that query should
|
||||||
# not be reported.
|
# not be reported.
|
||||||
@@ -192,7 +193,7 @@ $dbh->do('UPDATE test.query_review
|
|||||||
SET reviewed_by="daniel", reviewed_on="2008-12-24 12:00:00", comments="foo_tbl is ok, so are cranberries"
|
SET reviewed_by="daniel", reviewed_on="2008-12-24 12:00:00", comments="foo_tbl is ok, so are cranberries"
|
||||||
WHERE checksum=11676753765851784517');
|
WHERE checksum=11676753765851784517');
|
||||||
ok(
|
ok(
|
||||||
no_diff($run_with.'slow006.txt --review h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review', "t/pt-query-digest/samples/slow006_AR_2.txt"),
|
no_diff($run_with."slow006.txt --review $dsn,D=test,t=query_review", "t/pt-query-digest/samples/slow006_AR_2.txt"),
|
||||||
'Analyze-review pass 2 does not report the reviewed query'
|
'Analyze-review pass 2 does not report the reviewed query'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -200,7 +201,7 @@ ok(
|
|||||||
# to re-appear in the report with the reviewed_by, reviewed_on and comments
|
# to re-appear in the report with the reviewed_by, reviewed_on and comments
|
||||||
# info included.
|
# info included.
|
||||||
ok(
|
ok(
|
||||||
no_diff($run_with.'slow006.txt --review h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review --report-all', "t/pt-query-digest/samples/slow006_AR_4.txt"),
|
no_diff($run_with."slow006.txt --review $dsn,D=test,t=query_review --report-all", "t/pt-query-digest/samples/slow006_AR_4.txt"),
|
||||||
'Analyze-review pass 4 with --report-all reports reviewed query'
|
'Analyze-review pass 4 with --report-all reports reviewed query'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -209,7 +210,7 @@ $dbh->do('ALTER TABLE test.query_review ADD COLUMN foo INT');
|
|||||||
$dbh->do('UPDATE test.query_review
|
$dbh->do('UPDATE test.query_review
|
||||||
SET foo=42 WHERE checksum=15334040482108055940');
|
SET foo=42 WHERE checksum=15334040482108055940');
|
||||||
ok(
|
ok(
|
||||||
no_diff($run_with.'slow006.txt --review h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review', "t/pt-query-digest/samples/slow006_AR_5.txt"),
|
no_diff($run_with."slow006.txt --review $dsn,D=test,t=query_review", "t/pt-query-digest/samples/slow006_AR_5.txt"),
|
||||||
'Analyze-review pass 5 reports new review info column'
|
'Analyze-review pass 5 reports new review info column'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -218,7 +219,7 @@ ok(
|
|||||||
$dbh->do("update test.query_review set first_seen='0000-00-00 00:00:00', "
|
$dbh->do("update test.query_review set first_seen='0000-00-00 00:00:00', "
|
||||||
. " last_seen='0000-00-00 00:00:00'");
|
. " last_seen='0000-00-00 00:00:00'");
|
||||||
$output = 'foo'; # clear previous test results
|
$output = 'foo'; # clear previous test results
|
||||||
$cmd = "${run_with}slow022.txt --review h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review";
|
$cmd = "${run_with}slow022.txt --review $dsn,D=test,t=query_review";
|
||||||
$output = `$cmd`;
|
$output = `$cmd`;
|
||||||
unlike($output, qr/last_seen/, 'no last_seen when 0000 timestamp');
|
unlike($output, qr/last_seen/, 'no last_seen when 0000 timestamp');
|
||||||
unlike($output, qr/first_seen/, 'no first_seen when 0000 timestamp');
|
unlike($output, qr/first_seen/, 'no first_seen when 0000 timestamp');
|
||||||
@@ -232,7 +233,7 @@ unlike($output, qr/0000-00-00 00:00:00/, 'no 0000-00-00 00:00:00 timestamp');
|
|||||||
# Make sure a missing Time property does not cause a crash. Don't test data
|
# Make sure a missing Time property does not cause a crash. Don't test data
|
||||||
# in table, because it varies based on when you run the test.
|
# in table, because it varies based on when you run the test.
|
||||||
$output = 'foo'; # clear previous test results
|
$output = 'foo'; # clear previous test results
|
||||||
$cmd = "${run_with}slow021.txt --review h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review";
|
$cmd = "${run_with}slow021.txt --review $dsn,D=test,t=query_review";
|
||||||
$output = `$cmd`;
|
$output = `$cmd`;
|
||||||
unlike($output, qr/Use of uninitialized value/, 'didnt crash due to undef ts');
|
unlike($output, qr/Use of uninitialized value/, 'didnt crash due to undef ts');
|
||||||
|
|
||||||
@@ -240,7 +241,7 @@ unlike($output, qr/Use of uninitialized value/, 'didnt crash due to undef ts');
|
|||||||
# crash. Don't test data in table, because it varies based on when you run
|
# crash. Don't test data in table, because it varies based on when you run
|
||||||
# the test.
|
# the test.
|
||||||
$output = 'foo'; # clear previous test results
|
$output = 'foo'; # clear previous test results
|
||||||
$cmd = "${run_with}slow022.txt --review h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review";
|
$cmd = "${run_with}slow022.txt --review $dsn,D=test,t=query_review";
|
||||||
$output = `$cmd`;
|
$output = `$cmd`;
|
||||||
# Don't test data in table, because it varies based on when you run the test.
|
# Don't test data in table, because it varies based on when you run the test.
|
||||||
unlike($output, qr/Use of uninitialized value/, 'no crash due to totally missing ts');
|
unlike($output, qr/Use of uninitialized value/, 'no crash due to totally missing ts');
|
||||||
@@ -249,7 +250,7 @@ unlike($output, qr/Use of uninitialized value/, 'no crash due to totally missing
|
|||||||
# --review --no-report
|
# --review --no-report
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
$sb->load_file('master', 't/pt-query-digest/samples/query_review.sql');
|
$sb->load_file('master', 't/pt-query-digest/samples/query_review.sql');
|
||||||
$output = `${run_with}slow006.txt --review h=127.1,P=12345,u=msandbox,p=msandbox --review-table test.query_review --no-report --create-review-table`;
|
$output = `${run_with}slow006.txt --review $dsn,D=test,t=query_review --no-report`;
|
||||||
$res = $dbh->selectall_arrayref('SELECT * FROM test.query_review');
|
$res = $dbh->selectall_arrayref('SELECT * FROM test.query_review');
|
||||||
is(
|
is(
|
||||||
$res->[0]->[1],
|
$res->[0]->[1],
|
||||||
@@ -269,7 +270,7 @@ is(
|
|||||||
$dbh->do('truncate table test.query_review');
|
$dbh->do('truncate table test.query_review');
|
||||||
$dbh->do('truncate table test.query_review_history');
|
$dbh->do('truncate table test.query_review_history');
|
||||||
|
|
||||||
`${run_with}slow002.txt --review h=127.1,u=msandbox,p=msandbox,P=12345 --review-table test.query_review --history-table test.query_review_history --no-report --filter '\$event->{arg} =~ m/foo\.bar/' > /dev/null`;
|
`${run_with}slow002.txt --review $dsn,D=test,t=query_review --history $dsn,D=test,t=query_review_history --no-report --filter '\$event->{arg} =~ m/foo\.bar/' > /dev/null`;
|
||||||
|
|
||||||
$res = $dbh->selectall_arrayref( 'SELECT * FROM test.query_review_history',
|
$res = $dbh->selectall_arrayref( 'SELECT * FROM test.query_review_history',
|
||||||
{ Slice => {} } );
|
{ Slice => {} } );
|
||||||
@@ -397,9 +398,8 @@ $dbh->do($min_tbl);
|
|||||||
|
|
||||||
$output = output(
|
$output = output(
|
||||||
sub { pt_query_digest::main(
|
sub { pt_query_digest::main(
|
||||||
'--review', 'h=127.1,u=msandbox,p=msandbox,P=12345',
|
'--review', "$dsn,D=test,t=query_review",
|
||||||
'--review-table', 'test.query_review',
|
'--history', "$dsn,D=test,t=query_review_history",
|
||||||
'--history-table', 'test.query_review_history',
|
|
||||||
qw(--no-report --no-continue-on-error),
|
qw(--no-report --no-continue-on-error),
|
||||||
"$trunk/t/lib/samples/slow002.txt")
|
"$trunk/t/lib/samples/slow002.txt")
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user