diff --git a/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/Cache.kt b/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/Cache.kt index b6ef9c86e..328ae1e22 100644 --- a/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/Cache.kt +++ b/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/Cache.kt @@ -18,9 +18,15 @@ interface Cache { /** * @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 + /** + * @return Map of the [Value] associated with each [Key] in the cache. + */ + fun getAllPresent(): Map = throw NotImplementedError() + /** * Associates [value] with [key]. * If the cache previously contained a value associated with [key], the old value is replaced by [value]. diff --git a/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/LocalCache.kt b/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/LocalCache.kt index f0ec6ff0d..e9814cae0 100644 --- a/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/LocalCache.kt +++ b/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/LocalCache.kt @@ -1379,6 +1379,28 @@ internal class LocalCache(builder: CacheBuilder) { }*/ } + fun activeEntries(): Map { + // read-volatile + if (count.value == 0) return emptyMap() + reentrantLock.lock() + return try { + val activeMap = mutableMapOf() + 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) { @@ -1660,6 +1682,14 @@ internal class LocalCache(builder: CacheBuilder) { return segmentFor(hash).remove(key, hash) } + fun getAllPresent(): Map { + return buildMap { + for (segment in segments) { + segment?.let { putAll(it.activeEntries()) } + } + } + } + // Serialization Support internal class LocalManualCache private constructor(private val localCache: LocalCache) : Cache { @@ -1683,7 +1713,11 @@ internal class LocalCache(builder: CacheBuilder) { } override fun getAllPresent(keys: List<*>): Map { - TODO("Not yet implemented") + return localCache.getAllPresent().filterKeys { it in keys } + } + + override fun getAllPresent(): Map { + return localCache.getAllPresent() } override fun invalidateAll(keys: List) { diff --git a/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/StoreMultiCache.kt b/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/StoreMultiCache.kt index 7003bc582..1237e7b21 100644 --- a/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/StoreMultiCache.kt +++ b/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/StoreMultiCache.kt @@ -88,6 +88,16 @@ class StoreMultiCache, Single : StoreData.Single { + return accessor.getAllPresent().mapKeys { (key, _) -> + when (key) { + is StoreKey.Collection -> key.cast() + is StoreKey.Single -> key.cast() + else -> throw UnsupportedOperationException(invalidKeyErrorMessage(key)) + } + } as Map + } + override fun invalidateAll(keys: List) { keys.forEach { key -> invalidate(key) } } diff --git a/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/StoreMultiCacheAccessor.kt b/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/StoreMultiCacheAccessor.kt index 04e990569..e4f61641b 100644 --- a/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/StoreMultiCacheAccessor.kt +++ b/cache/src/commonMain/kotlin/org/mobilenativefoundation/store/cache5/StoreMultiCacheAccessor.kt @@ -50,6 +50,33 @@ class StoreMultiCacheAccessor, Any> = synchronized(this) { + val result = mutableMapOf, Any>() + for (key in keys) { + when (key) { + is StoreKey.Single -> { + val single = singlesCache.getIfPresent(key) + if (single != null) { + result[key] = single + } + } + + is StoreKey.Collection -> { + 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. * diff --git a/cache/src/commonTest/kotlin/org/mobilenativefoundation/store/cache5/CacheTests.kt b/cache/src/commonTest/kotlin/org/mobilenativefoundation/store/cache5/CacheTests.kt index 2488c4eda..e5693c419 100644 --- a/cache/src/commonTest/kotlin/org/mobilenativefoundation/store/cache5/CacheTests.kt +++ b/cache/src/commonTest/kotlin/org/mobilenativefoundation/store/cache5/CacheTests.kt @@ -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