The cache is divided into sets where each set contains "N" cache entries. In order to provide concurrency access in read
and write from multiple threads the set structure is called bag.
Each bag contains a double linked list of Cache
entry and a read write lock object.
The read write object control the concurrent access.
The CacheEntry
contains the key, value, last access time, creation time and CacheStatus
.
CacheStatus define if the entry will be deleted on the next eviction or not.
Graphically a Cache bag is represented as below:
All the CacheBag
are inserted in the cacheBags
list. This list is immutable and allocated during the cache initialization.
With also the CacheBag
representation the diagrams become:
The concurrency is managed only at level of each independent CacheBag
object.
This is possible because the cacheBags
List is immutable and defined at the nWay cache initialization.
The usage of a LinkedList
allow to use a write lock only when the CacheEntry
in the Block
is added or deleted. Any
other operation require the read lock only.
The usage of a concurrent list has been avoided because the class is synchronizing every access without making
distinction between read and write.
Read locks are used when:
- An immutable copy of the
Block
is created in order to give to theCacheEviction
implementation - A key is searched inside the current Block
Write locks are used when:
- The entries in the block are deleted as result of the eviction
- A new entry is created
No lock are necessary when:
- Access time is updated (the variable is declared as volatile)
- The entry value is updated (the variable is declared as volatile)
- Any read to the entry object
- Getting access to the CacheBag object
The main operation of a cache is retrieving a value. For retrieving a value you must have a key.
- It is used the key.hash function for having an integer value. This number is used to determine what is the key
position in the
cacheBags
list via a mod operation - The right cacheBag is retrieved
- A sequential search is applied to the block using the
key.equals()
function for find the rightCacheEntry
- If a cache entry has been found then the value is returned to the user
- An entry is not present then the
CacheLoader
is invoked CacheLoader
returns the value from some slow access memory (database, filesystem, network…)- A new Entry is created with the current key and the value loaded
- The Entry is added in the block. (
LinkedList
always add at the end of the structure) - The value is returned
In case of the Block
size is equals or bigger than “N” an eviction is called at the beginning of step 7.
Eviction is going to:
- Create an immutable list from the block. This operation is done via the guava immutable list class that is “smart” enough to avoid a physical copy if not necessary
Eviction
is called- Every
CacheEntry
that has status toDELETED
is going to be removed from the block - If the size of the block is major that the double of “N” an
OutOfMemoryException
is generated - A new Entry is created with the current key and the value loaded