Skip to content

Commit 0d84b8b

Browse files
authored
Merge pull request #517 from modelix/MODELIX-752
MODELIX-752 Improve model-server query performance by caching the model in memory
2 parents 4415c75 + 10260f7 commit 0d84b8b

File tree

19 files changed

+475
-59
lines changed

19 files changed

+475
-59
lines changed

model-api/src/commonMain/kotlin/org/modelix/model/api/INode.kt

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ interface INode {
4444
*/
4545
val concept: IConcept?
4646

47+
fun tryGetConcept(): IConcept? = getConceptReference()?.tryResolve()
48+
4749
/**
4850
* Role of this node in its parent node if it exists,or null otherwise.
4951
*/
@@ -329,11 +331,7 @@ fun INode.resolveProperty(role: String): IProperty {
329331
* or null, if this concept has no child link or an exception was thrown during concept resolution
330332
*/
331333
fun INode.tryResolveChildLink(role: String): IChildLink? {
332-
val c = try {
333-
this.concept ?: return null
334-
} catch (e: RuntimeException) {
335-
return null
336-
}
334+
val c = this.tryGetConcept() ?: return null
337335
val allLinks = c.getAllChildLinks()
338336
return allLinks.find { it.key(this) == role }
339337
?: allLinks.find { it.getSimpleName() == role }
@@ -350,11 +348,7 @@ fun INode.resolveChildLinkOrFallback(role: String?): IChildLink {
350348
* or null, if this node has no reference link or an exception was thrown during concept resolution
351349
*/
352350
fun INode.tryResolveReferenceLink(role: String): IReferenceLink? {
353-
val c = try {
354-
this.concept ?: return null
355-
} catch (e: RuntimeException) {
356-
return null
357-
}
351+
val c = this.tryGetConcept() ?: return null
358352
val allLinks = c.getAllReferenceLinks()
359353
return allLinks.find { it.key(this) == role }
360354
?: allLinks.find { it.getSimpleName() == role }
@@ -370,11 +364,7 @@ fun INode.resolveReferenceLinkOrFallback(role: String): IReferenceLink {
370364
* or null, if this node has no concept or an exception was thrown during concept resolution
371365
*/
372366
fun INode.tryResolveProperty(role: String): IProperty? {
373-
val c = try {
374-
this.concept ?: return null
375-
} catch (e: RuntimeException) {
376-
return null
377-
}
367+
val c = this.tryGetConcept() ?: return null
378368
val allLinks = c.getAllProperties()
379369
return allLinks.find { it.key(this) == role }
380370
?: allLinks.find { it.getSimpleName() == role }
@@ -417,4 +407,3 @@ fun INode.getContainmentLink() = if (this is INodeEx) {
417407
fun INode.getRoot(): INode = parent?.getRoot() ?: this
418408
fun INode.isInstanceOf(superConcept: IConcept?): Boolean = concept.let { it != null && it.isSubConceptOf(superConcept) }
419409
fun INode.isInstanceOfSafe(superConcept: IConcept): Boolean = tryGetConcept()?.isSubConceptOf(superConcept) ?: false
420-
fun INode.tryGetConcept(): IConcept? = getConceptReference()?.tryResolve()

model-datastructure/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ kotlin {
5353
// implementation(libs.guava)
5454
// implementation(libs.apache.commons.io)
5555
// implementation("org.json:json:20230618")
56-
// implementation(libs.trove4j)
56+
implementation(libs.trove4j)
5757
implementation(libs.apache.commons.collections)
58+
implementation(libs.kotlin.coroutines.core)
5859
//
5960
// implementation("com.google.oauth-client:google-oauth-client:1.34.1")
6061
// implementation("com.google.oauth-client:google-oauth-client-jetty:1.34.1")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class BulkQuery(private val store: IDeserializingKeyValueStore) : IBulkQuery {
5353
return Value(value)
5454
}
5555

56-
fun process() {
56+
override fun process() {
5757
if (processing) {
5858
throw RuntimeException("Already processing")
5959
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,23 +444,23 @@ class CLTree : ITree, IBulkTree {
444444
return changesOnly
445445
}
446446

447-
override fun entryAdded(key: Long, value: KVEntryReference<CPNode>?) {
447+
override fun entryAdded(key: Long, value: KVEntryReference<CPNode>) {
448448
if (visitor is ITreeChangeVisitorEx) {
449449
createElement(value, bulkQuery).map { element ->
450450
visitor.nodeAdded(element!!.id)
451451
}
452452
}
453453
}
454454

455-
override fun entryRemoved(key: Long, value: KVEntryReference<CPNode>?) {
455+
override fun entryRemoved(key: Long, value: KVEntryReference<CPNode>) {
456456
if (visitor is ITreeChangeVisitorEx) {
457457
oldVersion.createElement(value, bulkQuery).map { element ->
458458
visitor.nodeRemoved(element!!.id)
459459
}
460460
}
461461
}
462462

463-
override fun entryChanged(key: Long, oldValue: KVEntryReference<CPNode>?, newValue: KVEntryReference<CPNode>?) {
463+
override fun entryChanged(key: Long, oldValue: KVEntryReference<CPNode>, newValue: KVEntryReference<CPNode>) {
464464
oldVersion.createElement(oldValue, bulkQuery).map { oldElement ->
465465
createElement(newValue, bulkQuery).map { newElement ->
466466
if (oldElement!!::class != newElement!!::class) {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,19 +344,19 @@ private fun computeDelta(keyValueStore: IKeyValueStore, versionHash: String, bas
344344
oldTree.nodesMap!!,
345345
object : CPHamtNode.IChangeVisitor {
346346
override fun visitChangesOnly(): Boolean = false
347-
override fun entryAdded(key: Long, value: KVEntryReference<CPNode>?) {
347+
override fun entryAdded(key: Long, value: KVEntryReference<CPNode>) {
348348
changedNodeIds += key
349349
if (value != null) bulkQuery.get(value)
350350
}
351351

352-
override fun entryRemoved(key: Long, value: KVEntryReference<CPNode>?) {
352+
override fun entryRemoved(key: Long, value: KVEntryReference<CPNode>) {
353353
changedNodeIds += key
354354
}
355355

356356
override fun entryChanged(
357357
key: Long,
358-
oldValue: KVEntryReference<CPNode>?,
359-
newValue: KVEntryReference<CPNode>?,
358+
oldValue: KVEntryReference<CPNode>,
359+
newValue: KVEntryReference<CPNode>,
360360
) {
361361
changedNodeIds += key
362362
if (newValue != null) bulkQuery.get(newValue)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package org.modelix.model.lazy
1818
import org.modelix.model.persistent.IKVValue
1919

2020
interface IBulkQuery {
21+
fun process()
2122
fun <I, O> map(input_: Iterable<I>, f: (I) -> Value<O>): Value<List<O>>
2223
fun <T> constant(value: T): Value<T>
2324
operator fun <T : IKVValue> get(hash: KVEntryReference<T>): Value<T?>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class NonBulkQuery(private val store: IDeserializingKeyValueStore) : IBulkQuery
3131
return constant(hash.getValue(store))
3232
}
3333

34+
override fun process() {
35+
// all requests are processed immediately
36+
}
37+
3438
class Value<T>(private val value: T) : IBulkQuery.Value<T> {
3539
override fun execute(): T {
3640
return value
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2023.
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.IKeyValueStore
20+
21+
class NonCachingObjectStore(override val keyValueStore: IKeyValueStore) : IDeserializingKeyValueStore {
22+
23+
override fun <T> getAll(hashes_: Iterable<String>, deserializer: (String, String) -> T): Iterable<T> {
24+
val hashes = hashes_.toList()
25+
val serialized: Map<String, String?> = keyValueStore.getAll(hashes_)
26+
return hashes.map { hash ->
27+
val value = checkNotNull(serialized[hash]) { "Entry not found: $hash" }
28+
deserializer(hash, value)
29+
}
30+
}
31+
32+
override fun <T> get(hash: String, deserializer: (String) -> T): T? {
33+
return keyValueStore.get(hash)?.let(deserializer)
34+
}
35+
36+
override fun put(hash: String, deserialized: Any, serialized: String) {
37+
keyValueStore.put(hash, serialized)
38+
}
39+
40+
override fun prefetch(hash: String) {
41+
keyValueStore.prefetch(hash)
42+
}
43+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ class CPHamtInternal(
169169
return create(newBitmap, newChildren)
170170
}
171171

172-
override fun visitEntries(bulkQuery: IBulkQuery, visitor: (Long, KVEntryReference<CPNode>?) -> Unit): IBulkQuery.Value<Unit> {
172+
override fun visitEntries(bulkQuery: IBulkQuery, visitor: (Long, KVEntryReference<CPNode>) -> Unit): IBulkQuery.Value<Unit> {
173173
return bulkQuery.map(data.children.asIterable()) { bulkQuery.get(it) }.mapBulk { children ->
174174
bulkQuery.map(children) { it!!.visitEntries(bulkQuery, visitor) }.map { }
175175
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class CPHamtLeaf(
6767
return bulkQuery.constant(if (key == this.key) value else null)
6868
}
6969

70-
override fun visitEntries(bulkQuery: IBulkQuery, visitor: (Long, KVEntryReference<CPNode>?) -> Unit): IBulkQuery.Value<Unit> {
70+
override fun visitEntries(bulkQuery: IBulkQuery, visitor: (Long, KVEntryReference<CPNode>) -> Unit): IBulkQuery.Value<Unit> {
7171
return bulkQuery.constant(visitor(key, value))
7272
}
7373

@@ -83,17 +83,18 @@ class CPHamtLeaf(
8383
}
8484
} else {
8585
var oldValue: KVEntryReference<CPNode>? = null
86-
val bp = { k: Long?, v: KVEntryReference<CPNode>? ->
86+
val bp = { k: Long, v: KVEntryReference<CPNode> ->
8787
if (k == key) {
8888
oldValue = v
8989
} else {
90-
visitor.entryRemoved(k!!, v)
90+
visitor.entryRemoved(k, v)
9191
}
9292
}
9393
oldNode!!.visitEntries(bulkQuery, bp).onSuccess {
94+
val oldValue = oldValue
9495
if (oldValue == null) {
9596
visitor.entryAdded(key, value)
96-
} else if (oldValue?.getHash() !== value.getHash()) {
97+
} else if (oldValue.getHash() !== value.getHash()) {
9798
visitor.entryChanged(key, oldValue, value)
9899
}
99100
}

0 commit comments

Comments
 (0)