1 # Copyright (C) 2002 Stanislav Sinyagin
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17 # $Id: DataAccess.pm,v 1.1 2010-12-27 00:03:39 ivan Exp $
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
20 package Torrus::DataAccess;
22 use Torrus::ConfigTree;
29 # The Torrus::DataAccess object contains cached values, and it does not
30 # check the cache validity. We assume that a Torrus::DataAccess object
31 # lifetime is within a short period of time, such as one monitor cycle.
41 # Read the data from datasource file, depending on its type.
42 # If time is not specified, reads the latest available data.
43 # In case of rrd-cdef leaf type, the returned timestamp is the
44 # earliest timestamp of the data sources involved.
46 # ($value, $timestamp) = $da->read( $config_tree, $leaf_token )
48 # ($value, $timestamp) = $da->read( $config_tree, $leaf_token, $end_time )
50 # ($value, $timestamp) = $da->read( $config_tree, $leaf_token,
51 # $end_time, $start_time )
57 my $config_tree = shift;
62 my $cachekey = $token .
63 ':' . (defined($t_end)?$t_end:'') .
64 ':' . (defined($t_start)?$t_start:'');
66 if( exists( $self->{'cache_read'}{$cachekey} ) )
68 return @{$self->{'cache_read'}{$cachekey}};
71 if( not $config_tree->isLeaf( $token ) )
73 my $path = $config_tree->path( $token );
74 Error("Torrus::DataAccess::readLast: $path is not a leaf");
81 my $ds_type = $config_tree->getNodeParam( $token, 'ds-type' );
82 if( $ds_type eq 'rrd-file' or
83 $ds_type eq 'collector' )
85 my $leaf_type = $config_tree->getNodeParam( $token, 'leaf-type' );
87 if( $leaf_type eq 'rrd-def' )
89 my $file = $config_tree->getNodeParam( $token, 'data-file' );
90 my $dir = $config_tree->getNodeParam( $token, 'data-dir' );
91 my $ds = $config_tree->getNodeParam( $token, 'rrd-ds' );
92 my $cf = $config_tree->getNodeParam( $token, 'rrd-cf' );
93 ( $ret_val, $ret_time ) =
94 $self->read_RRD_DS( $dir.'/'.$file,
95 $cf, $ds, $t_end, $t_start );
97 elsif( $leaf_type eq 'rrd-cdef' )
99 my $expr = $config_tree->getNodeParam( $token, 'rpn-expr' );
100 ( $ret_val, $ret_time ) =
101 $self->read_RPN( $config_tree, $token, $expr,
107 my $path = $config_tree->path( $token );
108 Error("$path: leaf-type $leaf_type is not supported ".
114 my $path = $config_tree->path( $token );
115 Error("$path: ds-type $ds_type is not supported ".
119 $self->{'cache_read'}{$cachekey} = [ $ret_val, $ret_time ];
120 return ( $ret_val, $ret_time );
127 my $filename = shift;
133 my $cachekey = $filename . ':' . $cf .
134 ':' . (defined($t_end)?$t_end:'') .
135 ':' . (defined($t_start)?$t_start:'');
137 if( exists( $self->{'cache_RRD'}{$cachekey}{$ds} ) )
139 return @{$self->{'cache_RRD'}{$cachekey}{$ds}};
142 my $rrdinfo = RRDs::info( $filename );
143 my $ERR = RRDs::error;
146 Error("Error during RRD info for $filename: $ERR");
150 my $step = $rrdinfo->{'step'};
151 my $last_available = $rrdinfo->{'last_update'};
152 $last_available -= $last_available % $step;
154 if( not defined $t_end )
156 $t_end = $last_available;
158 elsif( index( $t_end, 'LAST' ) >= 0 )
160 $t_end =~ s/LAST/$last_available/g;
163 if( not defined $t_start )
165 $t_start = $t_end . '-' . int($step * 3);
167 elsif( index( $t_start, 'LAST' ) >= 0 )
169 $t_start =~ s/LAST/$last_available/g;
172 # From here on, f_ prefix means fetch results
173 my( $f_start, $f_step, $f_names, $f_data ) =
174 RRDs::fetch( $filename, $cf, '--start', $t_start, '--end', $t_end );
178 Error("Error during RRD fetch for $filename: $ERR");
183 # Memorize the DS names in cache
185 for( my $i = 0; $i < @{$f_names}; $i++ )
187 $self->{'cache_RRD'}{$cachekey}{$f_names->[$i]} = [];
190 # Get the last available data and store in cache
192 foreach my $f_line ( @{$f_data} )
194 for( my $i = 0; $i < @{$f_names}; $i++ )
196 if( defined $f_line->[$i] )
198 $self->{'cache_RRD'}{$cachekey}{$f_names->[$i]} =
199 [ $f_line->[$i], $f_start ];
205 if( not exists( $self->{'cache_RRD'}{$cachekey}{$ds} ) )
207 Error("DS name $ds is not found in $filename");
212 if( scalar( @{$self->{'cache_RRD'}{$cachekey}{$ds}} ) == 0 )
214 Warn("Value undefined for ",
215 "DS=$ds, CF=$cf, start=$t_start, end=$t_end in $filename");
220 return @{$self->{'cache_RRD'}{$cachekey}{$ds}};
227 # Data access for other CF than defined for the leaf doesn't make much
228 # sense. So we ignore the CF in DataAccess and leave it for the
229 # sake of Renderer compatibility
240 my $config_tree = shift;
246 my @expr_list = split(',', $expr);
248 my $timestamp = $t_end > 0 ? $t_end : time();
250 my $rpn = new Torrus::RPN;
254 my ($noderef, $timeoffset) = @_;
257 if( $noderef =~ s/^(.)\@// )
262 my $leaf = length($noderef) > 0 ?
263 $config_tree->getRelative($token, $noderef) : $token;
265 if( not defined $leaf )
267 my $path = $config_tree->path($token);
268 Error("Cannot find relative reference $noderef at $path");
272 my ($rval, $var_tstamp) = $self->read($config_tree,
278 if( $var_tstamp == 0 )
280 Warn("Torrus::DataAccess::read retirned zero timestamp ".
284 if( $var_tstamp < $timestamp )
286 $timestamp = $var_tstamp;
290 if( defined( $function ) )
292 if( $function eq 'T' )
296 elsif( not $cfNames{$function} )
298 Error("Function not supported in RPN: $function");
305 my $result = $rpn->run( $expr, $callback );
307 return ( $result, $timestamp );
315 # indent-tabs-mode: nil
316 # perl-indent-level: 4