View Javadoc

1   /* ============================================================
2    * JRobin : Pure java implementation of RRDTool's functionality
3    * ============================================================
4    *
5    * Project Info:  http://www.jrobin.org
6    * Project Lead:  Sasa Markovic (saxon@jrobin.org);
7    *
8    * (C) Copyright 2003-2005, by Sasa Markovic.
9    *
10   * Developers:    Sasa Markovic (saxon@jrobin.org)
11   *
12   *
13   * This library is free software; you can redistribute it and/or modify it under the terms
14   * of the GNU Lesser General Public License as published by the Free Software Foundation;
15   * either version 2.1 of the License, or (at your option) any later version.
16   *
17   * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18   * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19   * See the GNU Lesser General Public License for more details.
20   *
21   * You should have received a copy of the GNU Lesser General Public License along with this
22   * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23   * Boston, MA 02111-1307, USA.
24   */
25  
26  package org.jrobin.core;
27  
28  import java.io.IOException;
29  import java.util.HashMap;
30  
31  /**
32   * This class should be used to synchronize access to RRD files
33   * in a multithreaded environment. This class should be also used to prevent openning of
34   * too many RRD files at the same time (thus avoiding operating system limits)
35   */
36  
37  public class RrdDbPool {
38  	/**
39  	 * Initial capacity of the pool i.e. maximum number of simultaneously open RRD files. The pool will
40  	 * never open too many RRD files at the same time.
41  	 */
42  	public static final int INITIAL_CAPACITY = 200;
43  	private static RrdDbPool instance;
44  
45  	private int capacity = INITIAL_CAPACITY;
46  	private HashMap<String, RrdEntry> rrdMap = new HashMap<String, RrdEntry>(INITIAL_CAPACITY);
47  
48  	/**
49  	 * Creates a single instance of the class on the first call, or returns already existing one.
50  	 *
51  	 * @return Single instance of this class
52  	 * @throws RrdException Thrown if the default RRD backend is not derived from the {@link RrdFileBackendFactory}
53  	 */
54  	public synchronized static RrdDbPool getInstance() throws RrdException {
55  		if (instance == null) {
56  			instance = new RrdDbPool();
57  		}
58  		return instance;
59  	}
60  
61  	private RrdDbPool() throws RrdException {
62  		RrdBackendFactory factory = RrdBackendFactory.getDefaultFactory();
63  		if (!(factory instanceof RrdFileBackendFactory)) {
64  			throw new RrdException("Cannot create instance of " + getClass().getName() + " with " +
65  					"a default backend factory not derived from RrdFileBackendFactory");
66  		}
67  	}
68  
69  	/**
70  	 * Requests a RrdDb reference for the given RRD file path.<p>
71  	 * <ul>
72  	 * <li>If the file is already open, previously returned RrdDb reference will be returned. Its usage count
73  	 * will be incremented by one.
74  	 * <li>If the file is not already open and the number of already open RRD files is less than
75  	 * {@link #INITIAL_CAPACITY}, the file will be open and a new RrdDb reference will be returned.
76  	 * If the file is not already open and the number of already open RRD files is equal to
77  	 * {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
78  	 * </ul>
79  	 *
80  	 * @param path Path to existing RRD file
81  	 * @return reference for the give RRD file
82  	 * @throws IOException  Thrown in case of I/O error
83  	 * @throws RrdException Thrown in case of JRobin specific error
84  	 */
85  	public synchronized RrdDb requestRrdDb(String path) throws IOException, RrdException {
86  		String canonicalPath = Util.getCanonicalPath(path);
87  		while (!rrdMap.containsKey(canonicalPath) && rrdMap.size() >= capacity) {
88  			try {
89  				wait();
90  			}
91  			catch (InterruptedException e) {
92  				throw new RrdException(e);
93  			}
94  		}
95  		if (rrdMap.containsKey(canonicalPath)) {
96  			// already open, just increase usage count
97  			RrdEntry entry = rrdMap.get(canonicalPath);
98  			entry.count++;
99  			return entry.rrdDb;
100 		}
101 		else {
102 			// not open, open it now and add to the map
103 			RrdDb rrdDb = new RrdDb(canonicalPath);
104 			rrdMap.put(canonicalPath, new RrdEntry(rrdDb));
105 			return rrdDb;
106 		}
107 	}
108 
109 	/**
110 	 * Requests a RrdDb reference for the given RRD file definition object.<p>
111 	 * <ul>
112 	 * <li>If the file with the path specified in the RrdDef object is already open,
113 	 * the method blocks until the file is closed.
114 	 * <li>If the file is not already open and the number of already open RRD files is less than
115 	 * {@link #INITIAL_CAPACITY}, a new RRD file will be created and a its RrdDb reference will be returned.
116 	 * If the file is not already open and the number of already open RRD files is equal to
117 	 * {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
118 	 * </ul>
119 	 *
120 	 * @param rrdDef Definition of the RRD file to be created
121 	 * @return Reference to the newly created RRD file
122 	 * @throws IOException  Thrown in case of I/O error
123 	 * @throws RrdException Thrown in case of JRobin specific error
124 	 */
125 	public synchronized RrdDb requestRrdDb(RrdDef rrdDef) throws IOException, RrdException {
126 		String canonicalPath = Util.getCanonicalPath(rrdDef.getPath());
127 		while (rrdMap.containsKey(canonicalPath) || rrdMap.size() >= capacity) {
128 			try {
129 				wait();
130 			}
131 			catch (InterruptedException e) {
132 				throw new RrdException(e);
133 			}
134 		}
135 		RrdDb rrdDb = new RrdDb(rrdDef);
136 		rrdMap.put(canonicalPath, new RrdEntry(rrdDb));
137 		return rrdDb;
138 	}
139 
140 	/**
141 	 * Requests a RrdDb reference for the given path. The file will be created from
142 	 * external data (from XML dump, RRD file or RRDTool's binary RRD file).<p>
143 	 * <ul>
144 	 * <li>If the file with the path specified is already open,
145 	 * the method blocks until the file is closed.
146 	 * <li>If the file is not already open and the number of already open RRD files is less than
147 	 * {@link #INITIAL_CAPACITY}, a new RRD file will be created and a its RrdDb reference will be returned.
148 	 * If the file is not already open and the number of already open RRD files is equal to
149 	 * {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
150 	 * </ul>
151 	 *
152 	 * @param path	   Path to RRD file which should be created
153 	 * @param sourcePath Path to external data which is to be converted to JRobin's native RRD file format
154 	 * @return Reference to the newly created RRD file
155 	 * @throws IOException  Thrown in case of I/O error
156 	 * @throws RrdException Thrown in case of JRobin specific error
157 	 */
158 	public synchronized RrdDb requestRrdDb(String path, String sourcePath)
159 			throws IOException, RrdException {
160 		String canonicalPath = Util.getCanonicalPath(path);
161 		while (rrdMap.containsKey(canonicalPath) || rrdMap.size() >= capacity) {
162 			try {
163 				wait();
164 			}
165 			catch (InterruptedException e) {
166 				throw new RrdException(e);
167 			}
168 		}
169 		RrdDb rrdDb = new RrdDb(canonicalPath, sourcePath);
170 		rrdMap.put(canonicalPath, new RrdEntry(rrdDb));
171 		return rrdDb;
172 	}
173 
174 	/**
175 	 * Releases RrdDb reference previously obtained from the pool. When a reference is released, its usage
176 	 * count is decremented by one. If usage count drops to zero, the underlying RRD file will be closed.
177 	 *
178 	 * @param rrdDb RrdDb reference to be returned to the pool
179 	 * @throws IOException  Thrown in case of I/O error
180 	 * @throws RrdException Thrown in case of JRobin specific error
181 	 */
182 	public synchronized void release(RrdDb rrdDb) throws IOException, RrdException {
183 		// null pointer should not kill the thread, just ignore it
184 		if (rrdDb == null) {
185 			return;
186 		}
187 		String canonicalPath = Util.getCanonicalPath(rrdDb.getPath());
188 		if (!rrdMap.containsKey(canonicalPath)) {
189 			throw new RrdException("Could not release [" + canonicalPath + "], the file was never requested");
190 		}
191 		RrdEntry entry = rrdMap.get(canonicalPath);
192 		if (--entry.count <= 0) {
193 			// no longer used
194 			rrdMap.remove(canonicalPath);
195 			notifyAll();
196 			entry.rrdDb.close();
197 		}
198 	}
199 
200 	/**
201 	 * Returns the maximum number of simultaneously open RRD files.
202 	 *
203 	 * @return maximum number of simultaneously open RRD files
204 	 */
205 	public synchronized int getCapacity() {
206 		return capacity;
207 	}
208 
209 	/**
210 	 * Sets the maximum number of simultaneously open RRD files.
211 	 *
212 	 * @param capacity Maximum number of simultaneously open RRD files.
213 	 */
214 	public synchronized void setCapacity(int capacity) {
215 		this.capacity = capacity;
216 	}
217 
218 	/**
219 	 * Returns an array of open file names.
220 	 *
221 	 * @return Array with canonical paths to open RRD files held in the pool.
222 	 */
223 	public synchronized String[] getOpenFiles() {
224 		return rrdMap.keySet().toArray(new String[0]);
225 	}
226 
227 	/**
228 	 * Returns the number of open RRD files.
229 	 *
230 	 * @return Number of currently open RRD files held in the pool.
231 	 */
232 	public synchronized int getOpenFileCount() {
233 		return rrdMap.size();
234 	}
235 
236 	class RrdEntry {
237 		RrdDb rrdDb;
238 		int count;
239 
240 		RrdEntry(RrdDb rrdDb) {
241 			this.rrdDb = rrdDb;
242 			this.count = 1;
243 		}
244 	}
245 }
246 
247 // OLDER VERSION IS HERE
248 
249 ///* ============================================================
250 // * JRobin : Pure java implementation of RRDTool's functionality
251 // * ============================================================
252 // *
253 // * Project Info:  http://www.jrobin.org
254 // * Project Lead:  Sasa Markovic (saxon@jrobin.org);
255 // *
256 // * (C) Copyright 2003-2005, by Sasa Markovic.
257 // *
258 // * Developers:    Sasa Markovic (saxon@jrobin.org)
259 // *
260 // *
261 // * This library is free software; you can redistribute it and/or modify it under the terms
262 // * of the GNU Lesser General Public License as published by the Free Software Foundation;
263 // * either version 2.1 of the License, or (at your option) any later version.
264 // *
265 // * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
266 // * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
267 // * See the GNU Lesser General Public License for more details.
268 // *
269 // * You should have received a copy of the GNU Lesser General Public License along with this
270 // * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
271 // * Boston, MA 02111-1307, USA.
272 // */
273 //package org.jrobin.core;
274 //
275 //import java.io.IOException;
276 //import java.util.HashMap;
277 //import java.util.Iterator;
278 //import java.util.LinkedHashMap;
279 //import java.util.Set;
280 //
281 ///**
282 // * Class to represent the pool of open RRD files.<p>
283 // *
284 // * To open already existing RRD file with JRobin, you have to create a
285 // * {@link org.jrobin.core.RrdDb RrdDb} object by specifying RRD file path
286 // * as constructor argument. This operation can be time consuming
287 // * especially with large RRD files with many datasources and
288 // * several long archives.<p>
289 // *
290 // * In a multithreaded environment you might probably need a reference to the
291 // * same RRD file from two different threads (RRD file updates are performed in
292 // * one thread but data fetching and graphing is performed in another one). To make
293 // * the RrdDb construction process more efficient it might be convenient to open all
294 // * RRD files in a centralized place. That's the purpose of RrdDbPool class.<p>
295 // *
296 // * How does it work? The typical usage scenario goes like this:<p>
297 // *
298 // * <pre>
299 // * // obtain instance to RrdDbPool object
300 // * RrdDbPool pool = RrdDbPool.getInstance();
301 // *
302 // * // request a reference to RrdDb object
303 // * String path = "some_relative_or_absolute_path_to_any_RRD_file";
304 // * RrdDb rrdDb = RrdDbPool.requestRrdDb(path);
305 // *
306 // * // reference obtained, do whatever you want with it...
307 // * ...
308 // * ...
309 // *
310 // * // once you don't need the reference, release it.
311 // * // DO NOT CALL rrdDb.close() - files no longer in use are eventually closed by the pool
312 // * pool.release(rrdDb);
313 // * </pre>
314 // *
315 // * It's that simple. When the reference is requested for the first time, RrdDbPool will open the RRD file
316 // * for you and make some internal note that the RRD file is used only once. When the reference
317 // * to the same file (same RRD file path) is requested for the second time, the same RrdDb
318 // * reference will be returned, and its usage count will be increased by one. When the
319 // * reference is released its usage count will be decremented by one.<p>
320 // *
321 // * When the reference count drops to zero, RrdDbPool will not close the underlying
322 // * RRD file immediatelly. Instead of it, it will be marked as 'eligible for closing'.
323 // * If someone request the same RRD file again (before it gets closed), the same
324 // * reference will be returned again.<p>
325 // *
326 // * RrdDbPool has a 'garbage collector' which runs in a separate, low-priority
327 // * thread and gets activated only when the number of RRD files kept in the
328 // * pool is too big (greater than number returned from {@link #getCapacity getCapacity()}).
329 // * Only RRD files with a reference count equal to zero
330 // * will be eligible for closing. Unreleased RrdDb references are never invalidated.
331 // * RrdDbPool object keeps track of the time when each RRD file
332 // * becomes eligible for closing so that the oldest RRD file gets closed first.<p>
333 // *
334 // * Initial RrdDbPool capacity is set to {@link #INITIAL_CAPACITY}. Use {@link #setCapacity(int)}
335 // * method to change it at any time.<p>
336 // *
337 // * <b>WARNING:</b>Never use close() method on the reference returned from the pool.
338 // * When the reference is no longer needed, return it to the pool with the
339 // * {@link #release(RrdDb) release()} method.<p>
340 // *
341 // * However, you are not forced to use RrdDbPool methods to obtain RrdDb references
342 // * to RRD files, 'ordinary' RrdDb constructors are still available. But RrdDbPool class
343 // * offers serious performance improvement especially in complex applications with many
344 // * threads and many simultaneously open RRD files.<p>
345 // *
346 // * The pool is thread-safe. Not that the {@link RrdDb} objects returned from the pool are
347 // * also thread-safe<p>
348 // *
349 // * You should know that each operating system has its own internal limit on the number
350 // * of simultaneously open files. The capacity of your RrdDbPool should be
351 // * reasonably smaller than the limit imposed by your operating system.<p>
352 // *
353 // * <b>WARNING:</b> The pool cannot be used to manipulate RrdDb objects
354 // * with {@link RrdBackend backends} different from default.<p>
355 // */
356 //public class RrdDbPool implements Runnable {
357 //	static final String GC_THREAD_NAME = "RrdDbPool GC thread";
358 //	static final String CLOSING_THREAD_NAME = "RrdDbPool closing thread";
359 //	private static final boolean DEBUG = false;
360 //
361 //	// singleton pattern
362 //	private static RrdDbPool ourInstance;
363 //	private boolean closingOnExit = true;
364 //
365 //	private Thread shutdownHook = new Thread(CLOSING_THREAD_NAME) {
366 //		public void run() {
367 //			try {
368 //				close();
369 //			}
370 //			catch (IOException e) {
371 //				e.printStackTrace();
372 //			}
373 //		}
374 //	};
375 //
376 //	/**
377 //	 * Constant to represent the maximum number of internally open RRD files
378 //	 * which still does not force garbage collector (the process which closes RRD files) to run.
379 //	 */
380 //	public static final int INITIAL_CAPACITY = 500;
381 //	private int capacity = INITIAL_CAPACITY, maxUsedCapacity;
382 //	private boolean active = true;
383 //
384 //	/**
385 //	 * Constant to represent the internal behaviour of the pool.
386 //	 * Defaults to <code>true</code> but can be changed at runtime. See
387 //	 * {@link #setLimitedCapacity(boolean)} for more information.
388 //	 */
389 //	public static final boolean LIMITED_CAPACITY = false;
390 //	private boolean limitedCapacity = LIMITED_CAPACITY;
391 //
392 //	/**
393 //	 * Constant to represent the priority of the background thread which closes excessive RRD files
394 //	 * which are no longer in use.
395 //	 */
396 //	public static final int GC_THREAD_PRIORITY = /** Thread.NORM_PRIORITY - */ 1;
397 //
398 //	private HashMap<String, RrdEntry> rrdMap = new HashMap<String, RrdEntry>(INITIAL_CAPACITY);
399 //	private LinkedHashMap<String, RrdEntry> rrdIdleMap = new LinkedHashMap<String, RrdEntry>(INITIAL_CAPACITY);
400 //	private RrdBackendFactory factory;
401 //	private int poolHitsCount = 0, poolRequestsCount = 0;
402 //
403 //	/**
404 //	 * Returns an instance to RrdDbPool object. Only one such object may exist in each JVM.
405 //	 *
406 //	 * @return Instance to RrdDbPool object.
407 //	 */
408 //	public synchronized static RrdDbPool getInstance() {
409 //		if (ourInstance == null) {
410 //			ourInstance = new RrdDbPool();
411 //			ourInstance.startGarbageCollector();
412 //		}
413 //		return ourInstance;
414 //	}
415 //
416 //	private RrdDbPool() {
417 //		setClosingOnExit(closingOnExit);
418 //	}
419 //
420 //	/**
421 //	 * Checks the exiting behaviour of RrdDbPool.
422 //	 * @return <code>True</code>, if all RRD files are to be closed
423 //	 * when application invokes <code>System.exit()</code>.
424 //	 * <code>False</code> otherwise. The default behaviour is <code>true</code>
425 //	 * (all RRD files will be closed on exit).
426 //	 */
427 //	public synchronized boolean isClosingOnExit() {
428 //		return closingOnExit;
429 //	}
430 //
431 //	/**
432 //	 * Sets the exiting behaviour of RrdDbPool.
433 //	 * @param closingOnExit <code>True</code>, if all RRD files are to be closed
434 //	 * when application invokes <code>System.exit()</code>.
435 //	 * <code>False</code> otherwise. The default behaviour is <code>true</code>
436 //	 * (all RRD files will be closed on exit).
437 //	 */
438 //	public synchronized void setClosingOnExit(boolean closingOnExit) {
439 //		Runtime runtime = Runtime.getRuntime();
440 //		runtime.removeShutdownHook(shutdownHook);
441 //		if(closingOnExit) {
442 //			runtime.addShutdownHook(shutdownHook);
443 //		}
444 //		this.closingOnExit = closingOnExit;
445 //	}
446 //
447 //	private void startGarbageCollector() {
448 //		Thread gcThread = new Thread(this, GC_THREAD_NAME);
449 //		gcThread.setPriority(GC_THREAD_PRIORITY);
450 //		gcThread.setDaemon(true);
451 //		gcThread.start();
452 //	}
453 //
454 //	/**
455 //	 * Returns a reference to an existing RRD file with the specified path.
456 //	 * If the file is already open in the pool, existing reference to it will be returned.
457 //	 * Otherwise, the file is open and a newly created reference to it is returned.
458 //	 *
459 //	 * @param path Relative or absolute path to a RRD file.
460 //	 * @return Reference to a RrdDb object (RRD file).
461 //	 * @throws IOException  Thrown in case of I/O error.
462 //	 * @throws RrdException Thrown in case of JRobin specific error.
463 //	 */
464 //	public synchronized RrdDb requestRrdDb(String path) throws IOException, RrdException {
465 //		proveActive();
466 //		poolRequestsCount++;
467 //		String canonicalPath = getCanonicalPath(path);
468 //		for(;;) {
469 //			RrdEntry rrdEntry = rrdMap.get(canonicalPath);
470 //			if (rrdEntry != null) {
471 //				// already open, use it!
472 //				reportUsage(canonicalPath, rrdEntry);
473 //				poolHitsCount++;
474 ////				debug("CACHED: " + rrdEntry.dump());
475 //				return rrdEntry.getRrdDb();
476 //			}
477 //			else if(!limitedCapacity || rrdMap.size() < capacity) {
478 //				// not found, open it
479 //				RrdDb rrdDb = createRrdDb(path, null);
480 //				rrdEntry = new RrdEntry(rrdDb);
481 //				addRrdEntry(canonicalPath, rrdEntry);
482 ////				debug("ADDED: " + rrdEntry.dump());
483 //				return rrdDb;
484 //			}
485 //			else {
486 //				// we have to wait
487 //				try {
488 //					wait();
489 //				}
490 //				catch (InterruptedException e) {
491 //					throw new RrdException("Request for file '" + path + "' was interrupted");
492 //				}
493 //			}
494 //		}
495 //	}
496 //
497 //	/**
498 //	 * Returns a reference to a new RRD file. The new file will have the specified
499 //	 * relative or absolute path, and its contents will be provided from the specified
500 //	 * XML file (RRDTool comaptible).
501 //	 *
502 //	 * @param path    Relative or absolute path to a new RRD file.
503 //	 * @param xmlPath Relative or absolute path to an existing XML dump file (RRDTool comaptible)
504 //	 * @return Reference to a RrdDb object (RRD file).
505 //	 * @throws IOException  Thrown in case of I/O error.
506 //	 * @throws RrdException Thrown in case of JRobin specific error.
507 //	 */
508 //	public synchronized RrdDb requestRrdDb(String path, String xmlPath)
509 //			throws IOException, RrdException {
510 //		return requestNewRrdDb(path, xmlPath);
511 //	}
512 //
513 //	/**
514 //	 * Returns a reference to a new RRD file. The new file will be created based on the
515 //	 * definition contained in a RrdDef object.
516 //	 *
517 //	 * @param rrdDef RRD definition object
518 //	 * @return Reference to a RrdDb object (RRD file).
519 //	 * @throws IOException  Thrown in case of I/O error.
520 //	 * @throws RrdException Thrown in case of JRobin specific error.
521 //	 */
522 //	public synchronized RrdDb requestRrdDb(RrdDef rrdDef) throws IOException, RrdException {
523 //		return requestNewRrdDb(rrdDef.getPath(), rrdDef);
524 //	}
525 //
526 //	private RrdDb requestNewRrdDb(String path, Object creationDef) throws IOException, RrdException {
527 //		proveActive();
528 //		poolRequestsCount++;
529 //		String canonicalPath = getCanonicalPath(path);
530 //		for(;;) {
531 //			RrdEntry rrdEntry = rrdMap.get(canonicalPath);
532 //			if(rrdEntry != null) {
533 //				// already open
534 //				removeIfIdle(canonicalPath, rrdEntry);
535 //			}
536 //			else if(!limitedCapacity || rrdMap.size() < capacity) {
537 //				RrdDb rrdDb = createRrdDb(path, creationDef);
538 //				RrdEntry newRrdEntry = new RrdEntry(rrdDb);
539 //				addRrdEntry(canonicalPath, newRrdEntry);
540 ////				debug("ADDED: " + newRrdEntry.dump());
541 //				return rrdDb;
542 //			}
543 //			else {
544 //				 // we have to wait
545 //				try {
546 //					wait();
547 //				}
548 //				catch (InterruptedException e) {
549 //					throw new RrdException("Request for file '" + path + "' was interrupted");
550 //				}
551 //			}
552 //		}
553 //	}
554 //
555 //	private RrdDb createRrdDb(String path, Object creationDef) throws RrdException, IOException {
556 //		if(creationDef == null) {
557 //			// existing RRD
558 //			return new RrdDb(path, getFactory());
559 //		}
560 //		else if(creationDef instanceof String) {
561 //			// XML input
562 //			return new RrdDb(path, (String) creationDef, getFactory());
563 //		}
564 //		else if(creationDef instanceof RrdDef) {
565 //			// RrdDef
566 //			return new RrdDb((RrdDef) creationDef, getFactory());
567 //		}
568 //		else {
569 //			throw new RrdException("Unexpected input object type: " +
570 //				creationDef.getClass().getName());
571 //		}
572 //	}
573 //
574 //	private void reportUsage(String canonicalPath, RrdEntry rrdEntry) {
575 //		if (rrdEntry.reportUsage() == 1) {
576 //			// must not be garbage collected
577 //			rrdIdleMap.remove(canonicalPath);
578 //		}
579 //	}
580 //
581 //	private void reportRelease(String canonicalPath, RrdEntry rrdEntry) {
582 //		if (rrdEntry.reportRelease() == 0) {
583 //			// ready to be garbage collected
584 //			rrdIdleMap.put(canonicalPath, rrdEntry);
585 //		}
586 //	}
587 //
588 //	private void addRrdEntry(String canonicalPath, RrdEntry newRrdEntry) {
589 //		rrdMap.put(canonicalPath, newRrdEntry);
590 //		maxUsedCapacity = Math.max(rrdMap.size(), maxUsedCapacity);
591 //		// notify waiting threads
592 //		notifyAll();
593 //	}
594 //
595 //	private void removeIfIdle(String canonicalPath, RrdEntry rrdEntry)
596 //			throws RrdException, IOException {
597 //		// already open, check if active (not released)
598 //		if (rrdEntry.isInUse()) {
599 //			// not released, not allowed here
600 //			throw new RrdException("Cannot create new RrdDb file: " +
601 //					"File '" + canonicalPath + "' already in use");
602 //		} else {
603 //			// open but released... safe to close it
604 ////			debug("WILL BE RECREATED: " + rrdEntry.dump());
605 //			removeRrdEntry(canonicalPath, rrdEntry);
606 //		}
607 //	}
608 //
609 //	private void removeRrdEntry(String canonicalPath, RrdEntry rrdEntry) throws IOException {
610 //		rrdEntry.closeRrdDb();
611 //		rrdMap.remove(canonicalPath);
612 //		rrdIdleMap.remove(canonicalPath);
613 ////		debug("REMOVED: " + rrdEntry.dump());
614 //	}
615 //
616 //	/**
617 //	 * Method used to report that the reference to a RRD file is no longer needed. File that
618 //	 * is no longer needed (all references to it are released) is marked 'eligible for
619 //	 * closing'. It will be eventually closed by the pool when the number of open RRD files
620 //	 * becomes too big. Most recently released files will be closed last.
621 //	 *
622 //	 * @param rrdDb Reference to RRD file that is no longer needed.
623 //	 * @throws IOException  Thrown in case of I/O error.
624 //	 * @throws RrdException Thrown in case of JRobin specific error.
625 //	 */
626 //	public synchronized void release(RrdDb rrdDb) throws IOException, RrdException {
627 //		proveActive();
628 //		if (rrdDb == null) {
629 //			// we don't want NullPointerException
630 //			return;
631 //		}
632 //		if (rrdDb.isClosed()) {
633 //			throw new RrdException("File " + rrdDb.getPath() + " already closed");
634 //		}
635 //		String canonicalPath = getCanonicalPath(rrdDb.getPath());
636 //		if (rrdMap.containsKey(canonicalPath)) {
637 //			RrdEntry rrdEntry = rrdMap.get(canonicalPath);
638 //			reportRelease(canonicalPath, rrdEntry);
639 ////			debug("RELEASED: " + rrdEntry.dump());
640 //		} else {
641 //			throw new RrdException("RRD file " + rrdDb.getPath() + " not in the pool");
642 //		}
643 //		// notify waiting threads
644 //		notifyAll();
645 //	}
646 //
647 //	/**
648 //	 * This method runs garbage collector in a separate thread. If the number of
649 //	 * open RRD files kept in the pool is too big (greater than number
650 //	 * returned from {@link #getCapacity getCapacity()}), garbage collector will try
651 //	 * to close and remove RRD files with a reference count equal to zero.
652 //	 * Never call this method directly.
653 //	 */
654 //	public void run() {
655 ////		debug("GC: started");
656 //		while (active) {
657 //			synchronized (this) {
658 //				if (rrdMap.size() >= capacity && rrdIdleMap.size() > 0) {
659 //					try {
660 //						String canonicalPath = rrdIdleMap.keySet().iterator().next();
661 //						RrdEntry rrdEntry = rrdIdleMap.get(canonicalPath);
662 ////						debug("GC: closing " + rrdEntry.dump());
663 //						removeRrdEntry(canonicalPath, rrdEntry);
664 //					} catch (IOException e) {
665 //						e.printStackTrace();
666 //					}
667 //					notifyAll();
668 //				}
669 //				else {
670 //					try {
671 ////						debug("GC: waiting");
672 //						wait();
673 ////						debug("GC: running");
674 //					} catch (InterruptedException e) {
675 //						e.printStackTrace();
676 //					}
677 //				}
678 //			}
679 //		}
680 //	}
681 //
682 //	protected void finalize() throws IOException {
683 //		close();
684 //	}
685 //
686 //	/**
687 //	 * Clears the internal state of the pool entirely. All open RRD files are closed.
688 //	 *
689 //	 * @throws IOException Thrown in case of I/O related error.
690 //	 */
691 //	public synchronized void reset() throws IOException {
692 //		Iterator<RrdEntry> it = rrdMap.values().iterator();
693 //		while (it.hasNext()) {
694 //			RrdEntry rrdEntry = it.next();
695 //			rrdEntry.closeRrdDb();
696 //		}
697 //		rrdMap.clear();
698 //		rrdIdleMap.clear();
699 ////		debug("Pool cleared");
700 //	}
701 //
702 //	/**
703 //	 * Closes the pool and all RRD files currently held in the pool.
704 //	 * No further operations on the pool are allowed.
705 //	 * @throws IOException Thrown in case of I/O error.
706 //	 */
707 //	public synchronized void close() throws IOException {
708 //		if(active) {
709 //			active = false;
710 //			reset();
711 ////			debug("The pool is closed.");
712 //		}
713 //		else {
714 ////			debug("The pool is already closed!");
715 //		}
716 //	}
717 //
718 //	private static String getCanonicalPath(String path) throws IOException {
719 //		return Util.getCanonicalPath(path);
720 //	}
721 //
722 //	static void debug(String msg) {
723 //		if (DEBUG) {
724 //			System.out.println("POOL: " + msg);
725 //		}
726 //	}
727 //
728 //	/**
729 //	 * Returns the internal state of the pool. Useful for debugging purposes.
730 //	 *
731 //	 * @param dumpFiles <code>true</code>, if dumped information should contain paths to open files
732 //	 * currently held in the pool, <code>false</code> otherwise
733 //	 * @return Internal pool state (with an optional list of open RRD files and
734 //	 * the current number of usages for each one).
735 //	 * @throws IOException Thrown in case of I/O error.
736 //	 */
737 //	public synchronized String dump(boolean dumpFiles) throws IOException {
738 //		StringBuffer buff = new StringBuffer();
739 //		buff.append("==== POOL DUMP ===========================\n");
740 //		buff.append("open=" + rrdMap.size() + ", idle=" + rrdIdleMap.size() + "\n");
741 //		buff.append("capacity=" + capacity + ", " + "maxUsedCapacity=" + maxUsedCapacity + "\n");
742 //		buff.append("hits=" + poolHitsCount + ", " + "requests=" + poolRequestsCount + "\n");
743 //		buff.append("efficiency=" + getPoolEfficiency() + "\n");
744 //		if(dumpFiles) {
745 //			buff.append("---- CACHED FILES ------------------------\n");
746 //			Iterator<RrdEntry> it = rrdMap.values().iterator();
747 //			while (it.hasNext()) {
748 //				RrdEntry rrdEntry = it.next();
749 //				buff.append(rrdEntry.dump() + "\n");
750 //			}
751 //		}
752 //		return buff.toString();
753 //	}
754 //
755 //	/**
756 //	 * Returns the complete internal state of the pool. Useful for debugging purposes.
757 //	 *
758 //	 * @return Internal pool state (with a list of open RRD files and the current number of
759 //	 * usages for each one).
760 //	 * @throws IOException Thrown in case of I/O error.
761 //	 */
762 //	public synchronized String dump() throws IOException {
763 //		return dump(true);
764 //	}
765 //
766 //	/**
767 //	 * Returns paths to all open files currently held in the pool.
768 //	 * @return An array containing open file paths.
769 //	 */
770 //	public synchronized String[] getCachedFilePaths() {
771 //		Set<String> keySet = rrdMap.keySet();
772 //		int n = keySet.size(), i = 0;
773 //		String[] files = new String[n];
774 //		Iterator<String> it = keySet.iterator();
775 //		while(it.hasNext()) {
776 //			files[i++] = it.next();
777 //		}
778 //		return files;
779 //	}
780 //
781 //	/**
782 //	 * Returns maximum number of internally open RRD files
783 //	 * which still does not force garbage collector to run.
784 //	 *
785 //	 * @return Desired nuber of open files held in the pool.
786 //	 */
787 //	public synchronized int getCapacity() {
788 //		return capacity;
789 //	}
790 //
791 //	/**
792 //	 * Sets maximum number of internally open RRD files
793 //	 * which still does not force garbage collector to run.
794 //	 *
795 //	 * @param capacity Desired number of open files to hold in the pool
796 //	 */
797 //	public synchronized void setCapacity(int capacity) {
798 //		this.capacity = capacity;
799 ////		debug("Capacity set to: " + capacity);
800 //	}
801 //
802 //	private RrdBackendFactory getFactory() throws RrdException {
803 //		if (factory == null) {
804 //			factory = RrdBackendFactory.getDefaultFactory();
805 //			if (!(factory instanceof RrdFileBackendFactory)) {
806 //				factory = null;
807 //				throw new RrdException(
808 //					"RrdDbPool cannot work with factories not derived from RrdFileBackendFactory");
809 //			}
810 //		}
811 //		return factory;
812 //	}
813 //
814 //	private class RrdEntry {
815 //		private RrdDb rrdDb;
816 //		private int usageCount = 1;
817 //
818 //		public RrdEntry(RrdDb rrdDb) {
819 //			this.rrdDb = rrdDb;
820 //		}
821 //
822 //		RrdDb getRrdDb() {
823 //			return rrdDb;
824 //		}
825 //
826 //		int reportUsage() {
827 //			assert usageCount >= 0: "Unexpected reportUsage count: " + usageCount;
828 //			return ++usageCount;
829 //		}
830 //
831 //		int reportRelease() {
832 //			assert usageCount > 0: "Unexpected reportRelease count: " + usageCount;
833 //			return --usageCount;
834 //		}
835 //
836 //		boolean isInUse() {
837 //			return usageCount > 0;
838 //		}
839 //
840 //		void closeRrdDb() throws IOException {
841 //			rrdDb.close();
842 //		}
843 //
844 //		String dump() throws IOException {
845 //			String canonicalPath = getCanonicalPath(rrdDb.getPath());
846 //			return canonicalPath + " [" + usageCount + "]";
847 //		}
848 //	}
849 //
850 //	/**
851 //	 * Calculates pool's efficency ratio. The ratio is obtained by dividing the number of
852 //	 * RrdDb requests served from the internal pool of open RRD files
853 //	 * with the number of total RrdDb requests.
854 //	 *
855 //	 * @return Pool's efficiency ratio as a double between 1 (best) and 0 (worst).
856 //	 * If no RrdDb reference was ever requested, 1 would be returned.
857 //	 */
858 //	public synchronized double getPoolEfficiency() {
859 //		if (poolRequestsCount == 0) {
860 //			return 1.0;
861 //		}
862 //		double ratio = (double) poolHitsCount / (double) poolRequestsCount;
863 //		// round to 3 decimal digits
864 //		return Math.round(ratio * 1000.0) / 1000.0;
865 //	}
866 //
867 //	/**
868 //	 * Returns the number of RRD requests served from the internal pool of open RRD files
869 //	 *
870 //	 * @return The number of pool "hits".
871 //	 */
872 //	public synchronized int getPoolHitsCount() {
873 //		return poolHitsCount;
874 //	}
875 //
876 //	/**
877 //	 * Returns the total number of RRD requests successfully served by this pool.
878 //	 *
879 //	 * @return Total number of RRD requests
880 //	 */
881 //	public synchronized int getPoolRequestsCount() {
882 //		return poolRequestsCount;
883 //	}
884 //
885 //	/**
886 //	 * Returns the maximum number of open RRD files over the lifetime
887 //	 * of the pool.
888 //	 * @return maximum number of open RRD files.
889 //	 */
890 //	public synchronized int getMaxUsedCapacity() {
891 //		return maxUsedCapacity;
892 //	}
893 //
894 //	/**
895 //	 * Checks the internal behaviour of the pool. See {@link #setLimitedCapacity(boolean)} for
896 //	 * more information.
897 //	 *
898 //	 * @return <code>true</code> if the pool is 'flexible' (by not imposing the strict
899 //	 * limit on the number of simultaneously open files), <code>false</code> otherwise.
900 //	 */
901 //	public synchronized boolean isLimitedCapacity() {
902 //		return limitedCapacity;
903 //	}
904 //
905 //	/**
906 //	 * Sets the behaviour of the pool. If <code>true</code> is passed as argument, the pool will never
907 //	 * open more than {@link #getCapacity()} files at any time. If set to <code>false</code>,
908 //	 * the pool might keep more open files, but only for a short period of time. This method might be
909 //	 * useful if you want avoid OS limits when it comes to the number of simultaneously open files.<p>
910 //	 *
911 //	 * By default, the pool behaviour is 'flexible' (<code>limitedCapacity</code> property defaults
912 //	 * to false<p>
913 //	 *
914 //	 * @param limitedCapacity <code>true</code> if the pool should be 'flexible' (not imposing the strict
915 //	 * limit on the number of simultaneously open files), <code>false</code> otherwise.
916 //	 */
917 //	public synchronized void setLimitedCapacity(boolean limitedCapacity) {
918 //		this.limitedCapacity = limitedCapacity;
919 //	}
920 //
921 //	private void proveActive() throws IOException {
922 //		if(!active) {
923 //			throw new IOException("RrdDbPool is already closed");
924 //		}
925 //	}
926 //
927 //	/**
928 //	 * Checks if the pool is active. You can request RrdDb references only from the active pool. The
929 //	 * pool is deactived when the {@link #close()} method is called.
930 //	 * @return <code>true</code> if active, <code>false</code> otherwise.
931 //	 */
932 //	public synchronized boolean isActive() {
933 //		return active;
934 //	}
935 //}
936 //
937 
938