Skip to content

Commit d148937

Browse files
committed
performance improvement of INodeReferenceSerializer
1 parent 98ee59d commit d148937

File tree

3 files changed

+93
-35
lines changed

3 files changed

+93
-35
lines changed

light-model-client/src/commonMain/kotlin/org/modelix/client/light/LightModelClient.kt

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.modelix.model.area.IArea
99
import org.modelix.model.area.IAreaListener
1010
import org.modelix.model.area.IAreaReference
1111
import org.modelix.model.server.api.*
12+
import kotlin.reflect.KClass
1213
import kotlin.time.Duration
1314
import kotlin.time.Duration.Companion.milliseconds
1415
import kotlin.time.Duration.Companion.seconds
@@ -740,8 +741,10 @@ class LightClientNodeReference(val nodeId: NodeId) : INodeReference {
740741
}
741742
}
742743

743-
object LightClientReferenceSerializer : INodeReferenceSerializer {
744-
val PREFIX = "light-client:"
744+
object LightClientReferenceSerializer : INodeReferenceSerializerEx {
745+
override val prefix: String = "light-client"
746+
override val supportedReferenceClasses = setOf(LightClientNodeReference::class)
747+
745748
fun register() {
746749
INodeReferenceSerializer.register(LightClientReferenceSerializer)
747750
}
@@ -750,18 +753,12 @@ object LightClientReferenceSerializer : INodeReferenceSerializer {
750753
INodeReferenceSerializer.unregister(LightClientReferenceSerializer)
751754
}
752755

753-
override fun serialize(ref: INodeReference): String? {
754-
return when (ref) {
755-
is LightClientNodeReference -> PREFIX + ref.nodeId
756-
else -> null
757-
}
756+
override fun serialize(ref: INodeReference): String {
757+
return (ref as LightClientNodeReference).nodeId
758758
}
759759

760-
override fun deserialize(serialized: String): INodeReference? {
761-
if (serialized.startsWith(PREFIX)) {
762-
return LightClientNodeReference(serialized.substring(PREFIX.length))
763-
}
764-
return null
760+
override fun deserialize(serialized: String): INodeReference {
761+
return LightClientNodeReference(serialized)
765762
}
766763
}
767764

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

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,109 @@
11
package org.modelix.model.api
22

3+
import kotlin.reflect.KClass
4+
35
interface INodeReferenceSerializer {
46

57
fun serialize(ref: INodeReference): String?
68
fun deserialize(serialized: String): INodeReference?
79

810
companion object {
9-
private val serializers: MutableSet<INodeReferenceSerializer> = HashSet()
11+
private val LOG = mu.KotlinLogging.logger {}
12+
private val deserializerForPrefix: MutableMap<String, INodeReferenceSerializerEx> = HashMap()
13+
private val serializersForClass: MutableMap<KClass<*>, INodeReferenceSerializerEx> = HashMap()
14+
private val legacySerializers: MutableSet<INodeReferenceSerializer> = HashSet()
1015

1116
init {
1217
register(ByIdSerializer)
1318
}
1419

1520
fun register(serializer: INodeReferenceSerializer) {
16-
serializers.add(serializer)
21+
if (serializer is INodeReferenceSerializerEx) {
22+
val prefix = serializer.prefix
23+
val existingDeserializer = deserializerForPrefix[prefix]
24+
if (existingDeserializer != null) {
25+
throw IllegalStateException("Deserializer for '$prefix:' already registered: $existingDeserializer")
26+
}
27+
val supportedClasses = serializer.supportedReferenceClasses
28+
for (supportedClass in supportedClasses) {
29+
val existingSerializer = serializersForClass[supportedClass]
30+
if (existingSerializer != null) {
31+
throw IllegalStateException("Serializer for $supportedClass already registered: $existingSerializer")
32+
}
33+
}
34+
deserializerForPrefix[prefix] = serializer
35+
supportedClasses.forEach { serializersForClass[it] = serializer }
36+
} else {
37+
LOG.warn { "Migrate ${serializer::class} to INodeReferenceSerializerEx" }
38+
legacySerializers.add(serializer)
39+
}
1740
}
1841

1942
fun unregister(serializer: INodeReferenceSerializer) {
20-
serializers.remove(serializer)
43+
if (serializer is INodeReferenceSerializerEx) {
44+
val prefix = serializer.prefix
45+
if (deserializerForPrefix[prefix] == serializer) {
46+
deserializerForPrefix.remove(prefix)
47+
}
48+
for (supportedClass in serializer.supportedReferenceClasses) {
49+
if (serializersForClass[supportedClass] == serializer) {
50+
serializersForClass.remove(supportedClass)
51+
}
52+
}
53+
} else {
54+
legacySerializers.remove(serializer)
55+
}
2156
}
2257

2358
fun serialize(ref: INodeReference): String {
2459
if (ref is SerializedNodeReference) return ref.serialized
25-
return serializers.map { it.serialize(ref) }.firstOrNull { it != null }
26-
?: throw RuntimeException("No serializer found for ${ref::class}")
60+
61+
val serializer = serializersForClass[ref::class]
62+
return if (serializer != null) {
63+
serializer.serialize(ref)
64+
} else {
65+
legacySerializers.map { it.serialize(ref) }.firstOrNull { it != null }
66+
?: throw RuntimeException("No serializer found for ${ref::class}")
67+
}
68+
2769
}
2870

2971
fun deserialize(serialized: String): INodeReference {
30-
return serializers.map { it.deserialize(serialized) }.firstOrNull { it != null }
72+
val parts = serialized.split(INodeReferenceSerializerEx.SEPARATOR, limit = 2)
73+
if (parts.size == 2) {
74+
val deserializer = deserializerForPrefix[parts[0]]
75+
if (deserializer != null) {
76+
return deserializer.deserialize(parts[1])
77+
}
78+
}
79+
80+
return legacySerializers.map { it.deserialize(serialized) }.firstOrNull { it != null }
3181
?: throw RuntimeException("No deserializer found for: $serialized")
3282
}
3383
}
3484
}
3585

36-
private object ByIdSerializer : INodeReferenceSerializer {
37-
const val PREFIX = "id:"
38-
override fun serialize(ref: INodeReference): String? {
39-
return if (ref is NodeReferenceById) PREFIX + ref.nodeId else null
86+
interface INodeReferenceSerializerEx : INodeReferenceSerializer {
87+
val prefix: String
88+
val supportedReferenceClasses: Set<KClass<out INodeReference>>
89+
override fun serialize(ref: INodeReference): String
90+
override fun deserialize(serialized: String): INodeReference
91+
92+
companion object {
93+
val SEPARATOR = ":"
4094
}
95+
}
4196

42-
override fun deserialize(serialized: String): INodeReference? {
97+
private object ByIdSerializer : INodeReferenceSerializerEx {
98+
override val prefix: String = "id"
99+
override val supportedReferenceClasses = setOf(NodeReferenceById::class)
100+
101+
override fun serialize(ref: INodeReference): String {
102+
return (ref as NodeReferenceById).nodeId
103+
}
43104

44-
return if (serialized.startsWith(PREFIX)) NodeReferenceById(serialized.drop(PREFIX.length)) else null
105+
override fun deserialize(serialized: String): INodeReference {
106+
return NodeReferenceById(serialized)
45107
}
46108
}
47109

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

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.modelix.model.api
1717

1818
import org.modelix.model.area.IArea
19+
import kotlin.reflect.KClass
1920

2021
data class PNodeReference(val id: Long, val branchId: String) : INodeReference {
2122
init {
@@ -32,8 +33,10 @@ data class PNodeReference(val id: Long, val branchId: String) : INodeReference {
3233
}
3334
}
3435

35-
object PNodeReferenceSerializer : INodeReferenceSerializer {
36-
val PREFIX = "pnode:"
36+
object PNodeReferenceSerializer : INodeReferenceSerializerEx {
37+
override val prefix = "pnode"
38+
override val supportedReferenceClasses = setOf(PNodeReference::class)
39+
3740
init {
3841
INodeReferenceSerializer.register(this)
3942
}
@@ -42,16 +45,12 @@ object PNodeReferenceSerializer : INodeReferenceSerializer {
4245
// Is done in the init section. Calling this method just ensures that the object is initialized.
4346
}
4447

45-
override fun serialize(ref: INodeReference): String? {
46-
return (ref as? PNodeReference)?.let { "$PREFIX${ref.id.toString(16)}@${ref.branchId}" }
48+
override fun serialize(ref: INodeReference): String {
49+
return (ref as PNodeReference).let { "${ref.id.toString(16)}@${ref.branchId}" }
4750
}
4851

49-
override fun deserialize(serialized: String): INodeReference? {
50-
return if (serialized.startsWith(PREFIX)) {
51-
val parts = serialized.drop(PREFIX.length).split('@', limit = 2)
52-
PNodeReference(parts[0].toLong(16), parts[1])
53-
} else {
54-
null
55-
}
52+
override fun deserialize(serialized: String): INodeReference {
53+
val parts = serialized.split('@', limit = 2)
54+
return PNodeReference(parts[0].toLong(16), parts[1])
5655
}
5756
}

0 commit comments

Comments
 (0)