Skip to content

Commit 5458395

Browse files
author
Oleksandr Dzhychko
committed
fix(model-datastructure): cache entries acquired through get PrefetchCache.getAll
Cache entries when using `getAll` like they are cached when using get `get`. This guarantees that after accessing the values once no requests are required.
1 parent 1a362a4 commit 5458395

File tree

4 files changed

+105
-54
lines changed

4 files changed

+105
-54
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (c) 2024.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.model.lazy
18+
19+
import org.modelix.model.IKeyListener
20+
import org.modelix.model.IKeyValueStore
21+
22+
/**
23+
* Internal API.
24+
* Only public for tests.
25+
*/
26+
class AccessTrackingStore(val store: IKeyValueStore) : IKeyValueStore {
27+
val accessedEntries: MutableMap<String, String?> = LinkedHashMap()
28+
29+
override fun newBulkQuery(deserializingCache: IDeserializingKeyValueStore, config: BulkQueryConfiguration): IBulkQuery {
30+
return store.newBulkQuery(deserializingCache, config)
31+
}
32+
33+
override fun get(key: String): String? {
34+
val value = store.get(key)
35+
accessedEntries.put(key, value)
36+
return value
37+
}
38+
39+
override fun getIfCached(key: String): String? {
40+
val value = store.getIfCached(key)
41+
if (value != null) {
42+
accessedEntries[key] = value
43+
}
44+
return value
45+
}
46+
47+
override fun put(key: String, value: String?) {
48+
TODO("Not yet implemented")
49+
}
50+
51+
override fun getAll(keys: Iterable<String>): Map<String, String?> {
52+
val entries = store.getAll(keys)
53+
accessedEntries.putAll(entries)
54+
return entries
55+
}
56+
57+
override fun putAll(entries: Map<String, String?>) {
58+
TODO("Not yet implemented")
59+
}
60+
61+
override fun prefetch(key: String) {
62+
TODO("Not yet implemented")
63+
}
64+
65+
override fun listen(key: String, listener: IKeyListener) {
66+
TODO("Not yet implemented")
67+
}
68+
69+
override fun removeListener(key: String, listener: IKeyListener) {
70+
TODO("Not yet implemented")
71+
}
72+
73+
override fun getPendingSize(): Int {
74+
TODO("Not yet implemented")
75+
}
76+
}

model-datastructure/src/commonMain/kotlin/org/modelix/model/lazy/CLVersion.kt

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import kotlinx.datetime.Clock
1919
import kotlinx.datetime.Instant
2020
import kotlinx.datetime.TimeZone
2121
import kotlinx.datetime.toInstant
22-
import org.modelix.model.IKeyListener
2322
import org.modelix.model.IKeyValueStore
2423
import org.modelix.model.IVersion
2524
import org.modelix.model.LinearHistory
@@ -403,58 +402,6 @@ private fun trackAccessedEntries(store: IKeyValueStore, body: (IDeserializingKey
403402
return accessTrackingStore.accessedEntries
404403
}
405404

406-
private class AccessTrackingStore(val store: IKeyValueStore) : IKeyValueStore {
407-
val accessedEntries: MutableMap<String, String?> = LinkedHashMap()
408-
409-
override fun newBulkQuery(deserializingCache: IDeserializingKeyValueStore, config: BulkQueryConfiguration): IBulkQuery {
410-
return store.newBulkQuery(deserializingCache, config)
411-
}
412-
413-
override fun get(key: String): String? {
414-
val value = store.get(key)
415-
accessedEntries.put(key, value)
416-
return value
417-
}
418-
419-
override fun getIfCached(key: String): String? {
420-
val value = store.getIfCached(key)
421-
if (value != null) {
422-
accessedEntries[key] = value
423-
}
424-
return value
425-
}
426-
427-
override fun put(key: String, value: String?) {
428-
TODO("Not yet implemented")
429-
}
430-
431-
override fun getAll(keys: Iterable<String>): Map<String, String?> {
432-
val entries = store.getAll(keys)
433-
accessedEntries.putAll(entries)
434-
return entries
435-
}
436-
437-
override fun putAll(entries: Map<String, String?>) {
438-
TODO("Not yet implemented")
439-
}
440-
441-
override fun prefetch(key: String) {
442-
TODO("Not yet implemented")
443-
}
444-
445-
override fun listen(key: String, listener: IKeyListener) {
446-
TODO("Not yet implemented")
447-
}
448-
449-
override fun removeListener(key: String, listener: IKeyListener) {
450-
TODO("Not yet implemented")
451-
}
452-
453-
override fun getPendingSize(): Int {
454-
TODO("Not yet implemented")
455-
}
456-
}
457-
458405
fun CLVersion.runWrite(idGenerator: IIdGenerator, author: String?, body: (IWriteTransaction) -> Unit): CLVersion {
459406
val branch = OTBranch(TreePointer(getTree(), idGenerator), idGenerator, store)
460407
branch.computeWriteT(body)

model-datastructure/src/commonMain/kotlin/org/modelix/model/lazy/PrefetchCache.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ class PrefetchCache(private val store: IDeserializingKeyValueStore) : IDeseriali
5555
val missingHashes = hashes.filterNot { entries.containsKey(it) }
5656
val missingValues = store.getAll(missingHashes, deserializer).toList()
5757
val missingEntries = missingHashes.mapIndexed { index, hash -> hash to missingValues[index] }.associate { it }
58-
return hashes.map { missingEntries[it] ?: entries[it] as T }
58+
entries.putAll(missingEntries)
59+
return hashes.map { entries[it] as T }
5960
}
6061

6162
override fun put(hash: String, deserialized: Any, serialized: String) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import org.modelix.model.lazy.AccessTrackingStore
2+
import org.modelix.model.lazy.NonCachingObjectStore
3+
import org.modelix.model.lazy.PrefetchCache
4+
import org.modelix.model.persistent.MapBasedStore
5+
import kotlin.test.Test
6+
import kotlin.test.assertEquals
7+
import kotlin.test.assertTrue
8+
9+
class PrefetchCacheTest {
10+
11+
private val keyValueStore = MapBasedStore()
12+
private val accessTrackingKeyValueStore = AccessTrackingStore(keyValueStore)
13+
private val deserializingKeyValueStore = NonCachingObjectStore(accessTrackingKeyValueStore)
14+
private val prefetchCache = PrefetchCache(deserializingKeyValueStore)
15+
16+
@Test
17+
fun entriesAreCachedAfterGettingMultipleEntriesAsIterable() {
18+
keyValueStore.put("key", "value")
19+
prefetchCache.getAll(listOf("key")) { _, value -> value }
20+
accessTrackingKeyValueStore.accessedEntries.clear()
21+
22+
val result = prefetchCache.getAll(listOf("key")) { _, value -> value }
23+
24+
assertEquals(result, listOf("value"))
25+
assertTrue(accessTrackingKeyValueStore.accessedEntries.isEmpty())
26+
}
27+
}

0 commit comments

Comments
 (0)