/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.web.tomcat.service.session.distributedcache.impl.jbc;
import java.util.Map;
import java.util.Random;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
import org.jboss.cache.SuspectException;
import org.jboss.cache.config.Option;
import org.jboss.cache.lock.TimeoutException;
public class JBossCacheWrapper
{
private static final int RETRY = 3;
private static final String RETRY_FAIL_MSG =
"Continued to catch TimeoutException during " +
RETRY + " retry attempts. Giving up.";
private static final int[] BACK_OFF_INTERVALS = { 10, 100 };
private Cache<Object, Object> plainCache_;
private final Random random = new Random(System.currentTimeMillis());
private volatile boolean forceSynchronous = false;
JBossCacheWrapper(Cache<Object, Object> cache)
{
plainCache_ = cache;
}
Map<Object, Object> getData(Fqn<?> fqn, boolean gravitate)
{
CacheException ex = null;
for (int i = 0; i < RETRY; i++)
{
try
{
this.getOptionOverrides().setForceDataGravitation(gravitate);
return plainCache_.getData(fqn);
}
catch (TimeoutException e)
{
ex = e;
}
catch (SuspectException e)
{
ex = e;
}
if (!backOff(i))
{
return null;
}
}
throw new RuntimeException(RETRY_FAIL_MSG, ex);
}
/**
* Wrapper to embed retry logic.
*
* @param fqn
* @param id
* @return
*/
Object get(Fqn<?> fqn, String id)
{
return get(fqn, id, false);
}
/**
* Wrapper to embed retry logic.
*
* @param fqn
* @param id
* @return
*/
Object get(Fqn<?> fqn, String id, boolean gravitate)
{
CacheException ex = null;
for (int i = 0; i < RETRY; i++)
{
try
{
this.getOptionOverrides().setForceDataGravitation(gravitate);
return plainCache_.get(fqn, id);
}
catch (TimeoutException e)
{
ex = e;
}
catch (SuspectException e)
{
ex = e;
}
if (!backOff(i))
{
return null;
}
}
throw new RuntimeException(RETRY_FAIL_MSG, ex);
}
/**
* Wrapper to embed retry logic.
*
* @param fqn
* @param id
* @param value
* @return
*/
void put(Fqn<?> fqn, String id, Object value)
{
CacheException ex = null;
for (int i = 0; i < RETRY; i++)
{
try
{
this.getOptionOverrides();
plainCache_.put(fqn, id, value);
return;
}
catch (TimeoutException e)
{
ex = e;
}
catch (SuspectException e)
{
ex = e;
}
if (!backOff(i))
{
return;
}
}
throw new RuntimeException(RETRY_FAIL_MSG, ex);
}
/**
* Wrapper to embed retry logic.
*
* @param fqn
* @param map
*/
void put(Fqn<?> fqn, Map<Object, Object> map)
{
CacheException ex = null;
for (int i = 0; i < RETRY; i++)
{
try
{
this.getOptionOverrides();
plainCache_.put(fqn, map);
return;
}
catch (TimeoutException e)
{
ex = e;
}
catch (SuspectException e)
{
ex = e;
}
if (!backOff(i))
{
return;
}
}
throw new RuntimeException(RETRY_FAIL_MSG, ex);
}
/**
* Wrapper to embed retry logic.
*
* @param fqn
* @param id
* @return
*/
Object remove(Fqn<?> fqn, String id)
{
CacheException ex = null;
for (int i = 0; i < RETRY; i++)
{
try
{
this.getOptionOverrides();
return plainCache_.remove(fqn, id);
}
catch (TimeoutException e)
{
ex = e;
}
catch (SuspectException e)
{
ex = e;
}
if (!backOff(i))
{
return null;
}
}
throw new RuntimeException(RETRY_FAIL_MSG, ex);
}
/**
* Wrapper to embed retry logic.
*
* @param fqn
* @param id
* @return
*/
Object removeLocal(Fqn<?> fqn, String id)
{
TimeoutException ex = null;
for (int i = 0; i < RETRY; i++)
{
try
{
this.getOptionOverrides().setCacheModeLocal(true);
return plainCache_.remove(fqn, id);
}
catch (TimeoutException e)
{
ex = e;
}
if (!backOff(i))
{
return null;
}
}
throw new RuntimeException(RETRY_FAIL_MSG, ex);
}
/**
* Wrapper to embed retry logic.
*
* @param fqn
*/
void remove(Fqn<?> fqn)
{
CacheException ex = null;
for (int i = 0; i < RETRY; i++)
{
try
{
this.getOptionOverrides();
plainCache_.removeNode(fqn);
return;
}
catch (TimeoutException e)
{
ex = e;
}
catch (SuspectException e)
{
ex = e;
}
if (!backOff(i))
{
return;
}
}
throw new RuntimeException(RETRY_FAIL_MSG, ex);
}
/**
* Wrapper to embed retry logic.
*
* @param fqn
*/
void removeLocal(Fqn<?> fqn)
{
TimeoutException ex = null;
for (int i = 0; i < RETRY; i++)
{
try
{
this.getOptionOverrides().setCacheModeLocal(true);
plainCache_.removeNode(fqn);
return;
}
catch (TimeoutException e)
{
ex = e;
}
if (!backOff(i))
{
return;
}
}
throw new RuntimeException(RETRY_FAIL_MSG, ex);
}
void evictSubtree(Fqn<?> fqn)
{
TimeoutException ex = null;
for (int i = 0; i < RETRY; i++)
{
try
{
this.getOptionOverrides();
plainCache_.evict(fqn, true);
return;
}
catch (TimeoutException e)
{
ex = e;
}
if (!backOff(i))
{
return;
}
}
throw new RuntimeException(RETRY_FAIL_MSG, ex);
}
void setForceSynchronous(boolean forceSynchronous)
{
this.forceSynchronous = forceSynchronous;
}
/**
* Causes the calling thread to sleep a random amount of time up to
* BACK_OFF_INTERVALS[attempt].
*
* @param attempt zero based count of the retry count after failure of which
* this method was invoked
*
* @return <code>true</code> if it is safe for the operation to retry; false
* if an InterruptedException was caught while sleeping
*/
private boolean backOff(int attempt)
{
if (attempt < BACK_OFF_INTERVALS.length)
{
try
{
Thread.sleep(random.nextInt(BACK_OFF_INTERVALS[attempt]));
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
return false;
}
}
return true;
}
private Option getOptionOverrides()
{
Option option = this.plainCache_.getInvocationContext().getOptionOverrides();
option.setForceSynchronous(this.forceSynchronous);
return option;
}
}