2007-03-27 14:51:29 +00:00
|
|
|
##############################################
|
|
|
|
package main;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
use IO::File;
|
2008-07-24 07:39:15 +00:00
|
|
|
#use Devel::Size qw(size total_size);
|
2007-03-27 14:51:29 +00:00
|
|
|
|
2008-06-12 07:22:59 +00:00
|
|
|
sub seekTo($$$$);
|
|
|
|
|
2007-03-27 14:51:29 +00:00
|
|
|
#####################################
|
|
|
|
sub
|
|
|
|
FileLog_Initialize($)
|
|
|
|
{
|
|
|
|
my ($hash) = @_;
|
|
|
|
|
2008-05-09 13:58:10 +00:00
|
|
|
$hash->{DefFn} = "FileLog_Define";
|
|
|
|
$hash->{SetFn} = "FileLog_Set";
|
|
|
|
$hash->{GetFn} = "FileLog_Get";
|
|
|
|
$hash->{UndefFn} = "FileLog_Undef";
|
2007-03-27 14:51:29 +00:00
|
|
|
$hash->{NotifyFn} = "FileLog_Log";
|
|
|
|
$hash->{AttrFn} = "FileLog_Attr";
|
2007-05-24 11:30:25 +00:00
|
|
|
# logtype is used by the frontend
|
|
|
|
$hash->{AttrList} = "disable:0,1 logtype nrarchive archivedir archivecmd";
|
2007-03-27 14:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#####################################
|
|
|
|
sub
|
|
|
|
FileLog_Define($@)
|
|
|
|
{
|
|
|
|
my ($hash, $def) = @_;
|
|
|
|
my @a = split("[ \t][ \t]*", $def);
|
|
|
|
my $fh;
|
|
|
|
|
|
|
|
return "wrong syntax: define <name> FileLog filename regexp" if(int(@a) != 4);
|
|
|
|
|
|
|
|
eval { "Hallo" =~ m/^$a[3]$/ };
|
|
|
|
return "Bad regexp: $@" if($@);
|
|
|
|
|
|
|
|
my @t = localtime;
|
|
|
|
my $f = ResolveDateWildcards($a[2], @t);
|
|
|
|
$fh = new IO::File ">>$f";
|
2008-08-08 10:46:25 +00:00
|
|
|
return "Can't open $f: $!" if(!defined($fh));
|
2007-03-27 14:51:29 +00:00
|
|
|
|
|
|
|
$hash->{FH} = $fh;
|
|
|
|
$hash->{REGEXP} = $a[3];
|
2007-08-06 18:17:29 +00:00
|
|
|
$hash->{logfile} = $a[2];
|
|
|
|
$hash->{currentlogfile} = $f;
|
2007-03-27 14:51:29 +00:00
|
|
|
$hash->{STATE} = "active";
|
|
|
|
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
|
|
|
|
#####################################
|
|
|
|
sub
|
|
|
|
FileLog_Undef($$)
|
|
|
|
{
|
|
|
|
my ($hash, $name) = @_;
|
|
|
|
close($hash->{FH});
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
|
|
|
|
#####################################
|
|
|
|
sub
|
|
|
|
FileLog_Log($$)
|
|
|
|
{
|
|
|
|
# Log is my entry, Dev is the entry of the changed device
|
|
|
|
my ($log, $dev) = @_;
|
|
|
|
|
|
|
|
my $ln = $log->{NAME};
|
|
|
|
return if($attr{$ln} && $attr{$ln}{disable});
|
|
|
|
|
|
|
|
my $n = $dev->{NAME};
|
|
|
|
my $re = $log->{REGEXP};
|
|
|
|
my $max = int(@{$dev->{CHANGED}});
|
|
|
|
for (my $i = 0; $i < $max; $i++) {
|
|
|
|
my $s = $dev->{CHANGED}[$i];
|
|
|
|
$s = "" if(!defined($s));
|
|
|
|
if($n =~ m/^$re$/ || "$n:$s" =~ m/^$re$/) {
|
|
|
|
my $t = TimeNow();
|
|
|
|
$t = $dev->{CHANGETIME}[$i] if(defined($dev->{CHANGETIME}[$i]));
|
2009-12-22 11:00:54 +00:00
|
|
|
$t =~ s/ /_/o; # Makes it easier to parse with gnuplot
|
2007-03-27 14:51:29 +00:00
|
|
|
|
|
|
|
my $fh = $log->{FH};
|
|
|
|
my @t = localtime;
|
2007-08-06 18:17:29 +00:00
|
|
|
my $cn = ResolveDateWildcards($log->{logfile}, @t);
|
2007-03-27 14:51:29 +00:00
|
|
|
|
2007-08-06 18:17:29 +00:00
|
|
|
if($cn ne $log->{currentlogfile}) { # New logfile
|
2007-03-27 14:51:29 +00:00
|
|
|
$fh->close();
|
2007-05-24 11:30:25 +00:00
|
|
|
HandleArchiving($log);
|
2007-03-27 14:51:29 +00:00
|
|
|
$fh = new IO::File ">>$cn";
|
|
|
|
if(!defined($fh)) {
|
|
|
|
Log(0, "Can't open $cn");
|
|
|
|
return;
|
|
|
|
}
|
2007-08-06 18:17:29 +00:00
|
|
|
$log->{currentlogfile} = $cn;
|
2007-03-27 14:51:29 +00:00
|
|
|
$log->{FH} = $fh;
|
|
|
|
}
|
|
|
|
|
|
|
|
print $fh "$t $n $s\n";
|
|
|
|
$fh->flush;
|
2008-05-11 17:28:58 +00:00
|
|
|
$fh->sync if !($^O eq 'MSWin32'); #not implemented in Windows
|
2007-03-27 14:51:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2008-05-09 13:58:10 +00:00
|
|
|
###################################
|
2007-03-27 14:51:29 +00:00
|
|
|
sub
|
|
|
|
FileLog_Attr(@)
|
|
|
|
{
|
|
|
|
my @a = @_;
|
|
|
|
my $do = 0;
|
|
|
|
|
|
|
|
if($a[0] eq "set" && $a[2] eq "disable") {
|
|
|
|
$do = (!defined($a[3]) || $a[3]) ? 1 : 2;
|
|
|
|
}
|
|
|
|
$do = 2 if($a[0] eq "del" && (!$a[2] || $a[2] eq "disable"));
|
|
|
|
return if(!$do);
|
|
|
|
|
|
|
|
$defs{$a[1]}{STATE} = ($do == 1 ? "disabled" : "active");
|
|
|
|
|
|
|
|
return undef;
|
|
|
|
}
|
2008-05-09 13:58:10 +00:00
|
|
|
|
|
|
|
###################################
|
|
|
|
sub
|
|
|
|
FileLog_Set($@)
|
|
|
|
{
|
|
|
|
my ($hash, @a) = @_;
|
|
|
|
|
|
|
|
return "no set argument specified" if(int(@a) != 2);
|
|
|
|
return "Unknown argument $a[1], choose one of reopen"
|
|
|
|
if($a[1] ne "reopen");
|
|
|
|
|
|
|
|
my $fh = $hash->{FH};
|
|
|
|
my $cn = $hash->{currentlogfile};
|
|
|
|
$fh->close();
|
|
|
|
$fh = new IO::File ">>$cn";
|
|
|
|
return "Can't open $cn" if(!defined($fh));
|
|
|
|
$hash->{FH} = $fh;
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
|
|
|
|
###################################
|
2008-06-12 07:22:59 +00:00
|
|
|
# We use this function to be able to scroll/zoom in the plots created from the
|
|
|
|
# logfile. When outfile is specified, it is used with gnuplot post-processing,
|
|
|
|
# when outfile is "-" it is used to create SVG graphics
|
|
|
|
#
|
|
|
|
# Up till now following functions are impemented:
|
|
|
|
# - int (to cut off % from a number, as for the actuator)
|
|
|
|
# - delta-h / delta-d to get rain/h and rain/d values from continuous data.
|
2009-04-10 09:54:37 +00:00
|
|
|
#
|
|
|
|
# It will set the %data values
|
2010-04-02 10:22:38 +00:00
|
|
|
# min<x>, max<x>, avg<x>, cnt<x>, lastd<x>, lastv<x>, sum<x>
|
2009-04-10 09:54:37 +00:00
|
|
|
# for each requested column, beggining with <x> = 1
|
2008-06-12 07:22:59 +00:00
|
|
|
|
2008-05-09 13:58:10 +00:00
|
|
|
sub
|
|
|
|
FileLog_Get($@)
|
|
|
|
{
|
|
|
|
my ($hash, @a) = @_;
|
|
|
|
|
2008-07-11 07:25:31 +00:00
|
|
|
return "Usage: get $a[0] <infile> <outfile> <from> <to> <column_spec>...\n".
|
|
|
|
" where column_spec is <col>:<regexp>:<default>:<fn>\n" .
|
2008-06-12 07:22:59 +00:00
|
|
|
" see the FileLogGrep entries in he .gplot files\n" .
|
|
|
|
" <infile> is without direcory, - means the current file\n" .
|
|
|
|
" <outfile> is a prefix, - means stdout\n"
|
|
|
|
if(int(@a) < 5);
|
|
|
|
shift @a;
|
|
|
|
my $inf = shift @a;
|
|
|
|
my $outf = shift @a;
|
|
|
|
my $from = shift @a;
|
2008-07-11 07:25:31 +00:00
|
|
|
my $to = shift @a; # Now @a contains the list of column_specs
|
2008-07-24 07:39:15 +00:00
|
|
|
my $internal;
|
|
|
|
if($outf eq "INT") {
|
|
|
|
$outf = "-";
|
|
|
|
$internal = 1;
|
|
|
|
}
|
2008-06-12 07:22:59 +00:00
|
|
|
|
|
|
|
if($inf eq "-") {
|
|
|
|
$inf = $hash->{currentlogfile};
|
|
|
|
} else {
|
2009-12-22 11:00:54 +00:00
|
|
|
my $linf = "$1/$inf" if($hash->{currentlogfile} =~ m,^(.*)/[^/]*$,o);
|
2008-06-12 07:22:59 +00:00
|
|
|
if(!-f $linf) {
|
|
|
|
$linf = $attr{$hash->{NAME}}{archivedir} . "/" . $inf;
|
2010-03-13 11:22:13 +00:00
|
|
|
return "Error: cannot access $linf" if(!-f $linf);
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
|
|
|
$inf = $linf;
|
|
|
|
}
|
|
|
|
my $ifh = new IO::File $inf;
|
|
|
|
seekTo($inf, $ifh, $hash, $from);
|
|
|
|
|
|
|
|
#############
|
|
|
|
# Digest the input.
|
|
|
|
# last1: first delta value after d/h change
|
|
|
|
# last2: last delta value recorded (for the very last entry)
|
|
|
|
# last3: last delta timestamp (d or h)
|
|
|
|
my (@d, @fname);
|
2009-04-10 09:54:37 +00:00
|
|
|
my (@min, @max, @sum, @cnt, @lastv, @lastd);
|
|
|
|
|
2008-06-12 07:22:59 +00:00
|
|
|
for(my $i = 0; $i < int(@a); $i++) {
|
2008-07-11 07:25:31 +00:00
|
|
|
my @fld = split(":", $a[$i], 4);
|
2008-06-12 07:22:59 +00:00
|
|
|
|
|
|
|
my %h;
|
|
|
|
if($outf ne "-") {
|
|
|
|
$fname[$i] = "$outf.$i";
|
|
|
|
$h{fh} = new IO::File "> $fname[$i]";
|
|
|
|
}
|
2009-04-10 09:54:37 +00:00
|
|
|
$h{re} = $fld[1]; # Filter: regexp
|
|
|
|
$h{df} = defined($fld[2]) ? $fld[2] : ""; # default value
|
|
|
|
$h{fn} = $fld[3]; # function
|
|
|
|
$h{didx} = 10 if($fld[3] && $fld[3] eq "delta-d"); # delta idx, substr len
|
2008-07-11 07:25:31 +00:00
|
|
|
$h{didx} = 13 if($fld[3] && $fld[3] eq "delta-h");
|
2008-06-12 07:22:59 +00:00
|
|
|
|
2009-12-22 11:00:54 +00:00
|
|
|
if($fld[0] =~ m/"(.*)"/o) {
|
2008-06-12 07:22:59 +00:00
|
|
|
$h{col} = $1;
|
2008-07-28 12:33:29 +00:00
|
|
|
$h{type} = 0;
|
2008-06-12 07:22:59 +00:00
|
|
|
} else {
|
|
|
|
$h{col} = $fld[0]-1;
|
2008-07-28 12:33:29 +00:00
|
|
|
$h{type} = 1;
|
|
|
|
}
|
|
|
|
if($h{fn}) {
|
|
|
|
$h{type} = 4;
|
|
|
|
$h{type} = 2 if($h{didx});
|
|
|
|
$h{type} = 3 if($h{fn} eq "int");
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
2008-07-11 07:25:31 +00:00
|
|
|
$h{ret} = "";
|
2008-06-12 07:22:59 +00:00
|
|
|
$d[$i] = \%h;
|
2009-04-10 09:54:37 +00:00
|
|
|
$min[$i] = 999999;
|
|
|
|
$max[$i] = -999999;
|
|
|
|
$sum[$i] = 0;
|
|
|
|
$cnt[$i] = 0;
|
|
|
|
$lastv[$i] = 0;
|
|
|
|
$lastd[$i] = "undef";
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
my %lastdate;
|
2008-08-08 10:46:25 +00:00
|
|
|
my $d; # Used by eval functions
|
2008-06-12 07:22:59 +00:00
|
|
|
while(my $l = <$ifh>) {
|
2009-01-02 09:32:08 +00:00
|
|
|
next if($l lt $from);
|
2008-06-12 07:22:59 +00:00
|
|
|
last if($l gt $to);
|
2008-07-24 07:39:15 +00:00
|
|
|
my @fld = split("[ \r\n]+", $l); # 40%
|
|
|
|
|
2008-07-11 07:25:31 +00:00
|
|
|
for my $i (0..int(@a)-1) { # Process each req. field
|
2008-06-12 07:22:59 +00:00
|
|
|
my $h = $d[$i];
|
2010-06-04 06:48:59 +00:00
|
|
|
my @missingvals;
|
2008-07-28 12:33:29 +00:00
|
|
|
next if($h->{re} && $l !~ m/$h->{re}/); # 20%
|
2008-06-12 07:22:59 +00:00
|
|
|
|
|
|
|
my $col = $h->{col};
|
2008-07-28 12:33:29 +00:00
|
|
|
my $t = $h->{type};
|
2008-06-12 07:22:59 +00:00
|
|
|
|
2009-04-10 09:54:37 +00:00
|
|
|
my $val = undef;
|
|
|
|
my $dte = $fld[0];
|
|
|
|
|
2008-07-28 12:33:29 +00:00
|
|
|
if($t == 0) { # Fixed text
|
2009-04-10 09:54:37 +00:00
|
|
|
$val = $col;
|
2008-06-12 07:22:59 +00:00
|
|
|
|
2008-07-28 12:33:29 +00:00
|
|
|
} elsif($t == 1) { # The column
|
2009-04-10 09:54:37 +00:00
|
|
|
$val = $fld[$col] if(defined($fld[$col]));
|
2008-07-28 12:33:29 +00:00
|
|
|
|
|
|
|
} elsif($t == 2) { # delta-h or delta-d
|
2008-06-12 07:22:59 +00:00
|
|
|
|
2010-03-14 11:33:54 +00:00
|
|
|
my $hd = $h->{didx}; # TimeStamp-Length
|
|
|
|
my $ld = substr($fld[0],0,$hd); # TimeStamp-Part (hour or date)
|
2008-07-11 07:25:31 +00:00
|
|
|
if(!defined($h->{last1}) || $h->{last3} ne $ld) {
|
2008-06-12 07:22:59 +00:00
|
|
|
if(defined($h->{last1})) {
|
|
|
|
my @lda = split("[_:]", $lastdate{$hd});
|
2010-03-14 11:33:54 +00:00
|
|
|
my $ts = "12:00:00"; # middle timestamp
|
2008-07-11 07:25:31 +00:00
|
|
|
$ts = "$lda[1]:30:00" if($hd == 13);
|
|
|
|
my $v = $fld[$col]-$h->{last1};
|
2010-03-14 11:33:54 +00:00
|
|
|
$v = 0 if($v < 0); # Skip negative delta
|
2009-04-10 09:54:37 +00:00
|
|
|
$dte = "$lda[0]_$ts";
|
|
|
|
$val = sprintf("%0.1f", $v);
|
2010-06-04 06:48:59 +00:00
|
|
|
if($hd == 13) { # Generate missing 0 values / hour
|
|
|
|
my @cda = split("[_:]", $ld);
|
|
|
|
for(my $mi = $lda[1]+1; $mi < $cda[1]; $mi++) {
|
|
|
|
push @missingvals, sprintf("%s_%02d:30:00 0\n", $lda[0], $mi);
|
|
|
|
}
|
|
|
|
}
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
|
|
|
$h->{last1} = $fld[$col];
|
2008-07-11 07:25:31 +00:00
|
|
|
$h->{last3} = $ld;
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
|
|
|
$h->{last2} = $fld[$col];
|
|
|
|
$lastdate{$hd} = $fld[0];
|
2010-06-04 06:48:59 +00:00
|
|
|
|
2008-07-28 12:33:29 +00:00
|
|
|
} elsif($t == 3) { # int function
|
2009-12-22 11:00:54 +00:00
|
|
|
$val = $1 if($fld[$col] =~ m/^(\d+).*/o);
|
2008-07-11 07:25:31 +00:00
|
|
|
|
2008-07-28 12:33:29 +00:00
|
|
|
} else { # evaluate
|
2011-04-22 08:16:02 +00:00
|
|
|
|
2009-04-10 09:54:37 +00:00
|
|
|
$val = eval($h->{fn});
|
|
|
|
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
2009-04-10 09:54:37 +00:00
|
|
|
|
2009-12-21 18:03:56 +00:00
|
|
|
next if(!defined($val) || $val !~ m/^[-\.\d]+$/o);
|
2009-04-10 09:54:37 +00:00
|
|
|
$min[$i] = $val if($val < $min[$i]);
|
|
|
|
$max[$i] = $val if($val > $max[$i]);
|
|
|
|
$sum[$i] += $val;
|
|
|
|
$cnt[$i]++;
|
|
|
|
$lastv[$i] = $val;
|
|
|
|
$lastd[$i] = $dte;
|
2010-06-04 06:48:59 +00:00
|
|
|
foreach my $mval (@missingvals) {
|
|
|
|
$cnt[$i]++;
|
|
|
|
$min[$i] = 0 if(0 < $min[$i]);
|
|
|
|
}
|
2008-06-12 07:22:59 +00:00
|
|
|
|
|
|
|
if($outf eq "-") {
|
2009-04-10 09:54:37 +00:00
|
|
|
$h->{ret} .= "$dte $val\n";
|
2010-06-04 06:48:59 +00:00
|
|
|
foreach my $mval (@missingvals) { $h->{ret} .= $mval }
|
2008-06-12 07:22:59 +00:00
|
|
|
} else {
|
2009-04-10 09:54:37 +00:00
|
|
|
my $fh = $h->{fh}; # cannot use $h->{fh} in print directly
|
|
|
|
print $fh "$dte $val\n";
|
2010-06-04 06:48:59 +00:00
|
|
|
foreach my $mval (@missingvals) { print $fh $mval }
|
2008-07-28 12:33:29 +00:00
|
|
|
$h->{count}++;
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
2010-06-04 06:48:59 +00:00
|
|
|
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
$ifh->close();
|
|
|
|
|
|
|
|
my $ret = "";
|
|
|
|
for(my $i = 0; $i < int(@a); $i++) {
|
|
|
|
my $h = $d[$i];
|
|
|
|
my $hd = $h->{didx};
|
|
|
|
if($hd && $lastdate{$hd}) {
|
2010-03-14 11:33:54 +00:00
|
|
|
my $val = defined($h->{last1}) ? $h->{last2}-$h->{last1} : 0;
|
|
|
|
$min[$i] = $val if($min[$i] == 999999);
|
|
|
|
$max[$i] = $val if($max[$i] == -999999);
|
|
|
|
$lastv[$i] = $val if(!$lastv[$i]);
|
2010-04-02 10:22:38 +00:00
|
|
|
$sum[$i] = ($sum[$i] ? $sum[$i] + $val : $val);
|
|
|
|
$cnt[$i]++;
|
2008-06-12 07:22:59 +00:00
|
|
|
|
|
|
|
my @lda = split("[_:]", $lastdate{$hd});
|
|
|
|
my $ts = "12:00:00"; # middle timestamp
|
2008-07-12 08:16:51 +00:00
|
|
|
$ts = "$lda[1]:30:00" if($hd == 13);
|
2008-07-11 07:25:31 +00:00
|
|
|
my $line = sprintf("%s_%s %0.1f\n", $lda[0],$ts, $h->{last2}-$h->{last1});
|
2008-06-12 07:22:59 +00:00
|
|
|
|
|
|
|
if($outf eq "-") {
|
2008-07-11 07:25:31 +00:00
|
|
|
$h->{ret} .= $line;
|
2008-06-12 07:22:59 +00:00
|
|
|
} else {
|
|
|
|
my $fh = $h->{fh};
|
2008-07-11 07:25:31 +00:00
|
|
|
print $fh $line;
|
|
|
|
$h->{count}++;
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if($outf eq "-") {
|
2008-07-28 12:33:29 +00:00
|
|
|
$h->{ret} .= "$from $h->{df}\n" if(!$h->{ret} && $h->{df} ne "");
|
2008-07-11 07:25:31 +00:00
|
|
|
$ret .= $h->{ret} if($h->{ret});
|
|
|
|
$ret .= "#$a[$i]\n";
|
2008-06-12 07:22:59 +00:00
|
|
|
} else {
|
2008-07-11 07:25:31 +00:00
|
|
|
my $fh = $h->{fh};
|
|
|
|
if(!$h->{count} && $h->{df} ne "") {
|
|
|
|
print $fh "$from $h->{df}\n";
|
|
|
|
}
|
|
|
|
$fh->close();
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
2009-04-10 09:54:37 +00:00
|
|
|
|
|
|
|
my $j = $i+1;
|
|
|
|
$data{"min$j"} = $min[$i] == 999999 ? "undef" : $min[$i];
|
|
|
|
$data{"max$j"} = $max[$i] == -999999 ? "undef" : $max[$i];
|
|
|
|
$data{"avg$j"} = $cnt[$i] ? sprintf("%0.1f", $sum[$i]/$cnt[$i]) : "undef";
|
2010-03-23 09:03:04 +00:00
|
|
|
$data{"sum$j"} = $sum[$i];
|
2009-04-10 09:54:37 +00:00
|
|
|
$data{"cnt$j"} = $cnt[$i] ? $cnt[$i] : "undef";
|
|
|
|
$data{"currval$j"} = $lastv[$i];
|
|
|
|
$data{"currdate$j"} = $lastd[$i];
|
|
|
|
|
2008-05-09 13:58:10 +00:00
|
|
|
}
|
2008-07-24 07:39:15 +00:00
|
|
|
if($internal) {
|
|
|
|
$internal_data = \$ret;
|
2008-08-08 10:46:25 +00:00
|
|
|
return undef;
|
2008-07-24 07:39:15 +00:00
|
|
|
}
|
2008-05-09 13:58:10 +00:00
|
|
|
|
2008-06-12 07:22:59 +00:00
|
|
|
return ($outf eq "-") ? $ret : join(" ", @fname);
|
2008-05-09 13:58:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
###################################
|
|
|
|
sub
|
2008-06-12 07:22:59 +00:00
|
|
|
seekTo($$$$)
|
2008-05-09 13:58:10 +00:00
|
|
|
{
|
2008-06-12 07:22:59 +00:00
|
|
|
my ($fname, $fh, $hash, $ts) = @_;
|
2008-05-09 13:58:10 +00:00
|
|
|
|
|
|
|
# If its cached
|
2008-06-12 07:22:59 +00:00
|
|
|
if($hash->{pos} && $hash->{pos}{"$fname:$ts"}) {
|
|
|
|
$fh->seek($hash->{pos}{"$fname:$ts"}, 0);
|
2008-05-09 13:58:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$fh->seek(0, 2); # Go to the end
|
|
|
|
my $upper = $fh->tell;
|
|
|
|
|
|
|
|
my ($lower, $next, $last) = (0, $upper/2, 0);
|
2009-01-02 09:32:08 +00:00
|
|
|
my $div = 2;
|
2008-05-09 13:58:10 +00:00
|
|
|
while() { # Binary search
|
|
|
|
$fh->seek($next, 0);
|
|
|
|
my $data = <$fh>;
|
2009-01-02 09:32:08 +00:00
|
|
|
if(!$data) {
|
|
|
|
$last = $next;
|
|
|
|
last;
|
|
|
|
}
|
2009-12-22 11:00:54 +00:00
|
|
|
if($data !~ m/^\d\d\d\d-\d\d-\d\d_\d\d:\d\d:\d\d /o) {
|
2008-05-09 13:58:10 +00:00
|
|
|
$next = $fh->tell;
|
|
|
|
$data = <$fh>;
|
2008-07-11 07:25:31 +00:00
|
|
|
if(!$data) {
|
|
|
|
$last = $next;
|
|
|
|
last;
|
|
|
|
}
|
2009-01-02 09:32:08 +00:00
|
|
|
|
|
|
|
# If the second line is longer then the first,
|
|
|
|
# binary search will never get it:
|
2009-12-27 18:12:13 +00:00
|
|
|
if($next eq $last && $data ge $ts && $div < 8192 && $next < 1024) {
|
2009-01-02 09:32:08 +00:00
|
|
|
$last = 0;
|
|
|
|
$div *= 2;
|
|
|
|
}
|
2008-06-12 07:22:59 +00:00
|
|
|
}
|
|
|
|
if($next eq $last) {
|
|
|
|
$fh->seek($next, 0);
|
|
|
|
last;
|
2008-05-09 13:58:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$last = $next;
|
2008-06-12 07:22:59 +00:00
|
|
|
if(!$data || $data lt $ts) {
|
2009-01-02 09:32:08 +00:00
|
|
|
($lower, $next) = ($next, int(($next+$upper)/$div));
|
2008-05-09 13:58:10 +00:00
|
|
|
} else {
|
2009-01-02 09:32:08 +00:00
|
|
|
($upper, $next) = ($next, int(($lower+$next)/$div));
|
2008-05-09 13:58:10 +00:00
|
|
|
}
|
|
|
|
}
|
2008-06-12 07:22:59 +00:00
|
|
|
$hash->{pos}{"$fname:$ts"} = $last;
|
2008-05-09 13:58:10 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-03-27 14:51:29 +00:00
|
|
|
1;
|