#!/usr/bin/perl -w

# $Id$

=head1 NAME

	mysql-monitor-repl-util - мониторинг запаса производительности репликации

=head1 DESCRIPTION

    Получает один параметр --config= - имя конфига mysql-monitor
    Останавливает репликацию на N секунд (flush tables with read lock),
    потом запускает и ждёт, пока мы не догоним мастера (M секунд)
    В файл мониторинга дописывает 100*M/(N+M) - насколько процентов репликация загружена
    
    Конфиг заббикса определяет такие параметры:
     - mysql-monitor.repl_util[*] -- вещественное число от 0 до 1 - утилизация репликации
     - mysql-monitor.repl_check_age[*] -- насколько стар файл со статусом

    TODO: Автоматически пока не запускается

=cut

use strict;
use Getopt::Long;

use YAML;
use DBI;
use File::Slurp;
use Time::Local;
use Pid::File::Flock;

use utf8;
use open ':std' => ':utf8';

# на сколько секунд тормозим репликацию
my $REPL_PAUSE_INTERVAL = 300;

my $CONF_DIR = '/etc/mysql-monitor.d';

my $STATUS_DIR = '/var/spool/mysql-monitor';

my $CONFIG;

GetOptions(
    "help" => sub {system("podselect -section NAME -section DESCRIPTION $0 | pod2text-utf8 >&2"); exit 0;},
    "config=s" => \$CONFIG,
    "pause-interval=i" => \$REPL_PAUSE_INTERVAL,
    ) || die "Error occured";

if (!defined $CONFIG) {
    die "Parameter --config is not defined";
}

# читаем, проверяем конфиг
my $conf = read_config("$CONF_DIR/$CONFIG");

# блокировка от повторного запуска
my $flock = Pid::File::Flock->new(ext => ".$CONFIG.pid", quiet => 1, raise => 0);

my $dbh = DBI->connect("DBI:mysql:;mysql_socket=$conf->{socket};mysql_enable_utf8=1", "root", "");

wait_master($dbh);

while(1) {
    pause_repl($dbh, $REPL_PAUSE_INTERVAL);
    my $t1 = time();
    wait_master($dbh);
    my $wait_time = time() - $t1;
    my $status = {
        repl_util => sprintf("%.4f", $wait_time / ($wait_time + $REPL_PAUSE_INTERVAL)),
    };
    write_file("$STATUS_DIR/$CONFIG.repl",
               {atomic => 1},
               YAML::Dump($status)
        );
}

sub pause_repl {
    my ($dbh, $interval) = @_;
    $dbh->do("FLUSH NO_WRITE_TO_BINLOG TABLES WITH READ LOCK");
    sleep $interval;
    $dbh->do("UNLOCK TABLES");
}

sub wait_master {
    my ($dbh) = @_;
    while(1) {
        my $slave_status = $dbh->selectrow_hashref("SHOW SLAVE STATUS");
        my $slave_running = $slave_status
            && $slave_status->{Slave_IO_Running} && $slave_status->{Slave_IO_Running} eq 'Yes'
            && $slave_status->{Slave_SQL_Running} && $slave_status->{Slave_SQL_Running} eq 'Yes'
            ? 1 : 0
            ;
        die "Slave is not running" if !$slave_running;
        if ($slave_status->{Seconds_Behind_Master} <= 1) {
            return;
        }
        sleep 1;
    }
}

sub read_config {
    my ($file) = @_;
    my $conf = YAML::LoadFile($file);
    if (!exists $conf->{socket}) {
        die "Error in $file: socket is not defined";
    }
    return $conf;
}
