KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jrobin > core > jrrd > RRDatabase


1 /*
2  * Copyright (C) 2001 Ciaran Treanor <ciaran@codeloop.com>
3  *
4  * Distributable under GPL license.
5  * See terms of license at gnu.org.
6  *
7  * $Id: RRDatabase.java,v 1.2 2004/07/22 09:36:33 saxon64 Exp $
8  */

9 package org.jrobin.core.jrrd;
10
11 import java.io.*;
12 import java.util.*;
13 import java.text.NumberFormat JavaDoc;
14 import java.text.DecimalFormat JavaDoc;
15
16 /**
17  * Instances of this class model
18  * <a HREF="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/">Round Robin Database</a>
19  * (RRD) files.
20  *
21  * @author <a HREF="mailto:ciaran@codeloop.com">Ciaran Treanor</a>
22  * @version $Revision: 1.2 $
23  */

24 public class RRDatabase {
25
26     RRDFile rrdFile;
27
28     // RRD file name
29
private String JavaDoc name;
30     Header header;
31     ArrayList dataSources;
32     ArrayList archives;
33     Date lastUpdate;
34
35     /**
36      * Creates a database to read from.
37      *
38      * @param name the filename of the file to read from.
39      * @throws IOException if an I/O error occurs.
40      */

41     public RRDatabase(String JavaDoc name) throws IOException {
42         this(new File(name));
43     }
44
45     /**
46      * Creates a database to read from.
47      *
48      * @param file the file to read from.
49      * @throws IOException if an I/O error occurs.
50      */

51     public RRDatabase(File file) throws IOException {
52
53         name = file.getName();
54         rrdFile = new RRDFile(file);
55         header = new Header(rrdFile);
56
57         // Load the data sources
58
dataSources = new ArrayList();
59
60         for (int i = 0; i < header.dsCount; i++) {
61             DataSource ds = new DataSource(rrdFile);
62
63             dataSources.add(ds);
64         }
65
66         // Load the archives
67
archives = new ArrayList();
68
69         for (int i = 0; i < header.rraCount; i++) {
70             Archive archive = new Archive(this);
71
72             archives.add(archive);
73         }
74
75         rrdFile.align();
76
77         lastUpdate = new Date((long) (rrdFile.readInt()) * 1000);
78
79         // Load PDPStatus(s)
80
for (int i = 0; i < header.dsCount; i++) {
81             DataSource ds = (DataSource) dataSources.get(i);
82
83             ds.loadPDPStatusBlock(rrdFile);
84         }
85
86         // Load CDPStatus(s)
87
for (int i = 0; i < header.rraCount; i++) {
88             Archive archive = (Archive) archives.get(i);
89
90             archive.loadCDPStatusBlocks(rrdFile, header.dsCount);
91         }
92
93         // Load current row information for each archive
94
for (int i = 0; i < header.rraCount; i++) {
95             Archive archive = (Archive) archives.get(i);
96
97             archive.loadCurrentRow(rrdFile);
98         }
99
100         // Now load the data
101
for (int i = 0; i < header.rraCount; i++) {
102             Archive archive = (Archive) archives.get(i);
103
104             archive.loadData(rrdFile, header.dsCount);
105         }
106     }
107
108     /**
109      * Returns the <code>Header</code> for this database.
110      *
111      * @return the <code>Header</code> for this database.
112      */

113     public Header getHeader() {
114         return header;
115     }
116
117     /**
118      * Returns the date this database was last updated. To convert this date to
119      * the form returned by <code>rrdtool last</code> call Date.getTime() and
120      * divide the result by 1000.
121      *
122      * @return the date this database was last updated.
123      */

124     public Date getLastUpdate() {
125         return lastUpdate;
126     }
127
128     /**
129      * Returns the <code>DataSource</code> at the specified position in this database.
130      *
131      * @param index index of <code>DataSource</code> to return.
132      * @return the <code>DataSource</code> at the specified position in this database
133      */

134     public DataSource getDataSource(int index) {
135         return (DataSource) dataSources.get(index);
136     }
137
138     /**
139      * Returns an iterator over the data sources in this database in proper sequence.
140      *
141      * @return an iterator over the data sources in this database in proper sequence.
142      */

143     public Iterator getDataSources() {
144         return dataSources.iterator();
145     }
146
147     /**
148      * Returns the <code>Archive</code> at the specified position in this database.
149      *
150      * @param index index of <code>Archive</code> to return.
151      * @return the <code>Archive</code> at the specified position in this database.
152      */

153     public Archive getArchive(int index) {
154         return (Archive) archives.get(index);
155     }
156
157     /**
158      * Returns an iterator over the archives in this database in proper sequence.
159      *
160      * @return an iterator over the archives in this database in proper sequence.
161      */

162     public Iterator getArchives() {
163         return archives.iterator();
164     }
165
166     /**
167      * Returns the number of archives in this database.
168      *
169      * @return the number of archives in this database.
170      */

171     public int getNumArchives() {
172         return header.rraCount;
173     }
174
175     /**
176      * Returns an iterator over the archives in this database of the given type
177      * in proper sequence.
178      *
179      * @param type the consolidation function that should have been applied to
180      * the data.
181      * @return an iterator over the archives in this database of the given type
182      * in proper sequence.
183      */

184     public Iterator getArchives(ConsolidationFunctionType type) {
185         return getArchiveList(type).iterator();
186     }
187
188     ArrayList getArchiveList(ConsolidationFunctionType type) {
189
190         ArrayList subset = new ArrayList();
191
192         for (int i = 0; i < archives.size(); i++) {
193             Archive archive = (Archive) archives.get(i);
194
195             if (archive.getType().equals(type)) {
196                 subset.add(archive);
197             }
198         }
199
200         return subset;
201     }
202
203     /**
204      * Closes this database stream and releases any associated system resources.
205      *
206      * @throws IOException if an I/O error occurs.
207      */

208     public void close() throws IOException {
209         rrdFile.close();
210     }
211
212     /**
213      * Outputs the header information of the database to the given print stream
214      * using the default number format. The default format for <code>double</code>
215      * is 0.0000000000E0.
216      *
217      * @param s the PrintStream to print the header information to.
218      */

219     public void printInfo(PrintStream s) {
220
221         NumberFormat JavaDoc numberFormat = new DecimalFormat JavaDoc("0.0000000000E0");
222
223         printInfo(s, numberFormat);
224     }
225
226     /**
227      * Returns data from the database corresponding to the given consolidation
228      * function and a step size of 1.
229      *
230      * @param type the consolidation function that should have been applied to
231      * the data.
232      * @return the raw data.
233      * @throws RRDException if there was a problem locating a data archive with
234      * the requested consolidation function.
235      * @throws IOException if there was a problem reading data from the database.
236      */

237     public DataChunk getData(ConsolidationFunctionType type)
238             throws RRDException, IOException {
239         return getData(type, 1L);
240     }
241
242     /**
243      * Returns data from the database corresponding to the given consolidation
244      * function.
245      *
246      * @param type the consolidation function that should have been applied to
247      * the data.
248      * @param step the step size to use.
249      * @return the raw data.
250      * @throws RRDException if there was a problem locating a data archive with
251      * the requested consolidation function.
252      * @throws IOException if there was a problem reading data from the database.
253      */

254     public DataChunk getData(ConsolidationFunctionType type, long step)
255             throws RRDException, IOException {
256
257         ArrayList possibleArchives = getArchiveList(type);
258
259         if (possibleArchives.size() == 0) {
260             throw new RRDException("Database does not contain an Archive of consolidation function type "
261                     + type);
262         }
263
264         Calendar endCal = Calendar.getInstance();
265
266         endCal.set(Calendar.MILLISECOND, 0);
267
268         Calendar startCal = (Calendar) endCal.clone();
269
270         startCal.add(Calendar.DATE, -1);
271
272         long end = endCal.getTime().getTime() / 1000;
273         long start = startCal.getTime().getTime() / 1000;
274         Archive archive = findBestArchive(start, end, step, possibleArchives);
275
276         // Tune the parameters
277
step = header.pdpStep * archive.pdpCount;
278         start -= start % step;
279
280         if (end % step != 0) {
281             end += step - end % step;
282         }
283
284         int rows = (int) ((end - start) / step + 1);
285
286         //cat.debug("start " + start + " end " + end + " step " + step + " rows "
287
// + rows);
288

289         // Find start and end offsets
290
// This is terrible - some of this should be encapsulated in Archive - CT.
291
long lastUpdateLong = lastUpdate.getTime() / 1000;
292         long archiveEndTime = lastUpdateLong - (lastUpdateLong % step);
293         long archiveStartTime = archiveEndTime - (step * (archive.rowCount - 1));
294         int startOffset = (int) ((start - archiveStartTime) / step);
295         int endOffset = (int) ((archiveEndTime - end) / step);
296
297         //cat.debug("start " + archiveStartTime + " end " + archiveEndTime
298
// + " startOffset " + startOffset + " endOffset "
299
// + (archive.rowCount - endOffset));
300

301         DataChunk chunk = new DataChunk(start, startOffset, endOffset, step,
302                 header.dsCount, rows);
303
304         archive.loadData(chunk);
305
306         return chunk;
307     }
308
309     /*
310      * This is almost a verbatim copy of the original C code by Tobias Oetiker.
311      * I need to put more of a Java style on it - CT
312      */

313     private Archive findBestArchive(long start, long end, long step,
314                                     ArrayList archives) {
315
316         Archive archive = null;
317         Archive bestFullArchive = null;
318         Archive bestPartialArchive = null;
319         long lastUpdateLong = lastUpdate.getTime() / 1000;
320         int firstPart = 1;
321         int firstFull = 1;
322         long bestMatch = 0;
323         //long bestPartRRA = 0;
324
long bestStepDiff = 0;
325         long tmpStepDiff = 0;
326
327         for (int i = 0; i < archives.size(); i++) {
328             archive = (Archive) archives.get(i);
329
330             long calEnd = lastUpdateLong
331                     - (lastUpdateLong
332                     % (archive.pdpCount * header.pdpStep));
333             long calStart = calEnd
334                     - (archive.pdpCount * archive.rowCount
335                     * header.pdpStep);
336             long fullMatch = end - start;
337
338             if ((calEnd >= end) && (calStart < start)) { // Best full match
339
tmpStepDiff = Math.abs(step - (header.pdpStep * archive.pdpCount));
340
341                 if ((firstFull != 0) || (tmpStepDiff < bestStepDiff)) {
342                     firstFull = 0;
343                     bestStepDiff = tmpStepDiff;
344                     bestFullArchive = archive;
345                 }
346             } else { // Best partial match
347
long tmpMatch = fullMatch;
348
349                 if (calStart > start) {
350                     tmpMatch -= calStart - start;
351                 }
352
353                 if (calEnd < end) {
354                     tmpMatch -= end - calEnd;
355                 }
356
357                 if ((firstPart != 0) || (bestMatch < tmpMatch)) {
358                     firstPart = 0;
359                     bestMatch = tmpMatch;
360                     bestPartialArchive = archive;
361                 }
362             }
363         }
364
365         // See how the matching went
366
// optimise this
367
if (firstFull == 0) {
368             archive = bestFullArchive;
369         } else if (firstPart == 0) {
370             archive = bestPartialArchive;
371         }
372
373         return archive;
374     }
375
376     /**
377      * Outputs the header information of the database to the given print stream
378      * using the given number format. The format is almost identical to that
379      * produced by
380      * <a HREF="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/manual/rrdinfo.html">rrdtool info</a>
381      *
382      * @param s the PrintStream to print the header information to.
383      * @param numberFormat the format to print <code>double</code>s as.
384      */

385     public void printInfo(PrintStream s, NumberFormat JavaDoc numberFormat) {
386
387         s.print("filename = \"");
388         s.print(name);
389         s.println("\"");
390         s.print("rrd_version = \"");
391         s.print(header.version);
392         s.println("\"");
393         s.print("step = ");
394         s.println(header.pdpStep);
395         s.print("last_update = ");
396         s.println(lastUpdate.getTime() / 1000);
397
398         for (Iterator i = dataSources.iterator(); i.hasNext();) {
399             DataSource ds = (DataSource) i.next();
400
401             ds.printInfo(s, numberFormat);
402         }
403
404         int index = 0;
405
406         for (Iterator i = archives.iterator(); i.hasNext();) {
407             Archive archive = (Archive) i.next();
408
409             archive.printInfo(s, numberFormat, index++);
410         }
411     }
412
413     /**
414      * Outputs the content of the database to the given print stream
415      * as a stream of XML. The XML format is almost identical to that produced by
416      * <a HREF="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/manual/rrddump.html">rrdtool dump</a>
417      *
418      * @param s the PrintStream to send the XML to.
419      */

420     public void toXml(PrintStream s) {
421
422         s.println("<!--");
423         s.println(" -- Round Robin RRDatabase Dump ");
424         s.println(" -- Generated by jRRD <ciaran@codeloop.com>");
425         s.println(" -->");
426         s.println("<rrd>");
427         s.print("\t<version> ");
428         s.print(header.version);
429         s.println(" </version>");
430         s.print("\t<step> ");
431         s.print(header.pdpStep);
432         s.println(" </step> <!-- Seconds -->");
433         s.print("\t<lastupdate> ");
434         s.print(lastUpdate.getTime() / 1000);
435         s.print(" </lastupdate> <!-- ");
436         s.print(lastUpdate.toString());
437         s.println(" -->");
438         s.println();
439
440         for (int i = 0; i < header.dsCount; i++) {
441             DataSource ds = (DataSource) dataSources.get(i);
442
443             ds.toXml(s);
444         }
445
446         s.println("<!-- Round Robin Archives -->");
447
448         for (int i = 0; i < header.rraCount; i++) {
449             Archive archive = (Archive) archives.get(i);
450
451             archive.toXml(s);
452         }
453
454         s.println("</rrd>");
455     }
456
457     /**
458      * Returns a summary the contents of this database.
459      *
460      * @return a summary of the information contained in this database.
461      */

462     public String JavaDoc toString() {
463
464         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("\n");
465
466         sb.append(header.toString());
467
468         for (Iterator i = dataSources.iterator(); i.hasNext();) {
469             DataSource ds = (DataSource) i.next();
470
471             sb.append("\n\t");
472             sb.append(ds.toString());
473         }
474
475         for (Iterator i = archives.iterator(); i.hasNext();) {
476             Archive archive = (Archive) i.next();
477
478             sb.append("\n\t");
479             sb.append(archive.toString());
480         }
481
482         return sb.toString();
483     }
484 }
485
Popular Tags