-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create CacheExpiryCheck for automated removal of expired cached data
- Loading branch information
Showing
2 changed files
with
164 additions
and
0 deletions.
There are no files selected for viewing
62 changes: 62 additions & 0 deletions
62
src/main/java/gov/nist/oar/distrib/cachemgr/CacheExpiryCheck.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
102
src/test/java/gov/nist/oar/distrib/cachemgr/CacheExpiryCheckTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
|
||
} |