/dev/trunk

To get this branch, use:
bzr branch http://darksoft.org/webbzr/dev/trunk

« back to all changes in this revision

Viewing changes to classes/cache/datainterval.php

  • Committer: Suren A. Chilingaryan
  • Date: 2008-04-02 10:23:22 UTC
  • Revision ID: csa@dside.dyndns.org-20080402102322-okib92sicg2dx3o3
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
 
 
4
/*
 
5
 amount - is used for resolution calculation
 
6
 limit - limits maximal number of points
 
7
*/
 
8
 
 
9
class DATAInterval implements Iterator {
 
10
 var $cache;
 
11
 var $ids;
 
12
 var $ivl;
 
13
 var $amount, $limit, $resolution;
 
14
 
 
15
 var $res;
 
16
 var $row, $next, $lastrow;
 
17
 var $set_minmax;
 
18
 var $combine_ends;
 
19
 
 
20
 var $used_table;
 
21
 
 
22
 var $operation_info;
 
23
 var $use_subseconds;
 
24
 var $postfix;
 
25
 
 
26
 var $flags;
 
27
 
 
28
 function __construct(CACHEDB &$cache, MASK &$mask, INTERVAL &$ivl, $amount, $limit, $resolution, $flags = 0) {
 
29
    $this->cache = &$cache;
 
30
    $this->ids = &$mask->ids;
 
31
    $this->ivl = &$ivl;
 
32
    
 
33
    $this->amount = $amount;
 
34
    $this->limit = $limit;
 
35
    $this->resolution = $resolution;
 
36
    
 
37
    $this->use_subseconds = $this->cache->use_subseconds;
 
38
    
 
39
    $this->operation_info = array();
 
40
    $this->postfix = false;
 
41
 
 
42
    $this->flags = $flags;
 
43
 }
 
44
 
 
45
 function SetOption($option, $value) {
 
46
    $this->$option = $value;
 
47
 } 
 
48
 
 
49
 function SetOptions($options) {
 
50
    foreach ($options as $opt => &$value) {
 
51
        $this->$opt = $value;
 
52
    }
 
53
 }
 
54
 
 
55
 function combine(&$row, &$add, $ratio) {
 
56
        // We ignoring edges for missing calculation
 
57
        
 
58
    for ($i=0;isset($row['mean' . $i]);$i++) {
 
59
        if ($add['min' . $i] < $row['min' . $i])  
 
60
            $row['min' . $i] = $add['min' . $i];
 
61
        if ($add['max' . $i] > $row['max' . $i])
 
62
            $row['max' . $i] = $add['max' . $i];
 
63
 
 
64
//      $row['mean' . $i] = ($row['mean' . $i] + $ratio*$add['mean' . $i]) / (1 + $ratio);
 
65
        if ($add['items']) {
 
66
            $row['mean' . $i] = ($row['items']*$row['mean' . $i] + $add['items']*$add['mean' . $i]) / ($row['items'] + $add['items']);
 
67
        }
 
68
    }
 
69
    
 
70
    $row['items'] += $add['items'];
 
71
    $row['width'] += $add['width'];
 
72
 }
 
73
 
 
74
 function rewind() {
 
75
    global $CACHE_PRECISE_GAPS;
 
76
    
 
77
    if ($this->resolution === false) {
 
78
        $res = $this->cache->resolution->Get($this->ivl, $this->amount);
 
79
    } else {
 
80
        $res = $this->resolution;
 
81
    }
 
82
 
 
83
    $resolution = $this->cache->resolution->GetWindowSize($res);
 
84
 
 
85
    $table = $this->cache->GetTableName($resolution, $this->postfix);
 
86
    
 
87
    $this->operation_info["resolution"] = $resolution;
 
88
 
 
89
    $from = $this->ivl->window_start;
 
90
    $to = $from + $this->ivl->window_size;
 
91
 
 
92
    $combine_ends = false;
 
93
    
 
94
    if ($resolution > 0) {
 
95
        $ifrom = ceil($from);
 
96
        $rem = $ifrom % $resolution;
 
97
        if ($rem) $curfrom = $ifrom + ($resolution - $rem);
 
98
        else $curfrom = $ifrom;
 
99
                
 
100
        $ito = floor($to);
 
101
        $rem = $ito % $resolution;
 
102
        if ($rem) $curto = $ito - ($rem);
 
103
        else $curto = $ito;
 
104
        
 
105
        if ($this->ivl->flexibility) {
 
106
            if ($this->ivl->flexibility == INTERVAL::FLAG_REDUCIBLE) {
 
107
                $from = $curfrom;
 
108
                $to = $curto;
 
109
            } else {
 
110
                if ($from != $curfrom) {
 
111
                    $curfrom -= $resolution;
 
112
                    $from = $curfrom;
 
113
                }
 
114
                if ($to != $curto) {
 
115
                    $curto += $resolution;
 
116
                    $to = $curto;
 
117
                }
 
118
            }
 
119
        }
 
120
        
 
121
        $sqlfrom = $this->cache->SQLTime((int)$curfrom);
 
122
        $sqlto = $this->cache->SQLTime((int)$curto); 
 
123
 
 
124
        if (($from != $curfrom)||($to != $curto)) {
 
125
            $list = ""; $i = 0;
 
126
            foreach ($this->ids as $id) {
 
127
                $list = "MIN(v$id) AS min$i, MAX(v$id) AS max$i, AVG(v$id) AS mean$i";
 
128
                $i++;
 
129
            }
 
130
            $rawtable = $this->cache->GetTableName(0, $this->postfix);
 
131
        }
 
132
        
 
133
        $points = ($curto - $curfrom) / $resolution;
 
134
        $additional_points = 0;
 
135
        
 
136
        if ($from != $curfrom) {
 
137
            $sqltime = $this->cache->SQLTime($from);
 
138
 
 
139
            $width = $curfrom - $from;
 
140
 
 
141
//          $res = mysql_query("SELECT UNIX_TIMESTAMP(MIN(time)) AS timestamp $list FROM `$rawtable` WHERE `time` BETWEEN $sqltime AND $sqlfrom", $this->cache->dbh);
 
142
            $res = mysql_query("SELECT UNIX_TIMESTAMP(MIN(time)) AS timestamp, COUNT(*) AS items, $width AS width $list FROM `$rawtable` WHERE (`time` >= $sqltime) AND (`time` < $sqlfrom)", $this->cache->dbh);
 
143
            if ($res) {
 
144
                $firstrow = mysql_fetch_assoc($res);
 
145
                if (($firstrow)&&($firstrow['time'])) $additional_points++;
 
146
                else $firstrow = false;
 
147
 
 
148
                mysql_free_result($res);
 
149
            } else $firstrow = false;
 
150
        } else $firstrow = false;
 
151
        
 
152
        if ($to != $curto) {
 
153
            $sqltime = $this->cache->SQLTime($to);
 
154
            
 
155
            $width = $to - $curto;
 
156
            
 
157
//          $res = mysql_query("SELECT UNIX_TIMESTAMP(MIN(time)) AS timestamp $list FROM `$rawtable` WHERE `time` BETWEEN $sqlto AND $sqltime", $this->cache->dbh);
 
158
            $res = mysql_query("SELECT UNIX_TIMESTAMP(MIN(time)) AS timestamp, COUNT(*) AS items, $width AS width $list FROM `$rawtable` WHERE (`time` >= $sqlto) AND (`time` < $sqltime)", $this->cache->dbh);
 
159
            if ($res) {
 
160
                $this->lastrow = mysql_fetch_assoc($res);
 
161
                if (($this->lastrow)&&($this->lastrow['time'])) $additional_points++;
 
162
                else $this->lastrow = false;
 
163
                
 
164
                mysql_free_result($res);
 
165
            } else $this->lastrow = false;
 
166
        } else $this->lastrow = false;
 
167
 
 
168
        if (($this->limit)&&(($points + $aditional_points) > $this->limit)) {
 
169
            if ($additional_points) {
 
170
                if ($this->limit > 9) {
 
171
                    $limit = $this->limit - $aditional_points;
 
172
                } else {
 
173
                    $limit = $this->limit;
 
174
                    $this->combine_ends = true;
 
175
                }
 
176
            } else {
 
177
                $limit = $this->limit;
 
178
            }
 
179
            
 
180
            for ($grouping = $resolution; $points > $limit; $points /= 2) {
 
181
                $grouping *= 2;
 
182
            }
 
183
        } else $grouping = 0;
 
184
        
 
185
        $i = 0;
 
186
        $this->set_minmax = 0;
 
187
 
 
188
 
 
189
        if ($grouping) {
 
190
            $grouping = "GROUP BY FLOOR((UNIX_TIMESTAMP(`time`) - " . ((int)$curfrom) . " )/$grouping)";
 
191
            $list = "UNIX_TIMESTAMP(MIN(time)) AS timestamp, SUM(n) AS items, COUNT(*)*$resolution AS width";
 
192
            if ($this->flags&CACHE::MISSING_INFO) {
 
193
                if ($CACHE_PRECISE_GAPS) {
 
194
                    throw new ADEIException(translate("CACHE_PRECISE_GAPS is not supported yet"));
 
195
                } else {
 
196
                    $val = "FLOOR(COUNT(*)  / (1 + COUNT(*) - SUM(n = 0)))*$resolution";
 
197
                    $list .= ", IF($val > MAX(missing), $val, MAX(missing)) AS maxgap";
 
198
                }
 
199
            }
 
200
 
 
201
            if ($this->flags&CACHE::TRUNCATE_INTERVALS) {
 
202
                foreach ($this->ids as $id) {
 
203
                    $list .= ", MIN(min$id) AS min$i, MAX(max$id) AS max$i, AVG(mean$id) AS mean$i";
 
204
                    $i++;
 
205
                }
 
206
 
 
207
                if ($this->flags&CACHE::REPORT_EMPTY) {
 
208
                    $grouping .= ", n=0";
 
209
                    $cond = "WHERE ((`time` >= $sqlfrom) AND (`time` < $sqlto))";
 
210
                } else {
 
211
                    $cond = "WHERE ((`time` >= $sqlfrom) AND (`time` < $sqlto) AND (`n` > 0))";
 
212
                }
 
213
            } else {
 
214
                if (!($this->flags&CACHE::REPORT_EMPTY)) $grouping .= " HAVING(`items` > 0)";
 
215
 
 
216
                foreach ($this->ids as $id) {
 
217
                    $list .= ", MIN(IF(n,min$id,NULL)) AS min$i, MAX(IF(n,max$id,NULL)) AS max$i, AVG(IF(n,mean$id,NULL)) AS mean$i";
 
218
                    $i++;
 
219
                }
 
220
 
 
221
                $cond = "WHERE ((`time` >= $sqlfrom) AND (`time` < $sqlto))";
 
222
            }
 
223
            
 
224
        } else {
 
225
            $list = "UNIX_TIMESTAMP(time) AS timestamp, n AS items, $resolution AS width";
 
226
            if ($this->flags&CACHE::MISSING_INFO) {
 
227
                $list .= ", missing AS maxgap";
 
228
            }
 
229
            foreach ($this->ids as $id) {
 
230
                $list .= ", min$id AS min$i, max$id AS max$i, mean$id AS mean$i";
 
231
                $i++;
 
232
            }
 
233
            
 
234
            if ($this->flags&CACHE::REPORT_EMPTY)
 
235
                $cond = "WHERE ((`time` >= $sqlfrom) AND (`time` < $sqlto))";
 
236
            else
 
237
                $cond = "WHERE ((`time` >= $sqlfrom) AND (`time` < $sqlto) AND (`n` > 0))";
 
238
        }
 
239
        
 
240
 
 
241
//      $cond = "WHERE `time` BETWEEN $sqlfrom AND $sqlto";
 
242
//      $cond = "WHERE ((`time` >= $sqlfrom) AND (`time` < $sqlto))";
 
243
//      $cond = "WHERE ((`time` >= $sqlfrom) AND (`time` < $sqlto) AND (`n` > 0))";
 
244
        $sort = "ORDER BY `time` ASC";
 
245
    } else {
 
246
        $use_subseconds = false;
 
247
        $list = false; $i = 0;
 
248
        $this->nextrow = false;
 
249
 
 
250
        if ($this->limit) {
 
251
            $limit = $this->limit;
 
252
            $grouping = ($to - $from) / $limit;
 
253
        }
 
254
 
 
255
        if ($grouping) {
 
256
            $ifrom = floor($from);
 
257
 
 
258
            if ($grouping > 1) {
 
259
                $list = "UNIX_TIMESTAMP(MIN(time)) AS timestamp";
 
260
                $groupval = "FLOOR((UNIX_TIMESTAMP(`time`) - " . ((int)$ifrom) . " )/$grouping)";
 
261
                $grouping = "GROUP BY $groupval";
 
262
            } else {
 
263
                if (($grouping < 1)&&($this->use_subseconds)) {
 
264
                    $grouping *= 1000000000; /* in nanoseconds */
 
265
                    if ($grouping > 1) {
 
266
                        $use_subseconds = true;
 
267
                        $rfrom = ($from - $ifrom)*1000000000;
 
268
                    
 
269
                            /* There is should not be MIN arround ns (otherwise problems
 
270
                            when on the edge of the seconds. Should it be on time?*/
 
271
                        $list = "UNIX_TIMESTAMP(MIN(time)) AS timestamp, ns";
 
272
                        $groupval = "FLOOR(((UNIX_TIMESTAMP(`time`) - $ifrom) * 1000000000 + (`ns` - $rfrom))/$grouping)";
 
273
                        $grouping = "GROUP BY $groupval";
 
274
                    } else $grouping = false;
 
275
                } else $grouping = false;
 
276
            }
 
277
        } 
 
278
 
 
279
        if ($grouping) {
 
280
            $this->set_minmax = 0;
 
281
            
 
282
            $list .= ", COUNT(*) AS items, (UNIX_TIMESTAMP(MAX(time)) - UNIX_TIMESTAMP(MIN(time))) AS width";
 
283
            if ($this->flags&CACHE::MISSING_INFO) {
 
284
                if ($CACHE_PRECISE_GAPS) {
 
285
                    /* Unfortunately, this is working from mysql client, but not from php. We should implement it with
 
286
                    stored functions, actually:
 
287
                    // $list .= ", MAX(IF(@tmpvar_pos=$groupval, UNIX_TIMESTAMP(time)-@tmpvar_width, 0)) AS maxgap, @tmpvar_pos:=$groupval AS tmpcol1, @tmpvar_width:=UNIX_TIMESTAMP(time) AS tmpcol2";
 
288
                    */
 
289
                    throw new ADEIException(translate("CACHE_PRECISE_GAPS is not supported yet"));
 
290
                } else {
 
291
                    $list .= ", IF(COUNT(*)>1, (UNIX_TIMESTAMP(MAX(time)) - UNIX_TIMESTAMP(MIN(time))) / (COUNT(*) - 1), 0) AS maxgap";
 
292
                }
 
293
            }
 
294
            
 
295
            foreach ($this->ids as $id) {
 
296
                $list .= ", MIN(v$id) AS min$i, MAX(v$id) AS max$i, AVG(v$id) AS mean$i";
 
297
                $i++;
 
298
            }   
 
299
 
 
300
            $cond = "WHERE `time` BETWEEN $sqlfrom AND $sqlto";
 
301
        } else {
 
302
            $this->set_minmax = 1;
 
303
            
 
304
            if ($this->use_subseconds) {
 
305
                $use_subseconds = true;
 
306
                $list = "UNIX_TIMESTAMP(time) AS timestamp, ns";
 
307
            } else {
 
308
                $list = "UNIX_TIMESTAMP(time) AS timestamp";
 
309
            }
 
310
            
 
311
            $list .= ", 1 AS items, 0 AS width";
 
312
            if ($this->flags&CACHE::MISSING_INFO) $list .= ", 0 AS maxgap";
 
313
            
 
314
            foreach ($this->ids as $id) {
 
315
                $list .= ", v$id AS mean$i";
 
316
                $i++;
 
317
            }   
 
318
        }
 
319
 
 
320
        $ifrom = (int)floor($from);
 
321
        $ito = (int)floor($to);
 
322
 
 
323
//      print_r($this->ivl);
 
324
//      echo "$ifrom - $ito ($from - $to)\n";
 
325
        if (($use_subseconds)&&(($ifrom != $from)||($ito != $to))) {
 
326
            if ($ifrom == $ito) {
 
327
                $sqlfrom = $this->cache->SQLTime($ifrom);
 
328
                $nfrom = ($from - $ifrom)*1000000000;
 
329
                $nto = ($to - $ito)*1000000000;
 
330
//              $cond = "WHERE ((`time` = $sqlfrom) AND (`ns` BETWEEN $nfrom AND $nto))";
 
331
                $cond = "WHERE ((`time` = $sqlfrom) AND (`ns` >= $nfrom) AND (`ns` < $nto))";
 
332
            } else {
 
333
                $cond = "";
 
334
                if ($ifrom != $from) {
 
335
                    $nfrom = ($from - $ifrom)*1000000000;
 
336
                    $sqlfrom = $this->cache->SQLTime($ifrom);
 
337
                    $cond = "((`time` = $sqlfrom) AND (`ns` >= $nfrom))";
 
338
                    $ifrom++;
 
339
                }
 
340
 
 
341
                if ($ifrom != $ito) {
 
342
                    if ($cond) $cond .= " OR ";
 
343
 
 
344
                    $sqlfrom = $this->cache->SQLTime($ifrom);
 
345
                    $sqlto = $this->cache->SQLTime($ito); 
 
346
//                  $cond .= "(`time` BETWEEN $sqlfrom AND $sqlto)";
 
347
                    $cond .= "((`time` >= $sqlfrom) AND (`time` < $sqlto))";
 
348
                } else $sqlto = false;
 
349
 
 
350
                if ($ito != $to) {
 
351
                    if ($cond) $cond .= " OR ";
 
352
                    if (!$sqlto) $sqlto = $this->cache->SQLTime($ito);
 
353
                
 
354
                    $nto = ($to - $ito)*1000000000;
 
355
                    $cond .= "((`time` = $sqlto) AND (`ns` < $nto))";
 
356
                }
 
357
                $cond = "WHERE ($cond)";
 
358
            }
 
359
            $sort = "ORDER BY `time` ASC, `ns` ASC";
 
360
        } else {
 
361
            $sqlfrom = $this->cache->SQLTime($ifrom);
 
362
            $sqlto = $this->cache->SQLTime($ito);
 
363
//          $cond = "WHERE `time` BETWEEN $sqlfrom AND $sqlto";
 
364
            $cond = "WHERE ((`time`>= $sqlfrom) AND (`time` < $sqlto))";
 
365
            $sort = "ORDER BY `time` ASC";
 
366
            if ($use_subseconds) $sort .= ", `ns` ASC ";
 
367
        }
 
368
        
 
369
        $curfrom = $from;
 
370
    }
 
371
 
 
372
    if ($grouping) {
 
373
/*      $f=fopen("/tmp/xxx.9", "w");
 
374
        fwrite ($f, "SELECT $list FROM `$table` $cond $grouping $sort LIMIT $limit\n");
 
375
        fclose($f);*/
 
376
//      echo "SELECT $list FROM `$table` $cond $grouping $sort LIMIT $limit\n";
 
377
//      echo "SELECT $list FROM `$table` $cond $grouping $sort LIMIT $limit\n";
 
378
        $this->res = mysql_unbuffered_query("SELECT $list FROM `$table` $cond $grouping $sort LIMIT $limit", $this->cache->dbh);
 
379
    } else {
 
380
        $this->res = mysql_unbuffered_query("SELECT $list FROM `$table` $cond $sort", $this->cache->dbh);
 
381
    }
 
382
 
 
383
    if ($this->combine_ends) {
 
384
        $this->nextrow = false;
 
385
        $this->next();
 
386
        
 
387
        if ($firstrow) {
 
388
            $this->combine($this->nextrow, $firstrow, ($curfrom - $from)/$grouping);
 
389
            $this->nextrow['time'] = $firstrow['time'];
 
390
        }
 
391
        
 
392
        if ($this->lastrow) {
 
393
            if ($limit > 1) {
 
394
                $this->combine_ends = ($to - $curto)/$grouping;
 
395
            } else {
 
396
                $this->combine_ends = ($to - $curto)/($grouping + ($curfrom - $from));
 
397
            }
 
398
        } else $this->combine_ends = 0;
 
399
    } else {
 
400
        if ($firstrow) {
 
401
            $this->nextrow = &$firstrow;
 
402
        } else {
 
403
            $this->nextrow = false;
 
404
            $this->next();
 
405
        }
 
406
    }
 
407
    
 
408
    $this->next();
 
409
 }
 
410
 
 
411
 function current() {
 
412
    return $this->row;
 
413
 }
 
414
 
 
415
 function key() {
 
416
    if (isset($this->row['ns'])) {
 
417
        $l = strlen($this->row['ns']);
 
418
        if ($l < 9) return $this->row['timestamp'] . "." . str_repeat('0', 9 - $l) . $this->row['ns'];
 
419
        return $this->row['timestamp'] . "." . $this->row['ns'];
 
420
    }
 
421
    return $this->row['timestamp'];
 
422
 }
 
423
 
 
424
 /* FIXME: provide min-max if only mean, provide interval ends */
 
425
 function next() {
 
426
    $this->row = $this->nextrow; // FIXME. We can't reference here, howto optimize (php by itself?)
 
427
    if (($this->row)&&(!isset($this->row['min0']))) {
 
428
        for ($i=0;isset($this->row['mean' . $i]);$i++) {
 
429
            $this->row['min' . $i] = $this->row['mean' . $i];
 
430
            $this->row['max' . $i] = $this->row['mean' . $i];
 
431
        }
 
432
    }
 
433
 
 
434
    if ($this->res) {
 
435
        $this->nextrow = mysql_fetch_assoc($this->res);
 
436
 
 
437
        if (!$this->nextrow) {
 
438
            mysql_free_result($this->res);
 
439
            $this->res = false;
 
440
            
 
441
            if ($this->combine_ends) {
 
442
                $this->combine($this->row, $this->lastrow, $this->combine_ends);
 
443
                $this->nextrow = false;
 
444
            } else {
 
445
                $this->nextrow = $this->lastrow;
 
446
            }
 
447
        }
 
448
    } else $this->nextrow = false;
 
449
 }
 
450
 
 
451
 function valid() {
 
452
    return $this->row?true:false;
 
453
 }
 
454
 
 
455
 function GetOperationInfo() {
 
456
    return $this->operation_info;
 
457
 }
 
458
}
 
459
 
 
460
?>
 
 
b'\\ No newline at end of file'