Change to explicitly 'expiring' the oldest session.

This commit is contained in:
dotasek 2024-06-18 17:30:12 -04:00
parent 3a7507c832
commit 15e9ba30f0
2 changed files with 60 additions and 26 deletions

View File

@ -7,25 +7,31 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
public class MaxSizeSessionCacheDecorator implements SessionCache { public class ExplicitExpirySessionCacheDecorator implements SessionCache {
public final int maxSize;
public final SessionCache sessionCache; public final SessionCache sessionCache;
private final List<String> sessionIds; private final List<String> sessionIds;
public MaxSizeSessionCacheDecorator(SessionCache sessionCache, int maxSize) { public ExplicitExpirySessionCacheDecorator(SessionCache sessionCache) {
this.sessionCache = sessionCache; this.sessionCache = sessionCache;
this.maxSize = maxSize;
this.sessionIds = new ArrayList<>(sessionCache.getSessionIds()); this.sessionIds = new ArrayList<>(sessionCache.getSessionIds());
if (this.sessionIds.size() > maxSize) {
throw new IllegalArgumentException("Session cache size exceeds the maximum size");
} }
public boolean expireOldestSession() {
if (sessionIds.isEmpty()) {
return false;
}
String oldestSessionId = sessionIds.get(0);
sessionIds.remove(oldestSessionId);
sessionCache.removeSession(oldestSessionId);
return true;
} }
@Override @Override
public String cacheSession(ValidationEngine validationEngine) { public String cacheSession(ValidationEngine validationEngine) {
checkSizeAndMaintainMax(null); maintainSessionIds(null);
String key = sessionCache.cacheSession(validationEngine); String key = sessionCache.cacheSession(validationEngine);
sessionIds.add(key); sessionIds.add(key);
return key; return key;
@ -33,12 +39,14 @@ public class MaxSizeSessionCacheDecorator implements SessionCache {
@Override @Override
public String cacheSession(Supplier<ValidationEngine> validationEngineSupplier) { public String cacheSession(Supplier<ValidationEngine> validationEngineSupplier) {
checkSizeAndMaintainMax(null); maintainSessionIds(null);
ValidationEngine validationEngine = validationEngineSupplier.get(); ValidationEngine validationEngine = validationEngineSupplier.get();
return sessionCache.cacheSession(validationEngine); String key = sessionCache.cacheSession(validationEngine);
sessionIds.add(key);
return key;
} }
private void checkSizeAndMaintainMax(String keyToAdd) { private void maintainSessionIds(String keyToAdd) {
if (keyToAdd != null || sessionCache.sessionExists(keyToAdd)) { if (keyToAdd != null || sessionCache.sessionExists(keyToAdd)) {
return; return;
} }
@ -46,16 +54,11 @@ public class MaxSizeSessionCacheDecorator implements SessionCache {
//Sync our tracked keys, in case the underlying cache has changed //Sync our tracked keys, in case the underlying cache has changed
this.sessionIds.removeIf(key -> !sessionIds.contains(key)); this.sessionIds.removeIf(key -> !sessionIds.contains(key));
if (this.sessionIds.size() >= maxSize) {
final String key = this.sessionIds.remove(0);
sessionCache.removeSession(key);
}
} }
@Override @Override
public String cacheSession(String sessionId, ValidationEngine validationEngine) { public String cacheSession(String sessionId, ValidationEngine validationEngine) {
checkSizeAndMaintainMax(sessionId); maintainSessionIds(sessionId);
cacheSession(sessionId, validationEngine);
return sessionCache.cacheSession( return sessionCache.cacheSession(
sessionId, validationEngine); sessionId, validationEngine);
} }

View File

@ -32,23 +32,54 @@ public class MaxSizeSessionCacheDecoratorTest {
} }
@Test @Test
public void trivialCase() { public void trivialExpiryTest() {
MaxSizeSessionCacheDecorator maxSizeSessionCacheDecorator = new MaxSizeSessionCacheDecorator(new PassiveExpiringSessionCache(), 4); ExplicitExpirySessionCacheDecorator sessionCache = new ExplicitExpirySessionCacheDecorator(new PassiveExpiringSessionCache());
LinkedHashMap<String, ValidationEngine> initialEngines = addMockedEngines(maxSizeSessionCacheDecorator, 3); LinkedHashMap<String, ValidationEngine> initialEngines = addMockedEngines(sessionCache, 3);
Assertions.assertEquals(3, maxSizeSessionCacheDecorator.getSessionIds().size()); Assertions.assertEquals(3, sessionCache.getSessionIds().size());
LinkedHashMap<String, ValidationEngine> newEngines = addMockedEngines(maxSizeSessionCacheDecorator, 2); Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(initialEngines, 0)));
Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(initialEngines, 1)));
Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(initialEngines, 2)));
Assertions.assertTrue(sessionCache.expireOldestSession());
Assertions.assertEquals(4, maxSizeSessionCacheDecorator.getSessionIds().size()); Assertions.assertEquals(2, sessionCache.getSessionIds().size());
Assertions.assertTrue(maxSizeSessionCacheDecorator.getSessionIds().contains(getKeyByIndex(initialEngines, 1))); Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(initialEngines, 1)));
Assertions.assertTrue(maxSizeSessionCacheDecorator.getSessionIds().contains(getKeyByIndex(initialEngines, 2))); Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(initialEngines, 2)));
Assertions.assertTrue(maxSizeSessionCacheDecorator.getSessionIds().contains(getKeyByIndex(newEngines, 0)));
Assertions.assertTrue(maxSizeSessionCacheDecorator.getSessionIds().contains(getKeyByIndex(newEngines, 1)));
LinkedHashMap<String, ValidationEngine> newEngines = addMockedEngines(sessionCache, 2);
Assertions.assertEquals(4, sessionCache.getSessionIds().size());
Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(initialEngines, 1)));
Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(initialEngines, 2)));
Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(newEngines, 0)));
Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(newEngines, 1)));
Assertions.assertTrue(sessionCache.expireOldestSession());
Assertions.assertEquals(3, sessionCache.getSessionIds().size());
Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(initialEngines, 2)));
Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(newEngines, 0)));
Assertions.assertTrue(sessionCache.getSessionIds().contains(getKeyByIndex(newEngines, 1)));
Assertions.assertTrue(sessionCache.expireOldestSession());
Assertions.assertTrue(sessionCache.expireOldestSession());
Assertions.assertTrue(sessionCache.expireOldestSession());
Assertions.assertFalse(sessionCache.expireOldestSession());
}
@Test
public void producerAddTest() {
ExplicitExpirySessionCacheDecorator maxSizeSessionCacheDecorator = new ExplicitExpirySessionCacheDecorator(new PassiveExpiringSessionCache());
ValidationEngine producedEngine = mock(ValidationEngine.class);
String sessionId = maxSizeSessionCacheDecorator.cacheSession(() -> {
return producedEngine;
});
Assertions.assertEquals(1, maxSizeSessionCacheDecorator.getSessionIds().size());
Assertions.assertSame(producedEngine, maxSizeSessionCacheDecorator.fetchSessionValidatorEngine(sessionId));
} }
private String getKeyByIndex(LinkedHashMap<String, ValidationEngine> engineMap, int index) { private String getKeyByIndex(LinkedHashMap<String, ValidationEngine> engineMap, int index) {