Create a configurable 2-level cache.
##Requirements
- Cache should implement the following interface:
public interface Cache<K, T> {
void put(K key, T value);
T get(K key);
}
- Cache should have 2 levels: L1 - memory, L2 - file system.
- Cache should support different eviction policies.
- Cache size and eviction policy should be configurable.
- Code should be covered by unit tests using JUnit/TestNG + any mock library Mockito, EasyMock, etc.
- Project should be build via Maven, Gradle, Ant or similar tool.
- Cache should be thread safe.
mvn clean test
Note: There are some tests slow tests for thread safety. They are all tagged with:
@Category(SlowTest.class)
For your convenience, I modified the number of iterations to 100 (instead of 1000). Anyway, to run only the fast tests use
mvn clean test -DexcludedGroups="ro.j.test.SlowTest"
git@github.com:ojusti/cache.git
The cache is MultiLevelCache
. If correctly set up, it overflows to another cache (who could be another instance of MultiLevelCache...).
A policy is not a simple comparator, it implements its own data structures (a double linked list for LRU, FIFO and LFU). Arguably, they are a little more complex to implement, but the design is more open.
Map insertions and policy's data structure updates in the Cache's put method are protected by a synchronized block. I think it is acceptable, given that this is a fairly simple solution which respects the requirements (thread-safety).
I used ConcurrentHashMap as the cache backend as this allows letting the get method not synchronized.
Disk store
is an implementation of Cache
. It delegates almost everything to its collaborators: it use a Function
to calculate a filename from a key, a Marshaller
to serialize and a Folder
. I provided basic implementations for all of them.
'Complicated' objects are set up using builders.
See examples in CacheBuilderTest
.