📄 rrddbpool.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.IOException;
import java.util.*;
/**
* Class to represent the pool of open RRD files.<p>
*
* To open already existing RRD file with JRobin, you have to create a
* {@link net.jumperz.ext.org.jrobin.core.RrdDb RrdDb} object by specifying RRD file path
* as constructor argument. This operation can be time consuming
* especially with large RRD files with many datasources and
* several long archives.<p>
*
* In a multithreaded environment you might probably need a reference to the
* same RRD file from two different threads (RRD file updates are performed in
* one thread but data fetching and graphing is performed in another one). To make
* the RrdDb construction process more efficient it might be convenient to open all
* RRD files in a centralized place. That's the purpose of RrdDbPool class.<p>
*
* How does it work? The typical usage scenario goes like this:<p>
*
* <pre>
* // obtain instance to RrdDbPool object
* RrdDbPool pool = RrdDbPool.getInstance();
*
* // request a reference to RrdDb object
* String path = "some_relative_or_absolute_path_to_any_RRD_file";
* RrdDb rrdDb = RrdDbPool.requestRrdDb(path);
*
* // reference obtained, do whatever you want with it...
* ...
* ...
*
* // once you don't need the reference, release it.
* // DO NOT CALL rrdDb.close() - files no longer in use are eventually closed by the pool
* pool.release(rrdDb);
*</pre>
*
* It's that simple. When the reference is requested for
* the first time, RrdDbPool will open the RRD file
* for you and make some internal note that the RRD file is used only once. When the reference
* to the same file (same RRD file path) is requested for the second time, the same RrdDb
* reference will be returned, and its usage count will be increased by one. When the
* reference is released its usage count will be decremented by one.<p>
*
* When the reference count drops to zero, RrdDbPool will not close the underlying
* RRD file immediatelly. Instead of it, it will be marked as 'eligible for closing'.
* If someone request the same RRD file again (before it gets closed), the same
* reference will be returned again.<p>
*
* RrdDbPool has a 'garbage collector' which runs in a separate
* thread and gets activated only when the number of RRD files kept in the
* pool is too big (greater than number returned from {@link #getCapacity getCapacity()}).
* Only RRD files with a reference count equal to zero
* will be eligible for closing. Unreleased RrdDb references are never invalidated.
* RrdDbPool object keeps track of the time when each RRD file
* becomes eligible for closing so that the oldest RRD file gets closed first.<p>
*
* Initial RrdDbPool capacity is set to {@link #INITIAL_CAPACITY}. Use {@link #setCapacity(int)} method to
* change it at any time.<p>
*
* <b>WARNING:</b>Never use close() method on the reference returned from the pool.
* When the reference is no longer needed, return it to the pool with the
* {@link #release(RrdDb) release()} method.<p>
*
* However, you are not forced to use RrdDbPool methods to obtain RrdDb references
* to RRD files, 'ordinary' RrdDb constructors are still available. But RrdDbPool class
* offers serious performance improvement especially in complex applications with many
* threads and many simultaneously open RRD files.<p>
*
* The pool is thread-safe.<p>
*
* <b>WARNING:</b> The pool cannot be used to manipulate RrdDb objects
* with {@link RrdBackend backends} different from default.<p>
*/
public class RrdDbPool implements Runnable {
private static RrdDbPool ourInstance;
private static final boolean DEBUG = false;
/**
* Constant to represent the maximum number of internally open RRD files
* which still does not force garbage collector (the process which closes RRD files) to run.
*/
public static final int INITIAL_CAPACITY = 100;
private int capacity = INITIAL_CAPACITY;
private Map rrdMap = new HashMap();
private List rrdGcList = new LinkedList();
private RrdBackendFactory factory;
private int poolHitsCount, poolRequestsCount;
/**
* Returns an instance to RrdDbPool object. Only one such object may exist in each JVM.
* @return Instance to RrdDbPool object.
*/
public synchronized static RrdDbPool getInstance() {
if (ourInstance == null) {
ourInstance = new RrdDbPool();
ourInstance.startGarbageCollector();
}
return ourInstance;
}
private RrdDbPool() {
}
private void startGarbageCollector() {
Thread gcThread = new Thread(this);
gcThread.setDaemon(true);
gcThread.start();
}
/**
* Returns a reference to an existing RRD file with the specified path.
* If the file is already open in the pool, existing reference to it will be returned.
* Otherwise, the file is open and a newly created reference to it is returned.
*
* @param path Relative or absolute path to a RRD file.
* @return Reference to a RrdDb object (RRD file).
* @throws IOException Thrown in case of I/O error.
* @throws RrdException Thrown in case of JRobin specific error.
*/
public synchronized RrdDb requestRrdDb(String path) throws IOException, RrdException {
String keypath = getCanonicalPath(path);
RrdDb rrdDbRequested;
if (rrdMap.containsKey(keypath)) {
// already open
RrdEntry rrdEntry = (RrdEntry) rrdMap.get(keypath);
reportUsage(rrdEntry);
debug("EXISTING: " + rrdEntry.dump());
rrdDbRequested = rrdEntry.getRrdDb();
poolHitsCount++;
} else {
// not found, open it
RrdDb rrdDb = new RrdDb(path, getFactory());
addRrdEntry(keypath, rrdDb);
rrdDbRequested = rrdDb;
}
poolRequestsCount++;
return rrdDbRequested;
}
/**
* Returns a reference to a new RRD file. The new file will have the specified
* relative or absolute path, and its contents will be provided from the specified
* XML file (RRDTool comaptible).
* @param path Relative or absolute path to a new RRD file.
* @param xmlPath Relative or absolute path to an existing XML dump file (RRDTool comaptible)
* @return Reference to a RrdDb object (RRD file).
* @throws IOException Thrown in case of I/O error.
* @throws RrdException Thrown in case of JRobin specific error.
*/
public synchronized RrdDb requestRrdDb(String path, String xmlPath)
throws IOException, RrdException {
String keypath = getCanonicalPath(path);
prooveInactive(keypath);
RrdDb rrdDb = new RrdDb(path, xmlPath, getFactory());
addRrdEntry(keypath, rrdDb);
poolRequestsCount++;
return rrdDb;
}
/**
* Returns a reference to a new RRD file. The new file will be created based on the
* definition contained in a RrdDef object.
* @param rrdDef RRD definition object
* @return Reference to a RrdDb object (RRD file).
* @throws IOException Thrown in case of I/O error.
* @throws RrdException Thrown in case of JRobin specific error.
*/
public synchronized RrdDb requestRrdDb(RrdDef rrdDef) throws IOException, RrdException {
String path = rrdDef.getPath();
String keypath = getCanonicalPath(path);
prooveInactive(keypath);
RrdDb rrdDb = new RrdDb(rrdDef, getFactory());
addRrdEntry(keypath, rrdDb);
poolRequestsCount++;
return rrdDb;
}
private void reportUsage(RrdEntry rrdEntry) {
if(rrdEntry.reportUsage() == 1) {
// must not be garbage collected
rrdGcList.remove(rrdEntry);
}
}
private void reportRelease(RrdEntry rrdEntry) {
if(rrdEntry.reportRelease() == 0) {
// ready to be garbage collected
rrdGcList.add(rrdEntry);
}
}
private void addRrdEntry(String keypath, RrdDb rrdDb) throws IOException {
RrdEntry newEntry = new RrdEntry(rrdDb);
reportUsage(newEntry);
debug("NEW: " + newEntry.dump());
rrdMap.put(keypath, newEntry);
// notify garbage collector
notify();
}
private void prooveInactive(String keypath) throws RrdException, IOException {
if(rrdMap.containsKey(keypath)) {
// already open, check if active (not released)
RrdEntry rrdEntry = (RrdEntry) rrdMap.get(keypath);
if(rrdEntry.isInUse()) {
// not released, not allowed here
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -