Skip to content

Commit

Permalink
Add Cache.getAllPresent() (#609)
Browse files Browse the repository at this point in the history
* Add Cache.getAllPresent()

Signed-off-by: BoD <BoD@JRAF.org>

* Add comment and avoid nesting indentation level

Signed-off-by: BoD <BoD@JRAF.org>

* Don't use buildMap

Signed-off-by: BoD <BoD@JRAF.org>

---------

Signed-off-by: BoD <BoD@JRAF.org>
  • Loading branch information
BoD authored Apr 5, 2024
1 parent b7aa329 commit 63928aa
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@ interface Cache<Key : Any, Value : Any> {

/**
* @return Map of the [Value] associated with each [Key] in [keys]. Returned map only contains entries already present in the cache.
* The default implementation provided here throws a [NotImplementedError] to maintain backward compatibility for existing implementations.
*/
fun getAllPresent(keys: List<*>): Map<Key, Value>

/**
* @return Map of the [Value] associated with each [Key] in the cache.
*/
fun getAllPresent(): Map<Key, Value> = throw NotImplementedError()

/**
* Associates [value] with [key].
* If the cache previously contained a value associated with [key], the old value is replaced by [value].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,28 @@ internal class LocalCache<K : Any, V : Any>(builder: CacheBuilder<K, V>) {
}*/
}

fun activeEntries(): Map<K, V> {
// read-volatile
if (count.value == 0) return emptyMap()
reentrantLock.lock()
return try {
val activeMap = mutableMapOf<K, V>()
val table = table.value
for (i in 0 until table.size) {
var e = table[i]
while (e != null) {
if (e.valueReference?.isActive == true) {
activeMap[e.key] = e.valueReference?.get()!!
}
e = e.next
}
}
activeMap.ifEmpty { emptyMap() }
} finally {
reentrantLock.unlock()
}
}

init {
threshold = initialCapacity * 3 / 4 // 0.75
if (!map.customWeigher && threshold.toLong() == maxSegmentWeight) {
Expand Down Expand Up @@ -1660,6 +1682,14 @@ internal class LocalCache<K : Any, V : Any>(builder: CacheBuilder<K, V>) {
return segmentFor(hash).remove(key, hash)
}

fun getAllPresent(): Map<K, V> {
return buildMap {
for (segment in segments) {
segment?.let { putAll(it.activeEntries()) }
}
}
}

// Serialization Support
internal class LocalManualCache<K : Any, V : Any> private constructor(private val localCache: LocalCache<K, V>) :
Cache<K, V> {
Expand All @@ -1683,7 +1713,11 @@ internal class LocalCache<K : Any, V : Any>(builder: CacheBuilder<K, V>) {
}

override fun getAllPresent(keys: List<*>): Map<K, V> {
TODO("Not yet implemented")
return localCache.getAllPresent().filterKeys { it in keys }
}

override fun getAllPresent(): Map<K, V> {
return localCache.getAllPresent()
}

override fun invalidateAll(keys: List<K>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ class StoreMultiCache<Id : Any, Key : StoreKey<Id>, Single : StoreData.Single<Id
return map
}

override fun getAllPresent(): Map<Key, Output> {
return accessor.getAllPresent().mapKeys { (key, _) ->
when (key) {
is StoreKey.Collection<Id> -> key.cast()
is StoreKey.Single<Id> -> key.cast()
else -> throw UnsupportedOperationException(invalidKeyErrorMessage(key))
}
} as Map<Key, Output>
}

override fun invalidateAll(keys: List<Key>) {
keys.forEach { key -> invalidate(key) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,33 @@ class StoreMultiCacheAccessor<Id : Any, Collection : StoreData.Collection<Id, Si
singlesCache.getIfPresent(key)
}

/**
* Retrieves all items from the cache.
*
* This operation is thread-safe.
*/
fun getAllPresent(): Map<StoreKey<Id>, Any> = synchronized(this) {
val result = mutableMapOf<StoreKey<Id>, Any>()
for (key in keys) {
when (key) {
is StoreKey.Single<Id> -> {
val single = singlesCache.getIfPresent(key)
if (single != null) {
result[key] = single
}
}

is StoreKey.Collection<Id> -> {
val collection = collectionsCache.getIfPresent(key)
if (collection != null) {
result[key] = collection
}
}
}
}
result
}

/**
* Stores a collection of items in the cache and updates the key set.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ class CacheTests {
assertEquals("value", cache.getOrPut("key") { "value" })
}

@Ignore // Not implemented yet
@Test
fun getAllPresent() {
cache.put("key1", "value1")
cache.put("key2", "value2")
assertEquals(mapOf("key1" to "value1", "key2" to "value2"), cache.getAllPresent(listOf("key1", "key2")))
assertEquals(mapOf("key1" to "value1", "key2" to "value2"), cache.getAllPresent())
}

@Ignore // Not implemented yet
Expand Down

0 comments on commit 63928aa

Please sign in to comment.