package YATG::Retrieve::Disk; use strict; use warnings FATAL => 'all'; use Time::Local; use Tie::File::FixedRecLen; use Fcntl 'O_RDONLY'; use integer; sub retrieve { my ($config, $device, $port, $leaf, $start, $end, $step) = @_; my $root = $config->{yatg}->{disk_root}; $port ||= 1; $port =~ s/[^A-Za-z0-9]/./g; # just in case, re-squash port chars my @files = grep {m/\d{4}-\d\d-\d\d_\d\d-\d\d-\d\dZ?,\d+$/} glob("$root/$device/$leaf/$port/*"); die "File not found at '$root/$device/$leaf/$port'\n" if scalar @files == 0; my $filename = (sort @files)[-1]; die "File '$filename' empty!\n" unless -s $filename; my @store; tie @store, 'Tie::File::FixedRecLen', $filename, mode => O_RDONLY, record_length => 20; die "Failed to Tie::File::FixedRecLen file at '$filename'\n" if !tied @store; $filename =~ s#$root/$device/$leaf/$port/##; $filename =~ m/^(\d{4})-(\d\d)-(\d\d)_(\d\d)-(\d\d)-(\d\d)(Z?),(\d+)$/; my $base_time = $7 ? timegm($6,$5,$4,$3,$2-1,$1-1900) : timelocal($6,$5,$4,$3,$2-1,$1-1900); my $interval = $8; my $top_time = $base_time + ($#store * $interval); $step ||= $interval; $start = ($start - ($start % $step)); $end = ($end - ($end % $step)); my $nudge = ($step / $interval); my $num_steps = (($end - $start) / $step); my @data = map {'0'} (0 .. ($num_steps - 1)); # fenceposts! my $data_offset_start = (($start < $base_time) ? (($base_time - $start) / $step) : 0); my $store_offset_start = (($start > $base_time) ? ((($start - $base_time) / $interval)) : 0); my @store_pad = map {$_} ($store_offset_start .. $#store); while (my @chunk = splice @store_pad,0,$nudge) { $data[$data_offset_start] = $store[ $chunk[-1] ] || 0; ++$data_offset_start; last if $data_offset_start > $#data; } untie @store; return \@data; } 1; __END__ =head1 NAME YATG::Retrieve::Disk - Retrieve a set of data stored by YATG::Store::Disk =head1 DESCRIPTION You can load this module to retrieve a set of data which has previously been stored by YATG::Store::Disk. An implementation of this process is given in the CGI bundled with this distribution, which displays results of SNMP polls. For more information on the data storage format, see L. =head1 USAGE There is one subroutine, C which takes seven parameters: =over 4 =item C Load up your C config using the following idiom, and pass the result in this parameter (assuming the file is named C): use YATG::Config; YATG::Config->Defaults->{'no_validation'} = 1; my $yatg_conf = YATG::Config->parse('yatg.yml') || die 'failed to load yatg config'; # now pass in $yatg_conf =item C This should be the IP address of a device. =item C This should be the port name, for example C. =item C This should be the SNMP leaf name (and not the OID), for example C. =item C This should be a UNIX timestamp (i.e. seconds since the epoch) representing the start point for retrieved results. =item C This should be a UNIX timestamp (i.e. seconds since the epoch) representing the end point for retrieved results. =item C This parameter is optional. If not specified, the filename of the result set encodes the polling interval which will then be used for the returned results interval (i.e. one data point per C seconds returned). Alternatively you can pass a number of seconds in this parameter and the module will do its best to provide one data point per C seconds in the returned results. =back The subroutine will die if it encounters difficulty opening the data file or extracting results from it, so use an C construct or similar. Otherwise, the return value is an array reference of results corresponding to the data points you requested with start, end and step. =head1 SEE ALSO =over 4 =item L =back =head1 AUTHOR Oliver Gorwits C<< >> =head1 COPYRIGHT & LICENSE Copyright (c) The University of Oxford 2007. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut