/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.EvictionPolicyConfig;
import org.jboss.cache.config.EvictionRegionConfig;
import org.jboss.cache.eviction.EvictedEventNode;
import org.jboss.cache.eviction.EvictionPolicy;
import org.jboss.cache.eviction.NodeEventType;
import org.jboss.cache.util.Util;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* Default implementation of a {@link Region}
*
* @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
*/
public class RegionImpl implements Region
{
private static final Log log = LogFactory.getLog(RegionImpl.class);
private final RegionManager regionManager;
private Fqn fqn;
private Status status;
private ClassLoader classLoader;
private BlockingQueue<EvictedEventNode> nodeEventQueue = null;
private int capacityWarnThreshold = 0;
private EvictionRegionConfig configuration = new EvictionRegionConfig();
private EvictionPolicy policy;
/**
* Constructs a marshalling region from an fqn and region manager.
*/
public RegionImpl(Fqn fqn, RegionManager regionManager)
{
this.fqn = fqn;
this.regionManager = regionManager;
status = !regionManager.isDefaultInactive() ? Status.ACTIVE : Status.INACTIVE;
}
/**
* Constructs an eviction region from a policy and configuration, defined by an fqn and region manager.
*/
public RegionImpl(EvictionPolicy policy, EvictionRegionConfig config, Fqn fqn, RegionManager regionManager)
{
this(fqn, regionManager);
this.configuration = config;
this.policy = policy;
createQueue();
}
public Configuration getCacheConfiguration()
{
if (regionManager != null && regionManager.getCache() != null)
return regionManager.getCache().getConfiguration();
else
return null;
}
public void registerContextClassLoader(ClassLoader classLoader)
{
this.classLoader = classLoader;
}
public void unregisterContextClassLoader()
{
this.classLoader = null;
}
public void activate()
{
regionManager.activate(fqn);
status = Status.ACTIVE;
}
public void activateIfEmpty()
{
regionManager.activateIfEmpty(fqn);
status = Status.ACTIVE;
}
public void deactivate()
{
regionManager.deactivate(fqn);
status = Status.INACTIVE;
}
public boolean isActive()
{
return status == Status.ACTIVE;
}
public ClassLoader getClassLoader()
{
return classLoader;
}
public Fqn getFqn()
{
return fqn;
}
public void setStatus(Status status)
{
this.status = status;
}
public Status getStatus()
{
return status;
}
public void setActive(boolean b)
{
status = b ? Status.ACTIVE : Status.INACTIVE;
}
// -------- eviction stuff -----
public void markNodeCurrentlyInUse(Fqn fqn, long timeout)
{
EvictedEventNode markUse = new EvictedEventNode(fqn, NodeEventType.MARK_IN_USE_EVENT);
markUse.setInUseTimeout(timeout);
putNodeEvent(markUse);
}
public void unmarkNodeCurrentlyInUse(Fqn fqn)
{
EvictedEventNode markNoUse = new EvictedEventNode(fqn, NodeEventType.UNMARK_USE_EVENT);
putNodeEvent(markNoUse);
}
@Override
public String toString()
{
return "RegionImpl{" +
"fqn=" + fqn +
"; classloader=" + classLoader +
"; status=" + status +
"; eviction=" + (getEvictionPolicy() != null) +
"; timerThreadRegistered=" + (getEvictionPolicy() != null && regionManager.getEvictionTimerTask().isRegionRegisteredForProcessing(this)) +
'}';
}
public int compareTo(Region other)
{
return getFqn().compareTo(other.getFqn());
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RegionImpl region = (RegionImpl) o;
if (fqn != null ? !fqn.equals(region.fqn) : region.fqn != null) return false;
return true;
}
@Override
public int hashCode()
{
return (fqn != null ? fqn.hashCode() : 0);
}
public void putNodeEvent(EvictedEventNode event)
{
try
{
if (nodeEventQueue == null) createQueue();// in case the queue does not exist yet.
if (nodeEventQueue.size() > capacityWarnThreshold)
{
log.warn("putNodeEvent(): eviction node event queue size is at 98% threshold value of capacity: " + configuration.getEventQueueSize() +
" Region: " + fqn +
" You will need to reduce the wakeUpIntervalSeconds parameter.");
}
nodeEventQueue.put(event);
}
catch (InterruptedException e)
{
log.debug("give up put", e);
}
}
public EvictedEventNode takeLastEventNode()
{
try
{
return nodeEventQueue.poll(0, TimeUnit.SECONDS);
}
catch (InterruptedException e)
{
log.debug("trace", e);
}
return null;
}
public int nodeEventQueueSize()
{
return nodeEventQueue.size();
}
public void resetEvictionQueues()
{
nodeEventQueue.clear();
}
private synchronized void createQueue()
{
if (nodeEventQueue == null)
{
if (configuration == null)
{
throw new IllegalArgumentException("null eviction configuration");
}
int size = configuration.getEventQueueSize();
capacityWarnThreshold = (98 * size) / 100 - 100;
if (capacityWarnThreshold <= 0)
{
throw new RuntimeException("Capacity warn threshold used in eviction is smaller than 1.");
}
nodeEventQueue = new LinkedBlockingQueue<EvictedEventNode>(size);
}
}
public EvictionRegionConfig getEvictionRegionConfig()
{
return this.configuration;
}
public EvictionPolicyConfig getEvictionPolicyConfig()
{
return configuration == null ? null : configuration.getEvictionPolicyConfig();
}
public EvictionPolicy getEvictionPolicy()
{
return policy;
}
public void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig)
{
configuration.setEvictionPolicyConfig(evictionPolicyConfig);
policy = createPolicy(evictionPolicyConfig.getEvictionPolicyClass());
regionManager.getEvictionTimerTask().addRegionToProcess(this);
if (nodeEventQueue == null) createQueue();
}
private EvictionPolicy createPolicy(String className)
{
if (className == null)
{
throw new IllegalArgumentException("null className");
}
try
{
if (log.isTraceEnabled()) log.trace("Instantiating " + className);
EvictionPolicy ep = (EvictionPolicy) Util.loadClass(className).newInstance();
ep.setCache(regionManager.getCache());
return ep;
}
catch (Exception e)
{
log.fatal("Unable to instantiate eviction policy class " + className, e);
return null;
}
}
public RegionImpl clone(Fqn newRoot)
{
RegionImpl clone = null;
try
{
clone = (RegionImpl) super.clone();
clone.policy = policy;
clone.configuration = configuration;
clone.status = status;
clone.fqn = Fqn.fromRelativeFqn(newRoot, fqn);
// we also need to copy all of the eviction event nodes to the clone's queue
clone.createQueue();
for (EvictedEventNode een : this.nodeEventQueue)
{
EvictedEventNode cloneEEN = een.clone(newRoot);
clone.putNodeEvent(cloneEEN);
}
}
catch (CloneNotSupportedException e)
{
// problems cloning? Should never get here.
}
return clone;
}
}