/*******************************************************************************
* Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
* Copyright (c) 2011 The OpenNMS Group, Inc.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*******************************************************************************/
package org.jrobin.core;
import java.io.IOException;
import java.util.HashMap;
import org.jrobin.core.RrdException;
/**
* This class should be used to synchronize access to RRD files
* in a multithreaded environment. This class should be also used to prevent openning of
* too many RRD files at the same time (thus avoiding operating system limits)
*/
public class RrdDbPool {
/**
* Initial capacity of the pool i.e. maximum number of simultaneously open RRD files. The pool will
* never open too many RRD files at the same time.
*/
public static final int INITIAL_CAPACITY = 200;
private static RrdDbPool instance;
private int capacity = INITIAL_CAPACITY;
private HashMap<String, RrdEntry> rrdMap = new HashMap<String, RrdEntry>(INITIAL_CAPACITY);
/**
* Creates a single instance of the class on the first call, or returns already existing one.
*
* @return Single instance of this class
* @throws RrdException Thrown if the default RRD backend is not derived from the {@link RrdFileBackendFactory}
*/
public synchronized static RrdDbPool getInstance() throws RrdException {
if (instance == null) {
instance = new RrdDbPool();
}
return instance;
}
private RrdDbPool() throws RrdException {
RrdBackendFactory factory = RrdBackendFactory.getDefaultFactory();
if (!(factory instanceof RrdFileBackendFactory)) {
throw new RrdException("Cannot create instance of " + getClass().getName() + " with " +
"a default backend factory not derived from RrdFileBackendFactory");
}
}
/**
* Requests a RrdDb reference for the given RRD file path.<p>
* <ul>
* <li>If the file is already open, previously returned RrdDb reference will be returned. Its usage count
* will be incremented by one.
* <li>If the file is not already open and the number of already open RRD files is less than
* {@link #INITIAL_CAPACITY}, the file will be open and a new RrdDb reference will be returned.
* If the file is not already open and the number of already open RRD files is equal to
* {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
* </ul>
*
* @param path Path to existing RRD file
* @return reference for the give 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 canonicalPath = Util.getCanonicalPath(path);
while (!rrdMap.containsKey(canonicalPath) && rrdMap.size() >= capacity) {
try {
wait();
}
catch (InterruptedException e) {
throw new RrdException(e);
}
}
if (rrdMap.containsKey(canonicalPath)) {
// already open, just increase usage count
RrdEntry entry = rrdMap.get(canonicalPath);
entry.count++;
return entry.rrdDb;
}
else {
// not open, open it now and add to the map
RrdDb rrdDb = new RrdDb(canonicalPath);
rrdMap.put(canonicalPath, new RrdEntry(rrdDb));
return rrdDb;
}
}
/**
* Requests a RrdDb reference for the given RRD file definition object.<p>
* <ul>
* <li>If the file with the path specified in the RrdDef object is already open,
* the method blocks until the file is closed.
* <li>If the file is not already open and the number of already open RRD files is less than
* {@link #INITIAL_CAPACITY}, a new RRD file will be created and a its RrdDb reference will be returned.
* If the file is not already open and the number of already open RRD files is equal to
* {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
* </ul>
*
* @param rrdDef Definition of the RRD file to be created
* @return Reference to the newly created 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 canonicalPath = Util.getCanonicalPath(rrdDef.getPath());
while (rrdMap.containsKey(canonicalPath) || rrdMap.size() >= capacity) {
try {
wait();
}
catch (InterruptedException e) {
throw new RrdException(e);
}
}
RrdDb rrdDb = new RrdDb(rrdDef);
rrdMap.put(canonicalPath, new RrdEntry(rrdDb));
return rrdDb;
}
/**
* Requests a RrdDb reference for the given path. The file will be created from
* external data (from XML dump, RRD file or RRDTool's binary RRD file).<p>
* <ul>
* <li>If the file with the path specified is already open,
* the method blocks until the file is closed.
* <li>If the file is not already open and the number of already open RRD files is less than
* {@link #INITIAL_CAPACITY}, a new RRD file will be created and a its RrdDb reference will be returned.
* If the file is not already open and the number of already open RRD files is equal to
* {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
* </ul>
*
* @param path Path to RRD file which should be created
* @param sourcePath Path to external data which is to be converted to JRobin's native RRD file format
* @return Reference to the newly created 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 sourcePath)
throws IOException, RrdException,RrdException {
String canonicalPath = Util.getCanonicalPath(path);
while (rrdMap.containsKey(canonicalPath) || rrdMap.size() >= capacity) {
try {
wait();
}
catch (InterruptedException e) {
throw new RrdException(e);
}
}
RrdDb rrdDb = new RrdDb(canonicalPath, sourcePath);
rrdMap.put(canonicalPath, new RrdEntry(rrdDb));
return rrdDb;
}
/**
* Releases RrdDb reference previously obtained from the pool. When a reference is released, its usage
* count is decremented by one. If usage count drops to zero, the underlying RRD file will be closed.
*
* @param rrdDb RrdDb reference to be returned to the pool
* @throws IOException Thrown in case of I/O error
* @throws RrdException Thrown in case of JRobin specific error
*/
public synchronized void release(RrdDb rrdDb) throws IOException, RrdException {
// null pointer should not kill the thread, just ignore it
if (rrdDb == null) {
return;
}
String canonicalPath = Util.getCanonicalPath(rrdDb.getPath());
if (!rrdMap.containsKey(canonicalPath)) {
throw new RrdException("Could not release [" + canonicalPath + "], the file was never requested");
}
RrdEntry entry = rrdMap.get(canonicalPath);
if (--entry.count <= 0) {
// no longer used
rrdMap.remove(canonicalPath);
notifyAll();
entry.rrdDb.close();
}
}
/**
* Returns the maximum number of simultaneously open RRD files.
*
* @return maximum number of simultaneously open RRD files
*/
public synchronized int getCapacity() {
return capacity;
}
/**
* Sets the maximum number of simultaneously open RRD files.
*
* @param capacity Maximum number of simultaneously open RRD files.
*/
public synchronized void setCapacity(int capacity) {
this.capacity = capacity;
}
/**
* Returns an array of open file names.
*
* @return Array with canonical paths to open RRD files held in the pool.
*/
public synchronized String[] getOpenFiles() {
return rrdMap.keySet().toArray(new String[0]);
}
/**
* Returns the number of open RRD files.
*
* @return Number of currently open RRD files held in the pool.
*/
public synchronized int getOpenFileCount() {
return rrdMap.size();
}
private final static class RrdEntry {
RrdDb rrdDb;
int count;
RrdEntry(final RrdDb rrdDb) {
this.rrdDb = rrdDb;
this.count = 1;
}
}
}
// OLDER VERSION IS HERE
///* ============================================================
// * JRobin : Pure java implementation of RRDTool's functionality
// * ============================================================
// *
// * Project Info: http://www.jrobin.org
// * Project Lead: Sasa Markovic (saxon@jrobin.org);
// *
// * (C) Copyright 2003-2005, by Sasa Markovic.
// *
// * Developers: Sasa Markovic (saxon@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 org.jrobin.core;
//
//import java.io.IOException;
//import java.util.HashMap;
//import java.util.Iterator;
//import java.util.LinkedHashMap;
//import java.util.Set;
//
///**
// * Class to represent the pool of open RRD files.<p>
// *
// * To open already existing RRD file with JRobin, you have to create a
// * {@link 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, low-priority
// * 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. Not that the {@link RrdDb} objects returned from the pool are
// * also thread-safe<p>
// *
// * You should know that each operating system has its own internal limit on the number
// * of simultaneously open files. The capacity of your RrdDbPool should be
// * reasonably smaller than the limit imposed by your operating system.<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 {
// static final String GC_THREAD_NAME = "RrdDbPool GC thread";
// static final String CLOSING_THREAD_NAME = "RrdDbPool closing thread";
// private static final boolean DEBUG = false;
//
// // singleton pattern
// private static RrdDbPool ourInstance;
// private boolean closingOnExit = true;
//
// private Thread shutdownHook = new Thread(CLOSING_THREAD_NAME) {
// public void run() {
// try {
// close();
// }
// catch (IOException e) {
// e.printStackTrace();
// }
// }
// };
//
// /**
// * 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 = 500;
// private int capacity = INITIAL_CAPACITY, maxUsedCapacity;
// private boolean active = true;
//
// /**
// * Constant to represent the internal behaviour of the pool.
// * Defaults to <code>true</code> but can be changed at runtime. See
// * {@link #setLimitedCapacity(boolean)} for more information.
// */
// public static final boolean LIMITED_CAPACITY = false;
// private boolean limitedCapacity = LIMITED_CAPACITY;
//
// /**
// * Constant to represent the priority of the background thread which closes excessive RRD files
// * which are no longer in use.
// */
// public static final int GC_THREAD_PRIORITY = /** Thread.NORM_PRIORITY - */ 1;
//
// private HashMap<String, RrdEntry> rrdMap = new HashMap<String, RrdEntry>(INITIAL_CAPACITY);
// private LinkedHashMap<String, RrdEntry> rrdIdleMap = new LinkedHashMap<String, RrdEntry>(INITIAL_CAPACITY);
// private RrdBackendFactory factory;
// private int poolHitsCount = 0, poolRequestsCount = 0;
//
// /**
// * 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() {
// setClosingOnExit(closingOnExit);
// }
//
// /**
// * Checks the exiting behaviour of RrdDbPool.
// * @return <code>True</code>, if all RRD files are to be closed
// * when application invokes <code>System.exit()</code>.
// * <code>False</code> otherwise. The default behaviour is <code>true</code>
// * (all RRD files will be closed on exit).
// */
// public synchronized boolean isClosingOnExit() {
// return closingOnExit;
// }
//
// /**
// * Sets the exiting behaviour of RrdDbPool.
// * @param closingOnExit <code>True</code>, if all RRD files are to be closed
// * when application invokes <code>System.exit()</code>.
// * <code>False</code> otherwise. The default behaviour is <code>true</code>
// * (all RRD files will be closed on exit).
// */
// public synchronized void setClosingOnExit(boolean closingOnExit) {
// Runtime runtime = Runtime.getRuntime();
// runtime.removeShutdownHook(shutdownHook);
// if(closingOnExit) {
// runtime.addShutdownHook(shutdownHook);
// }
// this.closingOnExit = closingOnExit;
// }
//
// private void startGarbageCollector() {
// Thread gcThread = new Thread(this, GC_THREAD_NAME);
// gcThread.setPriority(GC_THREAD_PRIORITY);
// 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 {
// proveActive();
// poolRequestsCount++;
// String canonicalPath = getCanonicalPath(path);
// for(;;) {
// RrdEntry rrdEntry = rrdMap.get(canonicalPath);
// if (rrdEntry != null) {
// // already open, use it!
// reportUsage(canonicalPath, rrdEntry);
// poolHitsCount++;
//// debug("CACHED: " + rrdEntry.dump());
// return rrdEntry.getRrdDb();
// }
// else if(!limitedCapacity || rrdMap.size() < capacity) {
// // not found, open it
// RrdDb rrdDb = createRrdDb(path, null);
// rrdEntry = new RrdEntry(rrdDb);
// addRrdEntry(canonicalPath, rrdEntry);
//// debug("ADDED: " + rrdEntry.dump());
// return rrdDb;
// }
// else {
// // we have to wait
// try {
// wait();
// }
// catch (InterruptedException e) {
// throw new RrdException("Request for file '" + path + "' was interrupted");
// }
// }
// }
// }
//
// /**
// * 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 {
// return requestNewRrdDb(path, xmlPath);
// }
//
// /**
// * 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 {
// return requestNewRrdDb(rrdDef.getPath(), rrdDef);
// }
//
// private RrdDb requestNewRrdDb(String path, Object creationDef) throws IOException, RrdException {
// proveActive();
// poolRequestsCount++;
// String canonicalPath = getCanonicalPath(path);
// for(;;) {
// RrdEntry rrdEntry = rrdMap.get(canonicalPath);
// if(rrdEntry != null) {
// // already open
// removeIfIdle(canonicalPath, rrdEntry);
// }
// else if(!limitedCapacity || rrdMap.size() < capacity) {
// RrdDb rrdDb = createRrdDb(path, creationDef);
// RrdEntry newRrdEntry = new RrdEntry(rrdDb);
// addRrdEntry(canonicalPath, newRrdEntry);
//// debug("ADDED: " + newRrdEntry.dump());
// return rrdDb;
// }
// else {
// // we have to wait
// try {
// wait();
// }
// catch (InterruptedException e) {
// throw new RrdException("Request for file '" + path + "' was interrupted");
// }
// }
// }
// }
//
// private RrdDb createRrdDb(String path, Object creationDef) throws RrdException, IOException {
// if(creationDef == null) {
// // existing RRD
// return new RrdDb(path, getFactory());
// }
// else if(creationDef instanceof String) {
// // XML input
// return new RrdDb(path, (String) creationDef, getFactory());
// }
// else if(creationDef instanceof RrdDef) {
// // RrdDef
// return new RrdDb((RrdDef) creationDef, getFactory());
// }
// else {
// throw new RrdException("Unexpected input object type: " +
// creationDef.getClass().getName());
// }
// }
//
// private void reportUsage(String canonicalPath, RrdEntry rrdEntry) {
// if (rrdEntry.reportUsage() == 1) {
// // must not be garbage collected
// rrdIdleMap.remove(canonicalPath);
// }
// }
//
// private void reportRelease(String canonicalPath, RrdEntry rrdEntry) {
// if (rrdEntry.reportRelease() == 0) {
// // ready to be garbage collected
// rrdIdleMap.put(canonicalPath, rrdEntry);
// }
// }
//
// private void addRrdEntry(String canonicalPath, RrdEntry newRrdEntry) {
// rrdMap.put(canonicalPath, newRrdEntry);
// maxUsedCapacity = Math.max(rrdMap.size(), maxUsedCapacity);
// // notify waiting threads
// notifyAll();
// }
//
// private void removeIfIdle(String canonicalPath, RrdEntry rrdEntry)
// throws RrdException, IOException {
// // already open, check if active (not released)
// if (rrdEntry.isInUse()) {
// // not released, not allowed here
// throw new RrdException("Cannot create new RrdDb file: " +
// "File '" + canonicalPath + "' already in use");
// } else {
// // open but released... safe to close it
//// debug("WILL BE RECREATED: " + rrdEntry.dump());
// removeRrdEntry(canonicalPath, rrdEntry);
// }
// }
//
// private void removeRrdEntry(String canonicalPath, RrdEntry rrdEntry) throws IOException {
// rrdEntry.closeRrdDb();
// rrdMap.remove(canonicalPath);
// rrdIdleMap.remove(canonicalPath);
//// debug("REMOVED: " + rrdEntry.dump());
// }
//
// /**
// * Method used to report that the reference to a RRD file is no longer needed. File that
// * is no longer needed (all references to it are released) is marked 'eligible for
// * closing'. It will be eventually closed by the pool when the number of open RRD files
// * becomes too big. Most recently released files will be closed last.
// *
// * @param rrdDb Reference to RRD file that is no longer needed.
// * @throws IOException Thrown in case of I/O error.
// * @throws RrdException Thrown in case of JRobin specific error.
// */
// public synchronized void release(RrdDb rrdDb) throws IOException, RrdException {
// proveActive();
// if (rrdDb == null) {
// // we don't want NullPointerException
// return;
// }
// if (rrdDb.isClosed()) {
// throw new RrdException("File " + rrdDb.getPath() + " already closed");
// }
// String canonicalPath = getCanonicalPath(rrdDb.getPath());
// if (rrdMap.containsKey(canonicalPath)) {
// RrdEntry rrdEntry = rrdMap.get(canonicalPath);
// reportRelease(canonicalPath, rrdEntry);
//// debug("RELEASED: " + rrdEntry.dump());
// } else {
// throw new RrdException("RRD file " + rrdDb.getPath() + " not in the pool");
// }
// // notify waiting threads
// notifyAll();
// }
//
// /**
// * This method runs garbage collector in a separate thread. If the number of
// * open RRD files kept in the pool is too big (greater than number
// * returned from {@link #getCapacity getCapacity()}), garbage collector will try
// * to close and remove RRD files with a reference count equal to zero.
// * Never call this method directly.
// */
// public void run() {
//// debug("GC: started");
// while (active) {
// synchronized (this) {
// if (rrdMap.size() >= capacity && rrdIdleMap.size() > 0) {
// try {
// String canonicalPath = rrdIdleMap.keySet().iterator().next();
// RrdEntry rrdEntry = rrdIdleMap.get(canonicalPath);
//// debug("GC: closing " + rrdEntry.dump());
// removeRrdEntry(canonicalPath, rrdEntry);
// } catch (IOException e) {
// e.printStackTrace();
// }
// notifyAll();
// }
// else {
// try {
//// debug("GC: waiting");
// wait();
//// debug("GC: running");
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
// }
// }
//
// protected void finalize() throws IOException {
// close();
// }
//
// /**
// * Clears the internal state of the pool entirely. All open RRD files are closed.
// *
// * @throws IOException Thrown in case of I/O related error.
// */
// public synchronized void reset() throws IOException {
// Iterator<RrdEntry> it = rrdMap.values().iterator();
// while (it.hasNext()) {
// RrdEntry rrdEntry = it.next();
// rrdEntry.closeRrdDb();
// }
// rrdMap.clear();
// rrdIdleMap.clear();
//// debug("Pool cleared");
// }
//
// /**
// * Closes the pool and all RRD files currently held in the pool.
// * No further operations on the pool are allowed.
// * @throws IOException Thrown in case of I/O error.
// */
// public synchronized void close() throws IOException {
// if(active) {
// active = false;
// reset();
//// debug("The pool is closed.");
// }
// else {
//// debug("The pool is already closed!");
// }
// }
//
// private static String getCanonicalPath(String path) throws IOException {
// return Util.getCanonicalPath(path);
// }
//
// static void debug(String msg) {
// if (DEBUG) {
// System.out.println("POOL: " + msg);
// }
// }
//
// /**
// * Returns the internal state of the pool. Useful for debugging purposes.
// *
// * @param dumpFiles <code>true</code>, if dumped information should contain paths to open files
// * currently held in the pool, <code>false</code> otherwise
// * @return Internal pool state (with an optional list of open RRD files and
// * the current number of usages for each one).
// * @throws IOException Thrown in case of I/O error.
// */
// public synchronized String dump(boolean dumpFiles) throws IOException {
// StringBuffer buff = new StringBuffer();
// buff.append("==== POOL DUMP ===========================\n");
// buff.append("open=" + rrdMap.size() + ", idle=" + rrdIdleMap.size() + "\n");
// buff.append("capacity=" + capacity + ", " + "maxUsedCapacity=" + maxUsedCapacity + "\n");
// buff.append("hits=" + poolHitsCount + ", " + "requests=" + poolRequestsCount + "\n");
// buff.append("efficiency=" + getPoolEfficiency() + "\n");
// if(dumpFiles) {
// buff.append("---- CACHED FILES ------------------------\n");
// Iterator<RrdEntry> it = rrdMap.values().iterator();
// while (it.hasNext()) {
// RrdEntry rrdEntry = it.next();
// buff.append(rrdEntry.dump() + "\n");
// }
// }
// return buff.toString();
// }
//
// /**
// * Returns the complete internal state of the pool. Useful for debugging purposes.
// *
// * @return Internal pool state (with a list of open RRD files and the current number of
// * usages for each one).
// * @throws IOException Thrown in case of I/O error.
// */
// public synchronized String dump() throws IOException {
// return dump(true);
// }
//
// /**
// * Returns paths to all open files currently held in the pool.
// * @return An array containing open file paths.
// */
// public synchronized String[] getCachedFilePaths() {
// Set<String> keySet = rrdMap.keySet();
// int n = keySet.size(), i = 0;
// String[] files = new String[n];
// Iterator<String> it = keySet.iterator();
// while(it.hasNext()) {
// files[i++] = it.next();
// }
// return files;
// }
//
// /**
// * Returns maximum number of internally open RRD files
// * which still does not force garbage collector to run.
// *
// * @return Desired nuber of open files held in the pool.
// */
// public synchronized int getCapacity() {
// return capacity;
// }
//
// /**
// * Sets maximum number of internally open RRD files
// * which still does not force garbage collector to run.
// *
// * @param capacity Desired number of open files to hold in the pool
// */
// public synchronized void setCapacity(int capacity) {
// this.capacity = capacity;
//// debug("Capacity set to: " + capacity);
// }
//
// private RrdBackendFactory getFactory() throws RrdException {
// if (factory == null) {
// factory = RrdBackendFactory.getDefaultFactory();
// if (!(factory instanceof RrdFileBackendFactory)) {
// factory = null;
// throw new RrdException(
// "RrdDbPool cannot work with factories not derived from RrdFileBackendFactory");
// }
// }
// return factory;
// }
//
// private class RrdEntry {
// private RrdDb rrdDb;
// private int usageCount = 1;
//
// public RrdEntry(RrdDb rrdDb) {
// this.rrdDb = rrdDb;
// }
//
// RrdDb getRrdDb() {
// return rrdDb;
// }
//
// int reportUsage() {
// assert usageCount >= 0: "Unexpected reportUsage count: " + usageCount;
// return ++usageCount;
// }
//
// int reportRelease() {
// assert usageCount > 0: "Unexpected reportRelease count: " + usageCount;
// return --usageCount;
// }
//
// boolean isInUse() {
// return usageCount > 0;
// }
//
// void closeRrdDb() throws IOException {
// rrdDb.close();
// }
//
// String dump() throws IOException {
// String canonicalPath = getCanonicalPath(rrdDb.getPath());
// return canonicalPath + " [" + usageCount + "]";
// }
// }
//
// /**
// * Calculates pool's efficency ratio. The ratio is obtained by dividing the number of
// * RrdDb requests served from the internal pool of open RRD files
// * with the number of total RrdDb requests.
// *
// * @return Pool's efficiency ratio as a double between 1 (best) and 0 (worst).
// * If no RrdDb reference was ever requested, 1 would be returned.
// */
// public synchronized double getPoolEfficiency() {
// if (poolRequestsCount == 0) {
// return 1.0;
// }
// double ratio = (double) poolHitsCount / (double) poolRequestsCount;
// // round to 3 decimal digits
// return Math.round(ratio * 1000.0) / 1000.0;
// }
//
// /**
// * Returns the number of RRD requests served from the internal pool of open RRD files
// *
// * @return The number of pool "hits".
// */
// public synchronized int getPoolHitsCount() {
// return poolHitsCount;
// }
//
// /**
// * Returns the total number of RRD requests successfully served by this pool.
// *
// * @return Total number of RRD requests
// */
// public synchronized int getPoolRequestsCount() {
// return poolRequestsCount;
// }
//
// /**
// * Returns the maximum number of open RRD files over the lifetime
// * of the pool.
// * @return maximum number of open RRD files.
// */
// public synchronized int getMaxUsedCapacity() {
// return maxUsedCapacity;
// }
//
// /**
// * Checks the internal behaviour of the pool. See {@link #setLimitedCapacity(boolean)} for
// * more information.
// *
// * @return <code>true</code> if the pool is 'flexible' (by not imposing the strict
// * limit on the number of simultaneously open files), <code>false</code> otherwise.
// */
// public synchronized boolean isLimitedCapacity() {
// return limitedCapacity;
// }
//
// /**
// * Sets the behaviour of the pool. If <code>true</code> is passed as argument, the pool will never
// * open more than {@link #getCapacity()} files at any time. If set to <code>false</code>,
// * the pool might keep more open files, but only for a short period of time. This method might be
// * useful if you want avoid OS limits when it comes to the number of simultaneously open files.<p>
// *
// * By default, the pool behaviour is 'flexible' (<code>limitedCapacity</code> property defaults
// * to false<p>
// *
// * @param limitedCapacity <code>true</code> if the pool should be 'flexible' (not imposing the strict
// * limit on the number of simultaneously open files), <code>false</code> otherwise.
// */
// public synchronized void setLimitedCapacity(boolean limitedCapacity) {
// this.limitedCapacity = limitedCapacity;
// }
//
// private void proveActive() throws IOException {
// if(!active) {
// throw new IOException("RrdDbPool is already closed");
// }
// }
//
// /**
// * Checks if the pool is active. You can request RrdDb references only from the active pool. The
// * pool is deactived when the {@link #close()} method is called.
// * @return <code>true</code> if active, <code>false</code> otherwise.
// */
// public synchronized boolean isActive() {
// return active;
// }
//}
//