/*
* Copyright (C) 2006 http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
package org.chaidb.db.helper.cache;
import org.apache.log4j.Logger;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Iterator;
import java.util.LinkedHashSet;
public class CacheAdministrator {
public static synchronized CacheAdministrator getInstance() {
if (administrator == null) {
administrator = new CacheAdministrator();
}
return administrator;
}
public boolean register(Cache newCache) {
if (enableCacheTrace) {
synchronized (cacheSet) {
defragCacheSet();
return cacheSet.add(new SoftReference(newCache, cacheQueue));
}
} else {
return false;
}
}
public boolean register(MeasurableCache newMeasurableCache) {
if (enableCacheTrace) {
synchronized (measurableCacheSet) {
defragMeasurableCacheSet();
return measurableCacheSet.add(new SoftReference(newMeasurableCache, measurableCacheQueue));
}
} else {
return false;
}
}
public void report(boolean isVerbose) {
reportCaches(isVerbose);
reportMeasurableCaches(isVerbose);
}
protected void defragCacheSet() {
synchronized (cacheSet) {
Reference unusedReference = null;
while ((unusedReference = cacheQueue.poll()) != null) {
cacheSet.remove(unusedReference.get());
}
}
}
protected void defragMeasurableCacheSet() {
synchronized (measurableCacheSet) {
Reference unusedReference = null;
while ((unusedReference = measurableCacheQueue.poll()) != null) {
measurableCacheSet.remove(unusedReference.get());
}
}
}
protected void reportCaches(boolean isVerbose) {
synchronized (cacheSet) {
defragCacheSet();
logger.debug("Total number of caches is " + cacheSet.size());
if (isVerbose) {
logger.debug("Details: 'cache name ( current size / max size )'");
}
Iterator cacheIterator = cacheSet.iterator();
long totalCount = 0;
while (cacheIterator.hasNext()) {
Cache aCache = (Cache) cacheIterator.next();
if (isVerbose) {
logger.debug(aCache.getName() + " ( " + aCache.size() + " / " + aCache.maxSize() + " )");
}
totalCount += aCache.size();
}
logger.debug("Total number of elements retained by all caches is " + totalCount);
}
}
protected void reportMeasurableCaches(boolean isVerbose) {
synchronized (measurableCacheSet) {
defragMeasurableCacheSet();
logger.debug("Total number of measurable caches is " + measurableCacheSet.size());
if (isVerbose) {
logger.debug("Details: 'cache name ( current size in bytes / max size in bytes )'");
}
Iterator cacheIterator = measurableCacheSet.iterator();
long totalRetainedSize = 0;
while (cacheIterator.hasNext()) {
MeasurableCache aCache = (MeasurableCache) cacheIterator.next();
if (isVerbose) {
logger.debug(aCache.getName() + " ( " + aCache.getRetainedSize() + " / " + aCache.getSizeBoundary() + " )");
}
totalRetainedSize += aCache.getRetainedSize();
}
logger.debug("Total number of bytes retained by all measurable caches is " + totalRetainedSize);
}
}
private static boolean enableCacheTrace = Boolean.getBoolean("org.chaidb.cache.enabletrace");
private static CacheAdministrator administrator = enableCacheTrace ? new CacheAdministrator() : null;
private static Logger logger = enableCacheTrace ? Logger.getLogger(CacheAdministrator.class) : null;
private static Thread cacheReporter = enableCacheTrace ? new Thread() {
public void run() {
while (true) {
administrator.report(true);
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
}
}
}
}
: null;
static {
if (enableCacheTrace) {
cacheReporter.start();
}
}
private CacheAdministrator() {
}
private LinkedHashSet cacheSet = new LinkedHashSet();
private LinkedHashSet measurableCacheSet = new LinkedHashSet();
private ReferenceQueue cacheQueue = new ReferenceQueue();
private ReferenceQueue measurableCacheQueue = new ReferenceQueue();
}