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.
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
20 package Torrus
::DataAccess
;
24 use Torrus
::ConfigTree
;
32 # The Torrus::DataAccess object contains cached values, and it does not
33 # check the cache validity. We assume that a Torrus::DataAccess object
34 # lifetime is within a short period of time, such as one monitor cycle.
44 # Read the data from datasource file, depending on its type.
45 # If time is not specified, reads the latest available data.
46 # In case of rrd-cdef leaf type, the returned timestamp is the
47 # earliest timestamp of the data sources involved.
49 # ($value, $timestamp) = $da->read( $config_tree, $leaf_token )
51 # ($value, $timestamp) = $da->read( $config_tree, $leaf_token, $end_time )
53 # ($value, $timestamp) = $da->read( $config_tree, $leaf_token,
54 # $end_time, $start_time )
60 my $config_tree = shift;
65 my $cachekey = $token .
66 ':' . (defined($t_end)?
$t_end:'') .
67 ':' . (defined($t_start)?
$t_start:'');
69 if( exists( $self->{'cache_read'}{$cachekey} ) )
71 return @
{$self->{'cache_read'}{$cachekey}};
74 if( not $config_tree->isLeaf( $token ) )
76 my $path = $config_tree->path( $token );
77 Error
("Torrus::DataAccess::readLast: $path is not a leaf");
84 my $ds_type = $config_tree->getNodeParam( $token, 'ds-type' );
85 if( $ds_type eq 'rrd-file' or
86 $ds_type eq 'collector' )
88 my $leaf_type = $config_tree->getNodeParam( $token, 'leaf-type' );
90 if( $leaf_type eq 'rrd-def' )
92 my $file = $config_tree->getNodeParam( $token, 'data-file' );
93 my $dir = $config_tree->getNodeParam( $token, 'data-dir' );
94 my $ds = $config_tree->getNodeParam( $token, 'rrd-ds' );
95 my $cf = $config_tree->getNodeParam( $token, 'rrd-cf' );
96 ( $ret_val, $ret_time ) =
97 $self->read_RRD_DS( $dir.'/'.$file,
98 $cf, $ds, $t_end, $t_start );
100 elsif( $leaf_type eq 'rrd-cdef' )
102 my $expr = $config_tree->getNodeParam( $token, 'rpn-expr' );
103 ( $ret_val, $ret_time ) =
104 $self->read_RPN( $config_tree, $token, $expr,
110 my $path = $config_tree->path( $token );
111 Error
("$path: leaf-type $leaf_type is not supported ".
117 my $path = $config_tree->path( $token );
118 Error
("$path: ds-type $ds_type is not supported ".
122 $self->{'cache_read'}{$cachekey} = [ $ret_val, $ret_time ];
123 return ( $ret_val, $ret_time );
130 my $filename = shift;
136 my $cachekey = $filename . ':' . $cf .
137 ':' . (defined($t_end)?
$t_end:'') .
138 ':' . (defined($t_start)?
$t_start:'');
140 if( exists( $self->{'cache_RRD'}{$cachekey}{$ds} ) )
142 return @
{$self->{'cache_RRD'}{$cachekey}{$ds}};
145 my $rrdinfo = RRDs
::info
( $filename );
146 my $ERR = RRDs
::error
;
149 Error
("Error during RRD info for $filename: $ERR");
153 my $step = $rrdinfo->{'step'};
154 my $last_available = $rrdinfo->{'last_update'};
155 $last_available -= $last_available % $step;
157 if( not defined $t_end )
159 $t_end = $last_available;
161 elsif( index( $t_end, 'LAST' ) >= 0 )
163 $t_end =~ s/LAST/$last_available/g;
166 if( not defined $t_start )
168 $t_start = $t_end . '-' . int($step * 3);
170 elsif( index( $t_start, 'LAST' ) >= 0 )
172 $t_start =~ s/LAST/$last_available/g;
175 # From here on, f_ prefix means fetch results
176 my( $f_start, $f_step, $f_names, $f_data ) =
177 RRDs
::fetch
( $filename, $cf, '--start', $t_start, '--end', $t_end );
181 Error
("Error during RRD fetch for $filename: $ERR");
186 # Memorize the DS names in cache
188 for( my $i = 0; $i < @
{$f_names}; $i++ )
190 $self->{'cache_RRD'}{$cachekey}{$f_names->[$i]} = [];
193 # Get the last available data and store in cache
195 for my $f_line ( @
{$f_data} )
197 for( my $i = 0; $i < @
{$f_names}; $i++ )
199 if( defined $f_line->[$i] )
201 $self->{'cache_RRD'}{$cachekey}{$f_names->[$i]} =
202 [ $f_line->[$i], $f_start ];
208 if( not exists( $self->{'cache_RRD'}{$cachekey}{$ds} ) )
210 Error
("DS name $ds is not found in $filename");
215 if( scalar( @
{$self->{'cache_RRD'}{$cachekey}{$ds}} ) == 0 )
217 Warn
("Value undefined for ",
218 "DS=$ds, CF=$cf, start=$t_start, end=$t_end in $filename");
223 return @
{$self->{'cache_RRD'}{$cachekey}{$ds}};
230 # Data access for other CF than defined for the leaf doesn't make much
231 # sense. So we ignore the CF in DataAccess and leave it for the
232 # sake of Renderer compatibility
243 my $config_tree = shift;
249 my @expr_list = split(',', $expr);
251 my $timestamp = $t_end > 0 ?
$t_end : time();
253 my $rpn = Torrus
::RPN
->new();
257 my ($noderef, $timeoffset) = @_;
260 if( $noderef =~ s/^(.)\@// )
265 my $leaf = length($noderef) > 0 ?
266 $config_tree->getRelative($token, $noderef) : $token;
268 if( not defined $leaf )
270 my $path = $config_tree->path($token);
271 Error
("Cannot find relative reference $noderef at $path");
275 my ($rval, $var_tstamp) = $self->read($config_tree,
281 if( $var_tstamp == 0 )
283 Warn
("Torrus::DataAccess::read retirned zero timestamp ".
287 if( $var_tstamp < $timestamp )
289 $timestamp = $var_tstamp;
293 if( defined( $function ) )
295 if( $function eq 'T' )
299 elsif( not $cfNames{$function} )
301 Error
("Function not supported in RPN: $function");
308 my $result = $rpn->run( $expr, $callback );
310 return ( $result, $timestamp );
318 # indent-tabs-mode: nil
319 # perl-indent-level: 4