#!/usr/bin/perl use warnings; use strict; use DBI; ################################# # НАСТРОИТЬ ДЛЯ ДОСТУПА К БАЗЕ ################################# # Параметры доступа к базе. my ($inDbName, $inDbUser, $inDbPass) = ('trafstat', 'root', ''); my ($outDbName, $outDbUser, $outDbPass) = ('test', 'root', ''); ########################### # ВНУТРЕНЕЕ ПРОСТРАНСТВО ########################### # # размер хеша для временного хранения данных о трафике our $h_size = 10000; my ($inDbh, $inQuery); my ($outDbh, $outCreate, $outQuery); $inDbh = DBI->connect("DBI:mysql:host=localhost;database=$inDbName", $inDbUser, $inDbPass, {PrintError => 1, RaiseError => 1}); $outDbh = DBI->connect("DBI:mysql:host=localhost;database=$outDbName", $outDbUser, $outDbPass, {PrintError => 1, RaiseError => 1}); # Перенесем все таблицы которые не требуют изменений. # table 'config' transfer_table('config', $inDbh, $outDbh); # table 'groups' transfer_table('groups', $inDbh, $outDbh); # table 'list_traffic' transfer_table('list_traffic', $inDbh, $outDbh); # table 'privileges' transfer_table('privileges', $inDbh, $outDbh); # table 'proto' transfer_table('proto', $inDbh, $outDbh); # table 'users' transfer_table('users', $inDbh, $outDbh); # Перенесем таблицу 'traffic_cur'. $outCreate = "create table `traffic_cur` ( `date` datetime not null, `srcIp` int unsigned not null, `dstIp` int unsigned not null, `dstPort` smallint unsigned not null, `pId` tinyint not null, `inBytes` int unsigned not null, `outBytes` int unsigned not null, primary key (`date`, `srcIp`, `dstIp`, `dstPort`, `pId`) ) engine = MyISAM"; $inQuery = "select * from `traffic_cur`"; $outQuery = "insert into `traffic_cur` (`date`, `srcIp`, `dstIp`, `dstPort`, `pId`, `inBytes`, `outBytes`) values(?, ?, ?, ?, ?, ?, ?) on duplicate key update `inBytes` = `inBytes` + ?, `outBytes` = `outBytes` + ?"; transfer_update_table('traffic_cur', $outCreate, $inQuery, $outQuery, $inDbh, $outDbh, sub { my ($d, $t) = split ' ', shift; my $h = (split ':', $t)[0]; return "$d $h:30:00"; }); # Перенесем данные из архивных таблиц $outCreate = "create table `%TABLE_NAME%` ( `date` date not null, `srcIp` int unsigned not null, `dstIp` int unsigned not null, `dstPort` smallint unsigned not null, `pId` tinyint not null, `inBytes` int unsigned not null, `outBytes` int unsigned not null, primary key (`date`, `srcIp`, `dstIp`, `dstPort`, `pId`) ) engine = MyISAM"; $inQuery = "select * from `%TABLE_NAME%`"; $outQuery = "insert into `%TABLE_NAME%` (`date`, `srcIp`, `dstIp`, `dstPort`, `pId`, `inBytes`, `outBytes`) values(?, ?, ?, ?, ?, ?, ?) on duplicate key update `inBytes` = `inBytes` + ?, `outBytes` = `outBytes` + ?"; my $tabNames = $inDbh->selectall_arrayref("select year from list_traffic"); if (defined $tabNames) { foreach my $name (@{$tabNames}) { my $tmpName = 'traffic_' . $name->[0]; (my $tmpOutCreate = $outCreate) =~ s/%TABLE_NAME%/$tmpName/g; (my $tmpInQuery = $inQuery) =~ s/%TABLE_NAME%/$tmpName/g; (my $tmpOutQuery = $outQuery) =~ s/%TABLE_NAME%/$tmpName/g; transfer_update_table($tmpName, $tmpOutCreate, $tmpInQuery, $tmpOutQuery, $inDbh, $outDbh, sub { my ($y, $m) = $_[0] =~ /^(\d+)-(\d+)/; return "$y-$m-1"; }); } } # удалим файл статуса обслуживания таблиц my $config = "/etc/trafstat/trafstat.conf"; if (-r $config) { my $fileStatus; open CONFIG, $config or die "Failed open config file: $config\n"; while () { next if /^#|^$|^\[/; /^trafserve_file_status\s*=\s*([\w|\/]+)/ && do {$fileStatus = $1; last;}; } system "rm -f $fileStatus" if $fileStatus; } exit 0; # Переносит таблицу из одной базы в другую без изменений sub transfer_table { my ($name, $in, $out) = @_; # получим структуру таблицы my @tb = $in->selectrow_array("show create table `$name`"); # подсчитаем количество столбцов в таблице my $count = 0; foreach (split /\n/, $tb[1]) { $count++ if /^\s+`\w+`\s+/; } # запросы на получение и вставку данных в таблицы my $inQuery = "select * from `$tb[0]`"; my $outQuery = "insert into `$tb[0]` values (" . join(',', ('?') x $count) . ')'; # перенесем структуру таблицы в новую базу $out->do("drop table if exists `$tb[0]`"); $out->do($tb[1]); # перенесем данные в новую таблицу my $inSth = $in->prepare($inQuery); my $outSth = $out->prepare($outQuery); my @val; $inSth->execute(); $outSth->execute(@val) while @val = $inSth->fetchrow_array(); $inSth->finish(); $outSth->finish(); print "transfer table '$tb[0]' OK\n"; } # Переносит таблицу из одной базы в другую с изменением структуры таблицы sub transfer_update_table { my ($name, $outCreate, $inQuery, $outQuery, $inDbh, $outDbh, $getdate) = @_; my $query; # Создадим структуру таблицы. $query = "drop table if exists `$name`"; $outDbh->do($query); $outDbh->do($outCreate); # получим количество строк в таблице $inDbh->do("select sql_calc_found_rows * from `$name` limit 1"); my $total = $inDbh->selectrow_array("select found_rows()"); # Подготовим запрос на вставку my $outSth = $outDbh->prepare($outQuery); # Перенесем данные my $count = 0; LOOP_: { my $start = time(); my $i = 0; my %traffic = (); my $tmpQuery = $inQuery . " limit $count, $h_size"; my $inSth = $inDbh->prepare($tmpQuery); $inSth->execute(); while (my @val = $inSth->fetchrow_array()) { # округлим дату $val[0] = &$getdate($val[0]); # добавим данные в буфер my $key = join '@', @val[0..4]; if (exists $traffic{$key}) { $traffic{$key}[0] += $val[5]; $traffic{$key}[1] += $val[6]; } else { $traffic{$key} = [$val[5], $val[6]]; } $i++; } $inSth->finish(); # выгрузим данные в новую таблицу foreach my $key (sort keys %traffic) { $outSth->execute(split('@', $key), $traffic{$key}[0], $traffic{$key}[1], $traffic{$key}[0], $traffic{$key}[1]); } $count += $i; my $end = time(); printf "transfer table '%s', time = %d sec, total = %d: %d OK\n", $name, $end - $start, $total, $count; # перезапустим блок redo LOOP_ if $count < $total; } $outSth->finish(); }