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