Skip to content

Commit 078cf6b

Browse files
slissonmhuster23
authored andcommitted
perf(model-client): unnecessary overhead of BulkQuery
The ModelClientV2 uses a map based implementation of IKeyValueStore that doesn't benefit from batching of requests. This overhead can be removed.
1 parent 28fe813 commit 078cf6b

File tree

6 files changed

+36
-17
lines changed

6 files changed

+36
-17
lines changed

model-datastructure/src/commonMain/kotlin/org/modelix/model/IKeyValueStore.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515

1616
package org.modelix.model
1717

18+
import org.modelix.model.lazy.BulkQuery
19+
import org.modelix.model.lazy.IBulkQuery
20+
import org.modelix.model.lazy.IDeserializingKeyValueStore
21+
1822
interface IKeyValueStore {
23+
fun newBulkQuery(deserializingCache: IDeserializingKeyValueStore): IBulkQuery = BulkQuery(deserializingCache)
1924
operator fun get(key: String): String?
2025
fun put(key: String, value: String?)
2126
fun getAll(keys: Iterable<String>): Map<String, String?>

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class CLTree : ITree, IBulkTree {
9393
}
9494

9595
fun getSize(): Long {
96-
return (nodesMap ?: return 0L).calculateSize(BulkQuery(store)).execute()
96+
return (nodesMap ?: return 0L).calculateSize(store.newBulkQuery()).execute()
9797
}
9898

9999
fun prefetchAll() {
@@ -286,24 +286,24 @@ class CLTree : ITree, IBulkTree {
286286
}
287287

288288
override fun getAllChildren(parentId: Long): Iterable<Long> {
289-
val children = getChildren(resolveElement(parentId)!!, BulkQuery(store)).execute()
289+
val children = getChildren(resolveElement(parentId)!!, store.newBulkQuery()).execute()
290290
return children.map { it.id }
291291
}
292292

293293
override fun getDescendants(root: Long, includeSelf: Boolean): Iterable<CLNode> {
294294
val parent = resolveElement(root)
295-
return getDescendants(parent!!, BulkQuery(store), includeSelf).execute().map { CLNode(this, it) }
295+
return getDescendants(parent!!, store.newBulkQuery(), includeSelf).execute().map { CLNode(this, it) }
296296
}
297297

298298
override fun getDescendants(rootIds: Iterable<Long>, includeSelf: Boolean): Iterable<CLNode> {
299-
val bulkQuery = BulkQuery(store)
299+
val bulkQuery = store.newBulkQuery()
300300
val roots: IBulkQuery.Value<List<CPNode>> = resolveElements(rootIds.toList(), bulkQuery)
301301
val descendants = roots.mapBulk { bulkQuery.map(it) { getDescendants(it, bulkQuery, includeSelf) } }
302302
return descendants.execute().flatten().map { CLNode(this, it) }
303303
}
304304

305305
override fun getAncestors(nodeIds: Iterable<Long>, includeSelf: Boolean): Set<Long> {
306-
val bulkQuery = BulkQuery(store)
306+
val bulkQuery = store.newBulkQuery()
307307
val nodes: IBulkQuery.Value<List<CPNode>> = resolveElements(nodeIds, bulkQuery)
308308
val ancestors = nodes.mapBulk { bulkQuery.map(it) { getAncestors(it, bulkQuery, includeSelf) } }
309309
val result = HashSet<Long>()
@@ -314,15 +314,15 @@ class CLTree : ITree, IBulkTree {
314314
override fun getChildren(parentId: Long, role: String?): Iterable<Long> {
315315
checkChildRoleId(parentId, role)
316316
val parent = resolveElement(parentId)
317-
val children = getChildren(parent!!, BulkQuery(store)).execute()
317+
val children = getChildren(parent!!, store.newBulkQuery()).execute()
318318
return children
319319
.filter { it.roleInParent == role }
320320
.map { it.id }
321321
}
322322

323323
override fun getChildRoles(sourceId: Long): Iterable<String?> {
324324
val parent = resolveElement(sourceId)
325-
val children: Iterable<CPNode> = getChildren(parent!!, BulkQuery(store)).execute()
325+
val children: Iterable<CPNode> = getChildren(parent!!, store.newBulkQuery()).execute()
326326
return children.map { it.roleInParent }.distinct()
327327
}
328328

@@ -412,9 +412,9 @@ class CLTree : ITree, IBulkTree {
412412
}
413413

414414
override fun visitChanges(oldVersion: ITree, visitor: ITreeChangeVisitor) {
415-
val bulkQuery = BulkQuery(store)
415+
val bulkQuery = store.newBulkQuery()
416416
visitChanges(oldVersion, visitor, bulkQuery)
417-
bulkQuery.process()
417+
(bulkQuery as? BulkQuery)?.process()
418418
}
419419

420420
fun visitChanges(oldVersion: ITree, visitor: ITreeChangeVisitor, bulkQuery: IBulkQuery) {

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ private fun computeDelta(keyValueStore: IKeyValueStore, versionHash: String, bas
325325
// }
326326

327327
val history = LinearHistory(baseVersionHash).load(version)
328-
val bulkQuery = BulkQuery(store)
328+
val bulkQuery = store.newBulkQuery()
329329
var v1 = baseVersion
330330
for (v2 in history) {
331331
v2.operations // include them in the result
@@ -342,7 +342,7 @@ private fun computeDelta(keyValueStore: IKeyValueStore, versionHash: String, bas
342342
override fun visitChangesOnly(): Boolean = false
343343
override fun entryAdded(key: Long, value: KVEntryReference<CPNode>?) {
344344
changedNodeIds += key
345-
if (value != null) bulkQuery.query(value, {})
345+
if (value != null) bulkQuery.get(value)
346346
}
347347

348348
override fun entryRemoved(key: Long, value: KVEntryReference<CPNode>?) {
@@ -355,14 +355,14 @@ private fun computeDelta(keyValueStore: IKeyValueStore, versionHash: String, bas
355355
newValue: KVEntryReference<CPNode>?,
356356
) {
357357
changedNodeIds += key
358-
if (newValue != null) bulkQuery.query(newValue, {})
358+
if (newValue != null) bulkQuery.get(newValue)
359359
}
360360
},
361361
bulkQuery,
362362
)
363363
v1 = v2
364364
}
365-
bulkQuery.process()
365+
(bulkQuery as? BulkQuery)?.process()
366366
}
367367
val oldEntries: Map<String, String?> = trackAccessedEntries(keyValueStore) { store ->
368368
if (baseVersionHash == null) return@trackAccessedEntries
@@ -372,16 +372,16 @@ private fun computeDelta(keyValueStore: IKeyValueStore, versionHash: String, bas
372372
baseVersion.operations
373373

374374
val oldTree = baseVersion.getTree()
375-
val bulkQuery = BulkQuery(store)
375+
val bulkQuery = store.newBulkQuery()
376376

377377
val nodesMap = oldTree.nodesMap!!
378378
changedNodeIds.forEach { changedNodeId ->
379379
nodesMap.get(changedNodeId, 0, bulkQuery).onSuccess { nodeRef: KVEntryReference<CPNode>? ->
380-
if (nodeRef != null) bulkQuery.query(nodeRef) { a: CPNode? -> }
380+
if (nodeRef != null) bulkQuery.get(nodeRef)
381381
}
382382
}
383383

384-
bulkQuery.process()
384+
(bulkQuery as? BulkQuery)?.process()
385385
}
386386
return oldAndNewEntries - oldEntries.keys
387387
}
@@ -396,6 +396,10 @@ private fun trackAccessedEntries(store: IKeyValueStore, body: (IDeserializingKey
396396
private class AccessTrackingStore(val store: IKeyValueStore) : IKeyValueStore {
397397
val accessedEntries: MutableMap<String, String?> = HashMap()
398398

399+
override fun newBulkQuery(deserializingCache: IDeserializingKeyValueStore): IBulkQuery {
400+
return store.newBulkQuery(deserializingCache)
401+
}
402+
399403
override fun get(key: String): String? {
400404
val value = store.get(key)
401405
accessedEntries.put(key, value)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ package org.modelix.model.lazy
1818
import org.modelix.model.IKeyValueStore
1919

2020
interface IDeserializingKeyValueStore {
21+
fun newBulkQuery(): IBulkQuery = newBulkQuery(this)
22+
fun newBulkQuery(wrapper: IDeserializingKeyValueStore): IBulkQuery = keyValueStore.newBulkQuery(wrapper)
2123
val keyValueStore: IKeyValueStore
2224
operator fun <T> get(hash: String, deserializer: (String) -> T): T?
2325
fun <T> getAll(hash: Iterable<String>, deserializer: (String, String) -> T): Iterable<T>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import org.modelix.model.persistent.IKVValue
1919

2020
class NonBulkQuery(private val store: IDeserializingKeyValueStore) : IBulkQuery {
2121
override fun <I, O> map(input_: Iterable<I>, f: (I) -> IBulkQuery.Value<O>): IBulkQuery.Value<List<O>> {
22-
val list = input_.map(f).map { it.execute() }.toList()
22+
val list = input_.asSequence().map(f).map { it.execute() }.toList()
2323
return Value(list)
2424
}
2525

model-datastructure/src/commonMain/kotlin/org/modelix/model/persistent/MapBasedStore.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ package org.modelix.model.persistent
1717

1818
import org.modelix.model.IKeyListener
1919
import org.modelix.model.IKeyValueStore
20+
import org.modelix.model.lazy.IBulkQuery
21+
import org.modelix.model.lazy.IDeserializingKeyValueStore
22+
import org.modelix.model.lazy.NonBulkQuery
2023

2124
@Deprecated("Use MapBasedStore, without a typo.", ReplaceWith("MapBasedStore"))
2225
open class MapBaseStore : MapBasedStore()
@@ -27,6 +30,11 @@ open class MapBasedStore : IKeyValueStore {
2730
return map[key]
2831
}
2932

33+
override fun newBulkQuery(deserializingCache: IDeserializingKeyValueStore): IBulkQuery {
34+
// This implementation doesn't benefit from bulk queries. The NonBulkQuery has a lower performance overhead.
35+
return NonBulkQuery(deserializingCache)
36+
}
37+
3038
override fun getPendingSize(): Int = 0
3139

3240
override fun put(key: String, value: String?) {

0 commit comments

Comments
 (0)