📄 rrddb.java
字号:
/* ============================================================
* JRobin : Pure java implementation of RRDTool's functionality
* ============================================================
*
* Project Info: http://www.jrobin.org
* Project Lead: Sasa Markovic (saxon@jrobin.org);
*
* (C) Copyright 2003, by Sasa Markovic.
*
* Developers: Sasa Markovic (saxon@jrobin.org)
* Arne Vandamme (cobralord@jrobin.org)
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
package net.jumperz.ext.org.jrobin.core;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* <p>Main class used to create and manipulate round robin databases (RRDs). Use this class to perform
* update and fetch operations on exisiting RRDs, to create new RRD from
* the definition (object of class {@link net.jumperz.ext.org.jrobin.core.RrdDef RrdDef}) or
* from XML file (dumped content of RRDTool's or JRobin's RRD file).</p>
*
* <p>Each RRD is backed with some kind of storage. For example, RRDTool supports only one kind of
* storage (disk file). On the contrary, JRobin gives you freedom to use other storage (backend) types
* even to create your own backend types for some special purposes. JRobin by default stores
* RRD data in files (as RRDTool), but you might choose to store RRD data in memory (this is
* supported in JRobin), to use java.nio.* instead of java.io.* package for file manipulation
* (also supported) or to store whole RRDs in the SQL database
* (you'll have to extend some classes to do this).</p>
*
* <p>Note that JRobin uses binary format different from RRDTool's format. You cannot
* use this class to manipulate RRD files created with RRDTool. <b>However, if you perform
* the same sequence of create, update and fetch operations, you will get exactly the same
* results from JRobin and RRDTool.</b><p>
*
* <p>
* You will not be able to use JRobin API if you are not familiar with
* basic RRDTool concepts. Good place to start is the
* <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/tutorial/rrdtutorial.html">official RRD tutorial</a>
* and relevant RRDTool man pages: <a href="../../../../man/rrdcreate.html" target="man">rrdcreate</a>,
* <a href="../../../../man/rrdupdate.html" target="man">rrdupdate</a>,
* <a href="../../../../man/rrdfetch.html" target="man">rrdfetch</a> and
* <a href="../../../../man/rrdgraph.html" target="man">rrdgraph</a>.
* For RRDTool's advanced graphing capabilities (RPN extensions), also supported in JRobin,
* there is an excellent
* <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/tutorial/cdeftutorial.html" target="man">CDEF tutorial</a>.
* </p>
*
* @see RrdBackend
* @see RrdBackendFactory
*/
public class RrdDb implements RrdUpdater {
/** See {@link #getLockMode() getLockMode()} for explanation */
public static final int NO_LOCKS = 0;
/** See {@link #getLockMode() getLockMode()} for explanation */
public static final int WAIT_IF_LOCKED = 1;
/** See {@link #getLockMode() getLockMode()} for explanation */
public static final int EXCEPTION_IF_LOCKED = 2;
// static final String RRDTOOL = "rrdtool";
static final int XML_INITIAL_BUFFER_CAPACITY = 100000; // bytes
private static int lockMode = NO_LOCKS;
private RrdBackend backend;
private RrdAllocator allocator = new RrdAllocator();
private Header header;
private Datasource[] datasources;
private Archive[] archives;
private boolean closed = false;
/**
* <p>Constructor used to create new RRD object from the definition. This RRD object will be backed
* with a storage (backend) of the default type. Initially, storage type defaults to "NIO"
* (RRD bytes will be put in a file on the disk). Default storage type can be changed with a static
* {@link RrdBackendFactory#setDefaultFactory(String)} method call.</p>
*
* <p>New RRD file structure is specified with an object of class
* {@link org.jrobin.core.RrdDef <b>RrdDef</b>}. The underlying RRD storage is created as soon
* as the constructor returns.</p>
*
* <p>Typical scenario:</p>
*
* <pre>
* // create new RRD definition
* RrdDef def = new RrdDef("test.rrd", 300);
* def.addDatasource("input", "COUNTER", 600, 0, Double.NaN);
* def.addDatasource("output", "COUNTER", 600, 0, Double.NaN);
* def.addArchive("AVERAGE", 0.5, 1, 600);
* def.addArchive("AVERAGE", 0.5, 6, 700);
* def.addArchive("AVERAGE", 0.5, 24, 797);
* def.addArchive("AVERAGE", 0.5, 288, 775);
* def.addArchive("MAX", 0.5, 1, 600);
* def.addArchive("MAX", 0.5, 6, 700);
* def.addArchive("MAX", 0.5, 24, 797);
* def.addArchive("MAX", 0.5, 288, 775);
*
* // RRD definition is now completed, create the database!
* RrdDb rrd = new RrdDb(def);
* // new RRD file has been created on your disk
* </pre>
*
* @param rrdDef Object describing the structure of the new RRD file.
* @throws IOException Thrown in case of I/O error.
* @throws RrdException Thrown if invalid RrdDef object is supplied.
*/
public RrdDb(RrdDef rrdDef) throws RrdException, IOException {
this(rrdDef, RrdFileBackendFactory.getDefaultFactory());
}
/**
* <p>Constructor used to create new RRD object from the definition object but with a storage
* (backend) different from default.</p>
*
* <p>JRobin uses <i>factories</i> to create RRD backend objecs. There are three different
* backend factories supplied with JRobin, and each factory has its unique name:</p>
*
* <ul>
* <li><b>FILE</b>: backends created from this factory will store RRD data to files by using
* java.io.* classes and methods
* <li><b>NIO</b>: backends created from this factory will store RRD data to files by using
* java.nio.* classes and methods
* <li><b>MEMORY</b>: backends created from this factory will store RRD data in memory. This might
* be useful in runtime environments which prohibit disk utilization, or for storing temporary,
* non-critical data (it gets lost as soon as JVM exits).
* </ul>
*
* <p>For example, to create RRD in memory, use the following code</p>
* <pre>
* RrdBackendFactory factory = RrdBackendFactory.getFactory("MEMORY");
* RrdDb rrdDb = new RrdDb(rrdDef, factory);
* rrdDb.close();
* </pre>
*
* <p>New RRD file structure is specified with an object of class
* {@link org.jrobin.core.RrdDef <b>RrdDef</b>}. The underlying RRD storage is created as soon
* as the constructor returns.</p>
* @param rrdDef RRD definition object
* @param factory The factory which will be used to create storage for this RRD
* @throws RrdException Thrown if invalid factory or definition is supplied
* @throws IOException Thrown in case of I/O error
* @see RrdBackendFactory
*/
public RrdDb(RrdDef rrdDef, RrdBackendFactory factory) throws RrdException, IOException {
rrdDef.validate();
String path = rrdDef.getPath();
backend = factory.open(path, false, lockMode);
backend.setLength(rrdDef.getEstimatedSize());
// create header
header = new Header(this, rrdDef);
// create datasources
DsDef[] dsDefs = rrdDef.getDsDefs();
datasources = new Datasource[dsDefs.length];
for(int i = 0; i < dsDefs.length; i++) {
datasources[i] = new Datasource(this, dsDefs[i]);
}
// create archives
ArcDef[] arcDefs = rrdDef.getArcDefs();
archives = new Archive[arcDefs.length];
for(int i = 0; i < arcDefs.length; i++) {
archives[i] = new Archive(this, arcDefs[i]);
}
backend.afterCreate();
}
/**
* <p>Constructor used to open already existing RRD. This RRD object will be backed
* with a storage (backend) of the default type (file on the disk). Constructor
* obtains read or read/write access to this RRD.</p>
*
* @param path Path to existing RRD.
* @param readOnly Should be set to <code>false</code> if you want to update
* the underlying RRD. If you want just to fetch data from the RRD file
* (read-only access), specify <code>true</code>. If you try to update RRD file
* open in read-only mode (<code>readOnly</code> set to <code>true</code>),
* <code>IOException</code> will be thrown.
* @throws IOException Thrown in case of I/O error.
* @throws RrdException Thrown in case of JRobin specific error.
*/
public RrdDb(String path, boolean readOnly) throws IOException, RrdException {
this(path, readOnly, RrdBackendFactory.getDefaultFactory());
}
/**
* <p>Constructor used to open already existing RRD backed
* with a storage (backend) different from default. Constructor
* obtains read or read/write access to this RRD.</p>
*
* @param path Path to existing RRD.
* @param readOnly Should be set to <code>false</code> if you want to update
* the underlying RRD. If you want just to fetch data from the RRD file
* (read-only access), specify <code>true</code>. If you try to update RRD file
* open in read-only mode (<code>readOnly</code> set to <code>true</code>),
* <code>IOException</code> will be thrown.
* @param factory Backend factory which will be used for this RRD.
* @throws IOException Thrown in case of I/O error.
* @throws RrdException Thrown in case of JRobin specific error.
* @see RrdBackendFactory
*/
public RrdDb(String path, boolean readOnly, RrdBackendFactory factory)
throws IOException, RrdException {
// opens existing RRD file - throw exception if the file does not exist...
if(!factory.exists(path)) {
throw new IOException("Could not open " + path + " [non existent]");
}
backend = factory.open(path, readOnly, lockMode);
// restore header
header = new Header(this, (RrdDef) null);
header.validateHeader();
// restore datasources
int dsCount = header.getDsCount();
datasources = new Datasource[dsCount];
for(int i = 0; i < dsCount; i++) {
datasources[i] = new Datasource(this, null);
}
// restore archives
int arcCount = header.getArcCount();
archives = new Archive[arcCount];
for(int i = 0; i < arcCount; i++) {
archives[i] = new Archive(this, null);
}
}
/**
* <p>Constructor used to open already existing RRD in R/W mode, with a default storage
* (backend) type (file on the disk).
*
* @param path Path to existing RRD.
* @throws IOException Thrown in case of I/O error.
* @throws RrdException Thrown in case of JRobin specific error.
*/
public RrdDb(String path) throws IOException, RrdException {
this(path, false);
}
/**
* <p>Constructor used to open already existing RRD in R/W mode with a storage (backend) type
* different from default.</p>
*
* @param path Path to existing RRD.
* @param factory Backend factory used to create this RRD.
* @throws IOException Thrown in case of I/O error.
* @throws RrdException Thrown in case of JRobin specific error.
* @see RrdBackendFactory
*/
public RrdDb(String path, RrdBackendFactory factory) throws IOException, RrdException {
this(path, false, factory);
}
/**
* <p>Constructor used to create new RRD from XML dump. Newly created RRD will be backed
* with a default storage (backend) type (file on the disk). JRobin and RRDTool
* use the same format for XML dump and this constructor should be used to
* (re)create JRobin RRD from XML. In other words, it is possible to convert
* RRDTool RRD files to JRobin RRD files: first, dump the content of RRDTool
* RRD file (use command line):</p>
*
* <code>rrdtool dump original.rrd > original.xml</code>
*
* <p>Than, use file <code>original.xml</code> to create JRobin RRD file
* <code>copy.rrd</code>:</p>
*
* <code>RrdDb rrd = new RrdDb("copy.rrd", "original.xml");</code>
*
* <p>See documentation for {@link #dumpXml(java.lang.String) dumpXml()} method
* how to convert JRobin files to RRDTool format.</p>
*
* @param rrdPath Path to RRD file which will be created
* @param xmlPath Path to file containing XML dump of RRDTool's or JRobin's RRD file
* @throws IOException Thrown in case of I/O error
* @throws RrdException Thrown in case of JRobin specific error
*/
public RrdDb(String rrdPath, String xmlPath) throws IOException, RrdException {
this(rrdPath, xmlPath, RrdBackendFactory.getDefaultFactory());
}
/**
* <p>Constructor used to create new RRD from XML dump but with a storage (backend) type
* different from default.</p>
*
* @param rrdPath Path to RRD which will be created
* @param xmlPath Path to file containing XML dump of RRDTool's or JRobin's RRD file
* @param factory Backend factory which will be used to create storage (backend) for this RRD.
* @throws IOException Thrown in case of I/O error
* @throws RrdException Thrown in case of JRobin specific error
* @see RrdBackendFactory
*/
public RrdDb(String rrdPath, String xmlPath, RrdBackendFactory factory)
throws IOException, RrdException {
backend = factory.open(rrdPath, false, lockMode);
DataImporter reader;
if(xmlPath.startsWith("rrdtool:/")) {
String rrdToolPath = xmlPath.substring("rrdtool:/".length());
reader = new RrdToolReader(rrdToolPath);
}
else if(xmlPath.startsWith("xml:/")) {
xmlPath = xmlPath.substring("xml:/".length());
reader = new XmlReader(xmlPath);
}
else {
reader = new XmlReader(xmlPath);
}
backend.setLength(reader.getEstimatedSize());
// create header
header = new Header(this, reader);
// create datasources
datasources = new Datasource[reader.getDsCount()];
for(int i = 0; i < datasources.length; i++) {
datasources[i] = new Datasource(this, reader, i);
}
// create archives
archives = new Archive[reader.getArcCount()];
for(int i = 0; i < archives.length; i++) {
archives[i] = new Archive(this, reader, i);
}
reader.release();
// XMLReader is a rather huge DOM tree, release memory ASAP
reader = null;
backend.afterCreate();
}
/**
* Closes RRD. No further operations are allowed on this RrdDb object.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -