# -*- cperl -*-
package Celaenito::DbOptimizer;
use strict;
use warnings;
use POE::Session;
use POE::Kernel;
use Celaenito::Logger;
use Celaenito::HyperEstraier;
use Celaenito::DB;
use IO::All;
use Hash::Util qw(lock_keys);
use constant INTERVAL => 7 * 24 * 60 * 60; # 何秒毎に DB を最適化するか
use constant ALIAS => 'dbopt';

sub run {
    my $class = shift;
    my $this = bless {} => $class;

    lock_keys %$this;

    POE::Session->create(
	heap => $this,
	inline_states => {
	    _start    => \&_start_handler,
	    _stop     => \&_stop_handler,
	    shutdown  => \&_shutdown_handler,
	    optimize  => \&_optimize_handler,
	    _signal_stop => sub {
		$_[KERNEL]->sig_handled;
		$_[KERNEL]->yield('shutdown');
	    },
	},
       );
}

sub _start_handler {
    $_[KERNEL]->alias_set(ALIAS);
    $_[KERNEL]->delay('optimize', INTERVAL);
    foreach (qw[HUP INT QUIT ABRT TERM]) {
	$_[KERNEL]->sig($_ => '_signal_stop');
    }

    logdebug sprintf(
	'will optimize DB every %.2f days.', INTERVAL / 60 / 60 / 24);
}

sub _shutdown_handler {
    my $this = $_[HEAP];
    logdebug "is going to shutdown...";

    $_[KERNEL]->alias_remove(ALIAS);
    $_[KERNEL]->delay('optimize');
}

sub _stop_handler {
    logdebug 'STOPPED.';
}

sub _optimize_handler {
    my $this = $_[HEAP];

    my $sql = io('dbinit.sql')->all;
    my $re_table = qr{^create table (\S+)}m;
    foreach my $table ($sql =~ m/$re_table/g) {
	logdebug "is optimizing `$table'...";

	DB->do(qq{
            OPTIMIZE TABLE $table
        });
    }

    if (EST) {
	logdebug 'is optimizing HyperEst DB...';

	EST->write(
	    sub {
		shift->optimize(0);
	    });
    }
}

1;
