Skip to content

Commit 3b96f7c

Browse files
authored
Merge pull request #279 from modelix/fix/bulk-sync-import-fix
MODELIX-561 Import into model-server is unsuccessful
2 parents f4c640b + 2291043 commit 3b96f7c

File tree

7 files changed

+112
-32
lines changed

7 files changed

+112
-32
lines changed

bulk-model-sync-gradle-test/src/test/kotlin/org/modelix/model/sync/bulk/gradle/test/PushTest.kt

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,17 @@ import org.modelix.metamodel.TypedLanguagesRegistry
1010
import org.modelix.metamodel.typed
1111
import org.modelix.model.ModelFacade
1212
import org.modelix.model.api.ConceptReference
13-
import org.modelix.model.api.IBranch
1413
import org.modelix.model.api.getDescendants
1514
import org.modelix.model.api.getRootNode
15+
import org.modelix.model.client2.IModelClientV2
1616
import org.modelix.model.client2.ModelClientV2PlatformSpecificBuilder
1717
import org.modelix.model.client2.getReplicatedModel
18+
import org.modelix.model.client2.runWrite
1819
import org.modelix.model.data.ModelData
1920
import org.modelix.model.data.NodeData
21+
import org.modelix.model.lazy.BranchReference
2022
import org.modelix.model.lazy.RepositoryId
2123
import org.modelix.model.server.Main
22-
import org.modelix.model.sleep
2324
import org.modelix.model.sync.bulk.asExported
2425
import java.io.File
2526
import kotlin.test.assertContentEquals
@@ -40,32 +41,33 @@ class PushTest {
4041
val repoId = RepositoryId("ci-test")
4142
val branchName = "master"
4243
val url = "http://0.0.0.0:${Main.DEFAULT_PORT}/v2"
44+
4345
val branchRef = ModelFacade.createBranchReference(repoId, branchName)
44-
val client = ModelClientV2PlatformSpecificBuilder().url(url).build()
46+
val client = ModelClientV2PlatformSpecificBuilder().url(url).build().apply { runBlocking { init() } }
47+
val replicatedModel = client.getReplicatedModel(branchRef)
48+
val branch = runBlocking { replicatedModel.start() }
4549

46-
val branch = runBlocking {
47-
client.init()
48-
client.getReplicatedModel(branchRef).start()
49-
}
5050
branch.runRead {
5151
assertContentEquals(inputModel.root.children, branch.getRootNode().allChildren.map { it.asExported() })
5252
}
53+
replicatedModel.dispose()
5354

54-
applyChangesForPullTest(branch)
55+
applyChangesForPullTest(client, branchRef)
5556
}
5657

57-
private fun applyChangesForPullTest(branch: IBranch) {
58-
branch.runWrite {
59-
val graphNodes = branch.getRootNode()
60-
.getDescendants(false)
61-
.filter { it.getConceptReference() == ConceptReference(_C_UntypedImpl_Node.getUID()) }
62-
.map { it.typed<N_Node>() }
63-
.toList()
58+
private fun applyChangesForPullTest(client: IModelClientV2, branchRef: BranchReference) {
59+
runBlocking {
60+
client.runWrite(branchRef) { rootNode ->
61+
val graphNodes = rootNode
62+
.getDescendants(false)
63+
.filter { it.getConceptReference() == ConceptReference(_C_UntypedImpl_Node.getUID()) }
64+
.map { it.typed<N_Node>() }
65+
.toList()
6466

65-
graphNodes[0].name = "X"
66-
graphNodes[1].name = "Y"
67-
graphNodes[2].name = "Z"
67+
graphNodes[0].name = "X"
68+
graphNodes[1].name = "Y"
69+
graphNodes[2].name = "Z"
70+
}
6871
}
69-
sleep(5000) // changes are pushed asynchronously to the server. wait for the propagation
7072
}
7173
}

bulk-model-sync-gradle/src/main/kotlin/org/modelix/model/sync/bulk/gradle/tasks/ImportIntoModelServer.kt

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,8 @@ import org.gradle.api.tasks.TaskAction
3030
import org.modelix.model.ModelFacade
3131
import org.modelix.model.api.ILanguage
3232
import org.modelix.model.api.ILanguageRepository
33-
import org.modelix.model.api.getRootNode
3433
import org.modelix.model.client2.ModelClientV2PlatformSpecificBuilder
35-
import org.modelix.model.client2.getReplicatedModel
34+
import org.modelix.model.client2.runWrite
3635
import org.modelix.model.lazy.RepositoryId
3736
import org.modelix.model.sync.bulk.ModelImporter
3837
import org.modelix.model.sync.bulk.importFilesAsRootChildren
@@ -67,20 +66,17 @@ abstract class ImportIntoModelServer @Inject constructor(of: ObjectFactory) : De
6766

6867
val branchRef = ModelFacade.createBranchReference(repoId, branchName.get())
6968
val client = ModelClientV2PlatformSpecificBuilder().url(url.get()).build()
70-
val branch = runBlocking {
71-
client.init()
72-
client.getReplicatedModel(branchRef).start()
73-
}
74-
7569
val files = inputDir.listFiles()?.filter { it.extension == "json" }
7670
if (files.isNullOrEmpty()) error("no json files found")
7771

78-
branch.runWrite {
79-
val rootNode = branch.getRootNode()
80-
logger.info("Got root node: {}", rootNode)
81-
logger.info("Importing...")
82-
ModelImporter(branch.getRootNode()).importFilesAsRootChildren(*files.toTypedArray())
83-
logger.info("Import finished")
72+
runBlocking {
73+
client.init()
74+
client.runWrite(branchRef) { rootNode ->
75+
logger.info("Got root node: {}", rootNode)
76+
logger.info("Importing...")
77+
ModelImporter(rootNode).importFilesAsRootChildren(files)
78+
logger.info("Import finished")
79+
}
8480
}
8581
}
8682
}

bulk-model-sync-lib/src/commonMain/kotlin/org/modelix/model/sync/bulk/ModelImporter.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class ModelImporter(private val root: INode) {
5353
*/
5454
@JvmName("importData")
5555
fun import(data: ModelData) {
56+
logImportSize(data.root, logger)
5657
logger.info { "Building indices for import..." }
5758
originalIdToExisting.clear()
5859
postponedReferences.clear()

bulk-model-sync-lib/src/commonMain/kotlin/org/modelix/model/sync/bulk/Util.kt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,54 @@
1616

1717
package org.modelix.model.sync.bulk
1818

19+
import mu.KLogger
20+
import org.modelix.model.api.BuiltinLanguages
1921
import org.modelix.model.data.ModelData
2022
import org.modelix.model.data.NodeData
2123

24+
fun mergeModelData(models: Collection<ModelData>): ModelData {
25+
return ModelData(root = NodeData(children = models.map { it.root }))
26+
}
27+
28+
@Deprecated("use collection parameter for better performance")
2229
fun mergeModelData(vararg models: ModelData): ModelData {
2330
return ModelData(root = NodeData(children = models.map { it.root }))
2431
}
32+
33+
internal fun logImportSize(nodeData: NodeData, logger: KLogger) {
34+
logger.debug { measureImportSize(nodeData).toString() }
35+
}
36+
37+
private data class ImportSizeMetrics(
38+
var numModules: Int = 0,
39+
var numModels: Int = 0,
40+
val concepts: MutableSet<String> = mutableSetOf(),
41+
var numProperties: Int = 0,
42+
var numReferences: Int = 0,
43+
) {
44+
override fun toString(): String {
45+
return """
46+
[Bulk Model Sync Import Size]
47+
number of modules: $numModules
48+
number of models: $numModels
49+
number of concepts: ${concepts.size}
50+
number of properties: $numProperties
51+
number of references: $numReferences
52+
""".trimIndent()
53+
}
54+
}
55+
56+
private fun measureImportSize(data: NodeData, metrics: ImportSizeMetrics = ImportSizeMetrics()): ImportSizeMetrics {
57+
data.concept?.let { metrics.concepts.add(it) }
58+
59+
when (data.concept) {
60+
BuiltinLanguages.MPSRepositoryConcepts.Module.getUID() -> metrics.numModules++
61+
BuiltinLanguages.MPSRepositoryConcepts.Model.getUID() -> metrics.numModels++
62+
}
63+
64+
metrics.numProperties += data.properties.size
65+
metrics.numReferences += data.references.size
66+
67+
data.children.forEach { measureImportSize(it, metrics) }
68+
return metrics
69+
}

bulk-model-sync-lib/src/jvmMain/kotlin/org/modelix/model/sync/bulk/PlatformSpecific.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ fun ModelImporter.import(jsonFile: File) {
3535
import(data)
3636
}
3737

38+
fun ModelImporter.importFilesAsRootChildren(files: Collection<File>) {
39+
val models = files.map { ModelData.fromJson(it.readText()) }
40+
import(mergeModelData(models))
41+
}
42+
43+
@Deprecated("use collection parameter for better performance")
3844
fun ModelImporter.importFilesAsRootChildren(vararg files: File) {
3945
val models = files.map { ModelData.fromJson(it.readText()) }
4046
import(mergeModelData(*models.toTypedArray()))

model-client/src/commonMain/kotlin/org/modelix/model/client2/ModelClientV2.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,18 @@ import kotlinx.coroutines.launch
3434
import kotlinx.serialization.json.Json
3535
import org.modelix.model.IVersion
3636
import org.modelix.model.api.IIdGenerator
37+
import org.modelix.model.api.INode
3738
import org.modelix.model.api.IdGeneratorDummy
39+
import org.modelix.model.api.TreePointer
40+
import org.modelix.model.api.getRootNode
3841
import org.modelix.model.client.IdGenerator
3942
import org.modelix.model.lazy.BranchReference
43+
import org.modelix.model.lazy.CLTree
4044
import org.modelix.model.lazy.CLVersion
4145
import org.modelix.model.lazy.ObjectStoreCache
4246
import org.modelix.model.lazy.RepositoryId
4347
import org.modelix.model.lazy.computeDelta
48+
import org.modelix.model.operations.OTBranch
4449
import org.modelix.model.persistent.HashUtil
4550
import org.modelix.model.persistent.MapBasedStore
4651
import org.modelix.model.server.api.v2.VersionDelta
@@ -307,3 +312,25 @@ private fun URLBuilder.appendPathSegmentsEncodingSlash(vararg components: String
307312
}
308313

309314
fun VersionDelta.getAllObjects(): Map<String, String> = objectsMap + objects.associateBy { HashUtil.sha256(it) }
315+
316+
/**
317+
* Performs a write transaction on the root node of the given branch.
318+
*/
319+
suspend fun <T> IModelClientV2.runWrite(branchRef: BranchReference, body: (INode) -> T): T {
320+
val client = this
321+
val baseVersion = client.pull(branchRef, null)
322+
val branch = OTBranch(TreePointer(baseVersion.getTree(), client.getIdGenerator()), client.getIdGenerator(), (client as ModelClientV2).store)
323+
val result = branch.computeWrite {
324+
body(branch.getRootNode())
325+
}
326+
val (ops, newTree) = branch.getPendingChanges()
327+
val newVersion = CLVersion.createRegularVersion(
328+
id = client.getIdGenerator().generate(),
329+
author = client.getUserId(),
330+
tree = newTree as CLTree,
331+
baseVersion = baseVersion as CLVersion?,
332+
operations = ops.map { it.getOriginalOp() }.toTypedArray(),
333+
)
334+
client.push(branchRef, newVersion, baseVersion)
335+
return result
336+
}

model-client/src/commonMain/kotlin/org/modelix/model/client2/ReplicatedModel.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import org.modelix.model.lazy.CLTree
2121
import org.modelix.model.lazy.CLVersion
2222
import org.modelix.model.operations.OTBranch
2323

24+
/**
25+
* Dispose should be called on this, as otherwise a regular polling will go on.
26+
*/
2427
class ReplicatedModel(
2528
val client: IModelClientV2,
2629
val branchRef: BranchReference,

0 commit comments

Comments
 (0)