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