1 25 26 package org.jrobin.core; 27 28 import java.io.ByteArrayOutputStream ; 29 import java.io.FileOutputStream ; 30 import java.io.IOException ; 31 import java.io.OutputStream ; 32 33 68 public class RrdDb implements RrdUpdater { 69 70 public static final int NO_LOCKS = 0; 71 72 public static final int WAIT_IF_LOCKED = 1; 73 74 public static final int EXCEPTION_IF_LOCKED = 2; 75 76 static final int XML_INITIAL_BUFFER_CAPACITY = 100000; private static int lockMode = NO_LOCKS; 79 80 private RrdBackend backend; 81 private RrdAllocator allocator = new RrdAllocator(); 82 83 private Header header; 84 private Datasource[] datasources; 85 private Archive[] archives; 86 87 private boolean closed = false; 88 89 124 public RrdDb(RrdDef rrdDef) throws RrdException, IOException { 125 this(rrdDef, RrdFileBackendFactory.getDefaultFactory()); 126 } 127 128 161 public RrdDb(RrdDef rrdDef, RrdBackendFactory factory) throws RrdException, IOException { 162 rrdDef.validate(); 163 String path = rrdDef.getPath(); 164 backend = factory.open(path, false, lockMode); 165 backend.setLength(rrdDef.getEstimatedSize()); 166 header = new Header(this, rrdDef); 168 DsDef[] dsDefs = rrdDef.getDsDefs(); 170 datasources = new Datasource[dsDefs.length]; 171 for(int i = 0; i < dsDefs.length; i++) { 172 datasources[i] = new Datasource(this, dsDefs[i]); 173 } 174 ArcDef[] arcDefs = rrdDef.getArcDefs(); 176 archives = new Archive[arcDefs.length]; 177 for(int i = 0; i < arcDefs.length; i++) { 178 archives[i] = new Archive(this, arcDefs[i]); 179 } 180 backend.afterCreate(); 181 } 182 183 197 public RrdDb(String path, boolean readOnly) throws IOException , RrdException { 198 this(path, readOnly, RrdBackendFactory.getDefaultFactory()); 199 } 200 201 217 public RrdDb(String path, boolean readOnly, RrdBackendFactory factory) 218 throws IOException , RrdException { 219 if(!factory.exists(path)) { 221 throw new IOException ("Could not open " + path + " [non existent]"); 222 } 223 backend = factory.open(path, readOnly, lockMode); 224 header = new Header(this, (RrdDef) null); 226 header.validateHeader(); 227 int dsCount = header.getDsCount(); 229 datasources = new Datasource[dsCount]; 230 for(int i = 0; i < dsCount; i++) { 231 datasources[i] = new Datasource(this, null); 232 } 233 int arcCount = header.getArcCount(); 235 archives = new Archive[arcCount]; 236 for(int i = 0; i < arcCount; i++) { 237 archives[i] = new Archive(this, null); 238 } 239 } 240 241 249 public RrdDb(String path) throws IOException , RrdException { 250 this(path, false); 251 } 252 253 263 public RrdDb(String path, RrdBackendFactory factory) throws IOException , RrdException { 264 this(path, false, factory); 265 } 266 267 290 public RrdDb(String rrdPath, String xmlPath) throws IOException , RrdException { 291 this(rrdPath, xmlPath, RrdBackendFactory.getDefaultFactory()); 292 } 293 294 305 public RrdDb(String rrdPath, String xmlPath, RrdBackendFactory factory) 306 throws IOException , RrdException { 307 backend = factory.open(rrdPath, false, lockMode); 308 DataImporter reader; 309 if(xmlPath.startsWith("rrdtool:/")) { 310 String rrdToolPath = xmlPath.substring("rrdtool:/".length()); 311 reader = new RrdToolReader(rrdToolPath); 312 } 313 else if(xmlPath.startsWith("xml:/")) { 314 xmlPath = xmlPath.substring("xml:/".length()); 315 reader = new XmlReader(xmlPath); 316 } 317 else { 318 reader = new XmlReader(xmlPath); 319 } 320 backend.setLength(reader.getEstimatedSize()); 321 header = new Header(this, reader); 323 datasources = new Datasource[reader.getDsCount()]; 325 for(int i = 0; i < datasources.length; i++) { 326 datasources[i] = new Datasource(this, reader, i); 327 } 328 archives = new Archive[reader.getArcCount()]; 330 for(int i = 0; i < archives.length; i++) { 331 archives[i] = new Archive(this, reader, i); 332 } 333 reader.release(); 334 reader = null; 336 backend.afterCreate(); 337 } 338 339 344 public synchronized void close() throws IOException { 345 if(!closed) { 346 backend.close(); 347 closed = true; 348 } 349 } 350 351 355 public boolean isClosed() { 356 return closed; 357 } 358 359 363 public Header getHeader() { 364 return header; 365 } 366 367 372 public Datasource getDatasource(int dsIndex) { 373 return datasources[dsIndex]; 374 } 375 376 381 public Archive getArchive(int arcIndex) { 382 return archives[arcIndex]; 383 } 384 385 391 public String [] getDsNames() throws IOException { 392 int n = datasources.length; 393 String [] dsNames = new String [n]; 394 for(int i = 0; i < n; i++) { 395 dsNames[i] = datasources[i].getDsName(); 396 } 397 return dsNames; 398 } 399 400 413 public Sample createSample(long time) throws IOException { 414 return new Sample(this, time); 415 } 416 417 430 public Sample createSample() throws IOException { 431 return createSample(Util.getTime()); 432 } 433 434 449 public FetchRequest createFetchRequest(String consolFun, long fetchStart, long fetchEnd, 450 long resolution) throws RrdException { 451 return new FetchRequest(this, consolFun, fetchStart, fetchEnd, resolution); 452 } 453 454 470 public FetchRequest createFetchRequest(String consolFun, long fetchStart, long fetchEnd) 471 throws RrdException { 472 return createFetchRequest(consolFun, fetchStart, fetchEnd, 1); 473 } 474 475 synchronized void store(Sample sample) throws IOException , RrdException { 476 if(closed) { 477 throw new RrdException("RRD already closed, cannot store this sample"); 478 } 479 backend.beforeUpdate(); 480 long newTime = sample.getTime(); 481 long lastTime = header.getLastUpdateTime(); 482 if(lastTime >= newTime) { 483 throw new RrdException("Bad sample timestamp " + newTime + 484 ". Last update time was " + lastTime + ", at least one second step is required"); 485 } 486 double[] newValues = sample.getValues(); 487 for(int i = 0; i < datasources.length; i++) { 488 double newValue = newValues[i]; 489 datasources[i].process(newTime, newValue); 490 } 491 header.setLastUpdateTime(newTime); 492 backend.afterUpdate(); 493 } 494 495 synchronized FetchPoint[] fetch(FetchRequest request) throws IOException , RrdException { 496 if(closed) { 497 throw new RrdException("RRD already closed, cannot fetch data"); 498 } 499 backend.beforeFetch(); 500 Archive archive = findMatchingArchive(request); 501 FetchPoint[] points = archive.fetch(request); 502 backend.afterFetch(); 503 return points; 504 } 505 506 synchronized FetchData fetchData(FetchRequest request) throws IOException , RrdException { 507 if(closed) { 508 throw new RrdException("RRD already closed, cannot fetch data"); 509 } 510 backend.beforeFetch(); 511 Archive archive = findMatchingArchive(request); 512 FetchData fetchData = archive.fetchData(request); 513 backend.afterFetch(); 514 return fetchData; 515 } 516 517 public Archive findMatchingArchive(FetchRequest request) throws RrdException, IOException 518 { 519 String consolFun = request.getConsolFun(); 520 long fetchStart = request.getFetchStart(); 521 long fetchEnd = request.getFetchEnd(); 522 long resolution = request.getResolution(); 523 524 Archive bestFullMatch = null, bestPartialMatch = null; 525 526 long bestStepDiff = 0, bestMatch = 0; 527 528 for ( int i = 0; i < archives.length; i++ ) 529 { 530 if ( archives[i].getConsolFun().equals(consolFun) ) 531 { 532 long arcStep = archives[i].getArcStep(); 533 long arcStart = archives[i].getStartTime() - arcStep; 534 long arcEnd = archives[i].getEndTime(); 535 long fullMatch = fetchEnd - fetchStart; 536 537 if ( arcEnd >= fetchEnd && arcStart <= fetchStart ) { 539 long tmpStepDiff = Math.abs( archives[i].getArcStep() - resolution ); 540 541 if ( tmpStepDiff < bestStepDiff || bestFullMatch == null ) 542 { 543 bestStepDiff = tmpStepDiff; 544 bestFullMatch = archives[i]; 545 } 546 547 } 548 else { 550 long tmpMatch = fullMatch; 551 552 if ( arcStart > fetchStart ) 553 tmpMatch -= (arcStart - fetchStart); 554 if( arcEnd < fetchEnd ) 555 tmpMatch -= (fetchEnd - arcEnd); 556 557 if ( bestPartialMatch == null || bestMatch < tmpMatch ) 558 { 559 bestPartialMatch = archives[i]; 560 bestMatch = tmpMatch; 561 } 562 } 563 } 564 } 565 566 if ( bestFullMatch != null ) 567 return bestFullMatch; 568 else if ( bestPartialMatch != null ) 569 return bestPartialMatch; 570 else 571 throw new RrdException("RRD file does not contain RRA:" + consolFun + " archive"); 572 } 573 574 583 public Archive findStartMatchArchive( String consolFun, long startTime, long resolution ) throws IOException 584 { 585 long arcStep, diff; 586 int fallBackIndex = 0; 587 int arcIndex = -1; 588 long minDiff = Long.MAX_VALUE; 589 long fallBackDiff = Long.MAX_VALUE; 590 591 for ( int i = 0; i < archives.length; i++ ) 592 { 593 if ( archives[i].getConsolFun().equals(consolFun) ) 594 { 595 arcStep = archives[i].getArcStep(); 596 diff = Math.abs( resolution - arcStep ); 597 598 if ( startTime >= archives[i].getStartTime() ) 600 { 601 if ( diff == 0 ) return archives[i]; 603 else if ( diff < minDiff ) { 604 minDiff = diff; 605 arcIndex = i; 606 } 607 } 608 else if ( diff < fallBackDiff ) { 609 fallBackDiff = diff; 610 fallBackIndex = i; 611 } 612 } 613 } 614 615 return ( arcIndex >= 0 ? archives[arcIndex] : archives[fallBackIndex] ); 616 } 617 618 624 public synchronized String dump() throws IOException { 625 StringBuffer buffer = new StringBuffer (); 626 buffer.append(header.dump()); 627 for(int i = 0; i < datasources.length; i++) { 628 buffer.append(datasources[i].dump()); 629 } 630 for(int i = 0; i < archives.length; i++) { 631 buffer.append(archives[i].dump()); 632 } 633 return buffer.toString(); 634 } 635 636 void archive(Datasource datasource, double value, long numUpdates) 637 throws IOException , RrdException { 638 int dsIndex = getDsIndex(datasource.getDsName()); 639 for(int i = 0; i < archives.length; i++) { 640 archives[i].archive(dsIndex, value, numUpdates); 641 } 642 } 643 644 653 public int getDsIndex(String dsName) throws RrdException, IOException { 654 for(int i = 0; i < datasources.length; i++) { 655 if(datasources[i].getDsName().equals(dsName)) { 656 return i; 657 } 658 } 659 throw new RrdException("Unknown datasource name: " + dsName); 660 } 661 662 Datasource[] getDatasources() { 663 return datasources; 664 } 665 666 Archive[] getArchives() { 667 return archives; 668 } 669 670 677 public synchronized void dumpXml(OutputStream destination) throws IOException { 678 XmlWriter writer = new XmlWriter(destination); 679 writer.startTag("rrd"); 680 header.appendXml(writer); 682 for(int i = 0; i < datasources.length; i++) { 684 datasources[i].appendXml(writer); 685 } 686 for(int i = 0; i < archives.length; i++) { 688 archives[i].appendXml(writer); 689 } 690 writer.closeTag(); 691 writer.flush(); 692 } 693 694 698 public synchronized void exportXml(OutputStream destination) throws IOException { 699 dumpXml(destination); 700 } 701 702 710 public synchronized String getXml() throws IOException , RrdException { 711 ByteArrayOutputStream destination = new ByteArrayOutputStream (XML_INITIAL_BUFFER_CAPACITY); 712 dumpXml(destination); 713 return destination.toString(); 714 } 715 716 722 public synchronized String exportXml() throws IOException , RrdException { 723 return getXml(); 724 } 725 726 745 public synchronized void dumpXml(String filename) throws IOException , RrdException { 746 OutputStream outputStream = null; 747 try { 748 outputStream = new FileOutputStream (filename, false); 749 dumpXml(outputStream); 750 } 751 finally { 752 if(outputStream != null) { 753 outputStream.close(); 754 } 755 } 756 } 757 758 763 public synchronized void exportXml(String filename) throws IOException , RrdException { 764 dumpXml(filename); 765 } 766 767 771 public synchronized long getLastUpdateTime() throws IOException { 772 return header.getLastUpdateTime(); 773 } 774 775 792 public synchronized RrdDef getRrdDef() throws RrdException, IOException { 793 long startTime = header.getLastUpdateTime(); 795 long step = header.getStep(); 796 String path = backend.getPath(); 797 RrdDef rrdDef = new RrdDef(path, startTime, step); 798 for(int i = 0; i < datasources.length; i++) { 800 DsDef dsDef = new DsDef(datasources[i].getDsName(), 801 datasources[i].getDsType(), datasources[i].getHeartbeat(), 802 datasources[i].getMinValue(), datasources[i].getMaxValue()); 803 rrdDef.addDatasource(dsDef); 804 } 805 for(int i = 0; i < archives.length; i++) { 807 ArcDef arcDef = new ArcDef(archives[i].getConsolFun(), 808 archives[i].getXff(), archives[i].getSteps(), archives[i].getRows()); 809 rrdDef.addArchive(arcDef); 810 } 811 return rrdDef; 812 } 813 814 836 public static int getLockMode() { 837 return RrdDb.lockMode; 838 } 839 840 846 public static void setLockMode(int lockMode) { 847 RrdDb.lockMode = lockMode; 848 } 849 850 protected void finalize() throws Throwable { 851 close(); 852 } 853 854 860 public synchronized void copyStateTo(RrdUpdater other) throws IOException , RrdException { 861 if(!(other instanceof RrdDb)) { 862 throw new RrdException( 863 "Cannot copy RrdDb object to " + other.getClass().getName()); 864 } 865 RrdDb otherRrd = (RrdDb) other; 866 header.copyStateTo(otherRrd.header); 867 for(int i = 0; i < datasources.length; i++) { 868 int j = Util.getMatchingDatasourceIndex(this, i, otherRrd); 869 if(j >= 0) { 870 datasources[i].copyStateTo(otherRrd.datasources[j]); 871 } 872 } 873 for(int i = 0; i < archives.length; i++) { 874 int j = Util.getMatchingArchiveIndex(this, i, otherRrd); 875 if(j >= 0) { 876 archives[i].copyStateTo(otherRrd.archives[j]); 877 } 878 } 879 } 880 881 888 public Datasource getDatasource(String dsName) throws IOException { 889 try { 890 return getDatasource(getDsIndex(dsName)); 891 } 892 catch (RrdException e) { 893 return null; 894 } 895 } 896 897 906 public int getArcIndex(String consolFun, int steps) throws RrdException, IOException { 907 for(int i = 0; i < archives.length; i++) { 908 if(archives[i].getConsolFun().equals(consolFun) && 909 archives[i].getSteps() == steps) { 910 return i; 911 } 912 } 913 throw new RrdException("Could not find archive " + consolFun + "/" + steps); 914 } 915 916 924 public Archive getArchive(String consolFun, int steps) throws IOException { 925 try { 926 return getArchive(getArcIndex(consolFun, steps)); 927 } 928 catch (RrdException e) { 929 return null; 930 } 931 } 932 933 941 public String getCanonicalPath() throws IOException { 942 if(backend instanceof RrdFileBackend) { 943 return ((RrdFileBackend) backend).getCanonicalPath(); 944 } 945 else { 946 throw new IOException ("The underlying backend has no canonical path"); 947 } 948 } 949 950 954 public String getPath() { 955 return backend.getPath(); 956 } 957 958 962 public RrdBackend getRrdBackend() { 963 return backend; 964 } 965 966 970 public RrdAllocator getRrdAllocator() { 971 return allocator; 972 } 973 974 979 public synchronized byte[] getBytes() throws IOException { 980 return backend.readAll(); 981 } 982 983 995 public synchronized void sync() throws IOException { 996 backend.sync(); 997 } 998 999 1006 public static void setDefaultFactory(String factoryName) throws RrdException { 1007 RrdBackendFactory.setDefaultFactory(factoryName); 1008 } 1009 1010 public static void main(String [] args) { 1011 System.out.println("JRobin base directory: " + Util.getJRobinHomeDirectory()); 1012 System.out.println("JRobin Java Library :: RRDTool choice for the Java world"); 1013 System.out.println("http://www.jrobin.org"); 1014 System.out.println("(C) 2004 Sasa Markovic & Arne Vandamme"); 1015 } 1016 1017} 1018 | Popular Tags |