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
939