Skip to content

Commit

Permalink
create CacheExpiryCheck for automated removal of expired cached data
Browse files Browse the repository at this point in the history
  • Loading branch information
elmiomar committed Jan 31, 2024
1 parent 6f984f1 commit 9a4f79b
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
62 changes: 62 additions & 0 deletions src/main/java/gov/nist/oar/distrib/cachemgr/CacheExpiryCheck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package gov.nist.oar.distrib.cachemgr;

import gov.nist.oar.distrib.StorageVolumeException;

/**
* Implements a cache object check to identify and remove objects that have been in the cache
* longer than a specified duration, specifically two weeks. This check helps in
* managing cache integrity by ensuring that stale or outdated data are removed
* from the cache.
*/
public class CacheExpiryCheck implements CacheObjectCheck {

private static final long TWO_WEEKS_MILLIS = 14 * 24 * 60 * 60 * 1000; // 14 days in milliseconds
private StorageInventoryDB inventoryDB;

public CacheExpiryCheck(StorageInventoryDB inventoryDB) {
this.inventoryDB = inventoryDB;
}

/**
* Checks whether a cache object has expired based on its last modified time and removes it if expired.
* An object is considered expired if it has been in the cache for more than two weeks.
*
* @param co The CacheObject to be checked for expiry.
* @throws IntegrityException if the cache object's last modified time is unknown.
* @throws StorageVolumeException if there is an issue removing the expired object from the cache volume.
*/
@Override
public void check(CacheObject co) throws IntegrityException, StorageVolumeException {
long currentTime = System.currentTimeMillis();
long objectLastModifiedTime = co.getLastModified();

// Throw an exception if the last modified time is unknown
if (objectLastModifiedTime == -1) {
throw new IntegrityException("Last modified time of cache object is unknown: " + co.name);
}

// If the cache object is expired, remove it from the cache
if ((currentTime - objectLastModifiedTime) > TWO_WEEKS_MILLIS) {
removeExpiredObject(co);
}
}

/**
* Removes an expired object from the cache.
*
* @param co The expired CacheObject to be removed.
* @throws StorageVolumeException if there is an issue removing the object from the cache volume.
*/
protected void removeExpiredObject(CacheObject co) throws StorageVolumeException {
CacheVolume volume = co.volume;
if (volume != null && volume.remove(co.name)) {
try {
inventoryDB.removeObject(co.volname, co.name);
} catch (InventoryException e) {
throw new StorageVolumeException("Failed to remove object from inventory database: " + co.name, e);
}
} else {
throw new StorageVolumeException("Failed to remove expired object from cache volume: " + co.name);
}
}
}
102 changes: 102 additions & 0 deletions src/test/java/gov/nist/oar/distrib/cachemgr/CacheExpiryCheckTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package gov.nist.oar.distrib.cachemgr;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class CacheExpiryCheckTest {

@Mock
private StorageInventoryDB mockInventoryDB;
@Mock
private CacheVolume mockVolume;
@Mock
private CacheObject cacheObject;
private CacheExpiryCheck expiryCheck;

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
expiryCheck = new CacheExpiryCheck(mockInventoryDB);
}

/**
* Test to verify that {@link CacheExpiryCheck} correctly identifies and processes an expired cache object.
* An object is considered expired if its last modified time is more than two weeks ago.
* This test checks that the expired object is appropriately removed from both the cache volume and the inventory
* database.
*
* @throws Exception to handle any exceptions thrown during the test execution
*/
@Test
public void testExpiredObject() throws Exception {
// Setup mock
cacheObject.name = "testObject";
cacheObject.volname = "testVolume";
cacheObject.volume = mockVolume;
long lastModified = System.currentTimeMillis() - (15 * 24 * 60 * 60 * 1000); // 15 days in milliseconds
when(cacheObject.getLastModified()).thenReturn(lastModified);


when(mockVolume.remove("testObject")).thenReturn(true);

// Perform the check
expiryCheck.check(cacheObject);

// Verify the interactions
verify(mockVolume).remove("testObject");
verify(mockInventoryDB).removeObject(anyString(), anyString());
}


/**
* Test to ensure that {@link CacheExpiryCheck} does not flag a cache object as expired if it has been
* modified within the last two weeks. This test checks that no removal action is taken for a non-expired object.
*
* @throws Exception to handle any exceptions thrown during the test execution
*/
@Test
public void testNonExpiredObject() throws Exception {
// Setup mock
cacheObject.name = "nonExpiredObject";
cacheObject.volname = "testVolume";
cacheObject.volume = mockVolume;

long lastModified = System.currentTimeMillis() - (5 * 24 * 60 * 60 * 1000); // 5 days in milliseconds
when(cacheObject.getLastModified()).thenReturn(lastModified);

// Perform the check
expiryCheck.check(cacheObject);

// Verify that the remove method was not called as the object is not expired
verify(mockVolume, never()).remove("nonExpiredObject");
verify(mockInventoryDB, never()).removeObject("testVolume", "nonExpiredObject");
}

/**
* Test to verify that {@link CacheExpiryCheck} throws an {@link IntegrityException} when the last modified time
* of a cache object is unknown (indicated by a value of -1). This situation should be flagged as an error
* as the expiry status of the object cannot be determined.
*
* @throws Exception to handle any exceptions thrown during the test execution
*/
@Test(expected = IntegrityException.class)
public void testUnknownLastModifiedTime() throws Exception {
// Setup mock
cacheObject.name = "unknownLastModifiedObject";
cacheObject.volname = "testVolume";
cacheObject.volume = mockVolume;
long lastModified = -1; // Unknown last modified time
when(cacheObject.getLastModified()).thenReturn(lastModified);

// Perform the check, expecting an IntegrityException
expiryCheck.check(cacheObject);
}

}

0 comments on commit 9a4f79b

Please sign in to comment.