From f0b36a865dbf386033a5bee43ceaaeecf77ba6a1 Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Fri, 10 Mar 2023 13:28:12 +0000 Subject: [PATCH 01/10] Made agents trace runs per iteration. --- Simulation.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Simulation.kt b/Simulation.kt index 33c70251f..76e566c7a 100644 --- a/Simulation.kt +++ b/Simulation.kt @@ -77,7 +77,7 @@ abstract class Simulation, out CONTEXT: Context<*, *>>( agents.forEach { agent -> val start = Instant.now() val reports = agent.iterate(randomSource.nextSource()) - LOGGER.info("{}.{} took: {}", agent.javaClass.simpleName, agent.action, printDuration(start, Instant.now())) + LOGGER.info("{}.{} × {} took: {}", agent.javaClass.simpleName, agent.action, agent.runsPerIteration, printDuration(start, Instant.now())) agentReports[agent.javaClass.superclass.simpleName] = reports } context.incrementIteration() From 39ea0497b40725d148d5416163ec59987f372b38 Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Fri, 10 Mar 2023 13:28:52 +0000 Subject: [PATCH 02/10] Parametrised database reinitialisation. --- Context.kt | 1 + common/params/Config.kt | 7 +++++-- neo4j/Neo4jSimulation.kt | 3 +-- typedb/TypeDBSimulation.kt | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Context.kt b/Context.kt index 5ccdcd829..edd3f43c4 100644 --- a/Context.kt +++ b/Context.kt @@ -35,6 +35,7 @@ open class Context( val dbName = config.run.databaseName val iterationMax = config.run.iterations val partitionCount = config.run.partitions + val recreateDatabase = config.run.recreateDatabase val model = config.model diff --git a/common/params/Config.kt b/common/params/Config.kt index 04119c031..190b022f5 100644 --- a/common/params/Config.kt +++ b/common/params/Config.kt @@ -29,6 +29,7 @@ import com.vaticle.typedb.simulation.common.params.Config.Keys.TRACE_SAMPLING import com.vaticle.typedb.common.yaml.YAML import com.vaticle.typedb.simulation.common.params.Config.Keys.ACTION import com.vaticle.typedb.simulation.common.params.Config.Keys.PARTITIONS +import com.vaticle.typedb.simulation.common.params.Config.Keys.RECREATE_DATABASE import com.vaticle.typedb.simulation.common.params.Config.Keys.RUNS_PER_ITERATION import java.io.File import kotlin.math.ln @@ -82,13 +83,14 @@ class Config(val agents: List, val traceSampling: TraceSamplin } } - class Run(val randomSeed: Long, val iterations: Int, val partitions: Int, val databaseName: String) { + class Run(val randomSeed: Long, val iterations: Int, val partitions: Int, val databaseName: String, val recreateDatabase: Boolean) { companion object { internal fun of(yaml: YAML.Map) = Run( databaseName = yaml[DATABASE_NAME].asString().value(), iterations = yaml[ITERATIONS].asInt().value(), partitions = yaml[PARTITIONS].asInt().value(), - randomSeed = yaml[RANDOM_SEED].asInt().value().toLong() + randomSeed = yaml[RANDOM_SEED].asInt().value().toLong(), + recreateDatabase = yaml[RECREATE_DATABASE].asBoolean().value() ) } } @@ -118,6 +120,7 @@ class Config(val agents: List, val traceSampling: TraceSamplin const val PARTITIONS = "partitions" const val NAME = "name" const val RANDOM_SEED = "randomSeed" + const val RECREATE_DATABASE = "recreateDatabase" const val RUN = "run" const val RUNS_PER_ITERATION = "runsPerIteration" const val TRACE = "trace" diff --git a/neo4j/Neo4jSimulation.kt b/neo4j/Neo4jSimulation.kt index c87e7f70e..334550bcc 100644 --- a/neo4j/Neo4jSimulation.kt +++ b/neo4j/Neo4jSimulation.kt @@ -36,8 +36,7 @@ abstract class Neo4jSimulation> protected constructor override fun init(randomSource: RandomSource) { val nativeDriver = client.unpack() - initDatabase(nativeDriver) - + if (context.recreateDatabase) initDatabase(nativeDriver) LOGGER.info("Neo4j initialisation of $name simulation data started ...") val start = Instant.now() initData(nativeDriver, randomSource) diff --git a/typedb/TypeDBSimulation.kt b/typedb/TypeDBSimulation.kt index 44223bb44..1ea1c44ae 100644 --- a/typedb/TypeDBSimulation.kt +++ b/typedb/TypeDBSimulation.kt @@ -38,8 +38,8 @@ abstract class TypeDBSimulation> protected constructo override fun init(randomSource: RandomSource) { val nativeClient = client.unpack() - initDatabase(nativeClient) - initSchema(nativeClient) + if (context.recreateDatabase) initDatabase(nativeClient) + if (context.recreateDatabase) initSchema(nativeClient) nativeClient.session(context.dbName, DATA).use { nativeSession -> LOGGER.info("TypeDB initialisation of $name simulation data started ...") val start = Instant.now() From 3b99dd86b0ca45defa37ecc2301d50da76226605 Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Thu, 16 Mar 2023 14:47:58 +0000 Subject: [PATCH 03/10] Parametrised database reinitialisation. --- neo4j/Neo4jSimulation.kt | 2 +- typedb/TypeDBSimulation.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/neo4j/Neo4jSimulation.kt b/neo4j/Neo4jSimulation.kt index 334550bcc..4b0370132 100644 --- a/neo4j/Neo4jSimulation.kt +++ b/neo4j/Neo4jSimulation.kt @@ -39,7 +39,7 @@ abstract class Neo4jSimulation> protected constructor if (context.recreateDatabase) initDatabase(nativeDriver) LOGGER.info("Neo4j initialisation of $name simulation data started ...") val start = Instant.now() - initData(nativeDriver, randomSource) + if (context.recreateDatabase) initData(nativeDriver, randomSource) LOGGER.info("Neo4j initialisation of $name simulation data ended in: {}", printDuration(start, Instant.now())) } diff --git a/typedb/TypeDBSimulation.kt b/typedb/TypeDBSimulation.kt index 1ea1c44ae..ce8ac91c1 100644 --- a/typedb/TypeDBSimulation.kt +++ b/typedb/TypeDBSimulation.kt @@ -43,7 +43,7 @@ abstract class TypeDBSimulation> protected constructo nativeClient.session(context.dbName, DATA).use { nativeSession -> LOGGER.info("TypeDB initialisation of $name simulation data started ...") val start = Instant.now() - initData(nativeSession, randomSource) + if (context.recreateDatabase) initData(nativeSession, randomSource) LOGGER.info("TypeDB initialisation of $name simulation data ended in: {}", printDuration(start, Instant.now())) } } From c84431380c3a38f4733624c63fd70316b409fca8 Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Fri, 17 Mar 2023 17:02:26 +0000 Subject: [PATCH 04/10] empty commit From 1ec3b9bb480c45571d2e03b92c25b1af006efedc Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Fri, 17 Mar 2023 17:20:01 +0000 Subject: [PATCH 05/10] Refactor for clarity. --- typedb/TypeDBSimulation.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/typedb/TypeDBSimulation.kt b/typedb/TypeDBSimulation.kt index ce8ac91c1..0d270e474 100644 --- a/typedb/TypeDBSimulation.kt +++ b/typedb/TypeDBSimulation.kt @@ -38,8 +38,10 @@ abstract class TypeDBSimulation> protected constructo override fun init(randomSource: RandomSource) { val nativeClient = client.unpack() - if (context.recreateDatabase) initDatabase(nativeClient) - if (context.recreateDatabase) initSchema(nativeClient) + if (context.recreateDatabase) { + initDatabase(nativeClient) + initSchema(nativeClient) + } nativeClient.session(context.dbName, DATA).use { nativeSession -> LOGGER.info("TypeDB initialisation of $name simulation data started ...") val start = Instant.now() From 1431728bfe93a2b8bff9618f9164eaa34758e6e6 Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Fri, 17 Mar 2023 17:31:20 +0000 Subject: [PATCH 06/10] Refactor. --- Simulation.kt | 2 +- neo4j/Neo4jSimulation.kt | 4 ++-- typedb/TypeDBSimulation.kt | 8 +++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Simulation.kt b/Simulation.kt index 76e566c7a..e7a8039b4 100644 --- a/Simulation.kt +++ b/Simulation.kt @@ -36,7 +36,7 @@ abstract class Simulation, out CONTEXT: Context<*, *>>( protected abstract val name: String fun init() { - init(randomSource.nextSource()) + if (context.recreateDatabase) init(randomSource.nextSource()) } abstract fun init(randomSource: RandomSource) diff --git a/neo4j/Neo4jSimulation.kt b/neo4j/Neo4jSimulation.kt index 4b0370132..c4971d72d 100644 --- a/neo4j/Neo4jSimulation.kt +++ b/neo4j/Neo4jSimulation.kt @@ -36,10 +36,10 @@ abstract class Neo4jSimulation> protected constructor override fun init(randomSource: RandomSource) { val nativeDriver = client.unpack() - if (context.recreateDatabase) initDatabase(nativeDriver) + initDatabase(nativeDriver) LOGGER.info("Neo4j initialisation of $name simulation data started ...") val start = Instant.now() - if (context.recreateDatabase) initData(nativeDriver, randomSource) + initData(nativeDriver, randomSource) LOGGER.info("Neo4j initialisation of $name simulation data ended in: {}", printDuration(start, Instant.now())) } diff --git a/typedb/TypeDBSimulation.kt b/typedb/TypeDBSimulation.kt index 0d270e474..44223bb44 100644 --- a/typedb/TypeDBSimulation.kt +++ b/typedb/TypeDBSimulation.kt @@ -38,14 +38,12 @@ abstract class TypeDBSimulation> protected constructo override fun init(randomSource: RandomSource) { val nativeClient = client.unpack() - if (context.recreateDatabase) { - initDatabase(nativeClient) - initSchema(nativeClient) - } + initDatabase(nativeClient) + initSchema(nativeClient) nativeClient.session(context.dbName, DATA).use { nativeSession -> LOGGER.info("TypeDB initialisation of $name simulation data started ...") val start = Instant.now() - if (context.recreateDatabase) initData(nativeSession, randomSource) + initData(nativeSession, randomSource) LOGGER.info("TypeDB initialisation of $name simulation data ended in: {}", printDuration(start, Instant.now())) } } From ae0151206c1eaee7d0d7405b47a756513b15edcb Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Fri, 17 Mar 2023 19:17:11 +0000 Subject: [PATCH 07/10] Fix to ensure determinism. --- Simulation.kt | 1 + common/seed/RandomSource.kt | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Simulation.kt b/Simulation.kt index e7a8039b4..6bdd2f0b9 100644 --- a/Simulation.kt +++ b/Simulation.kt @@ -37,6 +37,7 @@ abstract class Simulation, out CONTEXT: Context<*, *>>( fun init() { if (context.recreateDatabase) init(randomSource.nextSource()) + else randomSource.increment() } abstract fun init(randomSource: RandomSource) diff --git a/common/seed/RandomSource.kt b/common/seed/RandomSource.kt index a8f9b9e5c..b3cbf7829 100644 --- a/common/seed/RandomSource.kt +++ b/common/seed/RandomSource.kt @@ -21,6 +21,10 @@ import java.util.Random class RandomSource(seed: Long) { private val random = Random(seed) + fun increment() { + random.nextBoolean() + } + fun nextSource(): RandomSource { return RandomSource(random.nextLong()) } From 609054904db385820f63fc8f84925bd40a13ac72 Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Fri, 17 Mar 2023 20:50:43 +0000 Subject: [PATCH 08/10] Fix to ensure determinism. --- Agent.kt | 2 +- Simulation.kt | 4 ++-- common/seed/RandomSource.kt | 4 ---- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Agent.kt b/Agent.kt index cf506f0dc..268a93578 100644 --- a/Agent.kt +++ b/Agent.kt @@ -51,7 +51,7 @@ abstract class Agent> prot fun run(session: SESSION, partition: PARTITION, random: RandomSource): List { return actionHandlers[action]?.let { - (0 until runsPerIteration).flatMap { it(session, partition, random) } + (0 until runsPerIteration).flatMap { it(session, partition, random.nextSource()) } } ?: throw IllegalArgumentException("The action '$action' has no registered handler in '${javaClass.simpleName}'" + if (action == DEFAULT_ACTION) " (help: '$action' is the default action)" else "") } diff --git a/Simulation.kt b/Simulation.kt index 6bdd2f0b9..845f05c25 100644 --- a/Simulation.kt +++ b/Simulation.kt @@ -36,8 +36,8 @@ abstract class Simulation, out CONTEXT: Context<*, *>>( protected abstract val name: String fun init() { - if (context.recreateDatabase) init(randomSource.nextSource()) - else randomSource.increment() + val randomSource2 = randomSource.nextSource() + if (context.recreateDatabase) init(randomSource2) } abstract fun init(randomSource: RandomSource) diff --git a/common/seed/RandomSource.kt b/common/seed/RandomSource.kt index b3cbf7829..a8f9b9e5c 100644 --- a/common/seed/RandomSource.kt +++ b/common/seed/RandomSource.kt @@ -21,10 +21,6 @@ import java.util.Random class RandomSource(seed: Long) { private val random = Random(seed) - fun increment() { - random.nextBoolean() - } - fun nextSource(): RandomSource { return RandomSource(random.nextLong()) } From 400fd95d569a730947b4a111539ed5f9dbde5f39 Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Mon, 27 Mar 2023 11:45:19 +0100 Subject: [PATCH 09/10] Removed redundant random sources. --- Agent.kt | 9 ++++----- Simulation.kt | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Agent.kt b/Agent.kt index 268a93578..368577cc9 100644 --- a/Agent.kt +++ b/Agent.kt @@ -60,16 +60,15 @@ abstract class Agent> prot return context.isTracing && this.tracingEnabled } - fun iterate(randomSrc: RandomSource): Map> { + fun iterate(randomSource: RandomSource): Map> { val reports = ConcurrentHashMap>() // We need to generate pairs of Partition and Random deterministically before passing them to a parallel stream if (context.partitionCount > partitions.size) throw IllegalArgumentException("Partition count exceeds supplied number of partitions.") val validPartitions = partitions.subList(0, context.partitionCount) val asyncRuns = validPartitions.map { partition -> - val randomSrc2 = randomSrc.nextSource() CompletableFuture.runAsync( { - val report = runAndMayTrace(partition, randomSrc2) + val report = runAndMayTrace(partition, randomSource) if (context.isReporting) reports[partition.tracker] = report else assert(report.isEmpty()) }, context.executor ) @@ -78,13 +77,13 @@ abstract class Agent> prot return reports } - private fun runAndMayTrace(partition: PARTITION, random: RandomSource): List { + private fun runAndMayTrace(partition: PARTITION, randomSource: RandomSource): List { var tracingCtx: FactoryTracingThreadStatic.ThreadContext? = null return try { if (shouldTrace()) tracingCtx = FactoryTracingThreadStatic.contextOnThread(partition.tracker, context.iterationNumber) val session = client.session(partition) - mayTrace(className(agentClass)) { run(session, partition, random) } + mayTrace(className(agentClass)) { run(session, partition, randomSource) } } finally { tracingCtx?.close() } diff --git a/Simulation.kt b/Simulation.kt index 845f05c25..6443686ce 100644 --- a/Simulation.kt +++ b/Simulation.kt @@ -77,7 +77,7 @@ abstract class Simulation, out CONTEXT: Context<*, *>>( val agents = initAgents() agents.forEach { agent -> val start = Instant.now() - val reports = agent.iterate(randomSource.nextSource()) + val reports = agent.iterate(randomSource) LOGGER.info("{}.{} × {} took: {}", agent.javaClass.simpleName, agent.action, agent.runsPerIteration, printDuration(start, Instant.now())) agentReports[agent.javaClass.superclass.simpleName] = reports } From 0a532598e870d14ec497ff82da9bca1b1254f095 Mon Sep 17 00:00:00 2001 From: James Whiteside Date: Mon, 27 Mar 2023 16:02:05 +0100 Subject: [PATCH 10/10] Added comment. --- Simulation.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Simulation.kt b/Simulation.kt index 6443686ce..d7c7001a2 100644 --- a/Simulation.kt +++ b/Simulation.kt @@ -36,6 +36,10 @@ abstract class Simulation, out CONTEXT: Context<*, *>>( protected abstract val name: String fun init() { + // The master random source is incremented regardless of whether the database is recreated or not to ensure determinism. + // The potentially redundant randomSource2 has to be created in this way for it to work. + // Please refer to: https://github.com/vaticle/typedb-simulation/issues/145 + val randomSource2 = randomSource.nextSource() if (context.recreateDatabase) init(randomSource2) }