@@ -25,6 +25,7 @@ import org.modelix.model.api.SerializedNodeReference
25
25
import org.modelix.model.api.getDescendants
26
26
import org.modelix.model.api.isChildRoleOrdered
27
27
import org.modelix.model.api.remove
28
+ import org.modelix.model.api.resolveInCurrentContext
28
29
import org.modelix.model.data.ModelData
29
30
import org.modelix.model.data.NodeData
30
31
import kotlin.jvm.JvmName
@@ -50,7 +51,13 @@ class ModelImporter(
50
51
) {
51
52
// We have seen imports where the `originalIdToExisting` had a dozen ten million entries.
52
53
// Therefore, choose a map with is optimized for memory usage.
53
- private var originalIdToExisting = MemoryEfficientMap <String , INode >()
54
+ // For the same reason store `INodeReference`s instead of `INode`s.
55
+ // In a few cases, where we need the `INode` we can resolve it.
56
+ private var originalIdToExisting = MemoryEfficientMap <String , INodeReference >()
57
+
58
+ // Use`INode` instead of `INodeReference` in `postponedReferences` and `nodesToRemove`
59
+ // because we know that we will always need the `INode`s in those cases.
60
+ // Those cases are deleting nodes and adding references to nodes.
54
61
private val postponedReferences = mutableListOf<PostponedReference >()
55
62
private val nodesToRemove = HashSet <INode >()
56
63
private var numExpectedNodes = 0
@@ -109,7 +116,7 @@ class ModelImporter(
109
116
buildExistingIndex(root)
110
117
111
118
logger.info { " Importing nodes..." }
112
- data.root.originalId()?.let { originalIdToExisting[it] = root }
119
+ data.root.originalId()?.let { originalIdToExisting[it] = root.reference }
113
120
syncNode(root, data.root, progressReporter)
114
121
115
122
logger.info { " Synchronizing references..." }
@@ -162,7 +169,7 @@ class ModelImporter(
162
169
val expectedId = expected.originalId()
163
170
checkNotNull(expectedId) { " Specified node '$expected ' has no ID." }
164
171
newChild.setPropertyValue(NodeData .idPropertyKey, expectedId)
165
- originalIdToExisting[expectedId] = newChild
172
+ originalIdToExisting[expectedId] = newChild.reference
166
173
syncNode(newChild, expected, progressReporter)
167
174
}
168
175
continue
@@ -197,13 +204,18 @@ class ModelImporter(
197
204
val nodeAtIndex = existingChildren.getOrNull(newIndex)
198
205
val expectedConcept = expected.concept?.let { s -> ConceptReference (s) }
199
206
val childNode = if (nodeAtIndex?.originalId() != expectedId) {
200
- val existingNode = originalIdToExisting[expectedId]
201
- if (existingNode == null ) {
207
+ val existingNodeReference = originalIdToExisting[expectedId]
208
+ if (existingNodeReference == null ) {
202
209
val newChild = existingParent.addNewChild(role, newIndex, expectedConcept)
203
210
newChild.setPropertyValue(NodeData .idPropertyKey, expectedId)
204
- originalIdToExisting[expectedId] = newChild
211
+ originalIdToExisting[expectedId] = newChild.reference
205
212
newChild
206
213
} else {
214
+ val existingNode = existingNodeReference.resolveInCurrentContext()
215
+ checkNotNull(existingNode) {
216
+ // This reference should always be resolvable because the node existed or was created before.
217
+ " Could not resolve $existingNodeReference ."
218
+ }
207
219
// The existing child node is not only moved to a new index,
208
220
// it is potentially moved to a new parent and role.
209
221
existingParent.moveChild(role, newIndex, existingNode)
@@ -230,7 +242,7 @@ class ModelImporter(
230
242
231
243
private fun buildExistingIndex (root : INode ) {
232
244
root.getDescendants(true ).forEach { node ->
233
- node.originalId()?.let { originalIdToExisting[it] = node }
245
+ node.originalId()?.let { originalIdToExisting[it] = node.reference }
234
246
}
235
247
}
236
248
0 commit comments