From 3e6cc7601c035423c536f410af8a8bbb649d118f Mon Sep 17 00:00:00 2001 From: Jono Morris Date: Sat, 26 Jul 2025 01:39:00 +1200 Subject: [PATCH] JCS-242 fix lateral cache in error state --- .../lateral/LateralCacheMonitor.java | 13 ++++ .../socket/tcp/TestTCPLateralUnitTest.java | 73 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/commons-jcs3-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheMonitor.java b/commons-jcs3-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheMonitor.java index fd207c946..60effc8a1 100644 --- a/commons-jcs3-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheMonitor.java +++ b/commons-jcs3-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheMonitor.java @@ -72,6 +72,19 @@ public void addCache(final LateralCacheNoWait cache) { this.caches.put(cache.getCacheName(), (LateralCacheNoWait)cache); + // Fix a cache where an exception occurred before it was added to this monitor. + // For instance, where a cache failed to connect to lateral TCP server. + if (cache.getStatus() == CacheStatus.ERROR) { + if (getState() == Thread.State.NEW) + { + // no need to signal trigger if monitor hasn't started + allright.compareAndSet(true, false); + } + else { + notifyError(); + } + } + // if not yet started, go ahead if (getState() == Thread.State.NEW) { diff --git a/commons-jcs3-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java b/commons-jcs3-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java index 2790bd23c..ecd452840 100644 --- a/commons-jcs3-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java +++ b/commons-jcs3-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java @@ -27,10 +27,13 @@ import java.util.Set; import org.apache.commons.jcs3.JCS; +import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheMonitor; import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes; +import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheNoWait; import org.apache.commons.jcs3.auxiliary.lateral.LateralCommand; import org.apache.commons.jcs3.auxiliary.lateral.LateralElementDescriptor; import org.apache.commons.jcs3.engine.CacheElement; +import org.apache.commons.jcs3.engine.CacheStatus; import org.apache.commons.jcs3.engine.behavior.ICacheElement; import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager; import org.apache.commons.jcs3.engine.behavior.IElementSerializer; @@ -313,6 +316,55 @@ void testSameKeyObjectDifferentValueObject() assertEquals( element2.getVal(), cacheElement.getVal(), "Didn't get the correct object: " + cacheElement ); } + /** + * Test that the cache has an error status after failing to connect to a TCP server. + */ + @Test + void testCacheErrorStatusTcpConnectionFail() + { + final TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes(); + lattr.setCacheName("test"); + lattr.setTransmissionType(LateralCacheAttributes.Type.TCP); + lattr.setTcpServer("localhost:1109"); + LateralTCPCacheFactory factory = new LateralTCPCacheFactory(); + factory.initialize(); + + LateralCacheNoWait lateralNoWait = factory.createCacheNoWait(lattr, null, new StandardSerializer()); + + assertEquals(CacheStatus.ERROR, lateralNoWait.getStatus()); + } + + /** + * Test that the cache monitor can fix a cache that is in error state after failing to connect to a TCP server. + * + * @throws Exception + */ + @Test + void testCacheRecoveryUsingMonitor() throws Exception + { + final TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes(); + lattr.setCacheName("test"); + lattr.setTransmissionType(LateralCacheAttributes.Type.TCP); + lattr.setTcpServer("localhost:1110"); + LateralTCPCacheFactory factory = new LateralTCPCacheFactory(); + factory.initialize(); + + // reduce the monitor idle period between 'fix' attempts for testing purposes + MyCacheMonitor.setIdle(500L); + LateralCacheNoWait lateralNoWait = factory.createCacheNoWait(lattr, null, new StandardSerializer()); + + // start a TCP server for the cache to connect to + createCache(1110); + // adding the cache to the monitor releases the monitor 'fix' thread + factory.monitorCache(lateralNoWait); + + Thread.sleep(2000L); + + // verify that the monitor has fixed the cache + assertEquals(CacheStatus.ALIVE, lateralNoWait.getStatus()); + } + + /** * @throws Exception */ @@ -338,4 +390,25 @@ void testSimpleSend() { simpleSend(new StandardSerializer(), 8111); } + + // used to reduce the monitor idle period between 'fix' attempts for testing purposes + private static class MyCacheMonitor extends AbstractAuxiliaryCacheMonitor { + public static void setIdle(long idlePeriod) { + AbstractAuxiliaryCacheMonitor.idlePeriod = idlePeriod; + } + + public MyCacheMonitor() { + super("test"); + } + + @Override + protected void dispose() { + // nothing to dispose + } + + @Override + protected void doWork() { + // nothing to do + } + } }