1 25 package org.jrobin.core; 26 27 import java.io.IOException ; 28 import java.util.*; 29 30 101 public class RrdDbPool implements Runnable { 102 private static RrdDbPool ourInstance; 103 private static final boolean DEBUG = false; 104 105 109 public static final int INITIAL_CAPACITY = 100; 110 private int capacity = INITIAL_CAPACITY; 111 112 private Map rrdMap = new HashMap(); 113 private List rrdGcList = new LinkedList(); 114 private RrdBackendFactory factory; 115 private int poolHitsCount, poolRequestsCount; 116 117 121 public synchronized static RrdDbPool getInstance() { 122 if (ourInstance == null) { 123 ourInstance = new RrdDbPool(); 124 ourInstance.startGarbageCollector(); 125 } 126 return ourInstance; 127 } 128 129 private RrdDbPool() { 130 } 131 132 private void startGarbageCollector() { 133 Thread gcThread = new Thread (this); 134 gcThread.setDaemon(true); 135 gcThread.start(); 136 } 137 138 148 public synchronized RrdDb requestRrdDb(String path) throws IOException , RrdException { 149 String keypath = getCanonicalPath(path); 150 RrdDb rrdDbRequested; 151 if (rrdMap.containsKey(keypath)) { 152 RrdEntry rrdEntry = (RrdEntry) rrdMap.get(keypath); 154 reportUsage(rrdEntry); 155 debug("EXISTING: " + rrdEntry.dump()); 156 rrdDbRequested = rrdEntry.getRrdDb(); 157 poolHitsCount++; 158 } else { 159 RrdDb rrdDb = new RrdDb(path, getFactory()); 161 addRrdEntry(keypath, rrdDb); 162 rrdDbRequested = rrdDb; 163 } 164 poolRequestsCount++; 165 return rrdDbRequested; 166 } 167 168 178 public synchronized RrdDb requestRrdDb(String path, String xmlPath) 179 throws IOException , RrdException { 180 String keypath = getCanonicalPath(path); 181 prooveInactive(keypath); 182 RrdDb rrdDb = new RrdDb(path, xmlPath, getFactory()); 183 addRrdEntry(keypath, rrdDb); 184 poolRequestsCount++; 185 return rrdDb; 186 } 187 188 196 public synchronized RrdDb requestRrdDb(RrdDef rrdDef) throws IOException , RrdException { 197 String path = rrdDef.getPath(); 198 String keypath = getCanonicalPath(path); 199 prooveInactive(keypath); 200 RrdDb rrdDb = new RrdDb(rrdDef, getFactory()); 201 addRrdEntry(keypath, rrdDb); 202 poolRequestsCount++; 203 return rrdDb; 204 } 205 206 private void reportUsage(RrdEntry rrdEntry) { 207 if(rrdEntry.reportUsage() == 1) { 208 rrdGcList.remove(rrdEntry); 210 } 211 } 212 213 private void reportRelease(RrdEntry rrdEntry) { 214 if(rrdEntry.reportRelease() == 0) { 215 rrdGcList.add(rrdEntry); 217 } 218 } 219 220 private void addRrdEntry(String keypath, RrdDb rrdDb) throws IOException { 221 RrdEntry newEntry = new RrdEntry(rrdDb); 222 reportUsage(newEntry); 223 debug("NEW: " + newEntry.dump()); 224 rrdMap.put(keypath, newEntry); 225 notify(); 227 } 228 229 private void prooveInactive(String keypath) throws RrdException, IOException { 230 if(rrdMap.containsKey(keypath)) { 231 RrdEntry rrdEntry = (RrdEntry) rrdMap.get(keypath); 233 if(rrdEntry.isInUse()) { 234 throw new RrdException("VALIDATOR: Cannot create new RrdDb file. " + 236 "File " + keypath + " already active in pool"); 237 } 238 else { 239 debug("WILL BE RECREATED: " + rrdEntry.dump()); 241 removeRrdEntry(rrdEntry); 242 } 243 } 244 } 245 246 private void removeRrdEntry(RrdEntry rrdEntry) throws IOException { 247 rrdEntry.closeRrdDb(); 248 rrdMap.values().remove(rrdEntry); 249 rrdGcList.remove(rrdEntry); 250 debug("REMOVED: " + rrdEntry.dump()); 251 } 252 253 262 public synchronized void release(RrdDb rrdDb) throws IOException , RrdException { 263 if(rrdDb == null) { 264 return; 266 } 267 if(rrdDb.isClosed()) { 268 throw new RrdException("Cannot release: already closed"); 269 } 270 String keypath = rrdDb.getCanonicalPath(); 271 if(rrdMap.containsKey(keypath)) { 272 RrdEntry rrdEntry = (RrdEntry) rrdMap.get(keypath); 273 reportRelease(rrdEntry); 274 debug("RELEASED: " + rrdEntry.dump()); 275 } 276 else { 277 throw new RrdException("RRD file " + keypath + " not in the pool"); 278 } 279 notify(); 281 } 282 283 290 public void run() { 291 debug("GC: started"); 292 synchronized (this) { 293 for (; ;) { 294 while (rrdMap.size() > capacity && rrdGcList.size() > 0) { 295 try { 296 RrdEntry oldestRrdEntry = (RrdEntry) rrdGcList.get(0); 297 debug("GC: closing " + oldestRrdEntry.dump()); 298 removeRrdEntry(oldestRrdEntry); 299 } catch (IOException e) { 300 e.printStackTrace(); 301 } 302 } 303 304 try { 305 debug("GC: waiting: " + 306 rrdMap.size() + " open, " + 307 rrdGcList.size() + " released, " + 308 "capacity = " + capacity + ", " + 309 "hits = " + poolHitsCount + ", " + 310 "requests = " + poolRequestsCount); 311 wait(); 312 debug("GC: running"); 313 } catch (InterruptedException e) { 314 } 315 } 316 } 317 } 318 319 protected void finalize() throws IOException { 320 reset(); 321 } 322 323 327 public synchronized void reset() throws IOException { 328 Iterator it = rrdMap.values().iterator(); 329 while(it.hasNext()) { 330 RrdEntry rrdEntry = (RrdEntry) it.next(); 331 rrdEntry.closeRrdDb(); 332 } 333 rrdMap.clear(); 334 rrdGcList.clear(); 335 debug("Nothing left in the pool"); 336 } 337 338 private static String getCanonicalPath(String path) throws IOException { 339 return RrdFileBackend.getCanonicalPath(path); 340 } 341 342 private static void debug(String msg) { 343 if(DEBUG) { 344 System.out.println("POOL: " + msg); 345 } 346 } 347 348 354 public synchronized String dump() throws IOException { 355 StringBuffer buff = new StringBuffer (); 356 Iterator it = rrdMap.values().iterator(); 357 while(it.hasNext()) { 358 RrdEntry rrdEntry = (RrdEntry) it.next(); 359 buff.append(rrdEntry.dump()); 360 buff.append("\n"); 361 } 362 return buff.toString(); 363 } 364 365 371 public synchronized int getCapacity() { 372 return capacity; 373 } 374 375 381 public synchronized void setCapacity(int capacity) { 382 this.capacity = capacity; 383 debug("Capacity set to: " + capacity); 384 } 385 386 private RrdBackendFactory getFactory() throws RrdException { 387 if(factory == null) { 388 factory = RrdBackendFactory.getDefaultFactory(); 389 if(!(factory instanceof RrdFileBackendFactory)) { 390 factory = null; 391 throw new RrdException( 392 "RrdDbPool cannot work with factories not derived from RrdFileBackendFactory"); 393 } 394 } 395 return factory; 396 } 397 398 private class RrdEntry { 399 private RrdDb rrdDb; 400 private int usageCount; 401 402 public RrdEntry(RrdDb rrdDb) { 403 this.rrdDb = rrdDb; 404 } 405 406 RrdDb getRrdDb() { 407 return rrdDb; 408 } 409 410 int reportUsage() { 411 assert usageCount >= 0: "Unexpected reportUsage count: " + usageCount; 412 return ++usageCount; 413 } 414 415 int reportRelease() { 416 assert usageCount > 0: "Unexpected reportRelease count: " + usageCount; 417 return --usageCount; 418 } 419 420 boolean isInUse() { 421 return usageCount > 0; 422 } 423 424 void closeRrdDb() throws IOException { 425 rrdDb.close(); 426 } 427 428 String dump() throws IOException { 429 String keypath = rrdDb.getCanonicalPath(); 430 return keypath + " [" + usageCount + "]"; 431 } 432 } 433 434 441 public synchronized double getPoolEfficency() { 442 if(poolRequestsCount == 0) { 443 return 1.0; 444 } 445 double ratio = (double) poolHitsCount / (double) poolRequestsCount; 446 return Math.round(ratio * 1000.0) / 1000.0; 448 } 449 450 454 public synchronized int getPoolHitsCount() { 455 return poolHitsCount; 456 } 457 458 462 public synchronized int getPoolRequestsCount() { 463 return poolRequestsCount; 464 } 465 } 466 467 | Popular Tags |