1
2
3
4
5
6
7
8
9 package org.jrobin.core.jrrd;
10
11 import java.io.File;
12 import java.io.IOException;
13 import java.io.PrintStream;
14 import java.text.DecimalFormat;
15 import java.text.NumberFormat;
16 import java.util.ArrayList;
17 import java.util.Calendar;
18 import java.util.Date;
19 import java.util.Iterator;
20
21
22
23
24
25
26
27
28
29 public class RRDatabase {
30
31 RRDFile rrdFile;
32
33
34 private String name;
35 Header header;
36 ArrayList<DataSource> dataSources;
37 ArrayList<Archive> archives;
38 Date lastUpdate;
39
40
41
42
43
44
45
46 public RRDatabase(String name) throws IOException {
47 this(new File(name));
48 }
49
50
51
52
53
54
55
56 public RRDatabase(File file) throws IOException {
57
58 name = file.getName();
59 rrdFile = new RRDFile(file);
60 header = new Header(rrdFile);
61
62
63 dataSources = new ArrayList<DataSource>();
64
65 for (int i = 0; i < header.dsCount; i++) {
66 DataSource ds = new DataSource(rrdFile);
67
68 dataSources.add(ds);
69 }
70
71
72 archives = new ArrayList<Archive>();
73
74 for (int i = 0; i < header.rraCount; i++) {
75 Archive archive = new Archive(this);
76
77 archives.add(archive);
78 }
79
80 rrdFile.align();
81
82 lastUpdate = new Date((long) (rrdFile.readInt()) * 1000);
83
84
85 for (int i = 0; i < header.dsCount; i++) {
86 DataSource ds = dataSources.get(i);
87
88 ds.loadPDPStatusBlock(rrdFile);
89 }
90
91
92 for (int i = 0; i < header.rraCount; i++) {
93 Archive archive = archives.get(i);
94
95 archive.loadCDPStatusBlocks(rrdFile, header.dsCount);
96 }
97
98
99 for (int i = 0; i < header.rraCount; i++) {
100 Archive archive = archives.get(i);
101
102 archive.loadCurrentRow(rrdFile);
103 }
104
105
106 for (int i = 0; i < header.rraCount; i++) {
107 Archive archive = archives.get(i);
108
109 archive.loadData(rrdFile, header.dsCount);
110 }
111 }
112
113
114
115
116
117
118 public Header getHeader() {
119 return header;
120 }
121
122
123
124
125
126
127
128
129 public Date getLastUpdate() {
130 return lastUpdate;
131 }
132
133
134
135
136
137
138
139 public DataSource getDataSource(int index) {
140 return dataSources.get(index);
141 }
142
143
144
145
146
147
148 public Iterator<DataSource> getDataSources() {
149 return dataSources.iterator();
150 }
151
152
153
154
155
156
157
158 public Archive getArchive(int index) {
159 return archives.get(index);
160 }
161
162
163
164
165
166
167 public Iterator<Archive> getArchives() {
168 return archives.iterator();
169 }
170
171
172
173
174
175
176 public int getNumArchives() {
177 return header.rraCount;
178 }
179
180
181
182
183
184
185
186
187
188
189 public Iterator<Archive> getArchives(ConsolidationFunctionType type) {
190 return getArchiveList(type).iterator();
191 }
192
193 ArrayList<Archive> getArchiveList(ConsolidationFunctionType type) {
194
195 ArrayList<Archive> subset = new ArrayList<Archive>();
196
197 for (int i = 0; i < archives.size(); i++) {
198 Archive archive = archives.get(i);
199
200 if (archive.getType().equals(type)) {
201 subset.add(archive);
202 }
203 }
204
205 return subset;
206 }
207
208
209
210
211
212
213 public void close() throws IOException {
214 rrdFile.close();
215 }
216
217
218
219
220
221
222
223
224 public void printInfo(PrintStream s) {
225
226 NumberFormat numberFormat = new DecimalFormat("0.0000000000E0");
227
228 printInfo(s, numberFormat);
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242 public DataChunk getData(ConsolidationFunctionType type)
243 throws RRDException, IOException {
244 return getData(type, 1L);
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258
259 public DataChunk getData(ConsolidationFunctionType type, long step)
260 throws RRDException, IOException {
261
262 ArrayList<Archive> possibleArchives = getArchiveList(type);
263
264 if (possibleArchives.size() == 0) {
265 throw new RRDException("Database does not contain an Archive of consolidation function type "
266 + type);
267 }
268
269 Calendar endCal = Calendar.getInstance();
270
271 endCal.set(Calendar.MILLISECOND, 0);
272
273 Calendar startCal = (Calendar) endCal.clone();
274
275 startCal.add(Calendar.DATE, -1);
276
277 long end = endCal.getTime().getTime() / 1000;
278 long start = startCal.getTime().getTime() / 1000;
279 Archive archive = findBestArchive(start, end, step, possibleArchives);
280
281
282 step = header.pdpStep * archive.pdpCount;
283 start -= start % step;
284
285 if (end % step != 0) {
286 end += step - end % step;
287 }
288
289 int rows = (int) ((end - start) / step + 1);
290
291
292
293
294
295
296 long lastUpdateLong = lastUpdate.getTime() / 1000;
297 long archiveEndTime = lastUpdateLong - (lastUpdateLong % step);
298 long archiveStartTime = archiveEndTime - (step * (archive.rowCount - 1));
299 int startOffset = (int) ((start - archiveStartTime) / step);
300 int endOffset = (int) ((archiveEndTime - end) / step);
301
302
303
304
305
306 DataChunk chunk = new DataChunk(start, startOffset, endOffset, step,
307 header.dsCount, rows);
308
309 archive.loadData(chunk);
310
311 return chunk;
312 }
313
314
315
316
317
318 private Archive findBestArchive(long start, long end, long step,
319 ArrayList<Archive> archives) {
320
321 Archive archive = null;
322 Archive bestFullArchive = null;
323 Archive bestPartialArchive = null;
324 long lastUpdateLong = lastUpdate.getTime() / 1000;
325 int firstPart = 1;
326 int firstFull = 1;
327 long bestMatch = 0;
328
329 long bestStepDiff = 0;
330 long tmpStepDiff = 0;
331
332 for (int i = 0; i < archives.size(); i++) {
333 archive = archives.get(i);
334
335 long calEnd = lastUpdateLong
336 - (lastUpdateLong
337 % (archive.pdpCount * header.pdpStep));
338 long calStart = calEnd
339 - (archive.pdpCount * archive.rowCount
340 * header.pdpStep);
341 long fullMatch = end - start;
342
343 if ((calEnd >= end) && (calStart < start)) {
344 tmpStepDiff = Math.abs(step - (header.pdpStep * archive.pdpCount));
345
346 if ((firstFull != 0) || (tmpStepDiff < bestStepDiff)) {
347 firstFull = 0;
348 bestStepDiff = tmpStepDiff;
349 bestFullArchive = archive;
350 }
351 }
352 else {
353 long tmpMatch = fullMatch;
354
355 if (calStart > start) {
356 tmpMatch -= calStart - start;
357 }
358
359 if (calEnd < end) {
360 tmpMatch -= end - calEnd;
361 }
362
363 if ((firstPart != 0) || (bestMatch < tmpMatch)) {
364 firstPart = 0;
365 bestMatch = tmpMatch;
366 bestPartialArchive = archive;
367 }
368 }
369 }
370
371
372
373 if (firstFull == 0) {
374 archive = bestFullArchive;
375 }
376 else if (firstPart == 0) {
377 archive = bestPartialArchive;
378 }
379
380 return archive;
381 }
382
383
384
385
386
387
388
389
390
391
392 public void printInfo(PrintStream s, NumberFormat numberFormat) {
393
394 s.print("filename = \"");
395 s.print(name);
396 s.println("\"");
397 s.print("rrd_version = \"");
398 s.print(header.version);
399 s.println("\"");
400 s.print("step = ");
401 s.println(header.pdpStep);
402 s.print("last_update = ");
403 s.println(lastUpdate.getTime() / 1000);
404
405 for (Iterator<DataSource> i = dataSources.iterator(); i.hasNext();) {
406 DataSource ds = i.next();
407
408 ds.printInfo(s, numberFormat);
409 }
410
411 int index = 0;
412
413 for (Iterator<Archive> i = archives.iterator(); i.hasNext();) {
414 Archive archive = i.next();
415
416 archive.printInfo(s, numberFormat, index++);
417 }
418 }
419
420
421
422
423
424
425
426
427 public void toXml(PrintStream s) {
428
429 s.println("<!--");
430 s.println(" -- Round Robin RRDatabase Dump ");
431 s.println(" -- Generated by jRRD <ciaran@codeloop.com>");
432 s.println(" -->");
433 s.println("<rrd>");
434 s.print("\t<version> ");
435 s.print(header.version);
436 s.println(" </version>");
437 s.print("\t<step> ");
438 s.print(header.pdpStep);
439 s.println(" </step> <!-- Seconds -->");
440 s.print("\t<lastupdate> ");
441 s.print(lastUpdate.getTime() / 1000);
442 s.print(" </lastupdate> <!-- ");
443 s.print(lastUpdate.toString());
444 s.println(" -->");
445 s.println();
446
447 for (int i = 0; i < header.dsCount; i++) {
448 DataSource ds = dataSources.get(i);
449
450 ds.toXml(s);
451 }
452
453 s.println("<!-- Round Robin Archives -->");
454
455 for (int i = 0; i < header.rraCount; i++) {
456 Archive archive = archives.get(i);
457
458 archive.toXml(s);
459 }
460
461 s.println("</rrd>");
462 }
463
464
465
466
467
468
469 public String toString() {
470
471 StringBuffer sb = new StringBuffer("\n");
472
473 sb.append(header.toString());
474
475 for (Iterator<DataSource> i = dataSources.iterator(); i.hasNext();) {
476 DataSource ds = i.next();
477
478 sb.append("\n\t");
479 sb.append(ds.toString());
480 }
481
482 for (Iterator<Archive> i = archives.iterator(); i.hasNext();) {
483 Archive archive = i.next();
484
485 sb.append("\n\t");
486 sb.append(archive.toString());
487 }
488
489 return sb.toString();
490 }
491 }