Author: tv Date: Thu Dec 3 16:41:49 2015 New Revision: 1717801 URL: http://svn.apache.org/viewvc?rev=1717801&view=rev Log: Address issues reported by Findbugs
Added: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java (with props) Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheListeners.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCache.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSConcurrentCacheAccessUnitTest.java commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/TestCacheAccess.java commons/proper/jcs/trunk/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java commons/proper/jcs/trunk/src/changes/changes.xml Added: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java?rev=1717801&view=auto ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java (added) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java Thu Dec 3 16:41:49 2015 @@ -0,0 +1,215 @@ +package org.apache.commons.jcs.auxiliary; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Used to monitor and repair any failed connection for the lateral cache service. By default the + * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an + * error. Upon the notification of a connection error, the monitor changes to operate in a time + * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed + * connections are restored, it changes back to the failure driven mode. + */ +public abstract class AbstractAuxiliaryCacheMonitor extends Thread +{ + /** The logger */ + protected final Log log = LogFactory.getLog( this.getClass() ); + + /** How long to wait between runs */ + protected static long idlePeriod = 20 * 1000; + + /** + * Must make sure AbstractAuxiliaryCacheMonitor is started before any error can be detected! + */ + private AtomicBoolean allright = new AtomicBoolean(true); + + /** + * shutdown flag + */ + private AtomicBoolean shutdown = new AtomicBoolean(false); + + /** Synchronization helper lock */ + private Lock lock = new ReentrantLock(); + + /** Synchronization helper condition */ + private Condition trigger = lock.newCondition(); + + /** + * Constructor + * + * @param name the thread name + */ + public AbstractAuxiliaryCacheMonitor(String name) + { + super(name); + } + + /** + * Configures the idle period between repairs. + * <p> + * @param idlePeriod The new idlePeriod value + */ + public static void setIdlePeriod( long idlePeriod ) + { + if ( idlePeriod > AbstractAuxiliaryCacheMonitor.idlePeriod ) + { + AbstractAuxiliaryCacheMonitor.idlePeriod = idlePeriod; + } + } + + /** + * Set error condition unconditionally + */ + protected void setError(boolean state) + { + allright.set(!state); + } + + /** + * Notifies the cache monitor that an error occurred, and kicks off the error recovery process. + */ + public void notifyError() + { + if (allright.compareAndSet(true, false)) + { + signalTrigger(); + } + } + + /** + * Notifies the cache monitor that the service shall shut down + */ + public void notifyShutdown() + { + if (shutdown.compareAndSet(false, true)) + { + signalTrigger(); + } + } + + // Trigger continuation of loop + private void signalTrigger() + { + try + { + lock.lock(); + trigger.signal(); + } + finally + { + lock.unlock(); + } + } + + /** + * Clean up all resources before shutdown + */ + protected abstract void dispose(); + + /** + * do actual work + */ + protected abstract void doWork(); + + + /** + * Main processing method for the AbstractAuxiliaryCacheMonitor object + */ + @Override + public void run() + { + do + { + if ( log.isDebugEnabled() ) + { + if ( allright.get() ) + { + log.debug( "ERROR DRIVEN MODE: allright = true, cache monitor will wait for an error." ); + } + else + { + log.debug( "ERROR DRIVEN MODE: allright = false cache monitor running." ); + } + } + + if ( allright.get() ) + { + // Failure driven mode. + try + { + lock.lock(); + trigger.await(); + // wake up only if there is an error. + } + catch ( InterruptedException ignore ) + { + //no op, this is expected + } + finally + { + lock.unlock(); + } + } + + // check for requested shutdown + if ( shutdown.get() ) + { + log.info( "Shutting down cache monitor" ); + dispose(); + return; + } + + // The "allright" flag must be false here. + // Simply presume we can fix all the errors until proven otherwise. + allright.set(true); + + if ( log.isDebugEnabled() ) + { + log.debug( "Cache monitor running." ); + } + + doWork(); + + try + { + // don't want to sleep after waking from an error + // run immediately and sleep here. + if ( log.isDebugEnabled() ) + { + log.debug( "Cache monitor sleeping for " + idlePeriod + " between runs." ); + } + + Thread.sleep( idlePeriod ); + } + catch ( InterruptedException ex ) + { + // ignore; + } + } + while ( true ); + } +} Propchange: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java Thu Dec 3 16:41:49 2015 @@ -700,24 +700,26 @@ public class BlockDiskCache<K, V> elems.add(new StatElement<Boolean>( "Is Alive", Boolean.valueOf(alive) ) ); elems.add(new StatElement<Integer>( "Key Map Size", Integer.valueOf(this.keyStore.size()) ) ); - try + if (this.dataFile != null) { - elems.add(new StatElement<Long>( "Data File Length", - Long.valueOf(this.dataFile != null ? this.dataFile.length() : -1L) ) ); - } - catch ( IOException e ) - { - log.error( e ); - } + try + { + elems.add(new StatElement<Long>( "Data File Length", Long.valueOf(this.dataFile.length()) ) ); + } + catch ( IOException e ) + { + log.error( e ); + } - elems.add(new StatElement<Integer>( "Block Size Bytes", - Integer.valueOf(this.dataFile.getBlockSizeBytes()) ) ); - elems.add(new StatElement<Integer>( "Number Of Blocks", - Integer.valueOf(this.dataFile.getNumberOfBlocks()) ) ); - elems.add(new StatElement<Long>( "Average Put Size Bytes", - Long.valueOf(this.dataFile.getAveragePutSizeBytes()) ) ); - elems.add(new StatElement<Integer>( "Empty Blocks", - Integer.valueOf(this.dataFile.getEmptyBlocks()) ) ); + elems.add(new StatElement<Integer>( "Block Size Bytes", + Integer.valueOf(this.dataFile.getBlockSizeBytes()) ) ); + elems.add(new StatElement<Integer>( "Number Of Blocks", + Integer.valueOf(this.dataFile.getNumberOfBlocks()) ) ); + elems.add(new StatElement<Long>( "Average Put Size Bytes", + Long.valueOf(this.dataFile.getAveragePutSizeBytes()) ) ); + elems.add(new StatElement<Integer>( "Empty Blocks", + Integer.valueOf(this.dataFile.getEmptyBlocks()) ) ); + } // get the stats from the super too IStats sStats = super.getStatistics(); Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java Thu Dec 3 16:41:49 2015 @@ -370,7 +370,7 @@ public class BlockDiskKeyStore<K> /** * <code>tag</code> tells us which map we are working on. */ - public final String tag = "orig-lru-size"; + public final static String TAG = "orig-lru-size"; // size of the content in kB private AtomicInteger contentSize; @@ -489,7 +489,7 @@ public class BlockDiskKeyStore<K> /** * <code>tag</code> tells us which map we are working on. */ - public final String tag = "orig-lru-count"; + public final static String TAG = "orig-lru-count"; public LRUMapCountLimited(int maxKeySize) { Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java Thu Dec 3 16:41:49 2015 @@ -1692,7 +1692,7 @@ public class IndexedDiskCache<K, V> exte /** * <code>tag</code> tells us which map we are working on. */ - public String tag = "orig"; + public static final String TAG = "orig"; // size of the content in kB private AtomicInteger contentSize; Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java Thu Dec 3 16:41:49 2015 @@ -252,6 +252,8 @@ public class JDBCDiskCache<K, V> private boolean insertRow( ICacheElement<K, V> ce, Connection con, byte[] element ) { boolean exists = false; + PreparedStatement psInsert = null; + try { String sqlI = "insert into " @@ -259,7 +261,7 @@ public class JDBCDiskCache<K, V> + " (CACHE_KEY, REGION, ELEMENT, MAX_LIFE_SECONDS, IS_ETERNAL, CREATE_TIME, UPDATE_TIME_SECONDS, SYSTEM_EXPIRE_TIME_SECONDS) " + " values (?, ?, ?, ?, ?, ?, ?, ?)"; - PreparedStatement psInsert = con.prepareStatement( sqlI ); + psInsert = con.prepareStatement( sqlI ); psInsert.setString( 1, (String) ce.getKey() ); psInsert.setString( 2, this.getCacheName() ); psInsert.setBytes( 3, element ); @@ -282,7 +284,6 @@ public class JDBCDiskCache<K, V> psInsert.setLong( 8, expireTime ); psInsert.execute(); - psInsert.close(); } catch ( SQLException e ) { @@ -301,6 +302,21 @@ public class JDBCDiskCache<K, V> exists = doesElementExist( ce, con ); } } + finally + { + if (psInsert != null) + { + try + { + psInsert.close(); + } + catch (SQLException e) + { + log.error( "Problem closing statement.", e ); + } + } + } + return exists; } @@ -314,12 +330,14 @@ public class JDBCDiskCache<K, V> private void updateRow( ICacheElement<K, V> ce, Connection con, byte[] element ) { String sqlU = null; + PreparedStatement psUpdate = null; + try { sqlU = "update " + getJdbcDiskCacheAttributes().getTableName() + " set ELEMENT = ?, CREATE_TIME = ?, UPDATE_TIME_SECONDS = ?, " + " SYSTEM_EXPIRE_TIME_SECONDS = ? " + " where CACHE_KEY = ? and REGION = ?"; - PreparedStatement psUpdate = con.prepareStatement( sqlU ); + psUpdate = con.prepareStatement( sqlU ); psUpdate.setBytes( 1, element ); Timestamp createTime = new Timestamp( ce.getElementAttributes().getCreateTime() ); @@ -334,7 +352,6 @@ public class JDBCDiskCache<K, V> psUpdate.setString( 5, (String) ce.getKey() ); psUpdate.setString( 6, this.getCacheName() ); psUpdate.execute(); - psUpdate.close(); if ( log.isDebugEnabled() ) { @@ -345,6 +362,20 @@ public class JDBCDiskCache<K, V> { log.error( "e2 sql [" + sqlU + "] Exception: ", e2 ); } + finally + { + if (psUpdate != null) + { + try + { + psUpdate.close(); + } + catch (SQLException e) + { + log.error( "Problem closing statement.", e ); + } + } + } } /** @@ -358,6 +389,8 @@ public class JDBCDiskCache<K, V> { boolean exists = false; PreparedStatement psSelect = null; + ResultSet rs = null; + try { // don't select the element, since we want this to be fast. @@ -368,7 +401,7 @@ public class JDBCDiskCache<K, V> psSelect.setString( 1, this.getCacheName() ); psSelect.setString( 2, (String) ce.getKey() ); - ResultSet rs = psSelect.executeQuery(); + rs = psSelect.executeQuery(); if ( rs.next() ) { @@ -379,8 +412,6 @@ public class JDBCDiskCache<K, V> { log.debug( "[" + ce.getKey() + "] existing status is " + exists ); } - - rs.close(); } catch ( SQLException e ) { @@ -390,14 +421,25 @@ public class JDBCDiskCache<K, V> { try { + if ( rs != null ) + { + rs.close(); + } + } + catch ( SQLException e ) + { + log.error( "Problem closing result set.", e ); + } + try + { if ( psSelect != null ) { psSelect.close(); } } - catch ( SQLException e1 ) + catch ( SQLException e ) { - log.error( "Problem closing statement.", e1 ); + log.error( "Problem closing statement.", e ); } } @@ -439,6 +481,7 @@ public class JDBCDiskCache<K, V> try { PreparedStatement psSelect = null; + try { psSelect = con.prepareStatement( selectString ); @@ -446,6 +489,7 @@ public class JDBCDiskCache<K, V> psSelect.setString( 2, key.toString() ); ResultSet rs = psSelect.executeQuery(); + try { if ( rs.next() ) Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java Thu Dec 3 16:41:49 2015 @@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHa import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory; import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; @@ -69,6 +70,9 @@ public class JDBCDiskCacheFactory /** Pool name to DataSourceFactories */ private ConcurrentMap<String, DataSourceFactory> dsFactories; + /** Lock to allow lengthy initialization of DataSourceFactories */ + private ReentrantLock dsFactoryLock; + /** props prefix */ protected static final String POOL_CONFIGURATION_PREFIX = "jcs.jdbcconnectionpool."; @@ -115,6 +119,7 @@ public class JDBCDiskCacheFactory this.tableStates = new ConcurrentHashMap<String, TableState>(); this.shrinkerThreadMap = new ConcurrentHashMap<String, ShrinkerThread>(); this.dsFactories = new ConcurrentHashMap<String, DataSourceFactory>(); + this.dsFactoryLock = new ReentrantLock(); } /** @@ -234,43 +239,56 @@ public class JDBCDiskCacheFactory poolName = cattr.getConnectionPoolName(); } - synchronized (this.dsFactories) + + DataSourceFactory dsFactory = this.dsFactories.get(poolName); + + if (dsFactory == null) { - DataSourceFactory dsFactory = this.dsFactories.get(poolName); + dsFactoryLock.lock(); + + try + { + // double check + dsFactory = this.dsFactories.get(poolName); + + if (dsFactory == null) + { + JDBCDiskCacheAttributes dsConfig = null; - if (dsFactory == null) - { - JDBCDiskCacheAttributes dsConfig = null; - - if (cattr.getConnectionPoolName() == null) - { - dsConfig = cattr; - } - else - { - dsConfig = new JDBCDiskCacheAttributes(); - String dsConfigAttributePrefix = POOL_CONFIGURATION_PREFIX + poolName + ATTRIBUTE_PREFIX; - PropertySetter.setProperties( dsConfig, - configProps, - dsConfigAttributePrefix + "." ); - - dsConfig.setConnectionPoolName(poolName); - } - - if ( dsConfig.getJndiPath() != null ) - { - dsFactory = new JndiDataSourceFactory(); - } - else - { - dsFactory = new SharedPoolDataSourceFactory(); - } - - dsFactory.initialize(dsConfig); - this.dsFactories.put(poolName, dsFactory); - } + if (cattr.getConnectionPoolName() == null) + { + dsConfig = cattr; + } + else + { + dsConfig = new JDBCDiskCacheAttributes(); + String dsConfigAttributePrefix = POOL_CONFIGURATION_PREFIX + poolName + ATTRIBUTE_PREFIX; + PropertySetter.setProperties( dsConfig, + configProps, + dsConfigAttributePrefix + "." ); + + dsConfig.setConnectionPoolName(poolName); + } + + if ( dsConfig.getJndiPath() != null ) + { + dsFactory = new JndiDataSourceFactory(); + } + else + { + dsFactory = new SharedPoolDataSourceFactory(); + } - return dsFactory; + dsFactory.initialize(dsConfig); + this.dsFactories.put(poolName, dsFactory); + } + } + finally + { + dsFactoryLock.unlock(); + } } + + return dsFactory; } } Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java Thu Dec 3 16:41:49 2015 @@ -19,17 +19,15 @@ package org.apache.commons.jcs.auxiliary * under the License. */ -import java.io.Serializable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheMonitor; import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory; import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes; import org.apache.commons.jcs.engine.CacheStatus; import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal; import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * Used to monitor and repair any failed connection for the lateral cache service. By default the @@ -38,19 +36,8 @@ import org.apache.commons.logging.LogFac * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed * connections are restored, it changes back to the failure driven mode. */ -public class LateralCacheMonitor extends Thread +public class LateralCacheMonitor extends AbstractAuxiliaryCacheMonitor { - /** The logger */ - private static final Log log = LogFactory.getLog( LateralCacheMonitor.class ); - - /** How long to wait between runs */ - private static long idlePeriod = 20 * 1000; - - /** - * Must make sure LateralCacheMonitor is started before any lateral error can be detected! - */ - private boolean allright = true; - /** * Map of caches to monitor */ @@ -62,30 +49,6 @@ public class LateralCacheMonitor extends private LateralTCPCacheFactory factory; /** - * shutdown flag - */ - private boolean shutdown = false; - - /** code for eror */ - private static final int ERROR = 1; - - /** The mode we are running in. Error driven */ - private static int mode = ERROR; - - /** - * Configures the idle period between repairs. - * <p> - * @param idlePeriod The new idlePeriod value - */ - public static void setIdlePeriod( long idlePeriod ) - { - if ( idlePeriod > LateralCacheMonitor.idlePeriod ) - { - LateralCacheMonitor.idlePeriod = idlePeriod; - } - } - - /** * Allows close classes, ie testers to set the idle period to something testable. * <p> * @param idlePeriod @@ -107,6 +70,7 @@ public class LateralCacheMonitor extends super("JCS-LateralCacheMonitor"); this.factory = factory; this.caches = new ConcurrentHashMap<String, LateralCacheNoWait<?,?>>(); + setIdlePeriod(20000L); } /** @@ -126,159 +90,46 @@ public class LateralCacheMonitor extends } /** - * Notifies the cache monitor that an error occurred, and kicks off the error recovery process. - */ - public void notifyError() - { - bad(); - synchronized ( this ) - { - notify(); - } - } - - /** - * Notifies the cache monitor that the service shall shut down + * Clean up all resources before shutdown */ - public void notifyShutdown() + @Override + public void dispose() { - synchronized ( this ) - { - this.shutdown = true; - notify(); - } + this.caches.clear(); } /** * Main processing method for the LateralCacheMonitor object */ @Override - public void run() + public void doWork() { - do + // Monitor each cache instance one after the other. + log.info( "Number of caches to monitor = " + caches.size() ); + //for + for (Map.Entry<String, LateralCacheNoWait<?, ?>> entry : caches.entrySet()) { - if ( mode == ERROR ) - { - if ( log.isDebugEnabled() ) - { - if ( allright ) - { - log.debug( "ERROR DRIVEN MODE: allright = " + allright - + ", connection monitor will wait for an error." ); - } - else - { - log.debug( "ERROR DRIVEN MODE: allright = " + allright + " connection monitor running." ); - } - } - - synchronized ( this ) - { - if ( allright ) - { - // Failure driven mode. - try - { - wait(); - // wake up only if there is an error. - } - catch ( InterruptedException ignore ) - { - //no op, this is expected - } - } - } - } - else - { - log.debug( "TIME DRIVEN MODE: connection monitor will sleep for " + idlePeriod + " after this run." ); - // Time driven mode: sleep between each round of recovery - // attempt. - // will need to test not just check status - } + String cacheName = entry.getKey(); - // check for requested shutdown - synchronized ( this ) + @SuppressWarnings("unchecked") // Downcast to match service + LateralCacheNoWait<Object, Object> c = (LateralCacheNoWait<Object, Object>) entry.getValue(); + if ( c.getStatus() == CacheStatus.ERROR ) { - if (shutdown) - { - log.info( "Shutting down cache monitor" ); - this.caches.clear(); - return; - } - } + log.info( "Found LateralCacheNoWait in error, " + cacheName ); - // The "allright" flag must be false here. - // Simply presume we can fix all the errors until proven otherwise. - synchronized ( this ) - { - allright = true; - } + ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)c.getAuxiliaryCacheAttributes(); - if ( log.isDebugEnabled() ) - { - log.debug( "Cache monitor running." ); - } - - // Monitor each cache instance one after the other. - log.info( "Number of caches to monitor = " + caches.size() ); - //for - for (Map.Entry<String, LateralCacheNoWait<?, ?>> entry : caches.entrySet()) - { - String cacheName = entry.getKey(); + // Get service instance + ICacheServiceNonLocal<Object, Object> cacheService = factory.getCSNLInstance(lca); - @SuppressWarnings("unchecked") // Downcast to match service - LateralCacheNoWait<Serializable, Serializable> c = - (LateralCacheNoWait<Serializable, Serializable>) entry.getValue(); - if ( c.getStatus() == CacheStatus.ERROR ) + // If we can't fix them, just skip and re-try in the + // next round. + if (cacheService instanceof ZombieCacheServiceNonLocal) { - log.info( "Found LateralCacheNoWait in error, " + cacheName ); - - ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)c.getAuxiliaryCacheAttributes(); - - // Get service instance - ICacheServiceNonLocal<Serializable, Serializable> cacheService = factory.getCSNLInstance(lca); - - // If we can't fix them, just skip and re-try in the - // next round. - if (cacheService instanceof ZombieCacheServiceNonLocal) - { - continue; - } - - c.fixCache(cacheService); + continue; } - } - - try - { - // don't want to sleep after waking from an error - // run immediately and sleep here. - if ( log.isDebugEnabled() ) - { - log.debug( "Lateral cache monitor sleeping for " + idlePeriod + " between runs." ); - } - - Thread.sleep( idlePeriod ); - } - catch ( InterruptedException ex ) - { - // ignore; - } - } - while ( true ); - } - /** - * Sets the "allright" flag to false in a critical section. - */ - private void bad() - { - if ( allright ) - { - synchronized ( this ) - { - allright = false; + c.fixCache(cacheService); } } } Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java Thu Dec 3 16:41:49 2015 @@ -23,6 +23,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory; import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; @@ -63,6 +64,9 @@ public class LateralTCPCacheFactory /** Address to service map. */ private ConcurrentHashMap<String, ICacheServiceNonLocal<?, ?>> csnlInstances; + /** Lock for initialization of address to service map */ + private ReentrantLock csnlLock; + /** Map of available discovery listener instances, keyed by port. */ private ConcurrentHashMap<String, LateralTCPDiscoveryListener> lTCPDLInstances; @@ -168,6 +172,7 @@ public class LateralTCPCacheFactory public void initialize() { this.csnlInstances = new ConcurrentHashMap<String, ICacheServiceNonLocal<?, ?>>(); + this.csnlLock = new ReentrantLock(); this.lTCPDLInstances = new ConcurrentHashMap<String, LateralTCPDiscoveryListener>(); // Create the monitoring daemon thread @@ -216,55 +221,68 @@ public class LateralTCPCacheFactory * * @return ICacheServiceNonLocal<K, V> */ + // Need to cast because of common map for all cache services + @SuppressWarnings("unchecked") public <K, V> ICacheServiceNonLocal<K, V> getCSNLInstance( ITCPLateralCacheAttributes lca ) { String key = lca.getTcpServer(); - synchronized ( csnlInstances ) + + ICacheServiceNonLocal<K, V> service = (ICacheServiceNonLocal<K, V>)csnlInstances.get( key ); + + if ( service == null || service instanceof ZombieCacheServiceNonLocal ) { - // Need to cast because of common map for all cache services - @SuppressWarnings("unchecked") - ICacheServiceNonLocal<K, V> service = (ICacheServiceNonLocal<K, V>)csnlInstances.get( key ); + csnlLock.lock(); - // If service creation did not succeed last time, force retry - if ( service instanceof ZombieCacheServiceNonLocal) + try { - service = null; - log.info("Disposing of zombie service instance for [" + key + "]"); - } + // double check + service = (ICacheServiceNonLocal<K, V>)csnlInstances.get( key ); - if ( service == null ) - { - log.info( "Instance for [" + key + "] is null, creating" ); + // If service creation did not succeed last time, force retry + if ( service instanceof ZombieCacheServiceNonLocal) + { + service = null; + log.info("Disposing of zombie service instance for [" + key + "]"); + } - // Create the service - try + if ( service == null ) { - if ( log.isInfoEnabled() ) + log.info( "Instance for [" + key + "] is null, creating" ); + + // Create the service + try { - log.info( "Creating TCP service, lca = " + lca ); + if ( log.isInfoEnabled() ) + { + log.info( "Creating TCP service, lca = " + lca ); + } + + service = new LateralTCPService<K, V>( lca ); + } + catch ( IOException ex ) + { + // Failed to connect to the lateral server. + // Configure this LateralCacheManager instance to use the + // "zombie" services. + log.error( "Failure, lateral instance will use zombie service", ex ); + + service = new ZombieCacheServiceNonLocal<K, V>( lca.getZombieQueueMaxSize() ); + + // Notify the cache monitor about the error, and kick off + // the recovery process. + monitor.notifyError(); } - service = new LateralTCPService<K, V>( lca ); + csnlInstances.put( key, service ); } - catch ( IOException ex ) - { - // Failed to connect to the lateral server. - // Configure this LateralCacheManager instance to use the - // "zombie" services. - log.error( "Failure, lateral instance will use zombie service", ex ); - - service = new ZombieCacheServiceNonLocal<K, V>( lca.getZombieQueueMaxSize() ); - - // Notify the cache monitor about the error, and kick off - // the recovery process. - monitor.notifyError(); - } - - csnlInstances.put( key, service ); } - - return service; + finally + { + csnlLock.unlock(); + } } + + return service; } /** Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java Thu Dec 3 16:41:49 2015 @@ -19,6 +19,10 @@ package org.apache.commons.jcs.auxiliary * under the License. */ +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpState; @@ -32,10 +36,6 @@ import org.apache.commons.jcs.utils.seri import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - /** Calls the service. */ public class RemoteHttpCacheDispatcher extends AbstractHttpClient @@ -129,7 +129,7 @@ public class RemoteHttpCacheDispatcher */ protected <K, V> String addParameters( RemoteCacheRequest<K, V> remoteCacheRequest, String baseUrl ) { - StringBuilder url = new StringBuilder( baseUrl ); + StringBuilder url = new StringBuilder( baseUrl == null ? "" : baseUrl ); try { Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java Thu Dec 3 16:41:49 2015 @@ -31,6 +31,8 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.jcs.access.exception.CacheException; import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener; @@ -82,21 +84,21 @@ public class RemoteCacheServer<K, V> private int puts = 0; /** Maps cache name to CacheListeners object. association of listeners (regions). */ - private final Map<String, CacheListeners<K, V>> cacheListenersMap = + private final transient ConcurrentMap<String, CacheListeners<K, V>> cacheListenersMap = new ConcurrentHashMap<String, CacheListeners<K, V>>(); /** maps cluster listeners to regions. */ - private final Map<String, CacheListeners<K, V>> clusterListenersMap = + private final transient ConcurrentMap<String, CacheListeners<K, V>> clusterListenersMap = new ConcurrentHashMap<String, CacheListeners<K, V>>(); /** The central hub */ private transient CompositeCacheManager cacheManager; /** relates listener id with a type */ - private final Map<Long, RemoteType> idTypeMap = new ConcurrentHashMap<Long, RemoteType>(); + private final ConcurrentMap<Long, RemoteType> idTypeMap = new ConcurrentHashMap<Long, RemoteType>(); /** relates listener id with an ip address */ - private final Map<Long, String> idIPMap = new ConcurrentHashMap<Long, String>(); + private final ConcurrentMap<Long, String> idIPMap = new ConcurrentHashMap<Long, String>(); /** Used to get the next listener id. */ private final int[] listenerId = new int[1]; @@ -111,6 +113,12 @@ public class RemoteCacheServer<K, V> /** An optional event logger */ private transient ICacheEventLogger cacheEventLogger; + /** Lock for Cache listener initialization */ + private ReentrantLock cacheListenersLock = new ReentrantLock(); + + /** Lock for Cluster listener initialization */ + private ReentrantLock clusterListenersLock = new ReentrantLock(); + /** * Constructor for the RemoteCacheServer object. This initializes the server with the values * from the config file. @@ -1145,19 +1153,16 @@ public class RemoteCacheServer<K, V> public void release() throws IOException { - synchronized ( cacheListenersMap ) + for (CacheListeners<K, V> cacheDesc : cacheListenersMap.values()) { - for (CacheListeners<K, V> cacheDesc : cacheListenersMap.values()) - { - ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, 0 ); + ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, 0 ); - for ( int i = 0; i < qlist.length; i++ ) - { - qlist[i].addDisposeEvent(); - } + for ( int i = 0; i < qlist.length; i++ ) + { + qlist[i].addDisposeEvent(); } - cacheManager.release(); } + cacheManager.release(); } /** @@ -1170,10 +1175,14 @@ public class RemoteCacheServer<K, V> protected CacheListeners<K, V> getCacheListeners( String cacheName ) { CacheListeners<K, V> cacheListeners = cacheListenersMap.get( cacheName ); - synchronized ( cacheListenersMap ) + + if ( cacheListeners == null ) { - if ( cacheListeners == null ) + cacheListenersLock.lock(); + + try { + // double check cacheListeners = cacheListenersMap.get( cacheName ); if ( cacheListeners == null ) { @@ -1182,7 +1191,12 @@ public class RemoteCacheServer<K, V> cacheListenersMap.put( cacheName, cacheListeners ); } } + finally + { + cacheListenersLock.unlock(); + } } + return cacheListeners; } @@ -1196,9 +1210,12 @@ public class RemoteCacheServer<K, V> protected CacheListeners<K, V> getClusterListeners( String cacheName ) { CacheListeners<K, V> cacheListeners = clusterListenersMap.get( cacheName ); - synchronized ( clusterListenersMap ) + + if ( cacheListeners == null ) { - if ( cacheListeners == null ) + clusterListenersLock.lock(); + + try { cacheListeners = clusterListenersMap.get( cacheName ); if ( cacheListeners == null ) @@ -1208,7 +1225,12 @@ public class RemoteCacheServer<K, V> clusterListenersMap.put( cacheName, cacheListeners ); } } + finally + { + clusterListenersLock.unlock(); + } } + return cacheListeners; } @@ -1227,11 +1249,7 @@ public class RemoteCacheServer<K, V> @SuppressWarnings("unchecked") // No generic arrays in java private ICacheEventQueue<K, V>[] getEventQList( CacheListeners<K, V> cacheListeners, long requesterId ) { - ICacheEventQueue<K, V>[] list = null; - synchronized ( cacheListeners.eventQMap ) - { - list = cacheListeners.eventQMap.values().toArray( new ICacheEventQueue[0] ); - } + ICacheEventQueue<K, V>[] list = cacheListeners.eventQMap.values().toArray( new ICacheEventQueue[0] ); int count = 0; // Set those not qualified to null; Count those qualified. for ( int i = 0; i < list.length; i++ ) Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheListeners.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheListeners.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheListeners.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheListeners.java Thu Dec 3 16:41:49 2015 @@ -19,12 +19,13 @@ package org.apache.commons.jcs.engine; * under the License. */ -import org.apache.commons.jcs.engine.behavior.ICache; -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; - import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.commons.jcs.engine.behavior.ICache; +import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; /** * Used to associates a set of [cache listener to cache event queue] for a @@ -36,7 +37,7 @@ public class CacheListeners<K, V> public final ICache<K, V> cache; /** Map ICacheListener to ICacheEventQueue */ - public final Map<Long, ICacheEventQueue<K, V>> eventQMap = + public final ConcurrentMap<Long, ICacheEventQueue<K, V>> eventQMap = new ConcurrentHashMap<Long, ICacheEventQueue<K, V>>(); /** Modified: commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCache.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCache.java?rev=1717801&r1=1717800&r2=1717801&view=diff ============================================================================== --- commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCache.java (original) +++ commons/proper/jcs/trunk/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCache.java Thu Dec 3 16:41:49 2015 @@ -28,6 +28,8 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.jcs.access.exception.CacheException; import org.apache.commons.jcs.access.exception.ObjectNotFoundException; @@ -82,7 +84,7 @@ public class CompositeCache<K, V> private AuxiliaryCache<K, V>[] auxCaches = new AuxiliaryCache[0]; /** is this alive? */ - private boolean alive = true; + private AtomicBoolean alive; /** Region Elemental Attributes, default. */ private IElementAttributes attr; @@ -91,22 +93,22 @@ public class CompositeCache<K, V> private ICompositeCacheAttributes cacheAttr; /** How many times update was called. */ - private int updateCount; + private AtomicInteger updateCount; /** How many times remove was called. */ - private int removeCount; + private AtomicInteger removeCount; /** Memory cache hit count */ - private int hitCountRam; + private AtomicInteger hitCountRam; /** Auxiliary cache hit count (number of times found in ANY auxiliary) */ - private int hitCountAux; + private AtomicInteger hitCountAux; /** Count of misses where element was not found. */ - private int missCountNotFound = 0; + private AtomicInteger missCountNotFound; /** Count of misses where element was expired. */ - private int missCountExpired = 0; + private AtomicInteger missCountExpired; /** * The cache hub can only have one memory cache. This could be made more flexible in the future, @@ -127,6 +129,13 @@ public class CompositeCache<K, V> { this.attr = attr; this.cacheAttr = cattr; + this.alive = new AtomicBoolean(true); + this.updateCount = new AtomicInteger(0); + this.removeCount = new AtomicInteger(0); + this.hitCountRam = new AtomicInteger(0); + this.hitCountAux = new AtomicInteger(0); + this.missCountNotFound = new AtomicInteger(0); + this.missCountExpired = new AtomicInteger(0); createMemoryCache( cattr ); @@ -233,16 +242,15 @@ public class CompositeCache<K, V> log.debug( "Updating memory cache " + cacheElement.getKey() ); } + updateCount.incrementAndGet(); + synchronized ( this ) { - updateCount++; - memCache.update( cacheElement ); - updateAuxiliaries( cacheElement, localOnly ); - - cacheElement.getElementAttributes().setLastAccessTimeNow(); } + + cacheElement.getElementAttributes().setLastAccessTimeNow(); } /** @@ -270,7 +278,6 @@ public class CompositeCache<K, V> // more can be added if future auxiliary caches don't fit the model // You could run a database cache as either a remote or a local disk. // The types would describe the purpose. - if ( log.isDebugEnabled() ) { if ( auxCaches.length > 0 ) @@ -283,85 +290,88 @@ public class CompositeCache<K, V> } } - for ( int i = 0; i < auxCaches.length; i++ ) + for ( ICache<K, V> aux : auxCaches ) { - ICache<K, V> aux = auxCaches[i]; - - if ( log.isDebugEnabled() ) + if ( aux == null ) { - log.debug( "Auxilliary cache type: " + aux.getCacheType() ); + continue; } - if ( aux == null ) + if ( log.isDebugEnabled() ) { - continue; + log.debug( "Auxiliary cache type: " + aux.getCacheType() ); } - // SEND TO REMOTE STORE - if ( aux.getCacheType() == CacheType.REMOTE_CACHE ) + switch (aux.getCacheType()) { - if ( log.isDebugEnabled() ) - { - log.debug( "ce.getElementAttributes().getIsRemote() = " - + cacheElement.getElementAttributes().getIsRemote() ); - } + // SEND TO REMOTE STORE + case REMOTE_CACHE: + if ( log.isDebugEnabled() ) + { + log.debug( "ce.getElementAttributes().getIsRemote() = " + + cacheElement.getElementAttributes().getIsRemote() ); + } - if ( cacheElement.getElementAttributes().getIsRemote() && !localOnly ) - { - try + if ( cacheElement.getElementAttributes().getIsRemote() && !localOnly ) { - // need to make sure the group cache understands that - // the key is a group attribute on update - aux.update( cacheElement ); - if ( log.isDebugEnabled() ) + try { - log.debug( "Updated remote store for " + cacheElement.getKey() + cacheElement ); + // need to make sure the group cache understands that + // the key is a group attribute on update + aux.update( cacheElement ); + if ( log.isDebugEnabled() ) + { + log.debug( "Updated remote store for " + cacheElement.getKey() + cacheElement ); + } + } + catch ( IOException ex ) + { + log.error( "Failure in updateExclude", ex ); } } - catch ( IOException ex ) - { - log.error( "Failure in updateExclude", ex ); - } - } + break; + // SEND LATERALLY - } - else if ( aux.getCacheType() == CacheType.LATERAL_CACHE ) - { - // lateral can't do the checking since it is dependent on the - // cache region restrictions - if ( log.isDebugEnabled() ) - { - log.debug( "lateralcache in aux list: cattr " + cacheAttr.isUseLateral() ); - } - if ( cacheAttr.isUseLateral() && cacheElement.getElementAttributes().getIsLateral() && !localOnly ) - { - // DISTRIBUTE LATERALLY - // Currently always multicast even if the value is - // unchanged, to cause the cache item to move to the front. - aux.update( cacheElement ); + case LATERAL_CACHE: + // lateral can't do the checking since it is dependent on the + // cache region restrictions if ( log.isDebugEnabled() ) { - log.debug( "updated lateral cache for " + cacheElement.getKey() ); + log.debug( "lateralcache in aux list: cattr " + cacheAttr.isUseLateral() ); } - } - } - // update disk if the usage pattern permits - else if ( aux.getCacheType() == CacheType.DISK_CACHE ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "diskcache in aux list: cattr " + cacheAttr.isUseDisk() ); - } - if ( cacheAttr.isUseDisk() - && cacheAttr.getDiskUsagePattern() == DiskUsagePattern.UPDATE - && cacheElement.getElementAttributes().getIsSpool() ) - { - aux.update( cacheElement ); + if ( cacheAttr.isUseLateral() && cacheElement.getElementAttributes().getIsLateral() && !localOnly ) + { + // DISTRIBUTE LATERALLY + // Currently always multicast even if the value is + // unchanged, to cause the cache item to move to the front. + aux.update( cacheElement ); + if ( log.isDebugEnabled() ) + { + log.debug( "updated lateral cache for " + cacheElement.getKey() ); + } + } + break; + + // update disk if the usage pattern permits + case DISK_CACHE: if ( log.isDebugEnabled() ) { - log.debug( "updated disk cache for " + cacheElement.getKey() ); + log.debug( "diskcache in aux list: cattr " + cacheAttr.isUseDisk() ); } - } + if ( cacheAttr.isUseDisk() + && cacheAttr.getDiskUsagePattern() == DiskUsagePattern.UPDATE + && cacheElement.getElementAttributes().getIsSpool() ) + { + aux.update( cacheElement ); + if ( log.isDebugEnabled() ) + { + log.debug( "updated disk cache for " + cacheElement.getKey() ); + } + } + break; + + default: // CACHE_HUB + break; } } } @@ -388,10 +398,8 @@ public class CompositeCache<K, V> boolean diskAvailable = false; // SPOOL TO DISK. - for ( int i = 0; i < auxCaches.length; i++ ) + for ( ICache<K, V> aux : auxCaches ) { - ICache<K, V> aux = auxCaches[i]; - if ( aux != null && aux.getCacheType() == CacheType.DISK_CACHE ) { diskAvailable = true; @@ -410,20 +418,17 @@ public class CompositeCache<K, V> log.error( "Problem spooling item to disk cache.", ex ); throw new IllegalStateException( ex.getMessage() ); } - catch ( Exception oee ) - { - // swallow - } + if ( log.isDebugEnabled() ) { - log.debug( "spoolToDisk done for: " + ce.getKey() + " on disk cache[" + i + "]" ); + log.debug( "spoolToDisk done for: " + ce.getKey() + " on disk cache[" + aux.getCacheName() + "]" ); } } else { if ( log.isDebugEnabled() ) { - log.debug( "DiskCache avaialbe, but JCS is not configured to use the DiskCache as a swap." ); + log.debug( "DiskCache available, but JCS is not configured to use the DiskCache as a swap." ); } } } @@ -505,10 +510,8 @@ public class CompositeCache<K, V> log.debug( cacheAttr.getCacheName() + " - Memory cache hit, but element expired" ); } - missCountExpired++; - + missCountExpired.incrementAndGet(); remove( key ); - element = null; } else @@ -519,7 +522,7 @@ public class CompositeCache<K, V> } // Update counters - hitCountRam++; + hitCountRam.incrementAndGet(); } found = true; @@ -528,11 +531,8 @@ public class CompositeCache<K, V> { // Item not found in memory. If local invocation look in aux // caches, even if not local look in disk auxiliaries - - for ( int i = 0; i < auxCaches.length; i++ ) + for (AuxiliaryCache<K, V> aux : auxCaches) { - AuxiliaryCache<K, V> aux = auxCaches[i]; - if ( aux != null ) { CacheType cacheType = aux.getCacheType(); @@ -567,28 +567,27 @@ public class CompositeCache<K, V> { if ( log.isDebugEnabled() ) { - log.debug( cacheAttr.getCacheName() + " - Aux cache[" + i + "] hit, but element expired." ); + log.debug( cacheAttr.getCacheName() + " - Aux cache[" + aux.getCacheName() + "] hit, but element expired." ); } - missCountExpired++; + missCountExpired.incrementAndGet(); // This will tell the remotes to remove the item // based on the element's expiration policy. The elements attributes // associated with the item when it created govern its behavior // everywhere. remove( key ); - element = null; } else { if ( log.isDebugEnabled() ) { - log.debug( cacheAttr.getCacheName() + " - Aux cache[" + i + "] hit" ); + log.debug( cacheAttr.getCacheName() + " - Aux cache[" + aux.getCacheName() + "] hit" ); } // Update counters - hitCountAux++; + hitCountAux.incrementAndGet(); copyAuxiliaryRetrievedItemToMemory( element ); } @@ -600,7 +599,7 @@ public class CompositeCache<K, V> } } } - catch ( Exception e ) + catch ( IOException e ) { log.error( "Problem encountered getting element.", e ); } @@ -608,7 +607,7 @@ public class CompositeCache<K, V> if ( !found ) { - missCountNotFound++; + missCountNotFound.incrementAndGet(); if ( log.isDebugEnabled() ) { @@ -683,7 +682,7 @@ public class CompositeCache<K, V> elements.putAll( getMultipleFromAuxiliaryCaches( remainingKeys, localOnly ) ); } } - catch ( Exception e ) + catch ( IOException e ) { log.error( "Problem encountered getting elements.", e ); } @@ -691,7 +690,7 @@ public class CompositeCache<K, V> // if we didn't find all the elements, increment the miss count by the number of elements not found if ( elements.size() != keys.size() ) { - missCountNotFound += keys.size() - elements.size(); + missCountNotFound.addAndGet(keys.size() - elements.size()); if ( log.isDebugEnabled() ) { @@ -730,8 +729,7 @@ public class CompositeCache<K, V> log.debug( cacheAttr.getCacheName() + " - Memory cache hit, but element expired" ); } - missCountExpired++; - + missCountExpired.incrementAndGet(); remove( element.getKey() ); elementsFromMemory.remove( element.getKey() ); } @@ -743,7 +741,7 @@ public class CompositeCache<K, V> } // Update counters - hitCountRam++; + hitCountRam.incrementAndGet(); } } } @@ -764,10 +762,8 @@ public class CompositeCache<K, V> Map<K, ICacheElement<K, V>> elements = new HashMap<K, ICacheElement<K, V>>(); Set<K> remainingKeys = new HashSet<K>( keys ); - for ( int i = 0; i < auxCaches.length; i++ ) + for ( AuxiliaryCache<K, V> aux : auxCaches ) { - AuxiliaryCache<K, V> aux = auxCaches[i]; - if ( aux != null ) { Map<K, ICacheElement<K, V>> elementsFromAuxiliary = @@ -798,7 +794,7 @@ public class CompositeCache<K, V> log.debug( "Got CacheElements: " + elementsFromAuxiliary ); } - processRetrievedElements( i, elementsFromAuxiliary ); + processRetrievedElements( aux, elementsFromAuxiliary ); elements.putAll( elementsFromAuxiliary ); @@ -952,7 +948,7 @@ public class CompositeCache<K, V> log.debug( "Got CacheElements: " + elementsFromAuxiliary ); } - processRetrievedElements( i, elementsFromAuxiliary ); + processRetrievedElements( aux, elementsFromAuxiliary ); elements.putAll( elementsFromAuxiliary ); } @@ -965,11 +961,11 @@ public class CompositeCache<K, V> /** * Remove expired elements retrieved from an auxiliary. Update memory with good items. * <p> - * @param i - the aux index + * @param aux the auxiliary cache instance * @param elementsFromAuxiliary * @throws IOException */ - private void processRetrievedElements( int i, Map<K, ICacheElement<K, V>> elementsFromAuxiliary ) + private void processRetrievedElements( AuxiliaryCache<K, V> aux, Map<K, ICacheElement<K, V>> elementsFromAuxiliary ) throws IOException { Iterator<ICacheElement<K, V>> elementFromAuxiliaryIterator = new HashMap<K, ICacheElement<K, V>>( elementsFromAuxiliary ).values().iterator(); @@ -985,10 +981,10 @@ public class CompositeCache<K, V> { if ( log.isDebugEnabled() ) { - log.debug( cacheAttr.getCacheName() + " - Aux cache[" + i + "] hit, but element expired." ); + log.debug( cacheAttr.getCacheName() + " - Aux cache[" + aux.getCacheName() + "] hit, but element expired." ); } - missCountExpired++; + missCountExpired.incrementAndGet(); // This will tell the remote caches to remove the item // based on the element's expiration policy. The elements attributes @@ -1001,11 +997,11 @@ public class CompositeCache<K, V> { if ( log.isDebugEnabled() ) { - log.debug( cacheAttr.getCacheName() + " - Aux cache[" + i + "] hit" ); + log.debug( cacheAttr.getCacheName() + " - Aux cache[" + aux.getCacheName() + "] hit" ); } // Update counters - hitCountAux++; + hitCountAux.incrementAndGet(); copyAuxiliaryRetrievedItemToMemory( element ); } } @@ -1077,9 +1073,8 @@ public class CompositeCache<K, V> HashSet<K> allKeys = new HashSet<K>(); allKeys.addAll( memCache.getKeySet() ); - for ( int i = 0; i < auxCaches.length; i++ ) + for ( AuxiliaryCache<K, V> aux : auxCaches ) { - AuxiliaryCache<K, V> aux = auxCaches[i]; if ( aux != null ) { if(!localOnly || aux.getCacheType() == CacheType.DISK_CACHE) @@ -1139,60 +1134,61 @@ public class CompositeCache<K, V> * @param localOnly * @return true if the item was in the cache, else false */ - protected synchronized boolean remove( K key, boolean localOnly ) + protected boolean remove( K key, boolean localOnly ) { - // not thread safe, but just for debugging and testing. - removeCount++; + removeCount.incrementAndGet(); boolean removed = false; - try - { - removed = memCache.remove( key ); - } - catch ( IOException e ) - { - log.error( e ); - } - - // Removes from all auxiliary caches. - for ( int i = 0; i < auxCaches.length; i++ ) + synchronized (this) { - ICache<K, V> aux = auxCaches[i]; - - if ( aux == null ) + try { - continue; + removed = memCache.remove( key ); } - - CacheType cacheType = aux.getCacheType(); - - // for now let laterals call remote remove but not vice versa - - if ( localOnly && ( cacheType == CacheType.REMOTE_CACHE || cacheType == CacheType.LATERAL_CACHE ) ) + catch ( IOException e ) { - continue; + log.error( e ); } - try + + // Removes from all auxiliary caches. + for ( ICache<K, V> aux : auxCaches ) { - if ( log.isDebugEnabled() ) + if ( aux == null ) { - log.debug( "Removing " + key + " from cacheType" + cacheType ); + continue; } - boolean b = aux.remove( key ); + CacheType cacheType = aux.getCacheType(); + + // for now let laterals call remote remove but not vice versa - // Don't take the remote removal into account. - if ( !removed && cacheType != CacheType.REMOTE_CACHE ) + if ( localOnly && ( cacheType == CacheType.REMOTE_CACHE || cacheType == CacheType.LATERAL_CACHE ) ) { - removed = b; + continue; + } + try + { + if ( log.isDebugEnabled() ) + { + log.debug( "Removing " + key + " from cacheType" + cacheType ); + } + + boolean b = aux.remove( key ); + + // Don't take the remote removal into account. + if ( !removed && cacheType != CacheType.REMOTE_CACHE ) + { + removed = b; + } + } + catch ( IOException ex ) + { + log.error( "Failure removing from aux", ex ); } - } - catch ( IOException ex ) - { - log.error( "Failure removing from aux", ex ); } } + return removed; } @@ -1227,42 +1223,43 @@ public class CompositeCache<K, V> * looping. * @throws IOException */ - protected synchronized void removeAll( boolean localOnly ) + protected void removeAll( boolean localOnly ) throws IOException { - try + synchronized (this) { - memCache.removeAll(); + try + { + memCache.removeAll(); - if ( log.isDebugEnabled() ) + if ( log.isDebugEnabled() ) + { + log.debug( "Removed All keys from the memory cache." ); + } + } + catch ( IOException ex ) { - log.debug( "Removed All keys from the memory cache." ); + log.error( "Trouble updating memory cache.", ex ); } - } - catch ( IOException ex ) - { - log.error( "Trouble updating memory cache.", ex ); - } - - // Removes from all auxiliary disk caches. - for ( int i = 0; i < auxCaches.length; i++ ) - { - ICache<K, V> aux = auxCaches[i]; - if ( aux != null && ( aux.getCacheType() == CacheType.DISK_CACHE || !localOnly ) ) + // Removes from all auxiliary disk caches. + for ( ICache<K, V> aux : auxCaches ) { - try + if ( aux != null && ( aux.getCacheType() == CacheType.DISK_CACHE || !localOnly ) ) { - if ( log.isDebugEnabled() ) + try { - log.debug( "Removing All keys from cacheType" + aux.getCacheType() ); - } + if ( log.isDebugEnabled() ) + { + log.debug( "Removing All keys from cacheType" + aux.getCacheType() ); + } - aux.removeAll(); - } - catch ( IOException ex ) - { - log.error( "Failure removing all from aux", ex ); + aux.removeAll(); + } + catch ( IOException ex ) + { + log.error( "Failure removing all from aux", ex ); + } } } } @@ -1284,7 +1281,7 @@ public class CompositeCache<K, V> * <p> * @param fromRemote */ - public synchronized void dispose( boolean fromRemote ) + public void dispose( boolean fromRemote ) { if ( log.isInfoEnabled() ) { @@ -1292,88 +1289,85 @@ public class CompositeCache<K, V> } // If already disposed, return immediately - if ( !alive ) + if ( alive.compareAndSet(true, false) == false ) { return; } - alive = false; - // Now, shut down the event queue - if (elementEventQ != null) - { - elementEventQ.dispose(); - elementEventQ = null; - } - - // Dispose of each auxiliary cache, Remote auxiliaries will be - // skipped if 'fromRemote' is true. - for ( int i = 0; i < auxCaches.length; i++ ) + synchronized (this) { - try + // Now, shut down the event queue + if (elementEventQ != null) { - ICache<K, V> aux = auxCaches[i]; - - // Skip this auxiliary if: - // - The auxiliary is null - // - The auxiliary is not alive - // - The auxiliary is remote and the invocation was remote + elementEventQ.dispose(); + elementEventQ = null; + } - if ( aux == null || aux.getStatus() != CacheStatus.ALIVE - || ( fromRemote && aux.getCacheType() == CacheType.REMOTE_CACHE ) ) + // Dispose of each auxiliary cache, Remote auxiliaries will be + // skipped if 'fromRemote' is true. + for ( ICache<K, V> aux : auxCaches ) + { + try { + // Skip this auxiliary if: + // - The auxiliary is null + // - The auxiliary is not alive + // - The auxiliary is remote and the invocation was remote + if ( aux == null || aux.getStatus() != CacheStatus.ALIVE + || ( fromRemote && aux.getCacheType() == CacheType.REMOTE_CACHE ) ) + { + if ( log.isInfoEnabled() ) + { + log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] SKIPPING auxiliary [" + aux.getCacheName() + "] fromRemote [" + + fromRemote + "]" ); + } + continue; + } + if ( log.isInfoEnabled() ) { - log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] SKIPPING auxiliary [" + aux.getCacheName() + "] fromRemote [" - + fromRemote + "]" ); + log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] auxiliary [" + aux.getCacheName() + "]" ); } - continue; - } - if ( log.isInfoEnabled() ) - { - log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] auxiliary [" + aux.getCacheName() + "]" ); - } + // IT USED TO BE THE CASE THAT (If the auxiliary is not a lateral, or the cache + // attributes + // have 'getUseLateral' set, all the elements currently in + // memory are written to the lateral before disposing) + // I changed this. It was excessive. Only the disk cache needs the items, since only + // the disk cache is in a situation to not get items on a put. + if ( aux.getCacheType() == CacheType.DISK_CACHE ) + { + int numToFree = memCache.getSize(); + memCache.freeElements( numToFree ); - // IT USED TO BE THE CASE THAT (If the auxiliary is not a lateral, or the cache - // attributes - // have 'getUseLateral' set, all the elements currently in - // memory are written to the lateral before disposing) - // I changed this. It was excessive. Only the disk cache needs the items, since only - // the disk cache - // is in a situation to not get items on a put. + if ( log.isInfoEnabled() ) + { + log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] put " + numToFree + " into auxiliary " + aux.getCacheName() ); + } + } - if ( aux.getCacheType() == CacheType.DISK_CACHE ) + // Dispose of the auxiliary + aux.dispose(); + } + catch ( IOException ex ) { - int numToFree = memCache.getSize(); - memCache.freeElements( numToFree ); - - if ( log.isInfoEnabled() ) - { - log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] put " + numToFree + " into auxiliary " + aux.getCacheName() ); - } + log.error( "Failure disposing of aux.", ex ); } + } - // Dispose of the auxiliary - aux.dispose(); + if ( log.isInfoEnabled() ) + { + log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] disposing of memory cache." ); + } + try + { + memCache.dispose(); } catch ( IOException ex ) { - log.error( "Failure disposing of aux.", ex ); + log.error( "Failure disposing of memCache", ex ); } } - - if ( log.isInfoEnabled() ) - { - log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] disposing of memory cache." ); - } - try - { - memCache.dispose(); - } - catch ( IOException ex ) - { - log.error( "Failure disposing of memCache", ex ); - } } /** @@ -1383,20 +1377,17 @@ public class CompositeCache<K, V> */ public void save() { - synchronized ( this ) + if ( alive.compareAndSet(true, false) == false ) { - if ( !alive ) - { - return; - } - alive = false; + return; + } - for ( int i = 0; i < auxCaches.length; i++ ) + synchronized ( this ) + { + for ( ICache<K, V> aux : auxCaches ) { try { - ICache<K, V> aux = auxCaches[i]; - if ( aux.getStatus() == CacheStatus.ALIVE ) { for (K key : memCache.getKeySet()) @@ -1451,9 +1442,9 @@ public class CompositeCache<K, V> * @return The status value */ @Override - public synchronized CacheStatus getStatus() + public CacheStatus getStatus() { - return alive ? CacheStatus.ALIVE : CacheStatus.DISPOSED; + return alive.get() ? CacheStatus.ALIVE : CacheStatus.DISPOSED; } /** @@ -1749,7 +1740,7 @@ public class CompositeCache<K, V> */ public int getHitCountRam() { - return hitCountRam; + return hitCountRam.get(); } /** @@ -1758,7 +1749,7 @@ public class CompositeCache<K, V> */ public int getHitCountAux() { - return hitCountAux; + return hitCountAux.get(); } /** @@ -1767,7 +1758,7 @@ public class CompositeCache<K, V> */ public int getMissCountNotFound() { - return missCountNotFound; + return missCountNotFound.get(); } /** @@ -1776,7 +1767,15 @@ public class CompositeCache<K, V> */ public int getMissCountExpired() { - return missCountExpired; + return missCountExpired.get(); + } + + /** + * @return Returns the updateCount. + */ + public int getUpdateCount() + { + return updateCount.get(); } /** @@ -1804,38 +1803,6 @@ public class CompositeCache<K, V> } /** - * @param updateCount The updateCount to set. - */ - public synchronized void setUpdateCount( int updateCount ) - { - this.updateCount = updateCount; - } - - /** - * @return Returns the updateCount. - */ - public synchronized int getUpdateCount() - { - return updateCount; - } - - /** - * @param removeCount The removeCount to set. - */ - public synchronized void setRemoveCount( int removeCount ) - { - this.removeCount = removeCount; - } - - /** - * @return Returns the removeCount. - */ - public synchronized int getRemoveCount() - { - return removeCount; - } - - /** * This returns the stats. * <p> * @return getStats()