From 86c4dfd9669e168d7203339fbc59682bd15de7aa Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Wed, 30 Nov 2022 11:17:10 -0600
Subject: [PATCH 01/19] partial fixes for nosqlbench-797 Race condition between
exceptional activity shutdown and normal scenario shutdown.
---
...sync_activity-Lifecycle_of_an_activity.svg | 236 ++++++++++++++++++
devdocs/concurrency/async_activity.puml | 105 ++++++++
...-Lifecycle_of_a_single_scenario_call__.svg | 160 ++++++++++++
devdocs/concurrency/async_scenario.puml | 67 +++++
...async_scenarios-Lifecycle_of_Scenarios.svg | 150 +++++++++++
devdocs/concurrency/async_scenarios.puml | 62 +++++
.../engine/api/activityapi/core/RunState.java | 98 ++++----
.../java/io/nosqlbench/engine/cli/NBCLI.java | 6 +-
.../lifecycle/ActivityExceptionHandler.java | 4 +-
.../core/lifecycle/ActivityFinisher.java | 4 +-
.../engine/core/lifecycle/ActivityStatus.java | 20 ++
...cutor.java => ActivityThreadsManager.java} | 180 ++++++-------
...arioResult.java => ExecMetricsResult.java} | 67 +----
.../engine/core/lifecycle/ExecResult.java | 68 +++++
.../core/lifecycle/ScenarioController.java | 67 ++---
.../core/lifecycle/ScenariosResults.java | 21 +-
.../core/lifecycle/StartedActivityInfo.java | 29 +++
.../engine/core/script/Scenario.java | 61 +++--
.../engine/core/script/ScenariosExecutor.java | 24 +-
...t.java => ActivityThreadsManagerTest.java} | 12 +-
.../resources/ScenarioExecutorEndpoint.java | 6 +-
.../engine/rest/transfertypes/ResultView.java | 6 +-
.../nbr/examples/ScriptExampleTests.java | 50 ++--
.../examples/SpeedCheckIntegrationTests.java | 6 +-
.../testing/ExitStatusIntegrationTests.java | 28 +--
25 files changed, 1184 insertions(+), 353 deletions(-)
create mode 100644 devdocs/concurrency/async_activity-Lifecycle_of_an_activity.svg
create mode 100644 devdocs/concurrency/async_activity.puml
create mode 100644 devdocs/concurrency/async_scenario-Lifecycle_of_a_single_scenario_call__.svg
create mode 100644 devdocs/concurrency/async_scenario.puml
create mode 100644 devdocs/concurrency/async_scenarios-Lifecycle_of_Scenarios.svg
create mode 100644 devdocs/concurrency/async_scenarios.puml
create mode 100644 engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityStatus.java
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ActivityExecutor.java => ActivityThreadsManager.java} (77%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ScenarioResult.java => ExecMetricsResult.java} (68%)
create mode 100644 engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecResult.java
create mode 100644 engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/StartedActivityInfo.java
rename engine-core/src/test/java/io/nosqlbench/engine/core/{ActivityExecutorTest.java => ActivityThreadsManagerTest.java} (94%)
diff --git a/devdocs/concurrency/async_activity-Lifecycle_of_an_activity.svg b/devdocs/concurrency/async_activity-Lifecycle_of_an_activity.svg
new file mode 100644
index 000000000..e159d5c6d
--- /dev/null
+++ b/devdocs/concurrency/async_activity-Lifecycle_of_an_activity.svg
@@ -0,0 +1,236 @@
+
+
+
diff --git a/devdocs/concurrency/async_activity.puml b/devdocs/concurrency/async_activity.puml
new file mode 100644
index 000000000..cb276a443
--- /dev/null
+++ b/devdocs/concurrency/async_activity.puml
@@ -0,0 +1,105 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+title: Lifecycle of an activity
+
+control caller as caller
+control ActivityExecutor as ae
+control "Activity\nException\nHandler" as aeh
+control "Activity\nThread\nFactory" as atf
+control ExecutorService as aes
+control Annotator as ann
+control Activity as activity
+
+== startup sequence ==
+caller -> ae**: create
+ ae -> aeh**: create
+ ae -> atf**: create(\w Exception Handler)
+ aeh -> atf:
+ ae -> aes**: create(\w Thread Factory)
+ atf -> aes:
+
+caller -> ae: startActivity()
+activate ae
+ ae -> ann: Annotate Activity Start
+
+ ae -> activity: initActivity()
+ activate activity
+ ae <- activity
+ deactivate activity
+
+ note over ae,aes: align threadcount as explained below
+
+caller <- ae
+deactivate ae
+
+== dynamic threadcount update ==
+note over ae, aes: threads can be changed dynamically
+
+caller -> ae: apply params
+activate ae
+ ae->ae: align motor count
+ ae->aes: stop extra motors
+ ae->aes:
+ group for each new thread/motor
+ ae -> aes: execute()
+ activate aes
+ aes -> atf: get()
+ atf -> thread**: create
+ activate atf
+ aes <- atf:
+ deactivate atf
+ aes --> thread: run()
+ note over ann, thread: At this point, the\nmotor thread starts running\nthe defined activity's action\nover cycles
+ ae->ae: await thread state update
+
+ ae<-aes:
+ deactivate aes
+ end group
+caller <- ae
+deactivate ae
+
+== shutdown sequence [after startup] ==
+
+caller -> ae: stopActivity()
+activate ae
+
+ ae -> ae: request stop motors
+ ae -> ae: await all stop
+
+ ae -> activity: shutdownActivity()
+ activate activity
+ ae <- activity
+ deactivate activity
+
+ ae -> ann: Annotate Activity Finish
+
+caller <- ae
+deactivate ae
+
+== on exception in motor thread ==
+thread -> aeh: catch()
+aeh -> ae: notifyException\n(,)
+activate ae
+ ae -> ae: save exception
+ ae -> ae: forceStopActivity()
+ ae -> aes: shutdown();
+ activate aes
+ ae <- aes:
+ deactivate aes
+
+ group if needed [after timeout]]
+ ae -> aes: shutdownNow();
+ activate aes
+ ae <- aes
+ deactivate aes
+ end group
+
+ ae -> activity: shutdownActivity();
+ ae -> activity: closeAutoCloseables();
+
+ note over thread: action\nthread\nterminates
+ destroy thread
+deactivate ae
+
+
+@enduml
diff --git a/devdocs/concurrency/async_scenario-Lifecycle_of_a_single_scenario_call__.svg b/devdocs/concurrency/async_scenario-Lifecycle_of_a_single_scenario_call__.svg
new file mode 100644
index 000000000..3bb291402
--- /dev/null
+++ b/devdocs/concurrency/async_scenario-Lifecycle_of_a_single_scenario_call__.svg
@@ -0,0 +1,160 @@
+
+
+
diff --git a/devdocs/concurrency/async_scenario.puml b/devdocs/concurrency/async_scenario.puml
new file mode 100644
index 000000000..eee38edf1
--- /dev/null
+++ b/devdocs/concurrency/async_scenario.puml
@@ -0,0 +1,67 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+
+title Lifecycle of a single scenario.call()
+control "caller" as c
+control "Scenario" as s
+control "Scenario\nController" as sc
+control "Scripting\nEngine" as engine
+control "Activity\nExecutor" as ae
+control "Java\nRuntime" as jrt
+control "Shutdown\nHook" as sh
+control "Annotations" as ann
+
+c -> s**: create
+
+c -> s: call()
+activate s
+
+ s -> sh**: create
+ s -> jrt: register(ShutdownHook)
+ s -> ann: Annotate Scenario Start
+
+ s -> sc**: create
+ s -> engine**: create
+
+ s -> engine: run(script)
+ activate engine
+ group async calls [javacript+Java]
+ engine <--> sc: scenario.(*)
+ engine <--> sc: activities.(*)
+ engine <--> sc: metrics.(*)
+ engine <--> sc: params.(*)
+ engine -> sc: start()
+ activate sc
+ sc -> ae**: create
+ sc -> ae: startActivity()
+
+ deactivate sc
+ end group
+ s <- engine: result
+ deactivate engine
+
+ s -> sc: awaitCompletion()
+ activate sc
+ group for each activity
+ sc -> ae: awaitCompletion()
+ activate ae
+ sc <- ae
+ deactivate ae
+ end group
+
+ s <- sc
+ deactivate sc
+
+ s -> jrt: unregister(ShutdownHook)
+ s -> sh: run()
+ sh -> ann: Annotate Scenario Finish
+
+c <- s: Scenario\nResult
+deactivate s
+
+== on exception during call() ==
+ jrt -> sh: run()
+ sh -> ann: Annotate Scenario Finish
+
+
+@enduml
diff --git a/devdocs/concurrency/async_scenarios-Lifecycle_of_Scenarios.svg b/devdocs/concurrency/async_scenarios-Lifecycle_of_Scenarios.svg
new file mode 100644
index 000000000..b482fb579
--- /dev/null
+++ b/devdocs/concurrency/async_scenarios-Lifecycle_of_Scenarios.svg
@@ -0,0 +1,150 @@
+
+
+
diff --git a/devdocs/concurrency/async_scenarios.puml b/devdocs/concurrency/async_scenarios.puml
new file mode 100644
index 000000000..89410edd7
--- /dev/null
+++ b/devdocs/concurrency/async_scenarios.puml
@@ -0,0 +1,62 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+
+title Lifecycle of Scenarios
+
+control "NBCLI" as nbcli
+control "Scenario" as s
+control "Scenario\nController" as sc
+control "Scenarios\nExecutor" as se
+control "Exception\nHandler" as seh
+control "Thread\nFactory" as stf
+control "Executor\nService" as ses
+
+nbcli -> se** : create
+ se -> seh** : create
+ se -> stf** : create ThreadFactory\n(w/ ExceptionHandler)
+ se -> ses** : create ExecutorService\n(w/ ThreadFactory)
+
+nbcli -> s** : create
+ s -> sc** : create
+nbcli --> se : execute(Scenario)
+se --> ses: submit( Scenario)
+activate ses
+ ses -> future**: create
+se <-- ses: >
+deactivate ses
+
+== [async] on thread from thread factory ==
+ses -> stf: get()
+ stf -> thread**: create
+ses <- stf:
+ses -> thread: run task
+activate thread
+thread -> s: call()
+activate s
+thread <- s: ScenarioResult
+deactivate s
+thread -> future: result
+deactivate thread
+
+== [async] on NBCLI thread ==
+
+nbcli -> se: awaitAllResults();
+activate se
+ se -> ses: shutdown
+ loop timeout
+ se -> ses: awaitTermination(timeout)
+ activate ses
+ se <- ses
+ deactivate ses
+ end loop
+ loop each future
+ se -> future: get()
+ activate future
+ se <- future: ScenarioResult
+ deactivate future
+ end loop
+
+nbcli <- se:
+deactivate se
+
+@enduml
diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/RunState.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/RunState.java
index b78b8a247..15ca92a96 100644
--- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/RunState.java
+++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/RunState.java
@@ -18,18 +18,36 @@ package io.nosqlbench.engine.api.activityapi.core;
public enum RunState {
- // Initial state after creation of this control
+
+ /**
+ * Initial state after creation of this control
+ */
Uninitialized("i⌀"),
- // This thread has been queued to run, but hasn't signaled yet that it is full started
- // This must be set by the executor before executing the slot runnable
+
+ /**
+ * This thread has been queued to run, but hasn't signaled yet that it is full started
+ * This must be set by the executor before executing the slot runnable
+ */
Starting("s⏫"),
- // This thread is running. This should only be set by the controlled thread
+
+ /**
+ * This thread is running. This should only be set by the controlled thread
+ */
Running("R\u23F5"),
- // This thread has completed all of its activity, and will do no further work without new input
+
+ /**
+ * This thread has completed all of its activity, and will do no further work without new input
+ */
Finished("F⏯"),
- // The thread has been requested to stop. This says nothing of the internal state.
+
+ /**
+ * The thread has been requested to stop. This says nothing of the internal state.
+ */
Stopping("s⏬"),
- // The thread has stopped. This should only be set by the controlled thread
+
+ /**
+ * The thread has stopped. This should only be set by the controlled thread
+ */
Stopped("_\u23F9");
private final String runcode;
@@ -42,53 +60,25 @@ public enum RunState {
return this.runcode;
}
- public boolean canTransitionTo(RunState to) {
- switch (this) {
- default:
- return false;
- case Uninitialized: // A motor was just created. This is its initial state.
- case Stopped:
- switch (to) {
- case Starting: // a motor has been reserved for an execution command
- return true;
- default:
- return false;
- }
- case Starting:
- switch (to) {
- case Running: // a motor has indicated that is in the run() method
- case Finished: // a motor has exhausted its input, and has declined to go into started mode
- return true;
- default:
- return false;
- }
- case Running:
- switch (to) {
- case Stopping: // A request was made to stop the motor before it finished
- case Finished: // A motor has exhausted its input, and is finished with its work
- return true;
- default:
- return false;
- }
- case Stopping:
- switch (to) {
- case Stopped: // A motor was stopped by request before exhausting input
- return true;
- default:
- return false;
- }// A motor was restarted after being stopped
- case Finished:
- switch (to) {
- case Running: // A motor was restarted?
- return true;
- // not useful as of yet.
- // Perhaps this will be allowed via explicit reset of input stream.
- // If the input isn't reset, then trying to start a finished motor
- // will cause it to short-circuit back to Finished state.
- default:
- return false;
- }
- }
+ /**
+ * @param target The target state
+ * @return true if the current state is allowed to transition to the target state
+ */
+ public boolean canTransitionTo(RunState target) {
+ return switch (this) {
+ default -> false; // A motor was just created. This is its initial state.
+ case Uninitialized, Stopped -> (target == Starting);
+ case Starting -> switch (target) { // a motor has indicated that is in the run() method
+ case Running, Finished -> true;// a motor has exhausted its input, and has declined to go into started mode
+ default -> false;
+ };
+ case Running -> switch (target) { // A request was made to stop the motor before it finished
+ case Stopping, Finished -> true;// A motor has exhausted its input, and is finished with its work
+ default -> false;
+ };
+ case Stopping -> (target == Stopped); // A motor was stopped by request before exhausting input
+ case Finished -> (target == Running); // A motor was restarted?
+ };
}
diff --git a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java
index 1111d4507..08df6ddc6 100644
--- a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java
+++ b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java
@@ -418,7 +418,7 @@ public class NBCLI implements Function {
// intentionally not shown for warn-only
logger.info("console logging level is " + options.getConsoleLogLevel());
- ScenariosExecutor executor = new ScenariosExecutor("executor-" + sessionName, 1);
+ ScenariosExecutor scenariosExecutor = new ScenariosExecutor("executor-" + sessionName, 1);
if (options.getConsoleLogLevel().isGreaterOrEqualTo(NBLogLevel.WARN)) {
options.setWantsStackTraces(true);
logger.debug("enabling stack traces since log level is " + options.getConsoleLogLevel());
@@ -466,7 +466,7 @@ public class NBCLI implements Function {
scriptParams.putAll(buffer.getCombinedParams());
scenario.addScenarioScriptParams(scriptParams);
- executor.execute(scenario);
+ scenariosExecutor.execute(scenario);
// while (true) {
// Optional pendingResult = executor.getPendingResult(scenario.getScenarioName());
@@ -476,7 +476,7 @@ public class NBCLI implements Function {
// LockSupport.parkNanos(100000000L);
// }
- ScenariosResults scenariosResults = executor.awaitAllResults();
+ ScenariosResults scenariosResults = scenariosExecutor.awaitAllResults();
logger.debug("Total of " + scenariosResults.getSize() + " result object returned from ScenariosExecutor");
ActivityMetrics.closeMetrics(options.wantsEnableChart());
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExceptionHandler.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExceptionHandler.java
index 5beb7643a..b088829f3 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExceptionHandler.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExceptionHandler.java
@@ -23,9 +23,9 @@ public class ActivityExceptionHandler implements Thread.UncaughtExceptionHandler
private static final Logger logger = LogManager.getLogger(ActivityExceptionHandler.class);
- private final ActivityExecutor executor;
+ private final ActivityThreadsManager executor;
- public ActivityExceptionHandler(ActivityExecutor executor) {
+ public ActivityExceptionHandler(ActivityThreadsManager executor) {
this.executor = executor;
logger.debug(() -> "Activity exception handler starting up for executor '" + executor + "'");
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityFinisher.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityFinisher.java
index 845f7c272..5b8588d80 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityFinisher.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityFinisher.java
@@ -22,11 +22,11 @@ import org.apache.logging.log4j.Logger;
public class ActivityFinisher extends Thread {
private final static Logger logger = LogManager.getLogger(ActivityFinisher.class);
- private final ActivityExecutor executor;
+ private final ActivityThreadsManager executor;
private final int timeout;
private boolean result;
- public ActivityFinisher(ActivityExecutor executor, int timeout) {
+ public ActivityFinisher(ActivityThreadsManager executor, int timeout) {
super(executor.getActivityDef().getAlias() + "_finisher");
this.executor = executor;
this.timeout = timeout;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityStatus.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityStatus.java
new file mode 100644
index 000000000..d77927fbc
--- /dev/null
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityStatus.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.core.lifecycle;
+
+public class ActivityStatus {
+}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExecutor.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityThreadsManager.java
similarity index 77%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExecutor.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityThreadsManager.java
index 2ca5bfd71..afc53094e 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExecutor.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityThreadsManager.java
@@ -26,11 +26,10 @@ import io.nosqlbench.engine.core.annotation.Annotators;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import java.util.*;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.*;
import java.util.stream.Collectors;
/**
@@ -49,9 +48,9 @@ import java.util.stream.Collectors;
*
*/
-public class ActivityExecutor implements ActivityController, ParameterMap.Listener, ProgressCapable {
+public class ActivityThreadsManager implements ActivityController, ParameterMap.Listener, ProgressCapable, Callable {
- private static final Logger logger = LogManager.getLogger(ActivityExecutor.class);
+ private static final Logger logger = LogManager.getLogger(ActivityThreadsManager.class);
private static final Logger activitylogger = LogManager.getLogger("ACTIVITY");
private final List> motors = new ArrayList<>();
@@ -68,25 +67,20 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
// private RunState intendedState = RunState.Uninitialized;
- public ActivityExecutor(Activity activity, String sessionId) {
+ public ActivityThreadsManager(Activity activity, String sessionId) {
this.activity = activity;
this.activityDef = activity.getActivityDef();
executorService = new ThreadPoolExecutor(
- 0, Integer.MAX_VALUE,
- 0L, TimeUnit.SECONDS,
- new SynchronousQueue<>(),
- new IndexedThreadFactory(activity.getAlias(), new ActivityExceptionHandler(this))
+ 0, Integer.MAX_VALUE,
+ 0L, TimeUnit.SECONDS,
+ new SynchronousQueue<>(),
+ new IndexedThreadFactory(activity.getAlias(), new ActivityExceptionHandler(this))
);
activity.getActivityDef().getParams().addListener(this);
activity.setActivityController(this);
this.sessionId = sessionId;
}
- public void setSessionId(String sessionId) {
- this.sessionId = sessionId;
- }
-
-
// TODO: Doc how uninitialized activities do not propagate parameter map changes and how
// TODO: this is different from preventing modification to uninitialized activities
@@ -101,14 +95,14 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
public synchronized void startActivity() {
logger.info("starting activity " + activity.getAlias() + " for cycles " + activity.getCycleSummary());
Annotators.recordAnnotation(Annotation.newBuilder()
- .session(sessionId)
- .now()
- .layer(Layer.Activity)
- .label("alias", getActivityDef().getAlias())
- .label("driver", getActivityDef().getActivityType())
- .label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
- .detail("params", getActivityDef().toString())
- .build()
+ .session(sessionId)
+ .now()
+ .layer(Layer.Activity)
+ .label("alias", getActivityDef().getAlias())
+ .label("driver", getActivityDef().getActivityType())
+ .label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
+ .detail("params", getActivityDef().toString())
+ .build()
);
activitylogger.debug("START/before alias=(" + activity.getAlias() + ")");
@@ -130,7 +124,7 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
/**
* Simply stop the motors
*/
- public synchronized void stopActivity() {
+ private synchronized void stopActivity() {
activitylogger.debug("STOP/before alias=(" + activity.getAlias() + ")");
activity.setRunState(RunState.Stopping);
@@ -142,19 +136,20 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
activity.setRunState(RunState.Stopped);
logger.info("stopped: " + this.getActivityDef().getAlias() + " with " + motors.size() + " slots");
activitylogger.debug("STOP/after alias=(" + activity.getAlias() + ")");
+
Annotators.recordAnnotation(Annotation.newBuilder()
- .session(sessionId)
- .interval(this.startedAt, this.stoppedAt)
- .layer(Layer.Activity)
- .label("alias", getActivityDef().getAlias())
- .label("driver", getActivityDef().getActivityType())
- .label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
- .detail("params", getActivityDef().toString())
- .build()
+ .session(sessionId)
+ .interval(this.startedAt, this.stoppedAt)
+ .layer(Layer.Activity)
+ .label("alias", getActivityDef().getAlias())
+ .label("driver", getActivityDef().getActivityType())
+ .label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
+ .detail("params", getActivityDef().toString())
+ .build()
);
}
- public synchronized RuntimeException forceStopScenario(int initialMillisToWait) {
+ public RuntimeException forceStopActivity(int initialMillisToWait) {
activitylogger.debug("FORCE STOP/before alias=(" + activity.getAlias() + ")");
activity.setRunState(RunState.Stopped);
@@ -206,14 +201,14 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
* @param initialMillisToWait milliseconds to wait after graceful shutdownActivity request, before forcing
* everything to stop
*/
- public synchronized void forceStopScenarioAndThrow(int initialMillisToWait, boolean rethrow) {
- RuntimeException exception = forceStopScenario(initialMillisToWait);
+ private synchronized void forceStopScenarioAndThrow(int initialMillisToWait, boolean rethrow) {
+ RuntimeException exception = forceStopActivity(initialMillisToWait);
if (exception != null && rethrow) {
throw exception;
}
}
- public boolean finishAndShutdownExecutor(int secondsToWait) {
+ private boolean finishAndShutdownExecutor(int secondsToWait) {
activitylogger.debug("REQUEST STOP/before alias=(" + activity.getAlias() + ")");
logger.debug("Stopping executor for " + activity.getAlias() + " when work completes.");
@@ -245,6 +240,7 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
if (stoppingException != null) {
logger.trace(() -> "an exception caused the activity to stop:" + stoppingException.getMessage());
+ logger.trace("Setting ERROR on activity executor: " + stoppingException.getMessage());
throw stoppingException;
}
@@ -270,10 +266,10 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
adjustToActivityDef(activity.getActivityDef());
}
motors.stream()
- .filter(m -> (m instanceof ActivityDefObserver))
+ .filter(m -> (m instanceof ActivityDefObserver))
// .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Uninitialized)
// .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Starting)
- .forEach(m -> ((ActivityDefObserver) m).onActivityDefUpdate(activityDef));
+ .forEach(m -> ((ActivityDefObserver) m).onActivityDefUpdate(activityDef));
}
}
@@ -288,25 +284,25 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
*
* TODO: move activity finisher thread to this class and remove separate implementation
*/
- public boolean awaitCompletion(int waitTime) {
- logger.debug(()-> "awaiting completion of '" + this.getActivity().getAlias() + "'");
+ private boolean awaitCompletion(int waitTime) {
+ logger.debug(() -> "awaiting completion of '" + this.getActivity().getAlias() + "'");
boolean finished = finishAndShutdownExecutor(waitTime);
Annotators.recordAnnotation(Annotation.newBuilder()
- .session(sessionId)
- .interval(startedAt, this.stoppedAt)
- .layer(Layer.Activity)
- .label("alias", getActivityDef().getAlias())
- .label("driver", getActivityDef().getActivityType())
- .label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
- .detail("params", getActivityDef().toString())
- .build()
+ .session(sessionId)
+ .interval(startedAt, this.stoppedAt)
+ .layer(Layer.Activity)
+ .label("alias", getActivityDef().getAlias())
+ .label("driver", getActivityDef().getActivityType())
+ .label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
+ .detail("params", getActivityDef().toString())
+ .build()
);
return finished;
}
- public boolean awaitFinish(int timeout) {
+ public boolean awaitFinishedOrStopped(int timeout) {
activitylogger.debug("AWAIT-FINISH/before alias=(" + activity.getAlias() + ")");
boolean awaited = awaitAllRequiredMotorState(timeout, 50, RunState.Finished, RunState.Stopped);
@@ -327,8 +323,8 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
private String getSlotStatus() {
return motors.stream()
- .map(m -> m.getSlotStateTracker().getSlotState().getCode())
- .collect(Collectors.joining(",", "[", "]"));
+ .map(m -> m.getSlotStateTracker().getSlotState().getCode())
+ .collect(Collectors.joining(",", "[", "]"));
}
/**
@@ -371,18 +367,18 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
case Running:
case Starting:
motors.stream()
- .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Running)
- .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Finished)
- .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Starting)
- .forEach(m -> {
- m.getSlotStateTracker().enterState(RunState.Starting);
- executorService.execute(m);
- });
+ .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Running)
+ .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Finished)
+ .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Starting)
+ .forEach(m -> {
+ m.getSlotStateTracker().enterState(RunState.Starting);
+ executorService.execute(m);
+ });
break;
case Stopped:
motors.stream()
- .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Stopped)
- .forEach(Motor::requestStop);
+ .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Stopped)
+ .forEach(Motor::requestStop);
break;
case Finished:
case Stopping:
@@ -421,31 +417,23 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
* Await a thread (aka motor/slot) entering a specific SlotState
*
* @param m motor instance
- * @param waitTime milliseco`nds to wait, total
+ * @param waitTime milliseconds to wait, total
* @param pollTime polling interval between state checks
* @param desiredRunStates any desired SlotState
* @return true, if the desired SlotState was detected
*/
- private boolean awaitMotorState(Motor m, int waitTime, int pollTime, RunState... desiredRunStates) {
+ private boolean awaitMotorState(Motor> m, int waitTime, int pollTime, RunState... desiredRunStates) {
long startedAt = System.currentTimeMillis();
while (System.currentTimeMillis() < (startedAt + waitTime)) {
- Map actualStates = new HashMap<>();
- for (RunState state : desiredRunStates) {
- actualStates.compute(state, (k, v) -> (v == null ? 0 : v) + 1);
- }
for (RunState desiredRunState : desiredRunStates) {
- actualStates.remove(desiredRunState);
- }
- logger.trace(() -> "state of remaining slots:" + actualStates);
- if (actualStates.size() == 0) {
- return true;
- } else {
- System.out.println("motor states:" + actualStates);
- try {
- Thread.sleep(pollTime);
- } catch (InterruptedException ignored) {
+ if (desiredRunState == m.getSlotStateTracker().getSlotState()) {
+ return true;
}
}
+ try {
+ Thread.sleep(pollTime);
+ } catch (InterruptedException ignored) {
+ }
}
logger.trace(() -> activityDef.getAlias() + "/Motor[" + m.getSlotId() + "] is now in state " + m.getSlotStateTracker().getSlotState());
return false;
@@ -461,7 +449,7 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
awaited = awaitMotorState(motor, waitTime, pollTime, awaitingState);
if (!awaited) {
logger.trace(() -> "failed awaiting motor " + motor.getSlotId() + " for state in " +
- Arrays.asList(awaitingState));
+ Arrays.asList(awaitingState));
break;
}
}
@@ -469,28 +457,6 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
return awaited;
}
-
- private boolean awaitAnyRequiredMotorState(int waitTime, int pollTime, RunState... awaitingState) {
- long startedAt = System.currentTimeMillis();
- while (System.currentTimeMillis() < (startedAt + waitTime)) {
- for (Motor motor : motors) {
- for (RunState state : awaitingState) {
- if (motor.getSlotStateTracker().getSlotState() == state) {
- logger.trace(() -> "at least one 'any' of " + activityDef.getAlias() + "/Motor[" + motor.getSlotId() + "] is now in state " + motor.getSlotStateTracker().getSlotState());
- return true;
- }
- }
- }
- try {
- Thread.sleep(pollTime);
- } catch (InterruptedException ignored) {
- }
- }
- logger.trace(() -> "none of " + activityDef.getAlias() + "/Motor [" + motors.size() + "] is in states in " + Arrays.asList(awaitingState));
- return false;
- }
-
-
/**
* Await a required thread (aka motor/slot) entering a specific SlotState
*
@@ -505,8 +471,8 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
boolean awaitedRequiredState = awaitMotorState(m, waitTime, pollTime, awaitingState);
if (!awaitedRequiredState) {
String error = "Unable to await " + activityDef.getAlias() +
- "/Motor[" + m.getSlotId() + "]: from state " + startingState + " to " + m.getSlotStateTracker().getSlotState()
- + " after waiting for " + waitTime + "ms";
+ "/Motor[" + m.getSlotId() + "]: from state " + startingState + " to " + m.getSlotStateTracker().getSlotState()
+ + " after waiting for " + waitTime + "ms";
RuntimeException e = new RuntimeException(error);
logger.error(error);
throw e;
@@ -532,7 +498,7 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
public synchronized void notifyException(Thread t, Throwable e) {
logger.debug(() -> "Uncaught exception in activity thread forwarded to activity executor: " + e.getMessage());
this.stoppingException = new RuntimeException("Error in activity thread " + t.getName(), e);
- forceStopScenario(10000);
+ forceStopActivity(10000);
}
@Override
@@ -564,4 +530,10 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
}
+ @Override
+ public synchronized ExecResult call() throws Exception {
+ boolean stopped = awaitCompletion(Integer.MAX_VALUE);
+ ExecResult result = new ExecResult(startedAt, stoppedAt, "", this.stoppingException);
+ return result;
+ }
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioResult.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecMetricsResult.java
similarity index 68%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioResult.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecMetricsResult.java
index 54bf4d007..f20b943b5 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioResult.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecMetricsResult.java
@@ -20,20 +20,16 @@ import com.codahale.metrics.*;
import io.nosqlbench.api.engine.metrics.ActivityMetrics;
import io.nosqlbench.engine.core.logging.Log4JMetricsReporter;
import io.nosqlbench.engine.core.metrics.NBMetricsSummary;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
-import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-public class ScenarioResult {
+public class ExecMetricsResult extends ExecResult {
- private final static Logger logger = LogManager.getLogger(ScenarioResult.class);
public static final Set INTERVAL_ONLY_METRICS = Set.of(
MetricAttribute.MIN,
MetricAttribute.MAX,
@@ -51,32 +47,12 @@ public class ScenarioResult {
MetricAttribute.M5_RATE,
MetricAttribute.M15_RATE
);
- private final long startedAt;
- private final long endedAt;
- private final Exception exception;
- private final String iolog;
-
- public ScenarioResult(Exception e, String iolog, long startedAt, long endedAt) {
- logger.debug("populating "+(e==null? "NORMAL" : "ERROR")+" scenario result");
- if (logger.isDebugEnabled()) {
- StackTraceElement[] st = Thread.currentThread().getStackTrace();
- for (int i = 0; i < st.length; i++) {
- logger.debug(":AT " + st[i].getFileName()+":"+st[i].getLineNumber()+":"+st[i].getMethodName());
- if (i>10) break;
- }
- }
- this.iolog = ((iolog!=null) ? iolog + "\n\n" : "") + (e!=null? e.getMessage() : "");
- this.startedAt = startedAt;
- this.endedAt = endedAt;
- this.exception = e;
+ public ExecMetricsResult(long startedAt, long endedAt, String iolog, Exception e) {
+ super(startedAt, endedAt, iolog, e);
}
- public void reportElapsedMillis() {
- logger.info("-- SCENARIO TOOK " + getElapsedMillis() + "ms --");
- }
-
- public String getSummaryReport() {
+ public String getMetricsSummary() {
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(os);
ConsoleReporter.Builder builder = ConsoleReporter.forRegistry(ActivityMetrics.getMetricRegistry())
@@ -91,45 +67,23 @@ public class ScenarioResult {
builder.disabledMetricAttributes(disabled);
ConsoleReporter consoleReporter = builder.build();
consoleReporter.report();
-
ps.flush();
+ consoleReporter.close();
String result = os.toString(StandardCharsets.UTF_8);
return result;
}
public void reportToConsole() {
- String summaryReport = getSummaryReport();
+ String summaryReport = getMetricsSummary();
System.out.println(summaryReport);
}
- public Optional getException() {
- return Optional.ofNullable(exception);
+ public void reportMetricsSummaryTo(PrintStream out) {
+ out.println(getMetricsSummary());
}
- public void rethrowIfError() {
- if (exception != null) {
- if (exception instanceof RuntimeException) {
- throw ((RuntimeException) exception);
- } else {
- throw new RuntimeException(exception);
- }
- }
- }
-
- public String getIOLog() {
- return this.iolog;
- }
-
- public long getElapsedMillis() {
- return endedAt - startedAt;
- }
-
- public void reportTo(PrintStream out) {
- out.println(getSummaryReport());
- }
-
- public void reportToLog() {
+ public void reportMetricsSummaryToLog() {
logger.debug("-- WARNING: Metrics which are taken per-interval (like histograms) will not have --");
logger.debug("-- active data on this last report. (The workload has already stopped.) Record --");
logger.debug("-- metrics to an external format to see values for each reporting interval. --");
@@ -142,10 +96,11 @@ public class ScenarioResult {
.outputTo(logger)
.build();
reporter.report();
+ reporter.close();
logger.debug("-- END METRICS DETAIL --");
}
- public void reportCountsTo(PrintStream printStream) {
+ public void reportMetricsCountsTo(PrintStream printStream) {
StringBuilder sb = new StringBuilder();
ActivityMetrics.getMetricRegistry().getMetrics().forEach((k, v) -> {
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecResult.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecResult.java
new file mode 100644
index 000000000..db1454143
--- /dev/null
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecResult.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.core.lifecycle;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Optional;
+
+/**
+ * Provide a result type back to a caller, including the start and end times,
+ * any exception that occurred, and any content written to stdout or stderr equivalent
+ * IO streams. This is an execution result.
+ *
+ */
+public class ExecResult {
+ protected final static Logger logger = LogManager.getLogger(ExecMetricsResult.class);
+ protected final long startedAt;
+ protected final long endedAt;
+ protected final Exception exception;
+ protected final String iolog;
+
+ public ExecResult(long startedAt, long endedAt, String iolog, Exception e) {
+ this.startedAt = startedAt;
+ this.endedAt = endedAt;
+ this.exception = e;
+ this.iolog = ((iolog != null) ? iolog + "\n\n" : "") + (e != null ? e.getMessage() : "");
+ logger.debug("populating "+(e==null? "NORMAL" : "ERROR")+" scenario result");
+ if (logger.isDebugEnabled()) {
+ StackTraceElement[] st = Thread.currentThread().getStackTrace();
+ for (int i = 0; i < st.length; i++) {
+ logger.debug(":AT " + st[i].getFileName()+":"+st[i].getLineNumber()+":"+st[i].getMethodName());
+ if (i>10) break;
+ }
+ }
+
+ }
+
+ public void reportElapsedMillisToLog() {
+ logger.info("-- SCENARIO TOOK " + getElapsedMillis() + "ms --");
+ }
+
+ public String getIOLog() {
+ return this.iolog;
+ }
+
+ public long getElapsedMillis() {
+ return endedAt - startedAt;
+ }
+
+ public Optional getException() {
+ return Optional.ofNullable(exception);
+ }
+}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioController.java
index 0bda67c11..99929eeb4 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioController.java
@@ -39,14 +39,15 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
- * A ScenarioController provides a way to start Activities, modify them while running, and forceStopMotors, pause or restart them.
+ * A ScenarioController provides a way to start Activities,
+ * modify them while running, and forceStopMotors, pause or restart them.
*/
public class ScenarioController {
private static final Logger logger = LogManager.getLogger(ScenarioController.class);
private static final Logger scenariologger = LogManager.getLogger("SCENARIO");
- private final Map activityExecutors = new ConcurrentHashMap<>();
+ private final Map activityExecutors = new ConcurrentHashMap<>();
private final String sessionId;
private final Maturity minMaturity;
@@ -72,10 +73,9 @@ public class ScenarioController {
.build());
- ActivityExecutor activityExecutor = getActivityExecutor(activityDef, true);
+ ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, true);
scenariologger.debug("START " + activityDef.getAlias());
- activityExecutor.startActivity();
-
+ activityThreadsManager.startActivity();
}
/**
@@ -120,12 +120,12 @@ public class ScenarioController {
.detail("params", activityDef.toString())
.build());
- ActivityExecutor activityExecutor = getActivityExecutor(activityDef, true);
+ ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, true);
scenariologger.debug("RUN alias=" + activityDef.getAlias());
scenariologger.debug(" (RUN/START) alias=" + activityDef.getAlias());
- activityExecutor.startActivity();
+ activityThreadsManager.startActivity();
scenariologger.debug(" (RUN/AWAIT before) alias=" + activityDef.getAlias());
- boolean completed = activityExecutor.awaitCompletion(timeout);
+ boolean completed = activityThreadsManager.awaitCompletion(timeout);
scenariologger.debug(" (RUN/AWAIT after) completed=" + activityDef.getAlias());
}
@@ -154,8 +154,8 @@ public class ScenarioController {
public boolean isRunningActivity(ActivityDef activityDef) {
- ActivityExecutor activityExecutor = getActivityExecutor(activityDef, false);
- return activityExecutor != null && activityExecutor.isRunning();
+ ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, false);
+ return activityThreadsManager != null && activityThreadsManager.isRunning();
}
public boolean isRunningActivity(Map activityDefMap) {
@@ -180,18 +180,18 @@ public class ScenarioController {
.detail("params", activityDef.toString())
.build());
- ActivityExecutor activityExecutor = getActivityExecutor(activityDef, false);
- if (activityExecutor == null) {
+ ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, false);
+ if (activityThreadsManager == null) {
throw new RuntimeException("could not stop missing activity:" + activityDef);
}
- RunState runstate = activityExecutor.getActivity().getRunState();
+ RunState runstate = activityThreadsManager.getActivity().getRunState();
if (runstate != RunState.Running) {
- logger.warn("NOT stopping activity '" + activityExecutor.getActivity().getAlias() + "' because it is in state '" + runstate + "'");
+ logger.warn("NOT stopping activity '" + activityThreadsManager.getActivity().getAlias() + "' because it is in state '" + runstate + "'");
return;
}
scenariologger.debug("STOP " + activityDef.getAlias());
- activityExecutor.stopActivity();
+ activityThreadsManager.stopActivity();
}
/**
@@ -240,8 +240,8 @@ public class ScenarioController {
if (param.equals("alias")) {
throw new InvalidParameterException("It is not allowed to change the name of an existing activity.");
}
- ActivityExecutor activityExecutor = getActivityExecutor(alias);
- ParameterMap params = activityExecutor.getActivityDef().getParams();
+ ActivityThreadsManager activityThreadsManager = getActivityExecutor(alias);
+ ParameterMap params = activityThreadsManager.getActivityDef().getParams();
scenariologger.debug("SET (" + alias + "/" + param + ")=(" + value + ")");
params.set(param, value);
}
@@ -261,7 +261,7 @@ public class ScenarioController {
throw new BasicError("alias must be provided");
}
- ActivityExecutor executor = activityExecutors.get(alias);
+ ActivityThreadsManager executor = activityExecutors.get(alias);
if (executor == null) {
logger.info("started scenario from apply:" + alias);
@@ -290,8 +290,8 @@ public class ScenarioController {
* @return the associated ActivityExecutor
* @throws RuntimeException a runtime exception if the named activity is not found
*/
- private ActivityExecutor getActivityExecutor(String activityAlias) {
- Optional executor =
+ private ActivityThreadsManager getActivityExecutor(String activityAlias) {
+ Optional executor =
Optional.ofNullable(activityExecutors.get(activityAlias));
return executor.orElseThrow(
() -> new RuntimeException("ActivityExecutor for alias " + activityAlias + " not found.")
@@ -315,9 +315,9 @@ public class ScenarioController {
return matching;
}
- private ActivityExecutor getActivityExecutor(ActivityDef activityDef, boolean createIfMissing) {
+ private ActivityThreadsManager getActivityExecutor(ActivityDef activityDef, boolean createIfMissing) {
synchronized (activityExecutors) {
- ActivityExecutor executor = activityExecutors.get(activityDef.getAlias());
+ ActivityThreadsManager executor = activityExecutors.get(activityDef.getAlias());
if (executor == null && createIfMissing) {
if (activityDef.getParams().containsKey("driver")) {
@@ -333,7 +333,7 @@ public class ScenarioController {
)
);
- executor = new ActivityExecutor(
+ executor = new ActivityThreadsManager(
activityType.getAssembledActivity(
activityDef,
getActivityMap()
@@ -342,7 +342,7 @@ public class ScenarioController {
);
activityExecutors.put(activityDef.getAlias(), executor);
} else {
- executor = new ActivityExecutor(
+ executor = new ActivityThreadsManager(
new StandardActivityType(activityDef).getAssembledActivity(
activityDef, getActivityMap()
), this.sessionId
@@ -392,7 +392,7 @@ public class ScenarioController {
*/
public List getActivityDefs() {
return activityExecutors.values().stream()
- .map(ActivityExecutor::getActivityDef)
+ .map(ActivityThreadsManager::getActivityDef)
.collect(Collectors.toList());
}
@@ -425,7 +425,8 @@ public class ScenarioController {
/**
* Await completion of all running activities, but do not force shutdownActivity. This method is meant to provide
- * the blocking point for calling logic. It waits.
+ * the blocking point for calling logic. It waits. If there is an error which should propagate into the scenario,
+ * then it should be thrown from this method.
*
* @param waitTimeMillis The time to wait, usually set very high
* @return true, if all activities completed before the timer expired, false otherwise
@@ -436,7 +437,7 @@ public class ScenarioController {
long remaining = waitTimeMillis;
List finishers = new ArrayList<>();
- for (ActivityExecutor ae : activityExecutors.values()) {
+ for (ActivityThreadsManager ae : activityExecutors.values()) {
ActivityFinisher finisher = new ActivityFinisher(ae, (int) remaining);
finishers.add(finisher);
finisher.start();
@@ -492,12 +493,12 @@ public class ScenarioController {
}
public boolean awaitActivity(ActivityDef activityDef) {
- ActivityExecutor activityExecutor = getActivityExecutor(activityDef, false);
- if (activityExecutor == null) {
+ ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, false);
+ if (activityThreadsManager == null) {
throw new RuntimeException("Could not await missing activity: " + activityDef);
}
scenariologger.debug("AWAIT/before alias=" + activityDef.getAlias());
- boolean finished = activityExecutor.awaitFinish(Integer.MAX_VALUE);
+ boolean finished = activityThreadsManager.awaitFinishedOrStopped(Integer.MAX_VALUE);
scenariologger.debug("AWAIT/after completed=" + finished);
return finished;
@@ -506,7 +507,7 @@ public class ScenarioController {
/**
* @return an unmodifyable String to executor map of all activities known to this scenario
*/
- public Map getActivityExecutorMap() {
+ public Map getActivityExecutorMap() {
return Collections.unmodifiableMap(activityExecutors);
}
@@ -516,7 +517,7 @@ public class ScenarioController {
private Map getActivityMap() {
Map activityMap = new HashMap();
- for (Map.Entry entry : activityExecutors.entrySet()) {
+ for (Map.Entry entry : activityExecutors.entrySet()) {
activityMap.put(entry.getKey(), entry.getValue().getActivity());
}
return activityMap;
@@ -524,7 +525,7 @@ public class ScenarioController {
public List getProgressMeters() {
List indicators = new ArrayList<>();
- for (ActivityExecutor ae : activityExecutors.values()) {
+ for (ActivityThreadsManager ae : activityExecutors.values()) {
indicators.add(ae.getProgressMeter());
}
indicators.sort(Comparator.comparing(ProgressMeterDisplay::getStartTime));
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenariosResults.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenariosResults.java
index 6eb5774ea..80c44b8c8 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenariosResults.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenariosResults.java
@@ -28,27 +28,26 @@ public class ScenariosResults {
private static final Logger logger = LogManager.getLogger(ScenariosResults.class);
private final String scenariosExecutorName;
- private final Map scenarioResultMap = new LinkedHashMap<>();
+ private final Map scenarioResultMap = new LinkedHashMap<>();
public ScenariosResults(ScenariosExecutor scenariosExecutor) {
this.scenariosExecutorName = scenariosExecutor.getName();
}
- public ScenariosResults(ScenariosExecutor scenariosExecutor, Map map) {
+ public ScenariosResults(ScenariosExecutor scenariosExecutor, Map map) {
this.scenariosExecutorName = scenariosExecutor.getName();
scenarioResultMap.putAll(map);
}
public String getExecutionSummary() {
- StringBuilder sb = new StringBuilder("executions: ");
- sb.append(scenarioResultMap.size()).append(" scenarios, ");
- sb.append(scenarioResultMap.values().stream().filter(r -> r.getException().isEmpty()).count()).append(" normal, ");
- sb.append(scenarioResultMap.values().stream().filter(r -> r.getException().isPresent()).count()).append(" errored");
- return sb.toString();
+ String sb = "executions: " + scenarioResultMap.size() + " scenarios, " +
+ scenarioResultMap.values().stream().filter(r -> r.getException().isEmpty()).count() + " normal, " +
+ scenarioResultMap.values().stream().filter(r -> r.getException().isPresent()).count() + " errored";
+ return sb;
}
- public ScenarioResult getOne() {
+ public ExecMetricsResult getOne() {
if (this.scenarioResultMap.size() != 1) {
throw new RuntimeException("getOne found " + this.scenarioResultMap.size() + " results instead of 1.");
}
@@ -57,14 +56,14 @@ public class ScenariosResults {
}
public void reportToLog() {
- for (Map.Entry entry : this.scenarioResultMap.entrySet()) {
+ for (Map.Entry entry : this.scenarioResultMap.entrySet()) {
Scenario scenario = entry.getKey();
- ScenarioResult oresult = entry.getValue();
+ ExecMetricsResult oresult = entry.getValue();
logger.info("results for scenario: " + scenario);
if (oresult != null) {
- oresult.reportElapsedMillis();
+ oresult.reportElapsedMillisToLog();
} else {
logger.error(scenario.getScenarioName() + ": incomplete (missing result)");
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/StartedActivityInfo.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/StartedActivityInfo.java
new file mode 100644
index 000000000..28b7f76c9
--- /dev/null
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/StartedActivityInfo.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.core.lifecycle;
+
+import io.nosqlbench.engine.api.activityapi.core.Activity;
+
+public class StartedActivityInfo {
+ private final Activity activity;
+
+ StartedActivityInfo(Activity activity) {
+ this.activity = activity;
+ }
+
+
+}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java b/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java
index 93fb5183c..a087b444d 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java
@@ -27,9 +27,9 @@ import io.nosqlbench.engine.api.extensions.ScriptingPluginInfo;
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
import io.nosqlbench.engine.core.annotation.Annotators;
import io.nosqlbench.engine.core.lifecycle.ActivityProgressIndicator;
+import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
import io.nosqlbench.engine.core.lifecycle.PolyglotScenarioController;
import io.nosqlbench.engine.core.lifecycle.ScenarioController;
-import io.nosqlbench.engine.core.lifecycle.ScenarioResult;
import io.nosqlbench.engine.core.metrics.PolyglotMetricRegistryBindings;
import io.nosqlbench.nb.annotations.Maturity;
import org.apache.logging.log4j.LogManager;
@@ -58,7 +58,7 @@ import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
-public class Scenario implements Callable {
+public class Scenario implements Callable {
private final String commandLine;
private final String reportSummaryTo;
@@ -71,9 +71,9 @@ public class Scenario implements Callable {
private Exception error;
private ScenarioMetadata scenarioMetadata;
- private ScenarioResult result;
+ private ExecMetricsResult result;
- public Optional getResultIfComplete() {
+ public Optional getResultIfComplete() {
return Optional.ofNullable(this.result);
}
@@ -171,7 +171,7 @@ public class Scenario implements Callable {
return this;
}
- private void initializeScriptingEngine() {
+ private void initializeScriptingEngine(ScenarioController scenarioController) {
logger.debug("Using engine " + engine.toString());
MetricRegistry metricRegistry = ActivityMetrics.getMetricRegistry();
@@ -198,12 +198,10 @@ public class Scenario implements Callable {
this.scriptEngine = GraalJSScriptEngine.create(polyglotEngine, contextSettings);
- scenarioController = new ScenarioController(this.scenarioName, minMaturity);
if (!progressInterval.equals("disabled")) {
activityProgressIndicator = new ActivityProgressIndicator(scenarioController, progressInterval);
}
-
scriptEnv = new ScenarioContext(scenarioController);
scriptEngine.setContext(scriptEnv);
@@ -264,9 +262,22 @@ public class Scenario implements Callable {
.build()
);
- initializeScriptingEngine();
logger.debug("Running control script for " + getScenarioName() + ".");
+ scenarioController = new ScenarioController(this.scenarioName, minMaturity);
+ initializeScriptingEngine(scenarioController);
+ executeScenarioScripts();
+ long awaitCompletionTime = 86400 * 365 * 1000L;
+ logger.debug("Awaiting completion of scenario and activities for " + awaitCompletionTime + " millis.");
+
+ scenarioController.awaitCompletion(awaitCompletionTime);
+ //TODO: Ensure control flow covers controller shutdown in event of internal error.
+
+ Runtime.getRuntime().removeShutdownHook(scenarioShutdownHook);
+ scenarioShutdownHook.run();
+ }
+
+ private void executeScenarioScripts() {
for (String script : scripts) {
try {
Object result = null;
@@ -304,6 +315,7 @@ public class Scenario implements Callable {
System.err.flush();
System.out.flush();
} catch (Exception e) {
+ this.error=e;
this.state = State.Errored;
logger.error("Error in scenario, shutting down. (" + e + ")");
try {
@@ -311,7 +323,6 @@ public class Scenario implements Callable {
} catch (Exception eInner) {
logger.debug("Found inner exception while forcing stop with rethrow=false: " + eInner);
} finally {
- this.error = e;
throw new RuntimeException(e);
}
} finally {
@@ -320,14 +331,6 @@ public class Scenario implements Callable {
endedAtMillis = System.currentTimeMillis();
}
}
- long awaitCompletionTime = 86400 * 365 * 1000L;
- logger.debug("Awaiting completion of scenario and activities for " + awaitCompletionTime + " millis.");
- scenarioController.awaitCompletion(awaitCompletionTime);
- //TODO: Ensure control flow covers controller shutdown in event of internal error.
-
- Runtime.getRuntime().removeShutdownHook(scenarioShutdownHook);
- scenarioShutdownHook = null;
- finish();
}
public void finish() {
@@ -370,9 +373,23 @@ public class Scenario implements Callable {
/**
* This should be the only way to get a ScenarioResult for a Scenario.
*
+ * The lifecycle of a scenario includes the lifecycles of all of the following:
+ *
+ *
The scenario control script, executing within a graaljs context.
+ *
The lifecycle of every activity which is started within the scenario.
+ *
+ *
+ * All of these run asynchronously within the scenario, however the same thread that calls
+ * the scenario is the one which executes the control script. A scenario ends when all
+ * of the following conditions are met:
+ *
+ *
The scenario control script has run to completion, or experienced an exception.
+ *
Each activity has run to completion, experienced an exception, or all
+ *
+ *
* @return
*/
- public synchronized ScenarioResult call() {
+ public synchronized ExecMetricsResult call() {
if (result == null) {
try {
runScenario();
@@ -386,15 +403,15 @@ public class Scenario implements Callable {
}
String iolog = scriptEnv.getTimedLog();
- this.result = new ScenarioResult(this.error, iolog, this.startedAtMillis, this.endedAtMillis);
- result.reportToLog();
+ this.result = new ExecMetricsResult(this.error, iolog, this.startedAtMillis, this.endedAtMillis);
+ result.reportMetricsSummaryToLog();
doReportSummaries(reportSummaryTo, result);
}
return result;
}
- private void doReportSummaries(String reportSummaryTo, ScenarioResult result) {
+ private void doReportSummaries(String reportSummaryTo, ExecMetricsResult result) {
List fullChannels = new ArrayList<>();
List briefChannels = new ArrayList<>();
@@ -437,7 +454,7 @@ public class Scenario implements Callable {
}
}
}
- fullChannels.forEach(result::reportTo);
+ fullChannels.forEach(result::reportMetricsSummaryTo);
// briefChannels.forEach(result::reportCountsTo);
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenariosExecutor.java b/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenariosExecutor.java
index 0d6581266..dedaf4ff3 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenariosExecutor.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenariosExecutor.java
@@ -50,7 +50,7 @@ public class ScenariosExecutor {
if (submitted.get(scenario.getScenarioName()) != null) {
throw new BasicError("Scenario " + scenario.getScenarioName() + " is already defined. Remove it first to reuse the name.");
}
- Future future = executor.submit(scenario);
+ Future future = executor.submit(scenario);
SubmittedScenario s = new SubmittedScenario(scenario, future);
submitted.put(s.getName(), s);
}
@@ -106,7 +106,7 @@ public class ScenariosExecutor {
throw new RuntimeException("executor still runningScenarios after awaiting all results for " + timeout
+ "ms. isTerminated:" + executor.isTerminated() + " isShutdown:" + executor.isShutdown());
}
- Map scenarioResultMap = new LinkedHashMap<>();
+ Map scenarioResultMap = new LinkedHashMap<>();
getAsyncResultStatus()
.entrySet()
.forEach(
@@ -133,26 +133,26 @@ public class ScenariosExecutor {
* All submitted scenarios are included. Those which are still pending
* are returned with an empty option.
*
- *
Results may be exceptional. If {@link ScenarioResult#getException()} is present,
+ *
Results may be exceptional. If {@link ExecMetricsResult#getException()} is present,
* then the result did not complete normally.
*
* @return map of async results, with incomplete results as Optional.empty()
*/
- public Map> getAsyncResultStatus() {
+ public Map> getAsyncResultStatus() {
- Map> optResults = new LinkedHashMap<>();
+ Map> optResults = new LinkedHashMap<>();
for (SubmittedScenario submittedScenario : submitted.values()) {
- Future resultFuture = submittedScenario.getResultFuture();
+ Future resultFuture = submittedScenario.getResultFuture();
- Optional oResult = Optional.empty();
+ Optional oResult = Optional.empty();
if (resultFuture.isDone()) {
try {
oResult = Optional.of(resultFuture.get());
} catch (Exception e) {
long now = System.currentTimeMillis();
logger.debug("creating exceptional scenario result from getAsyncResultStatus");
- oResult = Optional.of(new ScenarioResult(e, "errored output", now, now));
+ oResult = Optional.of(new ExecMetricsResult(now, now, "errored output", e));
}
}
@@ -179,7 +179,7 @@ public class ScenariosExecutor {
* @param scenarioName the scenario name of interest
* @return an optional result
*/
- public Optional> getPendingResult(String scenarioName) {
+ public Optional> getPendingResult(String scenarioName) {
return Optional.ofNullable(submitted.get(scenarioName)).map(s -> s.resultFuture);
}
@@ -224,9 +224,9 @@ public class ScenariosExecutor {
private static class SubmittedScenario {
private final Scenario scenario;
- private final Future resultFuture;
+ private final Future resultFuture;
- SubmittedScenario(Scenario scenario, Future resultFuture) {
+ SubmittedScenario(Scenario scenario, Future resultFuture) {
this.scenario = scenario;
this.resultFuture = resultFuture;
}
@@ -235,7 +235,7 @@ public class ScenariosExecutor {
return scenario;
}
- Future getResultFuture() {
+ Future getResultFuture() {
return resultFuture;
}
diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityThreadsManagerTest.java
similarity index 94%
rename from engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java
rename to engine-core/src/test/java/io/nosqlbench/engine/core/ActivityThreadsManagerTest.java
index a6e93e8d7..b82c1cd29 100644
--- a/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java
+++ b/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityThreadsManagerTest.java
@@ -28,7 +28,7 @@ import io.nosqlbench.engine.api.activityimpl.input.CoreInputDispenser;
import io.nosqlbench.engine.api.activityimpl.input.AtomicInput;
import io.nosqlbench.engine.api.activityimpl.motor.CoreMotor;
import io.nosqlbench.engine.api.activityimpl.motor.CoreMotorDispenser;
-import io.nosqlbench.engine.core.lifecycle.ActivityExecutor;
+import io.nosqlbench.engine.core.lifecycle.ActivityThreadsManager;
import io.nosqlbench.engine.core.lifecycle.ActivityTypeLoader;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
@@ -38,8 +38,8 @@ import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
-public class ActivityExecutorTest {
- private static final Logger logger = LogManager.getLogger(ActivityExecutorTest.class);
+public class ActivityThreadsManagerTest {
+ private static final Logger logger = LogManager.getLogger(ActivityThreadsManagerTest.class);
@Test
public synchronized void testRestart() {
@@ -55,7 +55,7 @@ public class ActivityExecutorTest {
a.setInputDispenserDelegate(idisp);
a.setMotorDispenserDelegate(mdisp);
- ActivityExecutor ae = new ActivityExecutor(a, "test-restart");
+ ActivityThreadsManager ae = new ActivityThreadsManager(a, "test-restart");
ad.setThreads(1);
ae.startActivity();
ae.stopActivity();
@@ -79,7 +79,7 @@ public class ActivityExecutorTest {
a.setInputDispenserDelegate(idisp);
a.setMotorDispenserDelegate(mdisp);
- ActivityExecutor ae = new ActivityExecutor(a, "test-delayed-start");
+ ActivityThreadsManager ae = new ActivityThreadsManager(a, "test-delayed-start");
ad.setThreads(1);
ae.startActivity();
ae.awaitCompletion(15000);
@@ -104,7 +104,7 @@ public class ActivityExecutorTest {
a.setInputDispenserDelegate(idisp);
a.setMotorDispenserDelegate(mdisp);
- ActivityExecutor ae = new ActivityExecutor(a, "test-new-executor");
+ ActivityThreadsManager ae = new ActivityThreadsManager(a, "test-new-executor");
ad.setThreads(5);
ae.startActivity();
diff --git a/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java b/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java
index 06a3f0d5e..52ecd9b22 100644
--- a/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java
+++ b/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java
@@ -21,7 +21,7 @@ import io.nosqlbench.engine.cli.BasicScriptBuffer;
import io.nosqlbench.engine.cli.Cmd;
import io.nosqlbench.engine.cli.NBCLICommandParser;
import io.nosqlbench.engine.cli.ScriptBuffer;
-import io.nosqlbench.engine.core.lifecycle.ScenarioResult;
+import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
import io.nosqlbench.engine.core.script.Scenario;
import io.nosqlbench.engine.core.script.ScenariosExecutor;
import io.nosqlbench.engine.rest.services.WorkSpace;
@@ -234,8 +234,8 @@ public class ScenarioExecutorEndpoint implements WebServiceObject {
Optional pendingScenario = executor.getPendingScenario(scenarioName);
if (pendingScenario.isPresent()) {
- Optional> pendingResult = executor.getPendingResult(scenarioName);
- Future scenarioResultFuture = pendingResult.get();
+ Optional> pendingResult = executor.getPendingResult(scenarioName);
+ Future scenarioResultFuture = pendingResult.get();
return new LiveScenarioView(pendingScenario.get());
} else {
throw new RuntimeException("Scenario name '" + scenarioName + "' not found.");
diff --git a/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/ResultView.java b/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/ResultView.java
index 1394ce7e6..e84da8113 100644
--- a/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/ResultView.java
+++ b/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/ResultView.java
@@ -16,13 +16,13 @@
package io.nosqlbench.engine.rest.transfertypes;
-import io.nosqlbench.engine.core.lifecycle.ScenarioResult;
+import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
public class ResultView {
- private final ScenarioResult result;
+ private final ExecMetricsResult result;
- public ResultView(ScenarioResult result) {
+ public ResultView(ExecMetricsResult result) {
this.result = result;
}
diff --git a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java
index bc230712f..a84a712b2 100644
--- a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java
+++ b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java
@@ -16,7 +16,7 @@
package io.nosqlbench.nbr.examples;
-import io.nosqlbench.engine.core.lifecycle.ScenarioResult;
+import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
import io.nosqlbench.engine.core.lifecycle.ScenariosResults;
import io.nosqlbench.engine.core.script.Scenario;
import io.nosqlbench.engine.core.script.ScenariosExecutor;
@@ -41,7 +41,7 @@ import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
public class ScriptExampleTests {
- public static ScenarioResult runScenario(String scriptname, String... params) {
+ public static ExecMetricsResult runScenario(String scriptname, String... params) {
if ((params.length % 2) != 0) {
throw new RuntimeException("params must be pairwise key, value, ...");
}
@@ -74,7 +74,7 @@ public class ScriptExampleTests {
// s.addScriptText("load('classpath:scripts/async/" + scriptname + ".js');");
executor.execute(s);
ScenariosResults scenariosResults = executor.awaitAllResults();
- ScenarioResult scenarioResult = scenariosResults.getOne();
+ ExecMetricsResult scenarioResult = scenariosResults.getOne();
executor.shutdownNow();
return scenarioResult;
}
@@ -86,7 +86,7 @@ public class ScriptExampleTests {
@Test
public void testLinkedInput() {
- ScenarioResult scenarioResult = runScenario("linkedinput");
+ ExecMetricsResult scenarioResult = runScenario("linkedinput");
Pattern p = Pattern.compile(".*started leader.*started follower.*stopped leader.*stopped follower.*",
Pattern.DOTALL);
assertThat(p.matcher(scenarioResult.getIOLog()).matches()).isTrue();
@@ -94,14 +94,14 @@ public class ScriptExampleTests {
@Test
public void testExceptionPropagationFromMotorThread() {
- ScenarioResult scenarioResult = runScenario("activityerror");
+ ExecMetricsResult scenarioResult = runScenario("activityerror");
assertThat(scenarioResult.getException()).isPresent();
assertThat(scenarioResult.getException().get().getMessage()).contains("For input string: \"unparsable\"");
}
@Test
public void testCycleRate() {
- ScenarioResult scenarioResult = runScenario("cycle_rate");
+ ExecMetricsResult scenarioResult = runScenario("cycle_rate");
String iolog = scenarioResult.getIOLog();
System.out.println("iolog\n" + iolog);
Pattern p = Pattern.compile(".*mean cycle rate = (\\d[.\\d]+).*", Pattern.DOTALL);
@@ -116,13 +116,13 @@ public class ScriptExampleTests {
@Test
public void testExtensionPoint() {
- ScenarioResult scenarioResult = runScenario("extensions");
+ ExecMetricsResult scenarioResult = runScenario("extensions");
assertThat(scenarioResult.getIOLog()).contains("sum is 46");
}
@Test
public void testOptimo() {
- ScenarioResult scenarioResult = runScenario("optimo");
+ ExecMetricsResult scenarioResult = runScenario("optimo");
String iolog = scenarioResult.getIOLog();
System.out.println("iolog\n" + iolog);
assertThat(iolog).contains("map of result was");
@@ -130,14 +130,14 @@ public class ScriptExampleTests {
@Test
public void testExtensionCsvLogger() {
- ScenarioResult scenarioResult = runScenario("extension_csvmetrics");
+ ExecMetricsResult scenarioResult = runScenario("extension_csvmetrics");
assertThat(scenarioResult.getIOLog()).contains("started new " +
"csvlogger: logs/csvmetricstestdir");
}
@Test
public void testScriptParamsVariable() {
- ScenarioResult scenarioResult = runScenario("params_variable", "one", "two", "three", "four");
+ ExecMetricsResult scenarioResult = runScenario("params_variable", "one", "two", "three", "four");
assertThat(scenarioResult.getIOLog()).contains("params[\"one\"]='two'");
assertThat(scenarioResult.getIOLog()).contains("params[\"three\"]='four'");
assertThat(scenarioResult.getIOLog()).contains("overridden[\"three\"] [overridden-three-five]='five'");
@@ -146,7 +146,7 @@ public class ScriptExampleTests {
@Test
public void testScriptParamsUndefVariableWithOverride() {
- ScenarioResult scenarioResult = runScenario("undef_param", "one", "two", "three", "four");
+ ExecMetricsResult scenarioResult = runScenario("undef_param", "one", "two", "three", "four");
assertThat(scenarioResult.getIOLog()).contains("before: params[\"three\"]:four");
assertThat(scenarioResult.getIOLog()).contains("before: params.three:four");
assertThat(scenarioResult.getIOLog()).contains("after: params[\"three\"]:undefined");
@@ -155,7 +155,7 @@ public class ScriptExampleTests {
@Test
public void testExtensionHistoStatsLogger() throws IOException {
- ScenarioResult scenarioResult = runScenario("extension_histostatslogger");
+ ExecMetricsResult scenarioResult = runScenario("extension_histostatslogger");
assertThat(scenarioResult.getIOLog()).contains("stdout started " +
"logging to logs/histostats.csv");
List strings = Files.readAllLines(Paths.get(
@@ -167,7 +167,7 @@ public class ScriptExampleTests {
@Test
public void testExtensionCsvOutput() throws IOException {
- ScenarioResult scenarioResult = runScenario("extension_csvoutput");
+ ExecMetricsResult scenarioResult = runScenario("extension_csvoutput");
List strings = Files.readAllLines(Paths.get(
"logs/csvoutputtestfile.csv"));
String logdata = strings.stream().collect(Collectors.joining("\n"));
@@ -177,7 +177,7 @@ public class ScriptExampleTests {
@Test
public void testExtensionHistogramLogger() throws IOException {
- ScenarioResult scenarioResult = runScenario("extension_histologger");
+ ExecMetricsResult scenarioResult = runScenario("extension_histologger");
assertThat(scenarioResult.getIOLog()).contains("stdout started logging to hdrhistodata.log");
List strings = Files.readAllLines(Paths.get("hdrhistodata.log"));
String logdata = strings.stream().collect(Collectors.joining("\n"));
@@ -187,7 +187,7 @@ public class ScriptExampleTests {
@Test
public void testBlockingRun() {
- ScenarioResult scenarioResult = runScenario("blockingrun");
+ ExecMetricsResult scenarioResult = runScenario("blockingrun");
int a1end = scenarioResult.getIOLog().indexOf("blockingactivity1 finished");
int a2start = scenarioResult.getIOLog().indexOf("running blockingactivity2");
assertThat(a1end).isLessThan(a2start);
@@ -195,12 +195,12 @@ public class ScriptExampleTests {
@Test
public void testAwaitFinished() {
- ScenarioResult scenarioResult = runScenario("awaitfinished");
+ ExecMetricsResult scenarioResult = runScenario("awaitfinished");
}
@Test
public void testStartStop() {
- ScenarioResult scenarioResult = runScenario("startstopdiag");
+ ExecMetricsResult scenarioResult = runScenario("startstopdiag");
int startedAt = scenarioResult.getIOLog().indexOf("starting activity teststartstopdiag");
int stoppedAt = scenarioResult.getIOLog().indexOf("stopped activity teststartstopdiag");
assertThat(startedAt).isGreaterThan(0);
@@ -210,7 +210,7 @@ public class ScriptExampleTests {
// TODO: find out why this causes a long delay after stop is called.
@Test
public void testThreadChange() {
- ScenarioResult scenarioResult = runScenario("threadchange");
+ ExecMetricsResult scenarioResult = runScenario("threadchange");
int changedTo1At = scenarioResult.getIOLog().indexOf("threads now 1");
int changedTo5At = scenarioResult.getIOLog().indexOf("threads now 5");
System.out.println("IOLOG:\n"+scenarioResult.getIOLog());
@@ -220,13 +220,13 @@ public class ScriptExampleTests {
@Test
public void testReadMetric() {
- ScenarioResult scenarioResult = runScenario("readmetrics");
+ ExecMetricsResult scenarioResult = runScenario("readmetrics");
assertThat(scenarioResult.getIOLog()).contains("count: ");
}
@Test
public void testShutdownHook() {
- ScenarioResult scenarioResult = runScenario("extension_shutdown_hook");
+ ExecMetricsResult scenarioResult = runScenario("extension_shutdown_hook");
assertThat(scenarioResult.getIOLog()).doesNotContain("shutdown hook running").describedAs(
"shutdown hooks should not run in the same IO context as the main scenario"
);
@@ -234,7 +234,7 @@ public class ScriptExampleTests {
@Test
public void testExceptionPropagationFromActivityInit() {
- ScenarioResult scenarioResult = runScenario("activityiniterror");
+ ExecMetricsResult scenarioResult = runScenario("activityiniterror");
assertThat(scenarioResult.getException()).isPresent();
assertThat(scenarioResult.getException().get().getMessage()).contains("Unable to convert end cycle from invalid");
assertThat(scenarioResult.getException()).isNotNull();
@@ -242,7 +242,7 @@ public class ScriptExampleTests {
@Test
public void testReportedCoDelayBursty() {
- ScenarioResult scenarioResult = runScenario("cocycledelay_bursty");
+ ExecMetricsResult scenarioResult = runScenario("cocycledelay_bursty");
assertThat(scenarioResult.getIOLog()).contains("step1 metrics.waittime=");
assertThat(scenarioResult.getIOLog()).contains("step2 metrics.waittime=");
String iolog = scenarioResult.getIOLog();
@@ -252,7 +252,7 @@ public class ScriptExampleTests {
@Test
public void testReportedCoDelayStrict() {
- ScenarioResult scenarioResult = runScenario("cocycledelay_strict");
+ ExecMetricsResult scenarioResult = runScenario("cocycledelay_strict");
assertThat(scenarioResult.getIOLog()).contains("step1 cycles.waittime=");
assertThat(scenarioResult.getIOLog()).contains("step2 cycles.waittime=");
String iolog = scenarioResult.getIOLog();
@@ -263,14 +263,14 @@ public class ScriptExampleTests {
@Test
public void testCycleRateChangeNewMetrics() {
- ScenarioResult scenarioResult = runScenario("cycle_rate_change");
+ ExecMetricsResult scenarioResult = runScenario("cycle_rate_change");
String ioLog = scenarioResult.getIOLog();
assertThat(ioLog).contains("cycles adjusted, exiting on iteration");
}
@Test
public void testExitLogic() {
- ScenarioResult scenarioResult = runScenario(
+ ExecMetricsResult scenarioResult = runScenario(
"basicdiag",
"type", "diag", "cyclerate", "5", "erroroncycle", "10", "cycles", "2000"
);
diff --git a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/SpeedCheckIntegrationTests.java b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/SpeedCheckIntegrationTests.java
index ee8fae02a..b750530d6 100644
--- a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/SpeedCheckIntegrationTests.java
+++ b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/SpeedCheckIntegrationTests.java
@@ -15,7 +15,7 @@
*/
package io.nosqlbench.nbr.examples;
-import io.nosqlbench.engine.core.lifecycle.ScenarioResult;
+import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -30,14 +30,14 @@ public class SpeedCheckIntegrationTests {
@Disabled
// Verified as working
public void testSpeedSanity() {
- ScenarioResult scenarioResult = ScriptExampleTests.runScenario("speedcheck");
+ ExecMetricsResult scenarioResult = ScriptExampleTests.runScenario("speedcheck");
}
@Test
@Disabled
// This seems incomplete
public void testThreadSpeeds() {
- ScenarioResult scenarioResult = ScriptExampleTests.runScenario("threadspeeds");
+ ExecMetricsResult scenarioResult = ScriptExampleTests.runScenario("threadspeeds");
}
diff --git a/nbr/src/test/java/io/nosqlbench/cli/testing/ExitStatusIntegrationTests.java b/nbr/src/test/java/io/nosqlbench/cli/testing/ExitStatusIntegrationTests.java
index 70a163eaf..c1b580e24 100644
--- a/nbr/src/test/java/io/nosqlbench/cli/testing/ExitStatusIntegrationTests.java
+++ b/nbr/src/test/java/io/nosqlbench/cli/testing/ExitStatusIntegrationTests.java
@@ -86,18 +86,18 @@ class ExitStatusIntegrationTests {
assertThat(result.exitStatus).isEqualTo(2);
}
-// This will not work reliablyl until the activity shutdown bug is fixed.
-// @Test
-// public void testCloseErrorHandlerOnSpace() {
-// ProcessInvoker invoker = new ProcessInvoker();
-// invoker.setLogDir("logs/test");
-// ProcessResult result = invoker.run("exitstatus_erroronclose", 30,
-// java, "-jar", JARNAME, "--logs-dir", "logs/test/error_on_close", "run",
-// "driver=diag", "threads=2", "rate=5", "op=noop", "cycles=10", "erroronclose=true", "-vvv"
-// );
-// String stdout = String.join("\n", result.getStdoutData());
-// String stderr = String.join("\n", result.getStderrData());
-// assertThat(result.exception).isNotNull();
-// assertThat(result.exception.getMessage()).contains("diag space was configured to throw");
-// }
+ @Test
+ public void testCloseErrorHandlerOnSpace() {
+ ProcessInvoker invoker = new ProcessInvoker();
+ invoker.setLogDir("logs/test");
+ ProcessResult result = invoker.run("exitstatus_erroronclose", 30,
+ java, "-jar", JARNAME, "--logs-dir", "logs/test/error_on_close", "run",
+ "driver=diag", "threads=2", "rate=5", "op=noop", "cycles=10", "erroronclose=true", "-vvv"
+ );
+ String stdout = String.join("\n", result.getStdoutData());
+ String stderr = String.join("\n", result.getStderrData());
+ assertThat(result.exception).isNotNull();
+ assertThat(result.exception.getMessage()).contains("diag space was configured to throw");
+ }
+
}
From bd129c442ee4fa91a35f743273c9f934f2070f6b Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:00:34 -0600
Subject: [PATCH 02/19] run activities within a dedicated executor
---
.../lifecycle/{ => scenario}/ScenarioController.java | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ => scenario}/ScenarioController.java (97%)
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
similarity index 97%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioController.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
index 99929eeb4..8869e50cd 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
@@ -51,9 +51,16 @@ public class ScenarioController {
private final String sessionId;
private final Maturity minMaturity;
- public ScenarioController(String sessionId, Maturity minMaturity) {
- this.sessionId = sessionId;
+ private ExecutorService activitiesExecutor;
+
+ public ScenarioController(Scenario scenario, Maturity minMaturity) {
+ this.scenario = scenario;
this.minMaturity = minMaturity;
+ this.activityLoader = new ActivityLoader(scenario);
+
+ ActivitiesExceptionHandler exceptionHandler = new ActivitiesExceptionHandler(this);
+ IndexedThreadFactory indexedThreadFactory = new IndexedThreadFactory("ACTIVITY", exceptionHandler);
+ this.activitiesExecutor = Executors.newCachedThreadPool(indexedThreadFactory);
}
/**
From 13219232298238006ac1565122fd1bb86edc2aa4 Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:01:22 -0600
Subject: [PATCH 03/19] remove unused code paths to simplify refactoring
---
.../bindings}/PolyglotScenarioController.java | 14 --------------
1 file changed, 14 deletions(-)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ => scenario/script/bindings}/PolyglotScenarioController.java (94%)
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/PolyglotScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java
similarity index 94%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/PolyglotScenarioController.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java
index 5d1e4e5c8..38bb7b195 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/PolyglotScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java
@@ -146,20 +146,6 @@ public class PolyglotScenarioController {
}
}
- public synchronized void apply(Object o) {
- if (o instanceof Value) {
- applyValue((Value) o);
- } else if (o instanceof Map) {
- controller.apply((Map) o);
- } else {
- throw new RuntimeException("unknown type: " + o.getClass().getCanonicalName());
- }
- }
-
- private synchronized void applyValue(Value spec) {
- Map map = spec.as(Map.class);
- controller.apply(map);
- }
public synchronized void awaitActivity(Object o) {
this.await(o);
From ba42bfea478d7483c5cbf890a032364c4052ef24 Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:01:33 -0600
Subject: [PATCH 04/19] allow conversion of missing config types
---
.../api/config/standard/ConfigModel.java | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/nb-api/src/main/java/io/nosqlbench/api/config/standard/ConfigModel.java b/nb-api/src/main/java/io/nosqlbench/api/config/standard/ConfigModel.java
index 811191eac..7fb1577c6 100644
--- a/nb-api/src/main/java/io/nosqlbench/api/config/standard/ConfigModel.java
+++ b/nb-api/src/main/java/io/nosqlbench/api/config/standard/ConfigModel.java
@@ -131,10 +131,20 @@ public class ConfigModel implements NBConfigModel {
return (T) Double.valueOf(string);
} else if (type == BigDecimal.class) {
return (T) BigDecimal.valueOf(Double.parseDouble(string));
+ } else if (type == boolean.class || type == Boolean.class) {
+ return (T) Boolean.valueOf(Boolean.parseBoolean(string));
} else {
throw new RuntimeException("CharSequence type " + type.getSimpleName() + " could " +
" not be converted from " + value.getClass().getSimpleName());
}
+ } else if (value instanceof Boolean bool) {
+ if (type == boolean.class) {
+ return (T) bool;
+ } else {
+ throw new RuntimeException("Boolean type " + type.getSimpleName() + " could " +
+ " not be converted from " + value.getClass().getSimpleName());
+
+ }
}
} catch (Exception e) {
@@ -318,11 +328,10 @@ public class ConfigModel implements NBConfigModel {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("[").append(
- params.stream().map(p -> p.getNames().get(0)).collect(Collectors.joining(",")))
- .append("]");
+ String sb = "[" +
+ params.stream().map(p -> p.getNames().get(0)).collect(Collectors.joining(",")) +
+ "]";
- return sb.toString();
+ return sb;
}
}
From 3f14fefcb122f38158047294a48962167ca6f89b Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:01:43 -0600
Subject: [PATCH 05/19] delegate activity instancing to dedicated loader
---
.../lifecycle/activity/ActivityLoader.java | 53 +++++++++++++++++++
.../{ => activity}/ActivityTypeLoader.java | 14 +----
.../scenario/ScenarioController.java | 8 +--
3 files changed, 59 insertions(+), 16 deletions(-)
create mode 100644 engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityLoader.java
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ => activity}/ActivityTypeLoader.java (87%)
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityLoader.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityLoader.java
new file mode 100644
index 000000000..fb0f9bd95
--- /dev/null
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityLoader.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.core.lifecycle.activity;
+
+import io.nosqlbench.api.engine.activityimpl.ActivityDef;
+import io.nosqlbench.engine.api.activityapi.core.Activity;
+import io.nosqlbench.engine.api.activityimpl.uniform.StandardActivityType;
+import io.nosqlbench.engine.core.lifecycle.scenario.Scenario;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Consolidates the activity type and activity instantiation logic into one place
+ * per scope. Within the lifetime of this ActivityLoader, all activities may
+ * see each other by name.
+ */
+public class ActivityLoader {
+ private final static Logger logger = LogManager.getLogger("ACTIVITIES");
+ private final Map activityMap = new ConcurrentHashMap<>();
+ private final Scenario scenario;
+
+ public ActivityLoader(Scenario scenario) {
+ this.scenario = scenario;
+ }
+
+ public synchronized Activity loadActivity(ActivityDef activityDef) {
+ Activity activity = new StandardActivityType(activityDef).getAssembledActivity(activityDef, activityMap);
+ activityMap.put(activity.getAlias(),activity);
+ logger.debug("Resolved activity for alias '" + activityDef.getAlias() + "'");
+ return activity;
+ }
+
+ public void purgeActivity(String activityAlias) {
+ this.activityMap.remove(activityAlias);
+ }
+}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityTypeLoader.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityTypeLoader.java
similarity index 87%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityTypeLoader.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityTypeLoader.java
index 071144417..59e873428 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityTypeLoader.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityTypeLoader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.activity;
import io.nosqlbench.engine.api.activityapi.core.ActivityType;
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
@@ -150,18 +150,6 @@ public class ActivityTypeLoader {
if (oda.isPresent()) {
DriverAdapter, ?> driverAdapter = oda.get();
-// activityDef.getParams().remove("driver");
-// if (driverAdapter instanceof NBConfigurable) {
-// NBConfigModel cfgModel = ((NBConfigurable) driverAdapter).getConfigModel();
-// Optional op_yaml_loc = activityDef.getParams().getOptionalString("yaml", "workload");
-// if (op_yaml_loc.isPresent()) {
-// Map disposable = new LinkedHashMap<>(activityDef.getParams());
-// StmtsDocList workload = StatementsLoader.loadPath(logger, op_yaml_loc.get(), disposable, "activities");
-// cfgModel=cfgModel.add(workload.getConfigModel());
-// }
-// NBConfiguration cfg = cfgModel.apply(activityDef.getParams());
-// ((NBConfigurable) driverAdapter).applyConfig(cfg);
-// }
ActivityType activityType = new StandardActivityType<>(driverAdapter, activityDef);
return Optional.of(activityType);
} else {
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
index 8869e50cd..150929fda 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
@@ -47,11 +47,13 @@ public class ScenarioController {
private static final Logger logger = LogManager.getLogger(ScenarioController.class);
private static final Logger scenariologger = LogManager.getLogger("SCENARIO");
- private final Map activityExecutors = new ConcurrentHashMap<>();
- private final String sessionId;
+ private final ActivityLoader activityLoader;
+
+ private final Map activityInfoMap = new ConcurrentHashMap<>();
+ private final Scenario scenario;
private final Maturity minMaturity;
- private ExecutorService activitiesExecutor;
+ private final ExecutorService activitiesExecutor;
public ScenarioController(Scenario scenario, Maturity minMaturity) {
this.scenario = scenario;
From a1cde761f51c3454f18f60ad1577f6edbb9a5b1c Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:01:57 -0600
Subject: [PATCH 06/19] fix unapplied bug in diag space
---
.../src/main/java/io/nosqlbench/adapter/diag/DiagSpace.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/DiagSpace.java b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/DiagSpace.java
index 4a8ca3d2c..eab297012 100644
--- a/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/DiagSpace.java
+++ b/adapter-diag/src/main/java/io/nosqlbench/adapter/diag/DiagSpace.java
@@ -38,6 +38,7 @@ public class DiagSpace implements ActivityDefObserver, AutoCloseable {
public DiagSpace(String name, NBConfiguration cfg) {
this.cfg = cfg;
this.name = name;
+ applyConfig(cfg);
logger.trace("diag space initialized as '" + name + "'");
}
From 31dc3ce8f7f7b70ba15270bb7f7832515a8182a5 Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:02:16 -0600
Subject: [PATCH 07/19] package housekeeping
---
.../java/io/nosqlbench/engine/cli/NBCLI.java | 20 +++++++-------
.../nosqlbench/engine/cli/NBCLIOptions.java | 2 +-
.../ActivityProgressIndicator.java | 3 ++-
.../{ => activity}/ActivityStatus.java | 2 +-
.../{ => process}/NBCLIErrorHandler.java | 2 +-
.../{ => process}/ShutdownManager.java | 2 +-
.../scenario/ScenarioController.java | 27 +++++++++----------
.../scenario}/ScenarioShutdownHook.java | 2 +-
.../scenario}/ScenariosExecutor.java | 6 +++--
.../{ => scenario}/ScenariosResults.java | 5 ++--
.../scenario}/script/MetricsMapper.java | 6 ++---
.../script/SandboxExtensionFinder.java | 2 +-
.../scenario}/script/ScenarioContext.java | 4 +--
.../script/ScenarioExceptionHandler.java | 4 ++-
.../script/ScriptExecutionError.java | 2 +-
.../scenario}/script/ScriptParams.java | 5 ++--
.../PolyglotMetricRegistryBindings.java | 3 ++-
.../bindings/PolyglotScenarioController.java | 3 ++-
.../script/bindings}/ReadOnlyBindings.java | 2 +-
.../bindings}/ReadOnlyBindingsException.java | 2 +-
.../engine/core/metrics/MetricReporters.java | 6 ++---
.../nosqlbench/engine/core/ScenarioTest.java | 2 +-
.../core/script/ScenariosExecutorTest.java | 4 ++-
.../resources/ScenarioExecutorEndpoint.java | 6 ++---
.../rest/transfertypes/LiveScenarioView.java | 2 +-
.../script/MetricsMapperIntegrationTest.java | 1 +
26 files changed, 66 insertions(+), 59 deletions(-)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ => activity}/ActivityProgressIndicator.java (97%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ => activity}/ActivityStatus.java (92%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ => process}/NBCLIErrorHandler.java (98%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ => process}/ShutdownManager.java (95%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{script => lifecycle/scenario}/ScenarioShutdownHook.java (94%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{script => lifecycle/scenario}/ScenariosExecutor.java (97%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ => scenario}/ScenariosResults.java (94%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{ => lifecycle/scenario}/script/MetricsMapper.java (95%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{ => lifecycle/scenario}/script/SandboxExtensionFinder.java (96%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{ => lifecycle/scenario}/script/ScenarioContext.java (90%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{ => lifecycle/scenario}/script/ScenarioExceptionHandler.java (88%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{ => lifecycle/scenario}/script/ScriptExecutionError.java (93%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{ => lifecycle/scenario}/script/ScriptParams.java (97%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{metrics => lifecycle/scenario/script/bindings}/PolyglotMetricRegistryBindings.java (97%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{script => lifecycle/scenario/script/bindings}/ReadOnlyBindings.java (95%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{script => lifecycle/scenario/script/bindings}/ReadOnlyBindingsException.java (93%)
diff --git a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java
index 08df6ddc6..ef73399dc 100644
--- a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java
+++ b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLI.java
@@ -32,14 +32,17 @@ import io.nosqlbench.engine.api.activityapi.input.InputType;
import io.nosqlbench.engine.api.activityapi.output.OutputType;
import io.nosqlbench.engine.api.activityconfig.rawyaml.RawStmtsLoader;
import io.nosqlbench.engine.core.annotation.Annotators;
-import io.nosqlbench.engine.core.lifecycle.*;
+import io.nosqlbench.engine.core.lifecycle.process.NBCLIErrorHandler;
+import io.nosqlbench.engine.core.lifecycle.activity.ActivityTypeLoader;
+import io.nosqlbench.engine.core.lifecycle.process.ShutdownManager;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenariosResults;
import io.nosqlbench.engine.core.logging.LoggerConfig;
-import io.nosqlbench.engine.core.metadata.MarkdownDocInfo;
+import io.nosqlbench.engine.core.metadata.MarkdownFinder;
import io.nosqlbench.engine.core.metrics.MetricReporters;
-import io.nosqlbench.engine.core.script.MetricsMapper;
-import io.nosqlbench.engine.core.script.Scenario;
-import io.nosqlbench.engine.core.script.ScenariosExecutor;
-import io.nosqlbench.engine.core.script.ScriptParams;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.MetricsMapper;
+import io.nosqlbench.engine.core.lifecycle.scenario.Scenario;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenariosExecutor;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.ScriptParams;
import io.nosqlbench.engine.docker.DockerMetricsManager;
import io.nosqlbench.nb.annotations.Maturity;
import io.nosqlbench.nb.annotations.Service;
@@ -56,7 +59,6 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
-import java.util.concurrent.locks.LockSupport;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -353,7 +355,7 @@ public class NBCLI implements Function {
}
if (options.wantsTopicalHelp()) {
- Optional helpDoc = MarkdownDocInfo.forHelpTopic(options.wantsTopicalHelpFor());
+ Optional helpDoc = MarkdownFinder.forHelpTopic(options.wantsTopicalHelpFor());
System.out.println(helpDoc.orElseThrow(
() -> new RuntimeException("No help could be found for " + options.wantsTopicalHelpFor())
));
@@ -486,7 +488,7 @@ public class NBCLI implements Function {
logger.info(scenariosResults.getExecutionSummary());
if (scenariosResults.hasError()) {
- Exception exception = scenariosResults.getOne().getException().get();
+ Exception exception = scenariosResults.getOne().getException();
logger.warn(scenariosResults.getExecutionSummary());
NBCLIErrorHandler.handle(exception, options.wantsStackTraces());
System.err.println(exception.getMessage()); // TODO: make this consistent with ConsoleLogging sequencing
diff --git a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLIOptions.java b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLIOptions.java
index 8cb3520ec..50abcebb0 100644
--- a/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLIOptions.java
+++ b/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLIOptions.java
@@ -18,7 +18,7 @@ package io.nosqlbench.engine.cli;
import io.nosqlbench.engine.api.metrics.IndicatorMode;
import io.nosqlbench.api.engine.util.Unit;
-import io.nosqlbench.engine.core.script.Scenario;
+import io.nosqlbench.engine.core.lifecycle.scenario.Scenario;
import io.nosqlbench.nb.annotations.Maturity;
import io.nosqlbench.api.system.NBEnvironment;
import io.nosqlbench.api.errors.BasicError;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityProgressIndicator.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java
similarity index 97%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityProgressIndicator.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java
index 494b7df3d..7d50e799c 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityProgressIndicator.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityProgressIndicator.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.activity;
import io.nosqlbench.engine.api.activityapi.core.RunState;
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
@@ -22,6 +22,7 @@ import io.nosqlbench.engine.api.activityapi.core.progress.StateCapable;
import io.nosqlbench.engine.api.metrics.IndicatorMode;
import io.nosqlbench.api.engine.metrics.PeriodicRunnable;
import io.nosqlbench.api.engine.util.Unit;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenarioController;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityStatus.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityStatus.java
similarity index 92%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityStatus.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityStatus.java
index d77927fbc..446df7ffc 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityStatus.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityStatus.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.activity;
public class ActivityStatus {
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/NBCLIErrorHandler.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/process/NBCLIErrorHandler.java
similarity index 98%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/NBCLIErrorHandler.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/process/NBCLIErrorHandler.java
index 1a786377f..226adbe6e 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/NBCLIErrorHandler.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/process/NBCLIErrorHandler.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.process;
import io.nosqlbench.api.errors.BasicError;
import org.apache.logging.log4j.LogManager;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ShutdownManager.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/process/ShutdownManager.java
similarity index 95%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ShutdownManager.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/process/ShutdownManager.java
index 3d5b004bf..bc4568f5a 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ShutdownManager.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/process/ShutdownManager.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.process;
import io.nosqlbench.engine.api.activityapi.core.Shutdownable;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
index 150929fda..64198b474 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
@@ -13,28 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.scenario;
-import io.nosqlbench.engine.api.activityapi.core.Activity;
-import io.nosqlbench.engine.api.activityapi.core.ActivityType;
-import io.nosqlbench.engine.api.activityapi.core.RunState;
-import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
-import io.nosqlbench.api.engine.activityimpl.ActivityDef;
-import io.nosqlbench.api.engine.activityimpl.ParameterMap;
-import io.nosqlbench.engine.api.activityimpl.uniform.StandardActivityType;
-import io.nosqlbench.api.engine.metrics.ActivityMetrics;
-import io.nosqlbench.engine.core.annotation.Annotators;
-import io.nosqlbench.nb.annotations.Maturity;
import io.nosqlbench.api.annotations.Annotation;
import io.nosqlbench.api.annotations.Layer;
-import io.nosqlbench.api.config.standard.ConfigSuggestions;
-import io.nosqlbench.api.errors.BasicError;
+import io.nosqlbench.api.engine.activityimpl.ActivityDef;
+import io.nosqlbench.api.engine.activityimpl.ParameterMap;
+import io.nosqlbench.api.engine.metrics.ActivityMetrics;
+import io.nosqlbench.engine.api.activityapi.core.Activity;
+import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
+import io.nosqlbench.engine.core.annotation.Annotators;
+import io.nosqlbench.engine.core.lifecycle.ExecutionResult;
+import io.nosqlbench.engine.core.lifecycle.IndexedThreadFactory;
+import io.nosqlbench.engine.core.lifecycle.activity.*;
+import io.nosqlbench.nb.annotations.Maturity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import java.security.InvalidParameterException;
import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenarioShutdownHook.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioShutdownHook.java
similarity index 94%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenarioShutdownHook.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioShutdownHook.java
index 679cb9dd3..e064f88b0 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenarioShutdownHook.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioShutdownHook.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario;
import org.apache.logging.log4j.Logger;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenariosExecutor.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java
similarity index 97%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenariosExecutor.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java
index dedaf4ff3..8c45134b1 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenariosExecutor.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario;
-import io.nosqlbench.engine.core.lifecycle.*;
import io.nosqlbench.api.errors.BasicError;
+import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
+import io.nosqlbench.engine.core.lifecycle.IndexedThreadFactory;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.ScenarioExceptionHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenariosResults.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java
similarity index 94%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenariosResults.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java
index 80c44b8c8..2d916e851 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ScenariosResults.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.scenario;
-import io.nosqlbench.engine.core.script.Scenario;
-import io.nosqlbench.engine.core.script.ScenariosExecutor;
+import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/MetricsMapper.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/MetricsMapper.java
similarity index 95%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/MetricsMapper.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/MetricsMapper.java
index 105ee23f0..1aa41324a 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/MetricsMapper.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/MetricsMapper.java
@@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario.script;
import com.codahale.metrics.*;
import io.nosqlbench.engine.api.activityapi.core.Activity;
import io.nosqlbench.engine.api.activityapi.core.ActivityType;
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.api.engine.metrics.ActivityMetrics;
-import io.nosqlbench.engine.core.lifecycle.ActivityTypeLoader;
-import io.nosqlbench.engine.core.metrics.PolyglotMetricRegistryBindings;
+import io.nosqlbench.engine.core.lifecycle.activity.ActivityTypeLoader;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.bindings.PolyglotMetricRegistryBindings;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/SandboxExtensionFinder.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/SandboxExtensionFinder.java
similarity index 96%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/SandboxExtensionFinder.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/SandboxExtensionFinder.java
index 8323d3c2b..e351d6db7 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/SandboxExtensionFinder.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/SandboxExtensionFinder.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario.script;
import io.nosqlbench.engine.api.extensions.ScriptingPluginInfo;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenarioContext.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScenarioContext.java
similarity index 90%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenarioContext.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScenarioContext.java
index f3e6a2c1a..78b80211d 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenarioContext.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScenarioContext.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario.script;
-import io.nosqlbench.engine.core.lifecycle.ScenarioController;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenarioController;
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
public class ScenarioContext extends ScriptEnvBuffer {
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenarioExceptionHandler.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScenarioExceptionHandler.java
similarity index 88%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenarioExceptionHandler.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScenarioExceptionHandler.java
index 2f3832c45..5cf420461 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScenarioExceptionHandler.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScenarioExceptionHandler.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario.script;
+
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenariosExecutor;
public class ScenarioExceptionHandler implements Thread.UncaughtExceptionHandler {
private final ScenariosExecutor scenariosExecutor;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScriptExecutionError.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScriptExecutionError.java
similarity index 93%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/ScriptExecutionError.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScriptExecutionError.java
index 7b826e042..1ddf59a18 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScriptExecutionError.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScriptExecutionError.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario.script;
public class ScriptExecutionError extends RuntimeException {
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScriptParams.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScriptParams.java
similarity index 97%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/ScriptParams.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScriptParams.java
index 69234c24e..a6d731fca 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ScriptParams.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/ScriptParams.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario.script;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -43,8 +43,7 @@ public class ScriptParams extends HashMap implements ProxyObject
Map map;
if (overrides instanceof Map) {
map = (Map) overrides;
- } else if (overrides instanceof Value) {
- Value v = (Value) overrides;
+ } else if (overrides instanceof Value v) {
map = v.as(Map.class);
} else {
throw new RuntimeException("Unrecognized overrides type: " + overrides.getClass().getCanonicalName());
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/metrics/PolyglotMetricRegistryBindings.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotMetricRegistryBindings.java
similarity index 97%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/metrics/PolyglotMetricRegistryBindings.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotMetricRegistryBindings.java
index 7b26f51c9..2167dca95 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/metrics/PolyglotMetricRegistryBindings.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotMetricRegistryBindings.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.metrics;
+package io.nosqlbench.engine.core.lifecycle.scenario.script.bindings;
import com.codahale.metrics.*;
import com.codahale.metrics.Timer;
+import io.nosqlbench.engine.core.metrics.MetricMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.graalvm.polyglot.Value;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java
index 38bb7b195..b1c9ef12d 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.scenario.script.bindings;
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenarioController;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.graalvm.polyglot.Value;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ReadOnlyBindings.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/ReadOnlyBindings.java
similarity index 95%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/ReadOnlyBindings.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/ReadOnlyBindings.java
index 54e61c19f..b45330a00 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ReadOnlyBindings.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/ReadOnlyBindings.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario.script.bindings;
import javax.script.Bindings;
import java.util.Map;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ReadOnlyBindingsException.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/ReadOnlyBindingsException.java
similarity index 93%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/ReadOnlyBindingsException.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/ReadOnlyBindingsException.java
index 73d05b507..60ee1049d 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/ReadOnlyBindingsException.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/ReadOnlyBindingsException.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario.script.bindings;
public class ReadOnlyBindingsException extends RuntimeException {
private final Object parent;
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/metrics/MetricReporters.java b/engine-core/src/main/java/io/nosqlbench/engine/core/metrics/MetricReporters.java
index 84754cb07..70994fbbe 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/metrics/MetricReporters.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/metrics/MetricReporters.java
@@ -21,7 +21,7 @@ import com.codahale.metrics.graphite.Graphite;
import com.codahale.metrics.graphite.GraphiteReporter;
import io.nosqlbench.engine.api.activityapi.core.Shutdownable;
import io.nosqlbench.api.engine.metrics.ActivityMetrics;
-import io.nosqlbench.engine.core.lifecycle.ShutdownManager;
+import io.nosqlbench.engine.core.lifecycle.process.ShutdownManager;
import io.nosqlbench.engine.core.logging.Log4JMetricsReporter;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
@@ -54,7 +54,7 @@ public class MetricReporters implements Shutdownable {
}
public MetricReporters addGraphite(String dest, String prefix) {
- logger.debug("Adding graphite reporter to " + dest + " with prefix " + prefix);
+ logger.debug(() -> "Adding graphite reporter to " + dest + " with prefix " + prefix);
if (dest.indexOf(":")>=0) {
String[] split = dest.split(":");
addGraphite(split[0],Integer.valueOf(split[1]),prefix);
@@ -65,7 +65,7 @@ public class MetricReporters implements Shutdownable {
}
public void addCSVReporter(String directoryName, String prefix) {
- logger.debug("Adding CSV reporter to " + directoryName + " with prefix " + prefix);
+ logger.debug(() -> "Adding CSV reporter to " + directoryName + " with prefix " + prefix);
if (metricRegistries.isEmpty()) {
throw new RuntimeException("There are no metric registries.");
diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/ScenarioTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/ScenarioTest.java
index 2678f0719..b210c95c5 100644
--- a/engine-core/src/test/java/io/nosqlbench/engine/core/ScenarioTest.java
+++ b/engine-core/src/test/java/io/nosqlbench/engine/core/ScenarioTest.java
@@ -17,7 +17,7 @@
package io.nosqlbench.engine.core;
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
-import io.nosqlbench.engine.core.script.Scenario;
+import io.nosqlbench.engine.core.lifecycle.scenario.Scenario;
import io.nosqlbench.nb.annotations.Maturity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScenariosExecutorTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScenariosExecutorTest.java
index a391e5f0b..ac7e0ed5e 100644
--- a/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScenariosExecutorTest.java
+++ b/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScenariosExecutorTest.java
@@ -16,7 +16,9 @@
package io.nosqlbench.engine.core.script;
-import io.nosqlbench.engine.core.lifecycle.ScenariosResults;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenariosResults;
+import io.nosqlbench.engine.core.lifecycle.scenario.Scenario;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenariosExecutor;
import io.nosqlbench.nb.annotations.Maturity;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
diff --git a/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java b/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java
index 52ecd9b22..561354767 100644
--- a/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java
+++ b/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java
@@ -21,9 +21,9 @@ import io.nosqlbench.engine.cli.BasicScriptBuffer;
import io.nosqlbench.engine.cli.Cmd;
import io.nosqlbench.engine.cli.NBCLICommandParser;
import io.nosqlbench.engine.cli.ScriptBuffer;
-import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
-import io.nosqlbench.engine.core.script.Scenario;
-import io.nosqlbench.engine.core.script.ScenariosExecutor;
+import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
+import io.nosqlbench.engine.core.lifecycle.scenario.Scenario;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenariosExecutor;
import io.nosqlbench.engine.rest.services.WorkSpace;
import io.nosqlbench.engine.rest.services.WorkspaceFinder;
import io.nosqlbench.engine.rest.transfertypes.LiveScenarioView;
diff --git a/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/LiveScenarioView.java b/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/LiveScenarioView.java
index bcd0e9a1f..2af423f65 100644
--- a/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/LiveScenarioView.java
+++ b/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/LiveScenarioView.java
@@ -19,7 +19,7 @@ package io.nosqlbench.engine.rest.transfertypes;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
-import io.nosqlbench.engine.core.script.Scenario;
+import io.nosqlbench.engine.core.lifecycle.scenario.Scenario;
import java.util.ArrayList;
import java.util.Collection;
diff --git a/nbr/src/test/java/io/nosqlbench/engine/core/script/MetricsMapperIntegrationTest.java b/nbr/src/test/java/io/nosqlbench/engine/core/script/MetricsMapperIntegrationTest.java
index 78050f837..ce80b70e5 100644
--- a/nbr/src/test/java/io/nosqlbench/engine/core/script/MetricsMapperIntegrationTest.java
+++ b/nbr/src/test/java/io/nosqlbench/engine/core/script/MetricsMapperIntegrationTest.java
@@ -16,6 +16,7 @@
package io.nosqlbench.engine.core.script;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.MetricsMapper;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
From c076b1079c2eb8756d487e1644291095c64353dd Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:02:28 -0600
Subject: [PATCH 08/19] make http extension docs distinct from http adapter
docs
---
.../engine/extensions/http/{http.md => http-extension.md} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename engine-extensions/src/main/java/io/nosqlbench/engine/extensions/http/{http.md => http-extension.md} (100%)
diff --git a/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/http/http.md b/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/http/http-extension.md
similarity index 100%
rename from engine-extensions/src/main/java/io/nosqlbench/engine/extensions/http/http.md
rename to engine-extensions/src/main/java/io/nosqlbench/engine/extensions/http/http-extension.md
From 1416c71d9149dfdce5042335b363039356368d51 Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:02:48 -0600
Subject: [PATCH 09/19] internalize activity start logic
---
.../scenario/ScenarioController.java | 28 +++++++++++--------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
index 64198b474..d7ab41ca1 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
@@ -78,10 +78,21 @@ public class ScenarioController {
.detail("params", activityDef.toString())
.build());
+ doStartActivity(activityDef);
+ }
- ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, true);
- scenariologger.debug("START " + activityDef.getAlias());
- activityThreadsManager.startActivity();
+
+ private synchronized ActivityRuntimeInfo doStartActivity(ActivityDef activityDef) {
+ if (!this.activityInfoMap.containsKey(activityDef.getAlias())) {
+ Activity activity = this.activityLoader.loadActivity(activityDef);
+ ActivityExecutor executor = new ActivityExecutor(activity, this.scenario.getScenarioName());
+ Future startedActivity = activitiesExecutor.submit(executor);
+ ActivityRuntimeInfo activityRuntimeInfo = new ActivityRuntimeInfo(activity, startedActivity, executor);
+ this.activityInfoMap.put(activity.getAlias(), activityRuntimeInfo);
+ executor.startActivity();
+ scenariologger.debug("STARTED " + activityDef.getAlias());
+ }
+ return this.activityInfoMap.get(activityDef.getAlias());
}
/**
@@ -107,7 +118,7 @@ public class ScenarioController {
public synchronized void run(int timeout, Map activityDefMap) {
ActivityDef ad = new ActivityDef(new ParameterMap(activityDefMap));
- run(timeout, ad);
+ run(ad, timeout);
}
/**
@@ -126,13 +137,8 @@ public class ScenarioController {
.detail("params", activityDef.toString())
.build());
- ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, true);
- scenariologger.debug("RUN alias=" + activityDef.getAlias());
- scenariologger.debug(" (RUN/START) alias=" + activityDef.getAlias());
- activityThreadsManager.startActivity();
- scenariologger.debug(" (RUN/AWAIT before) alias=" + activityDef.getAlias());
- boolean completed = activityThreadsManager.awaitCompletion(timeout);
- scenariologger.debug(" (RUN/AWAIT after) completed=" + activityDef.getAlias());
+ doStartActivity(activityDef);
+ awaitActivity(activityDef, timeoutMs);
}
public synchronized void run(int timeout, String activityDefString) {
From 1816381f97cc62247d3d448e010565ce716dfbc2 Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:03:12 -0600
Subject: [PATCH 10/19] make integrated tests more robust
---
.../src/test/resources/scripts/examples/activityerror.js | 2 +-
.../src/test/resources/scripts/examples/startstopdiag.js | 7 ++++---
.../nosqlbench/cli/testing/ExitStatusIntegrationTests.java | 4 ++--
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/nbr-examples/src/test/resources/scripts/examples/activityerror.js b/nbr-examples/src/test/resources/scripts/examples/activityerror.js
index 265729eb4..4e0050a11 100644
--- a/nbr-examples/src/test/resources/scripts/examples/activityerror.js
+++ b/nbr-examples/src/test/resources/scripts/examples/activityerror.js
@@ -19,7 +19,7 @@ activitydef1 = {
"driver" : "diag",
"cycles" : "0..1500000",
"threads" : "1",
- "targetrate" : "500",
+ "targetrate" : "10",
"op" : {
"log": "type=log modulo=1"
}
diff --git a/nbr-examples/src/test/resources/scripts/examples/startstopdiag.js b/nbr-examples/src/test/resources/scripts/examples/startstopdiag.js
index 4ef99242e..f7d17ebc6 100644
--- a/nbr-examples/src/test/resources/scripts/examples/startstopdiag.js
+++ b/nbr-examples/src/test/resources/scripts/examples/startstopdiag.js
@@ -18,17 +18,18 @@ activitydef = {
"alias" : "teststartstopdiag",
"driver" : "diag",
"cycles" : "0..1000000000",
- "threads" : "25",
+ "threads" : "5",
"interval" : "2000",
- "op" : "noop"
+ "op" : "noop",
+ "rate" : "5"
};
print('starting activity teststartstopdiag');
scenario.start(activitydef);
print('waiting 500 ms');
-
scenario.waitMillis(500);
+
print('waited, stopping activity teststartstopdiag');
scenario.stop(activitydef);
diff --git a/nbr/src/test/java/io/nosqlbench/cli/testing/ExitStatusIntegrationTests.java b/nbr/src/test/java/io/nosqlbench/cli/testing/ExitStatusIntegrationTests.java
index c1b580e24..39d254b2e 100644
--- a/nbr/src/test/java/io/nosqlbench/cli/testing/ExitStatusIntegrationTests.java
+++ b/nbr/src/test/java/io/nosqlbench/cli/testing/ExitStatusIntegrationTests.java
@@ -96,8 +96,8 @@ class ExitStatusIntegrationTests {
);
String stdout = String.join("\n", result.getStdoutData());
String stderr = String.join("\n", result.getStderrData());
- assertThat(result.exception).isNotNull();
- assertThat(result.exception.getMessage()).contains("diag space was configured to throw");
+ assertThat(result.exitStatus).isEqualTo(2);
+ assertThat(stderr).contains("diag space was configured to throw");
}
}
From 077b41a3c64ce7b534f3debd9aacec65d6b200de Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:03:22 -0600
Subject: [PATCH 11/19] misc naming, typo and formatting improvements
---
.../ActivityExceptionHandler.java | 8 +--
.../scenario/ScenarioController.java | 8 +--
.../lifecycle/scenario/ScenariosExecutor.java | 24 +++----
.../lifecycle/scenario/ScenariosResults.java | 10 +--
.../script/bindings/ActivityBindings.java} | 8 +--
.../bindings/PolyglotScenarioController.java | 6 +-
...rkdownDocInfo.java => MarkdownFinder.java} | 10 +--
.../engine/core/script/ScriptParamsTest.java | 2 +-
.../resources/ScenarioExecutorEndpoint.java | 4 +-
.../engine/rest/transfertypes/ResultView.java | 12 ++--
.../nbr/examples/ScriptExampleTests.java | 64 +++++++++----------
.../examples/SpeedCheckIntegrationTests.java | 6 +-
12 files changed, 81 insertions(+), 81 deletions(-)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ => activity}/ActivityExceptionHandler.java (87%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/{script/NashornActivityBindings.java => lifecycle/scenario/script/bindings/ActivityBindings.java} (93%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/metadata/{MarkdownDocInfo.java => MarkdownFinder.java} (89%)
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExceptionHandler.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExceptionHandler.java
similarity index 87%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExceptionHandler.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExceptionHandler.java
index b088829f3..751c26cbf 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityExceptionHandler.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExceptionHandler.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.activity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -23,9 +23,9 @@ public class ActivityExceptionHandler implements Thread.UncaughtExceptionHandler
private static final Logger logger = LogManager.getLogger(ActivityExceptionHandler.class);
- private final ActivityThreadsManager executor;
+ private final ActivityExecutor executor;
- public ActivityExceptionHandler(ActivityThreadsManager executor) {
+ public ActivityExceptionHandler(ActivityExecutor executor) {
this.executor = executor;
logger.debug(() -> "Activity exception handler starting up for executor '" + executor + "'");
}
@@ -33,7 +33,7 @@ public class ActivityExceptionHandler implements Thread.UncaughtExceptionHandler
@Override
public void uncaughtException(Thread t, Throwable e) {
- logger.error("Uncaught exception in thread '" + t.getName() + ", state[" + t.getState() + "], notifying executor '" + executor + "'");
+ logger.error("Uncaught exception in thread '" + t.getName() + ", state[" + t.getState() + "], notifying executor '" + executor + "': " + e);
executor.notifyException(t, e);
}
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
index d7ab41ca1..bef6a8c2e 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
@@ -124,10 +124,10 @@ public class ScenarioController {
/**
* Synchronously run the defined activity with a timeout in seconds.
*
- * @param timeout seconds to await completion of the activity.
+ * @param timeoutMs seconds to await completion of the activity.
* @param activityDef A definition for an activity to run
*/
- public synchronized void run(int timeout, ActivityDef activityDef) {
+ public synchronized void run(ActivityDef activityDef, long timeoutMs) {
Annotators.recordAnnotation(Annotation.newBuilder()
.session(sessionId)
.now()
@@ -143,7 +143,7 @@ public class ScenarioController {
public synchronized void run(int timeout, String activityDefString) {
ActivityDef activityDef = ActivityDef.parseActivityDef(activityDefString);
- run(timeout, activityDef);
+ run(activityDef, timeout);
}
public synchronized void run(Map activityDefMap) {
@@ -156,7 +156,7 @@ public class ScenarioController {
public synchronized void run(ActivityDef activityDef) {
- run(Integer.MAX_VALUE, activityDef);
+ run(activityDef, Long.MAX_VALUE);
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java
index 8c45134b1..b644b84d1 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java
@@ -52,7 +52,7 @@ public class ScenariosExecutor {
if (submitted.get(scenario.getScenarioName()) != null) {
throw new BasicError("Scenario " + scenario.getScenarioName() + " is already defined. Remove it first to reuse the name.");
}
- Future future = executor.submit(scenario);
+ Future future = executor.submit(scenario);
SubmittedScenario s = new SubmittedScenario(scenario, future);
submitted.put(s.getName(), s);
}
@@ -108,7 +108,7 @@ public class ScenariosExecutor {
throw new RuntimeException("executor still runningScenarios after awaiting all results for " + timeout
+ "ms. isTerminated:" + executor.isTerminated() + " isShutdown:" + executor.isShutdown());
}
- Map scenarioResultMap = new LinkedHashMap<>();
+ Map scenarioResultMap = new LinkedHashMap<>();
getAsyncResultStatus()
.entrySet()
.forEach(
@@ -135,26 +135,26 @@ public class ScenariosExecutor {
* All submitted scenarios are included. Those which are still pending
* are returned with an empty option.
*
- *
Results may be exceptional. If {@link ExecMetricsResult#getException()} is present,
+ *
Results may be exceptional. If {@link ExecutionMetricsResult#getException()} is present,
* then the result did not complete normally.
*
* @return map of async results, with incomplete results as Optional.empty()
*/
- public Map> getAsyncResultStatus() {
+ public Map> getAsyncResultStatus() {
- Map> optResults = new LinkedHashMap<>();
+ Map> optResults = new LinkedHashMap<>();
for (SubmittedScenario submittedScenario : submitted.values()) {
- Future resultFuture = submittedScenario.getResultFuture();
+ Future resultFuture = submittedScenario.getResultFuture();
- Optional oResult = Optional.empty();
+ Optional oResult = Optional.empty();
if (resultFuture.isDone()) {
try {
oResult = Optional.of(resultFuture.get());
} catch (Exception e) {
long now = System.currentTimeMillis();
logger.debug("creating exceptional scenario result from getAsyncResultStatus");
- oResult = Optional.of(new ExecMetricsResult(now, now, "errored output", e));
+ oResult = Optional.of(new ExecutionMetricsResult(now, now, "errored output", e));
}
}
@@ -181,7 +181,7 @@ public class ScenariosExecutor {
* @param scenarioName the scenario name of interest
* @return an optional result
*/
- public Optional> getPendingResult(String scenarioName) {
+ public Optional> getPendingResult(String scenarioName) {
return Optional.ofNullable(submitted.get(scenarioName)).map(s -> s.resultFuture);
}
@@ -226,9 +226,9 @@ public class ScenariosExecutor {
private static class SubmittedScenario {
private final Scenario scenario;
- private final Future resultFuture;
+ private final Future resultFuture;
- SubmittedScenario(Scenario scenario, Future resultFuture) {
+ SubmittedScenario(Scenario scenario, Future resultFuture) {
this.scenario = scenario;
this.resultFuture = resultFuture;
}
@@ -237,7 +237,7 @@ public class ScenariosExecutor {
return scenario;
}
- Future getResultFuture() {
+ Future getResultFuture() {
return resultFuture;
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java
index 2d916e851..2cd5e763b 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java
@@ -27,14 +27,14 @@ public class ScenariosResults {
private static final Logger logger = LogManager.getLogger(ScenariosResults.class);
private final String scenariosExecutorName;
- private final Map scenarioResultMap = new LinkedHashMap<>();
+ private final Map scenarioResultMap = new LinkedHashMap<>();
public ScenariosResults(ScenariosExecutor scenariosExecutor) {
this.scenariosExecutorName = scenariosExecutor.getName();
}
- public ScenariosResults(ScenariosExecutor scenariosExecutor, Map map) {
+ public ScenariosResults(ScenariosExecutor scenariosExecutor, Map map) {
this.scenariosExecutorName = scenariosExecutor.getName();
scenarioResultMap.putAll(map);
}
@@ -46,7 +46,7 @@ public class ScenariosResults {
return sb;
}
- public ExecMetricsResult getOne() {
+ public ExecutionMetricsResult getOne() {
if (this.scenarioResultMap.size() != 1) {
throw new RuntimeException("getOne found " + this.scenarioResultMap.size() + " results instead of 1.");
}
@@ -55,9 +55,9 @@ public class ScenariosResults {
}
public void reportToLog() {
- for (Map.Entry entry : this.scenarioResultMap.entrySet()) {
+ for (Map.Entry entry : this.scenarioResultMap.entrySet()) {
Scenario scenario = entry.getKey();
- ExecMetricsResult oresult = entry.getValue();
+ ExecutionMetricsResult oresult = entry.getValue();
logger.info("results for scenario: " + scenario);
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/NashornActivityBindings.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/ActivityBindings.java
similarity index 93%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/NashornActivityBindings.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/ActivityBindings.java
index d069f594e..3b7b9c581 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/NashornActivityBindings.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/ActivityBindings.java
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario.script.bindings;
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
-import io.nosqlbench.engine.core.lifecycle.ScenarioController;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenarioController;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.proxy.ProxyObject;
@@ -27,12 +27,12 @@ import java.util.stream.Collectors;
/**
* Provide a bindings wrapper around a ScenarioController,
*/
-public class NashornActivityBindings implements Bindings, ProxyObject {
+public class ActivityBindings implements Bindings, ProxyObject {
private final ScenarioController scenario;
private final Map elementMap = new HashMap();
- public NashornActivityBindings(ScenarioController scenarioController) {
+ public ActivityBindings(ScenarioController scenarioController) {
this.scenario = scenarioController;
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java
index b1c9ef12d..8d2504724 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/script/bindings/PolyglotScenarioController.java
@@ -81,7 +81,7 @@ public class PolyglotScenarioController {
private synchronized void runValue(int timeout, Value spec) {
logger.debug("run(Value) called with:" + spec);
if (spec.isHostObject()) {
- controller.run(timeout, (ActivityDef) spec.asHostObject());
+ controller.run(spec.asHostObject(),timeout);
} else if (spec.isString()) {
controller.run(timeout, spec.asString());
} else if (spec.hasMembers()) {
@@ -89,7 +89,7 @@ public class PolyglotScenarioController {
} else if (spec.isHostObject()) {
Object o = spec.asHostObject();
if (o instanceof ActivityDef) {
- controller.run(timeout, (ActivityDef) o);
+ controller.run((ActivityDef) o, timeout);
} else {
throw new RuntimeException("unrecognized polyglot host object type for run: " + spec);
}
@@ -165,7 +165,7 @@ public class PolyglotScenarioController {
private synchronized void awaitValue(Value spec) {
if (spec.isHostObject()) {
- controller.await((ActivityDef) spec.asHostObject());
+ controller.await(spec.asHostObject(), Long.MAX_VALUE);
} else if (spec.hasMembers()) {
controller.await(spec.as(Map.class));
} else if (spec.isString()) {
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/metadata/MarkdownDocInfo.java b/engine-core/src/main/java/io/nosqlbench/engine/core/metadata/MarkdownFinder.java
similarity index 89%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/metadata/MarkdownDocInfo.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/metadata/MarkdownFinder.java
index 45dd25263..26f719f79 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/metadata/MarkdownDocInfo.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/metadata/MarkdownFinder.java
@@ -18,7 +18,7 @@ package io.nosqlbench.engine.core.metadata;
import io.nosqlbench.engine.api.activityapi.core.ActivityType;
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
-import io.nosqlbench.engine.core.lifecycle.ActivityTypeLoader;
+import io.nosqlbench.engine.core.lifecycle.activity.ActivityTypeLoader;
import io.nosqlbench.nb.annotations.Service;
import io.nosqlbench.api.content.Content;
import io.nosqlbench.api.content.NBIO;
@@ -28,20 +28,20 @@ import org.apache.logging.log4j.Logger;
import java.util.Optional;
-public class MarkdownDocInfo {
- private final static Logger logger = LogManager.getLogger(MarkdownDocInfo.class);
+public class MarkdownFinder {
+ private final static Logger logger = LogManager.getLogger(MarkdownFinder.class);
public static Optional forHelpTopic(String topic) {
String help = null;
try {
- help = new MarkdownDocInfo().forActivityInstance(topic);
+ help = new MarkdownFinder().forActivityInstance(topic);
return Optional.ofNullable(help);
} catch (Exception e) {
logger.debug("Did not find help topic for activity instance: " + topic);
}
try {
- help = new MarkdownDocInfo().forResourceMarkdown(topic, "docs/");
+ help = new MarkdownFinder().forResourceMarkdown(topic, "docs/");
return Optional.ofNullable(help);
} catch (Exception e) {
logger.debug("Did not find help topic for generic markdown file: " + topic + "(.md)");
diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScriptParamsTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScriptParamsTest.java
index ee5da9aa9..1778689b4 100644
--- a/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScriptParamsTest.java
+++ b/engine-core/src/test/java/io/nosqlbench/engine/core/script/ScriptParamsTest.java
@@ -17,12 +17,12 @@
package io.nosqlbench.engine.core.script;
import io.nosqlbench.api.errors.BasicError;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.ScriptParams;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
-import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
public class ScriptParamsTest {
diff --git a/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java b/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java
index 561354767..ba1e4b132 100644
--- a/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java
+++ b/engine-rest/src/main/java/io/nosqlbench/engine/rest/resources/ScenarioExecutorEndpoint.java
@@ -234,8 +234,8 @@ public class ScenarioExecutorEndpoint implements WebServiceObject {
Optional pendingScenario = executor.getPendingScenario(scenarioName);
if (pendingScenario.isPresent()) {
- Optional> pendingResult = executor.getPendingResult(scenarioName);
- Future scenarioResultFuture = pendingResult.get();
+ Optional> pendingResult = executor.getPendingResult(scenarioName);
+ Future scenarioResultFuture = pendingResult.get();
return new LiveScenarioView(pendingScenario.get());
} else {
throw new RuntimeException("Scenario name '" + scenarioName + "' not found.");
diff --git a/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/ResultView.java b/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/ResultView.java
index e84da8113..9bf85980f 100644
--- a/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/ResultView.java
+++ b/engine-rest/src/main/java/io/nosqlbench/engine/rest/transfertypes/ResultView.java
@@ -16,18 +16,18 @@
package io.nosqlbench.engine.rest.transfertypes;
-import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
+import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
public class ResultView {
- private final ExecMetricsResult result;
+ private final ExecutionMetricsResult result;
- public ResultView(ExecMetricsResult result) {
+ public ResultView(ExecutionMetricsResult result) {
this.result = result;
}
public String getIOLog() {
- if (result!=null) {
+ if (result != null) {
return result.getIOLog();
} else {
return "";
@@ -35,8 +35,8 @@ public class ResultView {
}
public String getError() {
- if (result!=null && result.getException().isPresent()) {
- return result.getException().get().getMessage();
+ if (result != null && result.getException()!=null) {
+ return result.getException().getMessage();
}
return "";
}
diff --git a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java
index a84a712b2..28988115e 100644
--- a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java
+++ b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/ScriptExampleTests.java
@@ -16,10 +16,10 @@
package io.nosqlbench.nbr.examples;
-import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
-import io.nosqlbench.engine.core.lifecycle.ScenariosResults;
-import io.nosqlbench.engine.core.script.Scenario;
-import io.nosqlbench.engine.core.script.ScenariosExecutor;
+import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenariosResults;
+import io.nosqlbench.engine.core.lifecycle.scenario.Scenario;
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenariosExecutor;
import io.nosqlbench.nb.annotations.Maturity;
import org.apache.commons.compress.utils.IOUtils;
import org.assertj.core.data.Offset;
@@ -41,7 +41,7 @@ import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
public class ScriptExampleTests {
- public static ExecMetricsResult runScenario(String scriptname, String... params) {
+ public static ExecutionMetricsResult runScenario(String scriptname, String... params) {
if ((params.length % 2) != 0) {
throw new RuntimeException("params must be pairwise key, value, ...");
}
@@ -74,7 +74,7 @@ public class ScriptExampleTests {
// s.addScriptText("load('classpath:scripts/async/" + scriptname + ".js');");
executor.execute(s);
ScenariosResults scenariosResults = executor.awaitAllResults();
- ExecMetricsResult scenarioResult = scenariosResults.getOne();
+ ExecutionMetricsResult scenarioResult = scenariosResults.getOne();
executor.shutdownNow();
return scenarioResult;
}
@@ -86,7 +86,7 @@ public class ScriptExampleTests {
@Test
public void testLinkedInput() {
- ExecMetricsResult scenarioResult = runScenario("linkedinput");
+ ExecutionMetricsResult scenarioResult = runScenario("linkedinput");
Pattern p = Pattern.compile(".*started leader.*started follower.*stopped leader.*stopped follower.*",
Pattern.DOTALL);
assertThat(p.matcher(scenarioResult.getIOLog()).matches()).isTrue();
@@ -94,14 +94,14 @@ public class ScriptExampleTests {
@Test
public void testExceptionPropagationFromMotorThread() {
- ExecMetricsResult scenarioResult = runScenario("activityerror");
- assertThat(scenarioResult.getException()).isPresent();
- assertThat(scenarioResult.getException().get().getMessage()).contains("For input string: \"unparsable\"");
+ ExecutionMetricsResult scenarioResult = runScenario("activityerror");
+ assertThat(scenarioResult.getException()).isNotNull();
+ assertThat(scenarioResult.getException().getMessage()).contains("For input string: \"unparsable\"");
}
@Test
public void testCycleRate() {
- ExecMetricsResult scenarioResult = runScenario("cycle_rate");
+ ExecutionMetricsResult scenarioResult = runScenario("cycle_rate");
String iolog = scenarioResult.getIOLog();
System.out.println("iolog\n" + iolog);
Pattern p = Pattern.compile(".*mean cycle rate = (\\d[.\\d]+).*", Pattern.DOTALL);
@@ -116,13 +116,13 @@ public class ScriptExampleTests {
@Test
public void testExtensionPoint() {
- ExecMetricsResult scenarioResult = runScenario("extensions");
+ ExecutionMetricsResult scenarioResult = runScenario("extensions");
assertThat(scenarioResult.getIOLog()).contains("sum is 46");
}
@Test
public void testOptimo() {
- ExecMetricsResult scenarioResult = runScenario("optimo");
+ ExecutionMetricsResult scenarioResult = runScenario("optimo");
String iolog = scenarioResult.getIOLog();
System.out.println("iolog\n" + iolog);
assertThat(iolog).contains("map of result was");
@@ -130,14 +130,14 @@ public class ScriptExampleTests {
@Test
public void testExtensionCsvLogger() {
- ExecMetricsResult scenarioResult = runScenario("extension_csvmetrics");
+ ExecutionMetricsResult scenarioResult = runScenario("extension_csvmetrics");
assertThat(scenarioResult.getIOLog()).contains("started new " +
"csvlogger: logs/csvmetricstestdir");
}
@Test
public void testScriptParamsVariable() {
- ExecMetricsResult scenarioResult = runScenario("params_variable", "one", "two", "three", "four");
+ ExecutionMetricsResult scenarioResult = runScenario("params_variable", "one", "two", "three", "four");
assertThat(scenarioResult.getIOLog()).contains("params[\"one\"]='two'");
assertThat(scenarioResult.getIOLog()).contains("params[\"three\"]='four'");
assertThat(scenarioResult.getIOLog()).contains("overridden[\"three\"] [overridden-three-five]='five'");
@@ -146,7 +146,7 @@ public class ScriptExampleTests {
@Test
public void testScriptParamsUndefVariableWithOverride() {
- ExecMetricsResult scenarioResult = runScenario("undef_param", "one", "two", "three", "four");
+ ExecutionMetricsResult scenarioResult = runScenario("undef_param", "one", "two", "three", "four");
assertThat(scenarioResult.getIOLog()).contains("before: params[\"three\"]:four");
assertThat(scenarioResult.getIOLog()).contains("before: params.three:four");
assertThat(scenarioResult.getIOLog()).contains("after: params[\"three\"]:undefined");
@@ -155,7 +155,7 @@ public class ScriptExampleTests {
@Test
public void testExtensionHistoStatsLogger() throws IOException {
- ExecMetricsResult scenarioResult = runScenario("extension_histostatslogger");
+ ExecutionMetricsResult scenarioResult = runScenario("extension_histostatslogger");
assertThat(scenarioResult.getIOLog()).contains("stdout started " +
"logging to logs/histostats.csv");
List strings = Files.readAllLines(Paths.get(
@@ -167,7 +167,7 @@ public class ScriptExampleTests {
@Test
public void testExtensionCsvOutput() throws IOException {
- ExecMetricsResult scenarioResult = runScenario("extension_csvoutput");
+ ExecutionMetricsResult scenarioResult = runScenario("extension_csvoutput");
List strings = Files.readAllLines(Paths.get(
"logs/csvoutputtestfile.csv"));
String logdata = strings.stream().collect(Collectors.joining("\n"));
@@ -177,7 +177,7 @@ public class ScriptExampleTests {
@Test
public void testExtensionHistogramLogger() throws IOException {
- ExecMetricsResult scenarioResult = runScenario("extension_histologger");
+ ExecutionMetricsResult scenarioResult = runScenario("extension_histologger");
assertThat(scenarioResult.getIOLog()).contains("stdout started logging to hdrhistodata.log");
List strings = Files.readAllLines(Paths.get("hdrhistodata.log"));
String logdata = strings.stream().collect(Collectors.joining("\n"));
@@ -187,7 +187,7 @@ public class ScriptExampleTests {
@Test
public void testBlockingRun() {
- ExecMetricsResult scenarioResult = runScenario("blockingrun");
+ ExecutionMetricsResult scenarioResult = runScenario("blockingrun");
int a1end = scenarioResult.getIOLog().indexOf("blockingactivity1 finished");
int a2start = scenarioResult.getIOLog().indexOf("running blockingactivity2");
assertThat(a1end).isLessThan(a2start);
@@ -195,12 +195,12 @@ public class ScriptExampleTests {
@Test
public void testAwaitFinished() {
- ExecMetricsResult scenarioResult = runScenario("awaitfinished");
+ ExecutionMetricsResult scenarioResult = runScenario("awaitfinished");
}
@Test
public void testStartStop() {
- ExecMetricsResult scenarioResult = runScenario("startstopdiag");
+ ExecutionMetricsResult scenarioResult = runScenario("startstopdiag");
int startedAt = scenarioResult.getIOLog().indexOf("starting activity teststartstopdiag");
int stoppedAt = scenarioResult.getIOLog().indexOf("stopped activity teststartstopdiag");
assertThat(startedAt).isGreaterThan(0);
@@ -210,7 +210,7 @@ public class ScriptExampleTests {
// TODO: find out why this causes a long delay after stop is called.
@Test
public void testThreadChange() {
- ExecMetricsResult scenarioResult = runScenario("threadchange");
+ ExecutionMetricsResult scenarioResult = runScenario("threadchange");
int changedTo1At = scenarioResult.getIOLog().indexOf("threads now 1");
int changedTo5At = scenarioResult.getIOLog().indexOf("threads now 5");
System.out.println("IOLOG:\n"+scenarioResult.getIOLog());
@@ -220,13 +220,13 @@ public class ScriptExampleTests {
@Test
public void testReadMetric() {
- ExecMetricsResult scenarioResult = runScenario("readmetrics");
+ ExecutionMetricsResult scenarioResult = runScenario("readmetrics");
assertThat(scenarioResult.getIOLog()).contains("count: ");
}
@Test
public void testShutdownHook() {
- ExecMetricsResult scenarioResult = runScenario("extension_shutdown_hook");
+ ExecutionMetricsResult scenarioResult = runScenario("extension_shutdown_hook");
assertThat(scenarioResult.getIOLog()).doesNotContain("shutdown hook running").describedAs(
"shutdown hooks should not run in the same IO context as the main scenario"
);
@@ -234,15 +234,15 @@ public class ScriptExampleTests {
@Test
public void testExceptionPropagationFromActivityInit() {
- ExecMetricsResult scenarioResult = runScenario("activityiniterror");
- assertThat(scenarioResult.getException()).isPresent();
- assertThat(scenarioResult.getException().get().getMessage()).contains("Unable to convert end cycle from invalid");
+ ExecutionMetricsResult scenarioResult = runScenario("activityiniterror");
+ assertThat(scenarioResult.getException()).isNotNull();
+ assertThat(scenarioResult.getException().getMessage()).contains("Unable to convert end cycle from invalid");
assertThat(scenarioResult.getException()).isNotNull();
}
@Test
public void testReportedCoDelayBursty() {
- ExecMetricsResult scenarioResult = runScenario("cocycledelay_bursty");
+ ExecutionMetricsResult scenarioResult = runScenario("cocycledelay_bursty");
assertThat(scenarioResult.getIOLog()).contains("step1 metrics.waittime=");
assertThat(scenarioResult.getIOLog()).contains("step2 metrics.waittime=");
String iolog = scenarioResult.getIOLog();
@@ -252,7 +252,7 @@ public class ScriptExampleTests {
@Test
public void testReportedCoDelayStrict() {
- ExecMetricsResult scenarioResult = runScenario("cocycledelay_strict");
+ ExecutionMetricsResult scenarioResult = runScenario("cocycledelay_strict");
assertThat(scenarioResult.getIOLog()).contains("step1 cycles.waittime=");
assertThat(scenarioResult.getIOLog()).contains("step2 cycles.waittime=");
String iolog = scenarioResult.getIOLog();
@@ -263,14 +263,14 @@ public class ScriptExampleTests {
@Test
public void testCycleRateChangeNewMetrics() {
- ExecMetricsResult scenarioResult = runScenario("cycle_rate_change");
+ ExecutionMetricsResult scenarioResult = runScenario("cycle_rate_change");
String ioLog = scenarioResult.getIOLog();
assertThat(ioLog).contains("cycles adjusted, exiting on iteration");
}
@Test
public void testExitLogic() {
- ExecMetricsResult scenarioResult = runScenario(
+ ExecutionMetricsResult scenarioResult = runScenario(
"basicdiag",
"type", "diag", "cyclerate", "5", "erroroncycle", "10", "cycles", "2000"
);
diff --git a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/SpeedCheckIntegrationTests.java b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/SpeedCheckIntegrationTests.java
index b750530d6..f4b230c55 100644
--- a/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/SpeedCheckIntegrationTests.java
+++ b/nbr-examples/src/test/java/io/nosqlbench/nbr/examples/SpeedCheckIntegrationTests.java
@@ -15,7 +15,7 @@
*/
package io.nosqlbench.nbr.examples;
-import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
+import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -30,14 +30,14 @@ public class SpeedCheckIntegrationTests {
@Disabled
// Verified as working
public void testSpeedSanity() {
- ExecMetricsResult scenarioResult = ScriptExampleTests.runScenario("speedcheck");
+ ExecutionMetricsResult scenarioResult = ScriptExampleTests.runScenario("speedcheck");
}
@Test
@Disabled
// This seems incomplete
public void testThreadSpeeds() {
- ExecMetricsResult scenarioResult = ScriptExampleTests.runScenario("threadspeeds");
+ ExecutionMetricsResult scenarioResult = ScriptExampleTests.runScenario("threadspeeds");
}
From 0de80887b1c306a7df4f375263cd0e79b1a8d94b Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:03:33 -0600
Subject: [PATCH 12/19] move log4j.xml to log4j2.xml
---
.../{log4j-test.xml => log4j2-test.xml} | 20 ++++++-
.../main/resources/{log4j.xml => log4j2.xml} | 20 ++++++-
.../{log4j-test.xml => log4j2-test.xml} | 20 ++++++-
.../main/resources/{log4j.xml => log4j2.xml} | 20 ++++++-
engine-core/src/test/resources/log4j-test.xml | 41 -------------
.../src/test/resources/log4j2-test.xml | 57 +++++++++++++++++++
.../src/test/resources/log4j2-test.xml | 57 +++++++++++++++++++
nbr/src/main/resources/log4j.xml | 41 -------------
nbr/src/main/resources/log4j2.xml | 57 +++++++++++++++++++
.../src/test/resources/log4j-test.xml | 41 -------------
.../src/test/resources/log4j2-test.xml | 57 +++++++++++++++++++
.../src/test/resources/log4j-test.xml | 41 -------------
.../src/test/resources/log4j2-test.xml | 57 +++++++++++++++++++
.../src/main/resources/log4j.xml | 41 -------------
.../src/main/resources/log4j2.xml | 57 +++++++++++++++++++
.../src/test/resources/log4j-test.xml | 41 -------------
.../src/test/resources/log4j2-test.xml | 57 +++++++++++++++++++
17 files changed, 471 insertions(+), 254 deletions(-)
rename engine-api/src/test/resources/{log4j-test.xml => log4j2-test.xml} (68%)
rename engine-cli/src/main/resources/{log4j.xml => log4j2.xml} (68%)
rename engine-cli/src/test/resources/{log4j-test.xml => log4j2-test.xml} (68%)
rename engine-core/src/main/resources/{log4j.xml => log4j2.xml} (68%)
delete mode 100644 engine-core/src/test/resources/log4j-test.xml
create mode 100644 engine-core/src/test/resources/log4j2-test.xml
create mode 100644 engine-rest/src/test/resources/log4j2-test.xml
delete mode 100644 nbr/src/main/resources/log4j.xml
create mode 100644 nbr/src/main/resources/log4j2.xml
delete mode 100644 virtdata-lang/src/test/resources/log4j-test.xml
create mode 100644 virtdata-lang/src/test/resources/log4j2-test.xml
delete mode 100644 virtdata-lib-basics/src/test/resources/log4j-test.xml
create mode 100644 virtdata-lib-basics/src/test/resources/log4j2-test.xml
delete mode 100644 virtdata-userlibs/src/main/resources/log4j.xml
create mode 100644 virtdata-userlibs/src/main/resources/log4j2.xml
delete mode 100644 virtdata-userlibs/src/test/resources/log4j-test.xml
create mode 100644 virtdata-userlibs/src/test/resources/log4j2-test.xml
diff --git a/engine-api/src/test/resources/log4j-test.xml b/engine-api/src/test/resources/log4j2-test.xml
similarity index 68%
rename from engine-api/src/test/resources/log4j-test.xml
rename to engine-api/src/test/resources/log4j2-test.xml
index 70176aaf6..797a5780b 100644
--- a/engine-api/src/test/resources/log4j-test.xml
+++ b/engine-api/src/test/resources/log4j2-test.xml
@@ -1,4 +1,20 @@
+
+
@@ -28,7 +44,7 @@
-
+
@@ -38,4 +54,4 @@
-
\ No newline at end of file
+
diff --git a/engine-cli/src/main/resources/log4j.xml b/engine-cli/src/main/resources/log4j2.xml
similarity index 68%
rename from engine-cli/src/main/resources/log4j.xml
rename to engine-cli/src/main/resources/log4j2.xml
index 70176aaf6..797a5780b 100644
--- a/engine-cli/src/main/resources/log4j.xml
+++ b/engine-cli/src/main/resources/log4j2.xml
@@ -1,4 +1,20 @@
+
+
@@ -28,7 +44,7 @@
-
+
@@ -38,4 +54,4 @@
-
\ No newline at end of file
+
diff --git a/engine-cli/src/test/resources/log4j-test.xml b/engine-cli/src/test/resources/log4j2-test.xml
similarity index 68%
rename from engine-cli/src/test/resources/log4j-test.xml
rename to engine-cli/src/test/resources/log4j2-test.xml
index 70176aaf6..797a5780b 100644
--- a/engine-cli/src/test/resources/log4j-test.xml
+++ b/engine-cli/src/test/resources/log4j2-test.xml
@@ -1,4 +1,20 @@
+
+
@@ -28,7 +44,7 @@
-
+
@@ -38,4 +54,4 @@
-
\ No newline at end of file
+
diff --git a/engine-core/src/main/resources/log4j.xml b/engine-core/src/main/resources/log4j2.xml
similarity index 68%
rename from engine-core/src/main/resources/log4j.xml
rename to engine-core/src/main/resources/log4j2.xml
index 70176aaf6..797a5780b 100644
--- a/engine-core/src/main/resources/log4j.xml
+++ b/engine-core/src/main/resources/log4j2.xml
@@ -1,4 +1,20 @@
+
+
@@ -28,7 +44,7 @@
-
+
@@ -38,4 +54,4 @@
-
\ No newline at end of file
+
diff --git a/engine-core/src/test/resources/log4j-test.xml b/engine-core/src/test/resources/log4j-test.xml
deleted file mode 100644
index 70176aaf6..000000000
--- a/engine-core/src/test/resources/log4j-test.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %d %p %C{1.} [%t] %m%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/engine-core/src/test/resources/log4j2-test.xml b/engine-core/src/test/resources/log4j2-test.xml
new file mode 100644
index 000000000..797a5780b
--- /dev/null
+++ b/engine-core/src/test/resources/log4j2-test.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d %p %C{1.} [%t] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/engine-rest/src/test/resources/log4j2-test.xml b/engine-rest/src/test/resources/log4j2-test.xml
new file mode 100644
index 000000000..3ee115d07
--- /dev/null
+++ b/engine-rest/src/test/resources/log4j2-test.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d %p %C{1.} [%t] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nbr/src/main/resources/log4j.xml b/nbr/src/main/resources/log4j.xml
deleted file mode 100644
index 70176aaf6..000000000
--- a/nbr/src/main/resources/log4j.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %d %p %C{1.} [%t] %m%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/nbr/src/main/resources/log4j2.xml b/nbr/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..797a5780b
--- /dev/null
+++ b/nbr/src/main/resources/log4j2.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d %p %C{1.} [%t] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/virtdata-lang/src/test/resources/log4j-test.xml b/virtdata-lang/src/test/resources/log4j-test.xml
deleted file mode 100644
index 70176aaf6..000000000
--- a/virtdata-lang/src/test/resources/log4j-test.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %d %p %C{1.} [%t] %m%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/virtdata-lang/src/test/resources/log4j2-test.xml b/virtdata-lang/src/test/resources/log4j2-test.xml
new file mode 100644
index 000000000..797a5780b
--- /dev/null
+++ b/virtdata-lang/src/test/resources/log4j2-test.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d %p %C{1.} [%t] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/virtdata-lib-basics/src/test/resources/log4j-test.xml b/virtdata-lib-basics/src/test/resources/log4j-test.xml
deleted file mode 100644
index 70176aaf6..000000000
--- a/virtdata-lib-basics/src/test/resources/log4j-test.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %d %p %C{1.} [%t] %m%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/virtdata-lib-basics/src/test/resources/log4j2-test.xml b/virtdata-lib-basics/src/test/resources/log4j2-test.xml
new file mode 100644
index 000000000..797a5780b
--- /dev/null
+++ b/virtdata-lib-basics/src/test/resources/log4j2-test.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d %p %C{1.} [%t] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/virtdata-userlibs/src/main/resources/log4j.xml b/virtdata-userlibs/src/main/resources/log4j.xml
deleted file mode 100644
index 70176aaf6..000000000
--- a/virtdata-userlibs/src/main/resources/log4j.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %d %p %C{1.} [%t] %m%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/virtdata-userlibs/src/main/resources/log4j2.xml b/virtdata-userlibs/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..797a5780b
--- /dev/null
+++ b/virtdata-userlibs/src/main/resources/log4j2.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d %p %C{1.} [%t] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/virtdata-userlibs/src/test/resources/log4j-test.xml b/virtdata-userlibs/src/test/resources/log4j-test.xml
deleted file mode 100644
index 70176aaf6..000000000
--- a/virtdata-userlibs/src/test/resources/log4j-test.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %d %p %C{1.} [%t] %m%n
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/virtdata-userlibs/src/test/resources/log4j2-test.xml b/virtdata-userlibs/src/test/resources/log4j2-test.xml
new file mode 100644
index 000000000..797a5780b
--- /dev/null
+++ b/virtdata-userlibs/src/test/resources/log4j2-test.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d %p %C{1.} [%t] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From bf5a31b342a5b944d06f42625abdc4abbccfff3a Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:04:12 -0600
Subject: [PATCH 13/19] implement efficient concurrent thread state signaling
---
.../engine/api/activityapi/core/Activity.java | 3 +
.../engine/api/activityapi/core/RunState.java | 63 +++--
...{SlotStateTracker.java => MotorState.java} | 32 ++-
.../api/activityimpl/SimpleActivity.java | 17 +-
.../api/activityimpl/motor/RunStateImage.java | 71 +++++
.../api/activityimpl/motor/RunStateTally.java | 266 ++++++++++++++++++
.../activityimpl/motor/RunStateImageTest.java | 39 +++
.../activityimpl/motor/RunStateTallyTest.java | 214 ++++++++++++++
.../nosqlbench/engine/core/CoreMotorTest.java | 2 -
9 files changed, 672 insertions(+), 35 deletions(-)
rename engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/{SlotStateTracker.java => MotorState.java} (70%)
create mode 100644 engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateImage.java
create mode 100644 engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateTally.java
create mode 100644 engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateImageTest.java
create mode 100644 engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateTallyTest.java
diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Activity.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Activity.java
index 618def3db..cab8f0999 100644
--- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Activity.java
+++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Activity.java
@@ -28,6 +28,7 @@ import io.nosqlbench.engine.api.activityapi.ratelimits.RateLimiter;
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.api.engine.activityimpl.ParameterMap;
import io.nosqlbench.engine.api.activityimpl.SimpleActivity;
+import io.nosqlbench.engine.api.activityimpl.motor.RunStateTally;
import java.io.InputStream;
import java.io.PrintWriter;
@@ -215,4 +216,6 @@ public interface Activity extends Comparable, ActivityDefObserver, Pro
default int getHdrDigits() {
return getParams().getOptionalInteger("hdr_digits").orElse(4);
}
+
+ RunStateTally getRunStateTally();
}
diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/RunState.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/RunState.java
index 15ca92a96..0476dc762 100644
--- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/RunState.java
+++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/RunState.java
@@ -16,39 +16,69 @@
package io.nosqlbench.engine.api.activityapi.core;
+import io.nosqlbench.engine.api.activityimpl.MotorState;
+
+/**
+ *
This enum indicates the state of a thread within an activity. The state is kept in an atomic
+ * register. Ownership of state changes is shared between a supervising thread and a managed thread.
+ * Both can make changes to the state.
+ *
+ *
These states are ordered such that the highest ordinal state represents the most significant
+ * aggregate state of all motors. That is, if any has errored, then the other states do not matter.
+ * If any is finished, then stopped motors don't matter, and so on. This makes summarizing aggregate
+ * state simply a matter of ordering.
+ *
+ */
public enum RunState {
-
/**
- * Initial state after creation of this control
+ * Initial state after creation of a motor. This is the initial state upon instantiation of a motor, before
+ * it is called on to do any active logic besides what occurs in the constructor.
*/
Uninitialized("i⌀"),
/**
- * This thread has been queued to run, but hasn't signaled yet that it is full started
- * This must be set by the executor before executing the slot runnable
+ * A thread has been invoked, but is initializing and preparing for its main control loop.
+ * This is signaled by the motor after {@link Runnable#run}, but before entering the main processing
+ * loop.
*/
Starting("s⏫"),
/**
- * This thread is running. This should only be set by the controlled thread
+ * A thread is iterating within the main control loop.
+ * This is signaled by the motor once initialization in the main loop is complete and immediately
+ * before it enters it's main processing loop.
*/
Running("R\u23F5"),
/**
- * This thread has completed all of its activity, and will do no further work without new input
- */
- Finished("F⏯"),
-
- /**
- * The thread has been requested to stop. This says nothing of the internal state.
+ *
The thread has been requested to stop. This can be set by a managing thread which is not the
+ * motor thread, or by the motor thread. In either case, the motor thread is required to observe changes to this and initiate shutdown.
*/
Stopping("s⏬"),
/**
- * The thread has stopped. This should only be set by the controlled thread
+ * The thread has stopped. This should only be set by the motor. This state will only be visible
+ * to signaling mechanisms so long as the motor is still managed.
+ *
+ *
NOTE: When a motor is stopped or finished, its state will remain visible in state tracking until
+ * {@link Motor#getState()}.{@link MotorState#removeState()} is called.
A thread has exhausted its supply of values on the input (AKA cycles), thus has completed its work.
+ * This is signaled upon a short read of the input by the motor.
+ *
+ *
NOTE: When a motor is stopped or finished, its state will remain visible in state tracking until
+ * {@link Motor#getState()}.{@link MotorState#removeState()} is called.
+ */
+ Finished("F⏯"),
+
+ /**
+ * If a motor has seen an exception, it goes into errored state before propagating the error.
+ */
+ Errored("E⚠");
private final String runcode;
@@ -69,15 +99,16 @@ public enum RunState {
default -> false; // A motor was just created. This is its initial state.
case Uninitialized, Stopped -> (target == Starting);
case Starting -> switch (target) { // a motor has indicated that is in the run() method
- case Running, Finished -> true;// a motor has exhausted its input, and has declined to go into started mode
+ case Running, Finished, Errored -> true;// a motor has exhausted its input, and has declined to go into started mode
default -> false;
};
case Running -> switch (target) { // A request was made to stop the motor before it finished
- case Stopping, Finished -> true;// A motor has exhausted its input, and is finished with its work
+ case Stopping, Finished, Errored -> true;// A motor has exhausted its input, and is finished with its work
default -> false;
};
- case Stopping -> (target == Stopped); // A motor was stopped by request before exhausting input
+ case Stopping -> (target == Stopped||target==Finished); // A motor was stopped by request before exhausting input
case Finished -> (target == Running); // A motor was restarted?
+ case Errored -> target==Errored;
};
}
diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SlotStateTracker.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/MotorState.java
similarity index 70%
rename from engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SlotStateTracker.java
rename to engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/MotorState.java
index 5d164333e..0dfbfe2c6 100644
--- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SlotStateTracker.java
+++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/MotorState.java
@@ -17,26 +17,31 @@
package io.nosqlbench.engine.api.activityimpl;
import io.nosqlbench.engine.api.activityapi.core.RunState;
-import org.apache.logging.log4j.Logger;
+import io.nosqlbench.engine.api.activityimpl.motor.RunStateTally;
import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
/**
* Holds the state of a slot, allows only valid transitions, and shares the
* slot state as
*/
-public class SlotStateTracker {
- private final AtomicReference slotState = new AtomicReference<>(RunState.Uninitialized);
- private final static Logger logger = LogManager.getLogger(SlotStateTracker.class);
+public class MotorState implements Supplier {
+ private final static Logger logger = LogManager.getLogger("MOTORS");
+ private final AtomicReference atomicState = new AtomicReference<>(RunState.Uninitialized);
private final long slotId;
+ private final RunStateTally tally;
- public SlotStateTracker(long slotId) {
+ public MotorState(long slotId, RunStateTally tally) {
this.slotId = slotId;
+ this.tally = tally;
+ tally.add(atomicState.get());
}
- public RunState getSlotState() {
- return slotState.get();
+ public RunState get() {
+ return atomicState.get();
}
/**
@@ -46,7 +51,7 @@ public class SlotStateTracker {
* @return an atomic reference for SlotState
*/
public AtomicReference getAtomicSlotState() {
- return slotState;
+ return atomicState;
}
/**
@@ -56,16 +61,19 @@ public class SlotStateTracker {
* @param to The next SlotState for this thread/slot/motor
*/
public synchronized void enterState(RunState to) {
- RunState from = slotState.get();
+ RunState from = atomicState.get();
if (!from.canTransitionTo(to)) {
throw new RuntimeException("Invalid transition from " + from + " to " + to);
}
- while (!slotState.compareAndSet(from, to)) {
+ while (!atomicState.compareAndSet(from, to)) {
logger.trace("retrying transition from:" + from + " to:" + to);
}
+ tally.change(from,to);
logger.trace("TRANSITION[" + slotId + "]: " + from + " ==> " + to);
-
}
-
+ public void removeState() {
+ logger.trace(() -> "Removing motor state " + atomicState.get());
+ tally.remove(atomicState.get());
+ }
}
diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SimpleActivity.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SimpleActivity.java
index dec179776..a988d3634 100644
--- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SimpleActivity.java
+++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/SimpleActivity.java
@@ -36,6 +36,7 @@ import io.nosqlbench.engine.api.activityapi.ratelimits.RateSpec;
import io.nosqlbench.engine.api.activityconfig.StatementsLoader;
import io.nosqlbench.engine.api.activityconfig.yaml.OpTemplate;
import io.nosqlbench.engine.api.activityconfig.yaml.StmtsDocList;
+import io.nosqlbench.engine.api.activityimpl.motor.RunStateTally;
import io.nosqlbench.engine.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.engine.api.activityimpl.uniform.decorators.SyntheticOpTemplateProvider;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
@@ -82,6 +83,7 @@ public class SimpleActivity implements Activity, ProgressCapable, ActivityDefObs
private NBErrorHandler errorHandler;
private ActivityMetricProgressMeter progressMeter;
private String workloadSource = "unspecified";
+ private final RunStateTally tally = new RunStateTally();
public SimpleActivity(ActivityDef activityDef) {
this.activityDef = activityDef;
@@ -95,7 +97,7 @@ public class SimpleActivity implements Activity, ProgressCapable, ActivityDefObs
} else {
activityDef.getParams().set("alias",
activityDef.getActivityType().toUpperCase(Locale.ROOT)
- + String.valueOf(nameEnumerator++));
+ + nameEnumerator++);
}
}
}
@@ -190,7 +192,7 @@ public class SimpleActivity implements Activity, ProgressCapable, ActivityDefObs
}
public String toString() {
- return getAlias();
+ return getAlias()+":"+getRunState()+":"+getRunStateTally().toString();
}
@Override
@@ -217,7 +219,7 @@ public class SimpleActivity implements Activity, ProgressCapable, ActivityDefObs
@Override
public void closeAutoCloseables() {
for (AutoCloseable closeable : closeables) {
- logger.debug("CLOSING " + closeable.getClass().getCanonicalName() + ": " + closeable.toString());
+ logger.debug("CLOSING " + closeable.getClass().getCanonicalName() + ": " + closeable);
try {
closeable.close();
} catch (Exception e) {
@@ -392,7 +394,7 @@ public class SimpleActivity implements Activity, ProgressCapable, ActivityDefObs
if (threadSpec.isPresent()) {
String spec = threadSpec.get();
int processors = Runtime.getRuntime().availableProcessors();
- if (spec.toLowerCase().equals("auto")) {
+ if (spec.equalsIgnoreCase("auto")) {
int threads = processors * 10;
if (threads > activityDef.getCycleCount()) {
threads = (int) activityDef.getCycleCount();
@@ -652,7 +654,7 @@ public class SimpleActivity implements Activity, ProgressCapable, ActivityDefObs
return stmtsDocList;
} catch (Exception e) {
- throw new OpConfigError("Error loading op templates: " + e.toString(), workloadSource, e);
+ throw new OpConfigError("Error loading op templates: " + e, workloadSource, e);
}
}
@@ -677,6 +679,11 @@ public class SimpleActivity implements Activity, ProgressCapable, ActivityDefObs
return getActivityDef().getParams().getOptionalInteger("maxtries").orElse(10);
}
+ @Override
+ public RunStateTally getRunStateTally() {
+ return tally;
+ }
+
@Override
public String getName() {
diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateImage.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateImage.java
new file mode 100644
index 000000000..ae95eafaf
--- /dev/null
+++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateImage.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.api.activityimpl.motor;
+
+import io.nosqlbench.engine.api.activityapi.core.RunState;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * A value type which encodes the atomic state of a RunState tally.
+ */
+public class RunStateImage {
+ private final static Logger logger = LogManager.getLogger("TALLY");
+
+ private final int[] counts = new int[RunState.values().length];
+ private final boolean timedout;
+
+ public RunStateImage(int[] counts, boolean timedout) {
+ System.arraycopy(counts, 0, this.counts, 0, counts.length);
+ this.timedout = timedout;
+ }
+
+ public boolean isTimeout() {
+ return this.timedout;
+ }
+
+ public boolean is(RunState runState) {
+ return counts[runState.ordinal()]>0;
+ }
+
+ public boolean isOnly(RunState runState) {
+ for (int i = 0; i < counts.length; i++) {
+ if (counts[i]>0 && i!=runState.ordinal()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public RunState getMaxState() {
+ for (int ord = counts.length-1; ord >= 0; ord--) {
+ if (counts[ord]>0) {
+ return RunState.values()[ord];
+ }
+ }
+ throw new RuntimeException("There were zero states, so max state is undefined");
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (RunState runState : RunState.values()) {
+ sb.append(runState.getCode()).append(" ").append(counts[runState.ordinal()]).append(" ");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateTally.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateTally.java
new file mode 100644
index 000000000..dc861f9cc
--- /dev/null
+++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateTally.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.api.activityimpl.motor;
+
+import io.nosqlbench.engine.api.activityapi.core.RunState;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Arrays;
+
+/**
+ *
Synopsis
+ *
Event-oriented tally of the runtime states of all
+ * motor threads. This is meant to be used as the definitive
+ * aggregate scorecard for an activity's thread states.
+ *
+ *
Purpose
+ *
This limits inter-thread signaling requirements by constraining
+ * the cases for which blockers are notified. This is because the
+ * meaningful scenarios for which a blocker would want to be notified
+ * do not include changes of positive values to other positive values.
+ * This allows an explicit optimization around scenarios for which a
+ * state count increments to 1 or decrements to 0, as in "some" or "none".
+ * This is an effective optimization for scenarios with many active
+ * threads.
+ *
+ *
+ *
Calling Semantics
+ *
Callers of the await functions will block for the required condition or,
+ * if specified, the timeout to occur without the condition.
+ * These callers are unblocked atomically, after any state add, state remove,
+ * or state change events are fully completed.
+ *
{@link RunStateImage} is returned from blocking methods so that
+ * callers can know consistently what the current run states were at
+ * the time their condition was met or timed out. Any callers of such
+ * methods must check for whether the condition was successfully
+ * met via {@link RunStateImage#isTimeout()}
+ *
+ *
Invariants
+ *
+ *
Under consistent usage patterns, all counts should be zero or positive at all times.
+ *
The current count for each state should be equal to the visible {@link RunState} on each
+ * motor thread, as all transitions are made through the motor threads directly.
+ *
+ */
+public class RunStateTally {
+ private final static Logger logger = LogManager.getLogger("TALLY");
+
+ /**
+ * If no timeout is given for any of the await methods, then the default is to wait for
+ * approximately many eons. Some tests run until told to stop.
+ */
+ public final long DEFAULT_TIMEOUT_MS=Long.MAX_VALUE;
+
+ private final int[] counts = new int[RunState.values().length];
+
+ /**
+ * @return the current count for the specified state
+ * @param runState The {@link RunState} to count
+ *
+ */
+ public synchronized int tallyFor(RunState runState) {
+ return counts[runState.ordinal()];
+ }
+
+ /**
+ * Signal that a motor thread has left one {@link RunState} and entered another,
+ * atomically. After both counts are updated, if any RunState counts changed to or from zero,
+ * then all potential observers are notified to re-evaluate their await conditions.
+ * @param from the prior RunState
+ * @param to the next RunState
+ */
+ public synchronized void change(RunState from, RunState to) {
+ counts[from.ordinal()]--;
+ counts[to.ordinal()]++;
+ logger.trace(() -> this +" -"+from+ String.format(":%04d",counts[from.ordinal()])+ ", +"+to+ String.format(":%04d",counts[to.ordinal()]));
+
+ if (counts[from.ordinal()]==0 || counts[to.ordinal()]==1) {
+ logger.debug(() -> "NOTIFYing on edge "+
+ "from " + from + String.format(":%04d",counts[from.ordinal()]) +
+ " to " + to + String.format(":%04d",counts[to.ordinal()]));
+ notifyAll();
+ }
+ }
+
+ /**
+ * Add a previously untracked motor thread to state tracking with the provided {@link RunState}.
+ * If the given state's count becomes non-zero, then all potential observers are notified to re-evaluate
+ * their await conditions.
+ * @param state The initial tracking state for the related motor thread
+ */
+ public synchronized void add(RunState state) {
+ counts[state.ordinal()]++;
+ logger.trace(() -> this +" +"+state+ String.format(":%04d",counts[state.ordinal()]));
+ if (counts[state.ordinal()]==1) {
+ logger.debug(() -> "NOTIFYing on ++-SOME edge for " + state + String.format(":%04d",counts[state.ordinal()]));
+ notifyAll();
+ }
+ }
+
+ /**
+ * Remove a previously tracked motor thread from state tracking with the provided {@link RunState}.
+ * If the given state's count becomes zero, then all potential observers are notified to re-evaluate
+ * their await conditions.
+ * @param state The final tracking state for the related motor thread
+ */
+ public synchronized void remove(RunState state) {
+ counts[state.ordinal()]--;
+ logger.trace(() -> this +" -"+state+ String.format(":%04d",counts[state.ordinal()]));
+ if (counts[state.ordinal()]==0) {
+ logger.debug(() -> "NOTIFYing on 00-NONE edge for " + state + String.format(":%04d",counts[state.ordinal()]));
+ notifyAll();
+ }
+ }
+
+ /**
+ * Await until all states but the provided {@link RunState}s have zero counts.
+ * This condition matches if the provided states have zero or positive counts if and only if
+ * all other states have zero counts. Thus, if there are no positive values at all, this condition will
+ * still match.
+ * @param runStates The states which may have zero counts and still match the condition
+ * @return A {@link RunStateImage}, indicating success or failure, and the view of states at the time of evaluation
+ */
+ public synchronized RunStateImage awaitNoneOther(RunState... runStates) {
+ return this.awaitNoneOther(DEFAULT_TIMEOUT_MS, runStates);
+ }
+ /**
+ * Exactly like {@link #awaitNoneOther(long, RunState...)}, except that it allows for a timeout,
+ * after which the method will unblock and signal an error if the await condition is still false.
+ * @param runStates RunStates which are the only valid states before unblocking
+ * @return A {@link RunStateImage}, indicating success or failure, and the view of states at the time of evaluation
+ */
+ public synchronized RunStateImage awaitNoneOther(long timeoutMillis, RunState... runStates) {
+ logger.debug(() -> "☐ Awaiting only " + Arrays.toString(runStates) + " for " + timeoutMillis+"ms");
+ long timeoutAt = timeoutAt(timeoutMillis);
+
+ int sum=0;
+ for (RunState runState: RunState.values()) {
+ sum+=counts[runState.ordinal()];
+ }
+ for (RunState runState : runStates) {
+ sum-=counts[runState.ordinal()];
+ }
+ while (sum>0 && System.currentTimeMillis() (timedout ? "✘ TIMED-OUT awaiting only " : "☑ Awaited only " ) + toString(runStates));
+ return new RunStateImage(this.counts,timedout);
+ }
+
+ private long timeoutAt(long timeoutMillis) {
+ long delayTill= System.currentTimeMillis() + timeoutMillis;
+ return (delayTill>0) ? delayTill : Long.MAX_VALUE;
+ }
+ /**
+ * Await until there are zero counts for all of the specified {@link RunState}s.
+ * @param runStates all RunStates which must be zeroed before unblocking
+ * @return A {@link RunStateImage}, indicating success or failure, and the view of states at the time of evaluation
+ */
+ public synchronized RunStateImage awaitNoneOf(RunState... runStates) {
+ return this.awaitNoneOf(DEFAULT_TIMEOUT_MS, runStates);
+ }
+ /**
+ * Exactly like {@link #awaitNoneOf(RunState...)}, except that it allows for a timeout, after which the
+ * method will unblock and signal a timeout if the await condition is still not met.
+ * @param runStates all RunStates which must be zeroed before unblocking
+ * @return A {@link RunStateImage}, indicating success or failure, and the view of states at the time of evaluation
+ */
+ public synchronized RunStateImage awaitNoneOf(long timeoutMillis, RunState... runStates) {
+ logger.debug(() -> "☐ Awaiting none of " + Arrays.toString(runStates)+ " for " + timeoutMillis+"ms");
+ long timeoutAt = timeoutAt(timeoutMillis);
+
+ int sum=0;
+ for (RunState runState : runStates) {
+ sum+=counts[runState.ordinal()];
+ }
+ while (sum>0 && System.currentTimeMillis() (timedout ? "✘ TIMED-OUT awaiting none of " : "☑ Awaited none of " ) + toString(runStates));
+ return new RunStateImage(this.counts,timedout);
+ }
+
+ /**
+ * Await until at least one of the provided runStates has a positive value.
+ * @param runStates RunStates any of which allow unblocking
+ * @return A {@link RunStateImage}, indicating success or failure, and the view of states at the time of evaluation
+ */
+ public synchronized RunStateImage awaitAny(RunState... runStates) {
+ return this.awaitAny(DEFAULT_TIMEOUT_MS,runStates);
+ }
+
+ /**
+ * Exactly like {@link #awaitAny(RunState...)}, except that it allows for a timeout, after which
+ * the method will unblock and signal a timeout if the await condition is still not met.
+ * @param runStates RunStates any of which allow unblocking
+ * @param timeoutMillis Milliseconds to wait for any of the runstates before giving up
+ * @return A {@link RunStateImage}, indicating success or failure, and the view of states at the time of evaluation
+ */
+ public synchronized RunStateImage awaitAny(long timeoutMillis, RunState... runStates) {
+ logger.debug(() -> "☐ Awaiting any " + Arrays.toString(runStates) + " for " + timeoutMillis + "ms");
+ long timeoutAt = timeoutAt(timeoutMillis);
+
+ while (System.currentTimeMillis()0) {
+ logger.debug("☑ Awaited any " + toString(runStates));
+ return new RunStateImage(this.counts,false);
+ }
+ }
+ try {
+ wait(timeoutAt-System.currentTimeMillis());
+ } catch (InterruptedException e) {
+ }
+ }
+ logger.debug(() -> "✘ TIMED-OUT awaiting any of " + toString(runStates));
+ return new RunStateImage(this.counts,true);
+ }
+
+ public String toString(RunState... runStates) {
+ StringBuilder sb = new StringBuilder();
+ for (RunState runState : runStates) {
+ sb.append(runState.getCode()).append("(").append(counts[runState.ordinal()]).append(") ");
+ }
+ sb.setLength(sb.length()-1);
+ return sb.toString();
+ }
+ public String toString() {
+ return toString(RunState.values());
+ }
+}
diff --git a/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateImageTest.java b/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateImageTest.java
new file mode 100644
index 000000000..d457225ca
--- /dev/null
+++ b/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateImageTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.api.activityimpl.motor;
+
+import io.nosqlbench.engine.api.activityapi.core.RunState;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RunStateImageTest {
+
+ @Test
+ public void testMaxStateImage() {
+ int[] counts = new int[RunState.values().length];
+ counts[RunState.Running.ordinal()]=3;
+ RunStateImage image = new RunStateImage(counts, false);
+ assertThat(image.is(RunState.Running)).isTrue();
+ assertThat(image.isTimeout()).isFalse();
+ assertThat(image.is(RunState.Errored)).isFalse();
+ assertThat(image.isOnly(RunState.Running)).isTrue();
+ RunState maxState = image.getMaxState();
+ assertThat(maxState).isEqualTo(RunState.values()[2]);
+ }
+
+}
diff --git a/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateTallyTest.java b/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateTallyTest.java
new file mode 100644
index 000000000..ffb545158
--- /dev/null
+++ b/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/motor/RunStateTallyTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.api.activityimpl.motor;
+
+import io.nosqlbench.engine.api.activityapi.core.RunState;
+import org.junit.jupiter.api.*;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class RunStateTallyTest {
+
+ volatile boolean awaited = false;
+ volatile RunStateImage event = null;
+
+ @BeforeEach
+ public void setup() {
+ awaited = false;
+ event = null;
+ }
+
+ @Test
+ @Order(1)
+ public void testAwaitAny() {
+ Thread.currentThread().setName("SETTER");
+
+ RunStateTally tally = new RunStateTally();
+ awaited = false;
+ Thread waiter = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ event = tally.awaitAny(RunState.Running);
+ awaited = true;
+ }
+ });
+ waiter.setName("WAITER");
+ waiter.setDaemon(true);
+ waiter.start();
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ }
+
+ assertThat(awaited).isFalse();
+ tally.add(RunState.Running);
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ }
+
+
+ assertThat(event.is(RunState.Running)).isTrue();
+ assertThat(event.isOnly(RunState.Running)).isTrue();
+
+ assertThat(awaited).isTrue();
+ assertThat(waiter.getState()).isNotEqualTo(Thread.State.RUNNABLE);
+ }
+
+ @Test
+ @Order(2)
+ public void testAwaitNoneOf() {
+ Thread.currentThread().setName("SETTER");
+
+ RunStateTally tally = new RunStateTally();
+ tally.add(RunState.Uninitialized);
+ tally.add(RunState.Stopped);
+ awaited = false;
+ Thread waiter = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ tally.awaitNoneOf(RunState.Stopped, RunState.Uninitialized);
+ awaited = true;
+ }
+ });
+ waiter.setName("WAITER");
+ waiter.setDaemon(true);
+ waiter.start();
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ }
+
+ assertThat(awaited).isFalse();
+ tally.change(RunState.Stopped, RunState.Finished);
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ }
+
+ assertThat(awaited).isFalse();
+ tally.change(RunState.Uninitialized, RunState.Finished);
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ }
+
+ assertThat(awaited).isTrue();
+ assertThat(waiter.getState()).isNotEqualTo(Thread.State.RUNNABLE);
+
+ }
+
+ @Test
+ @Order(3)
+ public void testAwaitNoneOther() {
+ Thread.currentThread().setName("SETTER");
+
+ RunStateTally tally = new RunStateTally();
+ tally.add(RunState.Uninitialized);
+ tally.add(RunState.Running);
+ awaited = false;
+ Thread waiter = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ event = tally.awaitNoneOther(RunState.Stopped, RunState.Finished);
+ awaited = true;
+ }
+ });
+ waiter.setName("WAITER");
+ waiter.setDaemon(true);
+ waiter.start();
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ }
+
+ assertThat(awaited).isFalse();
+ tally.change(RunState.Uninitialized, RunState.Finished);
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ }
+
+ assertThat(awaited).isFalse();
+
+ // Note that neither Stopped or Finished are required to be positive,
+ // as long as all others are zero total.
+ tally.remove(RunState.Running);
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ }
+
+ assertThat(awaited).isTrue();
+ assertThat(waiter.getState()).isNotEqualTo(Thread.State.RUNNABLE);
+
+ }
+
+ @Test
+ @Order(4)
+ public void testAwaitNoneOtherTimedOut() {
+ Thread.currentThread().setName("SETTER");
+
+ RunStateTally tally = new RunStateTally();
+ tally.add(RunState.Uninitialized);
+ tally.add(RunState.Running);
+ Thread waiter = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ event = tally.awaitNoneOther(1500, RunState.Stopped, RunState.Finished);
+ awaited = true;
+ }
+ });
+ waiter.setName("WAITER");
+ waiter.setDaemon(true);
+ waiter.start();
+
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ }
+
+ assertThat(awaited).isFalse();
+ tally.change(RunState.Uninitialized, RunState.Finished);
+
+ try {
+ Thread.sleep(1500);
+ } catch (Exception e) {
+ }
+
+// try {
+// waiter.join();
+// } catch (InterruptedException e) {
+// throw new RuntimeException(e);
+// }
+
+ assertThat(event.isOnly(RunState.Errored)).isFalse();
+ assertThat(waiter.getState()).isNotEqualTo(Thread.State.RUNNABLE);
+
+ }
+
+
+}
diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/CoreMotorTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/CoreMotorTest.java
index 7f12dd609..bcc1d6ecc 100644
--- a/engine-core/src/test/java/io/nosqlbench/engine/core/CoreMotorTest.java
+++ b/engine-core/src/test/java/io/nosqlbench/engine/core/CoreMotorTest.java
@@ -38,7 +38,6 @@ public class CoreMotorTest {
Motor cm = new CoreMotor(activity, 5L, lockstepper);
AtomicLong observableAction = new AtomicLong(-3L);
cm.setAction(getTestConsumer(observableAction));
- cm.getSlotStateTracker().enterState(RunState.Starting);
Thread t = new Thread(cm);
t.setName("TestMotor");
t.start();
@@ -58,7 +57,6 @@ public class CoreMotorTest {
AtomicLongArray ary = new AtomicLongArray(10);
Action a1 = getTestArrayConsumer(ary);
cm1.setAction(a1);
- cm1.getSlotStateTracker().enterState(RunState.Starting);
Thread t1 = new Thread(cm1);
t1.setName("cm1");
From b9365bff725c8746e69d56ef936fd5f791924fc8 Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 20:04:17 -0600
Subject: [PATCH 14/19] improve concurrency patterns for activity execution
---
.../engine/api/activityapi/core/Motor.java | 5 +-
.../api/activityimpl/motor/CoreMotor.java | 119 ++---
.../core/lifecycle/ActivityFinisher.java | 50 --
...esult.java => ExecutionMetricsResult.java} | 6 +-
.../{ExecResult.java => ExecutionResult.java} | 22 +-
.../core/lifecycle/StartedActivityInfo.java | 29 --
.../activity/ActivitiesExceptionHandler.java | 40 ++
.../ActivityExecutor.java} | 459 +++++++++---------
.../activity/ActivityRuntimeInfo.java | 97 ++++
.../scenario}/Scenario.java | 68 +--
.../scenario/ScenarioController.java | 281 ++++-------
.../lifecycle/scenario/ScenariosExecutor.java | 7 +-
.../lifecycle/scenario/ScenariosResults.java | 6 +-
...gerTest.java => ActivityExecutorTest.java} | 84 +++-
14 files changed, 624 insertions(+), 649 deletions(-)
delete mode 100644 engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityFinisher.java
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ExecMetricsResult.java => ExecutionMetricsResult.java} (95%)
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ExecResult.java => ExecutionResult.java} (75%)
delete mode 100644 engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/StartedActivityInfo.java
create mode 100644 engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesExceptionHandler.java
rename engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/{ActivityThreadsManager.java => activity/ActivityExecutor.java} (62%)
create mode 100644 engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityRuntimeInfo.java
rename engine-core/src/main/java/io/nosqlbench/engine/core/{script => lifecycle/scenario}/Scenario.java (88%)
rename engine-core/src/test/java/io/nosqlbench/engine/core/{ActivityThreadsManagerTest.java => ActivityExecutorTest.java} (71%)
diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Motor.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Motor.java
index 9ad35f877..ee208e4fd 100644
--- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Motor.java
+++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityapi/core/Motor.java
@@ -17,7 +17,7 @@
package io.nosqlbench.engine.api.activityapi.core;
import io.nosqlbench.engine.api.activityapi.input.Input;
-import io.nosqlbench.engine.api.activityimpl.SlotStateTracker;
+import io.nosqlbench.engine.api.activityimpl.MotorState;
/**
* The core threading harness within an activity.
@@ -54,6 +54,7 @@ public interface Motor extends Runnable, Stoppable {
* Get a description of the current slot run status.
* @return - a value from the {@link RunState} enum
*/
- SlotStateTracker getSlotStateTracker();
+ MotorState getState();
+ void removeState();
}
diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/CoreMotor.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/CoreMotor.java
index d31028ecc..cb074b910 100644
--- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/CoreMotor.java
+++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/motor/CoreMotor.java
@@ -29,12 +29,11 @@ import io.nosqlbench.engine.api.activityapi.input.Input;
import io.nosqlbench.engine.api.activityapi.output.Output;
import io.nosqlbench.engine.api.activityapi.ratelimits.RateLimiter;
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
-import io.nosqlbench.engine.api.activityimpl.SlotStateTracker;
+import io.nosqlbench.engine.api.activityimpl.MotorState;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
import static io.nosqlbench.engine.api.activityapi.core.RunState.*;
@@ -70,8 +69,8 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
private final Activity activity;
private Output output;
- private final SlotStateTracker slotStateTracker;
- private final AtomicReference slotState;
+ private final MotorState motorState;
+ // private final AtomicReference slotState;
private int stride = 1;
private OpTracker opTracker;
@@ -86,14 +85,13 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
* @param input A LongSupplier which provides the cycle number inputs.
*/
public CoreMotor(
- Activity activity,
- long slotId,
- Input input) {
+ Activity activity,
+ long slotId,
+ Input input) {
this.activity = activity;
this.slotId = slotId;
setInput(input);
- slotStateTracker = new SlotStateTracker(slotId);
- slotState = slotStateTracker.getAtomicSlotState();
+ motorState = new MotorState(slotId, activity.getRunStateTally());
onActivityDefUpdate(activity.getActivityDef());
}
@@ -107,10 +105,10 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
* @param action An LongConsumer which is applied to the input for each cycle.
*/
public CoreMotor(
- Activity activity,
- long slotId,
- Input input,
- Action action
+ Activity activity,
+ long slotId,
+ Input input,
+ Action action
) {
this(activity, slotId, input);
setAction(action);
@@ -126,11 +124,11 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
* @param output An optional opTracker.
*/
public CoreMotor(
- Activity activity,
- long slotId,
- Input input,
- Action action,
- Output output
+ Activity activity,
+ long slotId,
+ Input input,
+ Action action,
+ Output output
) {
this(activity, slotId, input);
setAction(action);
@@ -178,12 +176,18 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
}
@Override
- public SlotStateTracker getSlotStateTracker() {
- return slotStateTracker;
+ public MotorState getState() {
+ return motorState;
+ }
+
+ @Override
+ public void removeState() {
+ motorState.removeState();
}
@Override
public void run() {
+ motorState.enterState(Starting);
try {
inputTimer = activity.getInstrumentation().getOrCreateInputTimer();
@@ -195,12 +199,10 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
cycleRateLimiter = activity.getCycleLimiter();
- if (slotState.get() == Finished) {
+ if (motorState.get() == Finished) {
logger.warn("Input was already exhausted for slot " + slotId + ", remaining in finished state.");
}
- slotStateTracker.enterState(Running);
-
long cyclenum;
action.init();
@@ -235,7 +237,8 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
strideconsumer = (StrideOutputConsumer) async;
}
- while (slotState.get() == Running) {
+ motorState.enterState(Running);
+ while (motorState.get() == Running) {
CycleSegment cycleSegment = null;
@@ -245,7 +248,7 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
if (cycleSegment == null) {
logger.trace("input exhausted (input " + input + ") via null segment, stopping motor thread " + slotId);
- slotStateTracker.enterState(Finished);
+ motorState.enterState(Finished);
continue;
}
@@ -256,27 +259,27 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
StrideTracker strideTracker = new StrideTracker<>(
strideServiceTimer,
- stridesResponseTimer,
- strideDelay,
- cycleSegment.peekNextCycle(),
- stride,
- output,
- strideconsumer);
+ stridesResponseTimer,
+ strideDelay,
+ cycleSegment.peekNextCycle(),
+ stride,
+ output,
+ strideconsumer);
strideTracker.start();
long strideStart = System.nanoTime();
- while (!cycleSegment.isExhausted() && slotState.get() == Running) {
+ while (!cycleSegment.isExhausted() && motorState.get() == Running) {
cyclenum = cycleSegment.nextCycle();
if (cyclenum < 0) {
if (cycleSegment.isExhausted()) {
logger.trace("input exhausted (input " + input + ") via negative read, stopping motor thread " + slotId);
- slotStateTracker.enterState(Finished);
+ motorState.enterState(Finished);
continue;
}
}
- if (slotState.get() != Running) {
+ if (motorState.get() != Running) {
logger.trace("motor stopped in cycle " + cyclenum + ", stopping motor thread " + slotId);
continue;
}
@@ -287,7 +290,7 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
}
try {
- TrackedOp op = opTracker.newOp(cyclenum,strideTracker);
+ TrackedOp op = opTracker.newOp(cyclenum, strideTracker);
op.setWaitTime(cycleDelay);
synchronized (opTracker) {
@@ -312,7 +315,7 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
}
- if (slotState.get() == Finished) {
+ if (motorState.get() == Finished) {
boolean finished = opTracker.awaitCompletion(60000);
if (finished) {
logger.debug("slot " + this.slotId + " completed successfully");
@@ -321,12 +324,12 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
}
}
- if (slotState.get() == Stopping) {
- slotStateTracker.enterState(Stopped);
+ if (motorState.get() == Stopping) {
+ motorState.enterState(Stopped);
}
- } else if (action instanceof SyncAction) {
+ } else if (action instanceof SyncAction sync) {
cycleServiceTimer = activity.getInstrumentation().getOrCreateCyclesServiceTimer();
strideServiceTimer = activity.getInstrumentation().getOrCreateStridesServiceTimer();
@@ -335,9 +338,8 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
throw new RuntimeException("The async parameter was given for this activity, but it does not seem to know how to do async.");
}
- SyncAction sync = (SyncAction) action;
-
- while (slotState.get() == Running) {
+ motorState.enterState(Running);
+ while (motorState.get() == Running) {
CycleSegment cycleSegment = null;
CycleResultSegmentBuffer segBuffer = new CycleResultSegmentBuffer(stride);
@@ -348,7 +350,7 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
if (cycleSegment == null) {
logger.trace("input exhausted (input " + input + ") via null segment, stopping motor thread " + slotId);
- slotStateTracker.enterState(Finished);
+ motorState.enterState(Finished);
continue;
}
@@ -366,12 +368,12 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
if (cyclenum < 0) {
if (cycleSegment.isExhausted()) {
logger.trace("input exhausted (input " + input + ") via negative read, stopping motor thread " + slotId);
- slotStateTracker.enterState(Finished);
+ motorState.enterState(Finished);
continue;
}
}
- if (slotState.get() != Running) {
+ if (motorState.get() != Running) {
logger.trace("motor stopped after input (input " + cyclenum + "), stopping motor thread " + slotId);
continue;
}
@@ -391,6 +393,9 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
result = sync.runCycle(cyclenum);
long phaseEnd = System.nanoTime();
+ } catch (Exception e) {
+ motorState.enterState(Errored);
+ throw e;
} finally {
long cycleEnd = System.nanoTime();
cycleServiceTimer.update((cycleEnd - cycleStart) + cycleDelay, TimeUnit.NANOSECONDS);
@@ -414,25 +419,29 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
}
}
- if (slotState.get() == Stopping) {
- slotStateTracker.enterState(Stopped);
- }
-
} else {
throw new RuntimeException("Valid Action implementations must implement either the SyncAction or the AsyncAction sub-interface");
}
+ if (motorState.get() == Stopping) {
+ motorState.enterState(Stopped);
+ logger.trace(() -> Thread.currentThread().getName() + " shutting down as " + motorState.get());
+ } else if (motorState.get() == Finished) {
+ logger.trace(() -> Thread.currentThread().getName() + " shutting down as " + motorState.get());
+ } else {
+ logger.warn("Unexpected motor state for CoreMotor shutdown: " + motorState.get());
+ }
} catch (Throwable t) {
logger.error("Error in core motor loop:" + t, t);
+ motorState.enterState(Errored);
throw t;
}
}
-
@Override
public String toString() {
- return "slot:" + this.slotId + "; state:" + slotState.get();
+ return "slot:" + this.slotId + "; state:" + motorState.get();
}
@Override
@@ -452,17 +461,17 @@ public class CoreMotor implements ActivityDefObserver, Motor, Stoppable {
@Override
public synchronized void requestStop() {
- if (slotState.get() == Running) {
+ if (motorState.get() == Running) {
if (input instanceof Stoppable) {
((Stoppable) input).requestStop();
}
if (action instanceof Stoppable) {
((Stoppable) action).requestStop();
}
- slotStateTracker.enterState(RunState.Stopping);
+ motorState.enterState(RunState.Stopping);
} else {
- if (slotState.get() != Stopped && slotState.get() != Stopping) {
- logger.warn("attempted to stop motor " + this.getSlotId() + ": from non Running state:" + slotState.get());
+ if (motorState.get() != Stopped && motorState.get() != Stopping) {
+ logger.warn("attempted to stop motor " + this.getSlotId() + ": from non Running state:" + motorState.get());
}
}
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityFinisher.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityFinisher.java
deleted file mode 100644
index 5b8588d80..000000000
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityFinisher.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2022 nosqlbench
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.nosqlbench.engine.core.lifecycle;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-public class ActivityFinisher extends Thread {
- private final static Logger logger = LogManager.getLogger(ActivityFinisher.class);
-
- private final ActivityThreadsManager executor;
- private final int timeout;
- private boolean result;
-
- public ActivityFinisher(ActivityThreadsManager executor, int timeout) {
- super(executor.getActivityDef().getAlias() + "_finisher");
- this.executor = executor;
- this.timeout = timeout;
- }
-
- @Override
- public void run() {
- logger.debug(this + " awaiting async completion of " + executor.getActivity().getAlias() + " on " + executor + " for timeout " + timeout);
- result = executor.awaitCompletion(timeout);
- logger.debug(this + " awaited async completion of " + executor.getActivity().getAlias());
- }
-
- public boolean getResult() {
- return result;
- }
-
- @Override
- public String toString() {
- return this.getClass().getSimpleName()+"/" + executor.getActivity().getAlias();
- }
-}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecMetricsResult.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecutionMetricsResult.java
similarity index 95%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecMetricsResult.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecutionMetricsResult.java
index f20b943b5..e81360e56 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecMetricsResult.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecutionMetricsResult.java
@@ -28,7 +28,7 @@ import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-public class ExecMetricsResult extends ExecResult {
+public class ExecutionMetricsResult extends ExecutionResult {
public static final Set INTERVAL_ONLY_METRICS = Set.of(
MetricAttribute.MIN,
@@ -48,8 +48,8 @@ public class ExecMetricsResult extends ExecResult {
MetricAttribute.M15_RATE
);
- public ExecMetricsResult(long startedAt, long endedAt, String iolog, Exception e) {
- super(startedAt, endedAt, iolog, e);
+ public ExecutionMetricsResult(long startedAt, long endedAt, String iolog, Exception error) {
+ super(startedAt, endedAt, iolog, error);
}
public String getMetricsSummary() {
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecResult.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecutionResult.java
similarity index 75%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecResult.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecutionResult.java
index db1454143..5db6c12d9 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecResult.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ExecutionResult.java
@@ -19,28 +19,26 @@ package io.nosqlbench.engine.core.lifecycle;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import java.util.Optional;
-
/**
* Provide a result type back to a caller, including the start and end times,
* any exception that occurred, and any content written to stdout or stderr equivalent
* IO streams. This is an execution result.
*
*/
-public class ExecResult {
- protected final static Logger logger = LogManager.getLogger(ExecMetricsResult.class);
+public class ExecutionResult {
+ protected final static Logger logger = LogManager.getLogger(ExecutionMetricsResult.class);
protected final long startedAt;
protected final long endedAt;
protected final Exception exception;
protected final String iolog;
- public ExecResult(long startedAt, long endedAt, String iolog, Exception e) {
+ public ExecutionResult(long startedAt, long endedAt, String iolog, Exception error) {
this.startedAt = startedAt;
this.endedAt = endedAt;
- this.exception = e;
- this.iolog = ((iolog != null) ? iolog + "\n\n" : "") + (e != null ? e.getMessage() : "");
- logger.debug("populating "+(e==null? "NORMAL" : "ERROR")+" scenario result");
- if (logger.isDebugEnabled()) {
+ this.exception = error;
+ this.iolog = ((iolog != null) ? iolog + "\n\n" : "") + exception;
+ logger.debug("populating "+(error==null ? "NORMAL" : "ERROR")+" scenario result");
+ if (logger.isTraceEnabled()) {
StackTraceElement[] st = Thread.currentThread().getStackTrace();
for (int i = 0; i < st.length; i++) {
logger.debug(":AT " + st[i].getFileName()+":"+st[i].getLineNumber()+":"+st[i].getMethodName());
@@ -51,7 +49,7 @@ public class ExecResult {
}
public void reportElapsedMillisToLog() {
- logger.info("-- SCENARIO TOOK " + getElapsedMillis() + "ms --");
+ logger.info(() -> String.format("-- SCENARIO TOOK %.3fS --",(getElapsedMillis()/1000.0f)));
}
public String getIOLog() {
@@ -62,7 +60,7 @@ public class ExecResult {
return endedAt - startedAt;
}
- public Optional getException() {
- return Optional.ofNullable(exception);
+ public Exception getException() {
+ return exception;
}
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/StartedActivityInfo.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/StartedActivityInfo.java
deleted file mode 100644
index 28b7f76c9..000000000
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/StartedActivityInfo.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2022 nosqlbench
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.nosqlbench.engine.core.lifecycle;
-
-import io.nosqlbench.engine.api.activityapi.core.Activity;
-
-public class StartedActivityInfo {
- private final Activity activity;
-
- StartedActivityInfo(Activity activity) {
- this.activity = activity;
- }
-
-
-}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesExceptionHandler.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesExceptionHandler.java
new file mode 100644
index 000000000..dd20c7948
--- /dev/null
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivitiesExceptionHandler.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.core.lifecycle.activity;
+
+import io.nosqlbench.engine.core.lifecycle.scenario.ScenarioController;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ActivitiesExceptionHandler implements Thread.UncaughtExceptionHandler {
+
+ private static final Logger logger = LogManager.getLogger(ActivitiesExceptionHandler.class);
+
+ private final ScenarioController controller;
+
+ public ActivitiesExceptionHandler(ScenarioController controller) {
+ this.controller = controller;
+ logger.debug(() -> "Activity exception handler starting up for executor '" + this.controller + "'");
+ }
+
+
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ logger.error("Uncaught exception in thread '" + t.getName() + ", state[" + t.getState() + "], notifying executor '" + controller + "'");
+ controller.notifyException(t, e);
+ }
+}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityThreadsManager.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java
similarity index 62%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityThreadsManager.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java
index afc53094e..e24aea1e0 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/ActivityThreadsManager.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityExecutor.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.nosqlbench.engine.core.lifecycle;
+package io.nosqlbench.engine.core.lifecycle.activity;
import io.nosqlbench.api.annotations.Annotation;
import io.nosqlbench.api.annotations.Layer;
@@ -22,42 +22,48 @@ import io.nosqlbench.api.engine.activityimpl.ParameterMap;
import io.nosqlbench.engine.api.activityapi.core.*;
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressCapable;
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
+import io.nosqlbench.engine.api.activityimpl.motor.RunStateImage;
+import io.nosqlbench.engine.api.activityimpl.motor.RunStateTally;
import io.nosqlbench.engine.core.annotation.Annotators;
+import io.nosqlbench.engine.core.lifecycle.ExecutionResult;
+import io.nosqlbench.engine.core.lifecycle.IndexedThreadFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;
/**
- *
An ActivityExecutor is a named instance of an execution harness for a single activity instance.
+ *
An ActivityExecutor is an execution harness for a single activity instance.
* It is responsible for managing threads and activity settings which may be changed while the activity is running.
*
- *
An ActivityExecutor may be represent an activity that is defined and active in the running
- * scenario, but which is inactive. This can occur when an activity is paused by controlling logic, or when the threads
- * are set to zero.
+ *
In order to allow for dynamic thread management, which is not easily supported as an explicit feature
+ * of most executor services, threads are started as long-running processes and managed via state signaling.
+ * The {@link RunState} enum, {@link io.nosqlbench.engine.api.activityimpl.MotorState} type, and {@link RunStateTally}
+ * state tracking class are used together to represent valid states and transitions, contain and transition state atomically,
+ * and provide blocking conditions for observers, respectively.
+ *
+ *
Some basic rules and invariants must be observed for consistent concurrent behavior.
+ * Any state changes for a Motor must be made through {@link Motor#getState()}.
+ * This allows the state tracking to work consistently for all observers.
*
- *
- * Invariants:
- *
- *
- *
Motors may not receive parameter updates before their owning activities are initialized.
- *
*/
-public class ActivityThreadsManager implements ActivityController, ParameterMap.Listener, ProgressCapable, Callable {
+public class ActivityExecutor implements ActivityController, ParameterMap.Listener, ProgressCapable, Callable {
- private static final Logger logger = LogManager.getLogger(ActivityThreadsManager.class);
+ // TODO Encapsulate valid state transitions to be only modifiable within the appropriate type view.
+
+ private static final Logger logger = LogManager.getLogger(ActivityExecutor.class);
private static final Logger activitylogger = LogManager.getLogger("ACTIVITY");
private final List> motors = new ArrayList<>();
private final Activity activity;
private final ActivityDef activityDef;
- private final ExecutorService executorService;
- private RuntimeException stoppingException;
+ private final RunStateTally tally;
+ private ExecutorService executorService;
+ private Exception exception;
private final static int waitTime = 10000;
private String sessionId = "";
@@ -67,75 +73,32 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
// private RunState intendedState = RunState.Uninitialized;
- public ActivityThreadsManager(Activity activity, String sessionId) {
+ public ActivityExecutor(Activity activity, String sessionId) {
this.activity = activity;
this.activityDef = activity.getActivityDef();
- executorService = new ThreadPoolExecutor(
- 0, Integer.MAX_VALUE,
- 0L, TimeUnit.SECONDS,
- new SynchronousQueue<>(),
- new IndexedThreadFactory(activity.getAlias(), new ActivityExceptionHandler(this))
- );
activity.getActivityDef().getParams().addListener(this);
activity.setActivityController(this);
this.sessionId = sessionId;
+ this.tally = activity.getRunStateTally();
}
// TODO: Doc how uninitialized activities do not propagate parameter map changes and how
// TODO: this is different from preventing modification to uninitialized activities
- /**
- *
True-up the number of motor instances known to the executor. Start all non-running motors.
- * The protocol between the motors and the executor should be safe as long as each state change is owned by either
- * the motor logic or the activity executor but not both, and strictly serialized as well. This is enforced by
- * forcing start(...) to be serialized as well as using CAS on the motor states.
- *
The startActivity method may be called to true-up the number of active motors in an activity executor after
- * changes to threads.
- */
- public synchronized void startActivity() {
- logger.info("starting activity " + activity.getAlias() + " for cycles " + activity.getCycleSummary());
- Annotators.recordAnnotation(Annotation.newBuilder()
- .session(sessionId)
- .now()
- .layer(Layer.Activity)
- .label("alias", getActivityDef().getAlias())
- .label("driver", getActivityDef().getActivityType())
- .label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
- .detail("params", getActivityDef().toString())
- .build()
- );
-
- activitylogger.debug("START/before alias=(" + activity.getAlias() + ")");
- try {
- activity.setRunState(RunState.Starting);
- this.startedAt = System.currentTimeMillis();
- activity.initActivity();
- //activity.onActivityDefUpdate(activityDef);
- } catch (Exception e) {
- this.stoppingException = new RuntimeException("Error initializing activity '" + activity.getAlias() + "':\n" + e.getMessage(), e);
-// activitylogger.error("error initializing activity '" + activity.getAlias() + "': " + stoppingException);
- throw stoppingException;
- }
- adjustToActivityDef(activity.getActivityDef());
- activity.setRunState(RunState.Running);
- activitylogger.debug("START/after alias=(" + activity.getAlias() + ")");
- }
-
/**
* Simply stop the motors
*/
- private synchronized void stopActivity() {
- activitylogger.debug("STOP/before alias=(" + activity.getAlias() + ")");
-
- activity.setRunState(RunState.Stopping);
+ public void stopActivity() {
logger.info("stopping activity in progress: " + this.getActivityDef().getAlias());
+ activity.setRunState(RunState.Stopping);
motors.forEach(Motor::requestStop);
- motors.forEach(m -> awaitRequiredMotorState(m, 30000, 50, RunState.Stopped, RunState.Finished));
- activity.shutdownActivity();
- activity.closeAutoCloseables();
+ tally.awaitNoneOther(RunState.Stopped,RunState.Finished);
+
+ shutdownExecutorService(Integer.MAX_VALUE);
+ tally.awaitNoneOther(RunState.Stopped,RunState.Finished);
activity.setRunState(RunState.Stopped);
+
logger.info("stopped: " + this.getActivityDef().getAlias() + " with " + motors.size() + " slots");
- activitylogger.debug("STOP/after alias=(" + activity.getAlias() + ")");
Annotators.recordAnnotation(Annotation.newBuilder()
.session(sessionId)
@@ -149,7 +112,7 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
);
}
- public RuntimeException forceStopActivity(int initialMillisToWait) {
+ public Exception forceStopActivity(int initialMillisToWait) {
activitylogger.debug("FORCE STOP/before alias=(" + activity.getAlias() + ")");
activity.setRunState(RunState.Stopped);
@@ -188,10 +151,10 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
logger.debug("took " + (activityShutdownEndedAt - activityShutdownStartedAt) + " ms to shutdown activity threads");
activitylogger.debug("FORCE STOP/after alias=(" + activity.getAlias() + ")");
- if (stoppingException != null) {
+ if (exception != null) {
activitylogger.debug("FORCE STOP/exception alias=(" + activity.getAlias() + ")");
}
- return stoppingException;
+ return exception;
}
@@ -201,60 +164,19 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
* @param initialMillisToWait milliseconds to wait after graceful shutdownActivity request, before forcing
* everything to stop
*/
- private synchronized void forceStopScenarioAndThrow(int initialMillisToWait, boolean rethrow) {
- RuntimeException exception = forceStopActivity(initialMillisToWait);
+ public synchronized void forceStopScenarioAndThrow(int initialMillisToWait, boolean rethrow) {
+ Exception exception = forceStopActivity(initialMillisToWait);
if (exception != null && rethrow) {
- throw exception;
+ throw new RuntimeException(exception);
}
}
- private boolean finishAndShutdownExecutor(int secondsToWait) {
-
- activitylogger.debug("REQUEST STOP/before alias=(" + activity.getAlias() + ")");
- logger.debug("Stopping executor for " + activity.getAlias() + " when work completes.");
-
- boolean wasStopped = false;
- try {
- executorService.shutdown();
- logger.trace(() -> "awaiting termination with timeout of " + secondsToWait + " seconds");
- wasStopped = executorService.awaitTermination(secondsToWait, TimeUnit.SECONDS);
- } catch (InterruptedException ie) {
- logger.trace("interrupted while awaiting termination");
- wasStopped = false;
- logger.warn("while waiting termination of shutdown " + activity.getAlias() + ", " + ie.getMessage());
- activitylogger.debug("REQUEST STOP/exception alias=(" + activity.getAlias() + ") wasstopped=" + wasStopped);
- } catch (RuntimeException e) {
- logger.trace("Received exception while awaiting termination: " + e.getMessage());
- wasStopped = true;
- stoppingException = e;
- } finally {
-
- logger.trace(() -> "finally shutting down activity " + this.getActivity().getAlias());
- activity.shutdownActivity();
-
- logger.trace("closing auto-closeables");
- activity.closeAutoCloseables();
- activity.setRunState(RunState.Stopped);
- this.stoppedAt = System.currentTimeMillis();
- }
-
- if (stoppingException != null) {
- logger.trace(() -> "an exception caused the activity to stop:" + stoppingException.getMessage());
- logger.trace("Setting ERROR on activity executor: " + stoppingException.getMessage());
- throw stoppingException;
- }
-
- activitylogger.debug("REQUEST STOP/after alias=(" + activity.getAlias() + ") wasstopped=" + wasStopped);
-
- return wasStopped;
- }
-
/**
* Listens for changes to parameter maps, maps them to the activity instance, and notifies all eligible listeners of
* changes.
*/
@Override
- public synchronized void handleParameterMapUpdate(ParameterMap parameterMap) {
+ public void handleParameterMapUpdate(ParameterMap parameterMap) {
activity.onActivityDefUpdate(activityDef);
@@ -263,7 +185,7 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
// by the RunState.
if (activity.getRunState() != RunState.Uninitialized) {
if (activity.getRunState() == RunState.Running) {
- adjustToActivityDef(activity.getActivityDef());
+ adjustMotorCountToThreadParam(activity.getActivityDef());
}
motors.stream()
.filter(m -> (m instanceof ActivityDefObserver))
@@ -286,7 +208,7 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
*/
private boolean awaitCompletion(int waitTime) {
logger.debug(() -> "awaiting completion of '" + this.getActivity().getAlias() + "'");
- boolean finished = finishAndShutdownExecutor(waitTime);
+ boolean finished = shutdownExecutorService(waitTime);
Annotators.recordAnnotation(Annotation.newBuilder()
.session(sessionId)
@@ -302,28 +224,13 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
return finished;
}
- public boolean awaitFinishedOrStopped(int timeout) {
- activitylogger.debug("AWAIT-FINISH/before alias=(" + activity.getAlias() + ")");
-
- boolean awaited = awaitAllRequiredMotorState(timeout, 50, RunState.Finished, RunState.Stopped);
- if (awaited) {
- awaited = awaitCompletion(timeout);
- }
- if (stoppingException != null) {
- activitylogger.debug("AWAIT-FINISH/exception alias=(" + activity.getAlias() + ")");
- throw stoppingException;
- }
- activitylogger.debug("AWAIT-FINISH/after alias=(" + activity.getAlias() + ")");
- return awaited;
- }
-
public String toString() {
return getClass().getSimpleName() + "~" + activityDef.getAlias();
}
private String getSlotStatus() {
return motors.stream()
- .map(m -> m.getSlotStateTracker().getSlotState().getCode())
+ .map(m -> m.getState().get().getCode())
.collect(Collectors.joining(",", "[", "]"));
}
@@ -332,17 +239,19 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
*
* @param activityDef the activityDef for this activity instance
*/
- private synchronized void adjustToActivityDef(ActivityDef activityDef) {
+ private void adjustMotorCountToThreadParam(ActivityDef activityDef) {
logger.trace(() -> ">-pre-adjust->" + getSlotStatus());
- // Stop and remove extra motor slots
- while (motors.size() > activityDef.getThreads()) {
- Motor motor = motors.get(motors.size() - 1);
- logger.trace(() -> "Stopping cycle motor thread:" + motor);
- motor.requestStop();
- motors.remove(motors.size() - 1);
- }
+ reduceActiveMotorCountDownToThreadParam(activityDef);
+ increaseActiveMotorCountUpToThreadParam(activityDef);
+ alignMotorStateToIntendedActivityState();
+ awaitAlignmentOfMotorStateToActivityState();
+ logger.trace(() -> ">post-adjust->" + getSlotStatus());
+
+ }
+
+ private void increaseActiveMotorCountUpToThreadParam(ActivityDef activityDef) {
// Create motor slots
while (motors.size() < activityDef.getThreads()) {
@@ -350,15 +259,27 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
logger.trace(() -> "Starting cycle motor thread:" + motor);
motors.add(motor);
}
-
- applyIntendedStateToDivergentMotors();
- awaitActivityAndMotorStateAlignment();
-
- logger.trace(() -> ">post-adjust->" + getSlotStatus());
-
}
- private void applyIntendedStateToDivergentMotors() {
+ private void reduceActiveMotorCountDownToThreadParam(ActivityDef activityDef) {
+ // Stop and remove extra motor slots
+ while (motors.size() > activityDef.getThreads()) {
+ Motor motor = motors.get(motors.size() - 1);
+ logger.trace(() -> "Stopping cycle motor thread:" + motor);
+ motor.requestStop();
+ motor.removeState();
+
+ /**
+ * NOTE: this leaves trailing, longer-running threads which might hold the executor open
+ * to potentially be cleaned up by {@link ExecutorService#shutdown()} or
+ * {@link ExecutorService#shutdownNow()}. At this point, the motor thread has
+ * been instructed to shutdown, and it is effectively thread-non-grata to the activity.
+ */
+ motors.remove(motors.size() - 1);
+ }
+ }
+
+ private void alignMotorStateToIntendedActivityState() {
RunState intended = activity.getRunState();
logger.trace(() -> "ADJUSTING to INTENDED " + intended);
switch (intended) {
@@ -367,17 +288,16 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
case Running:
case Starting:
motors.stream()
- .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Running)
- .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Finished)
- .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Starting)
+ .filter(m -> m.getState().get() != RunState.Running)
+ .filter(m -> m.getState().get() != RunState.Finished)
+ .filter(m -> m.getState().get() != RunState.Starting)
.forEach(m -> {
- m.getSlotStateTracker().enterState(RunState.Starting);
executorService.execute(m);
});
break;
case Stopped:
motors.stream()
- .filter(m -> m.getSlotStateTracker().getSlotState() != RunState.Stopped)
+ .filter(m -> m.getState().get() != RunState.Stopped)
.forEach(Motor::requestStop);
break;
case Finished:
@@ -389,20 +309,21 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
}
}
- private void awaitActivityAndMotorStateAlignment() {
+ private void awaitAlignmentOfMotorStateToActivityState() {
+ logger.debug(()->"awaiting state alignment from " + activity.getRunState());
switch (activity.getRunState()) {
case Starting:
case Running:
- motors.forEach(m -> awaitRequiredMotorState(m, waitTime, 50, RunState.Running, RunState.Finished));
+ tally.awaitNoneOther(RunState.Running, RunState.Finished);
break;
case Stopped:
- motors.forEach(m -> awaitRequiredMotorState(m, waitTime, 50, RunState.Stopped, RunState.Finished));
+ tally.awaitNoneOther(RunState.Stopped, RunState.Finished);
break;
case Uninitialized:
break;
case Finished:
- motors.forEach(m -> awaitRequiredMotorState(m, waitTime, 50, RunState.Finished));
+ tally.awaitNoneOther(RunState.Finished);
break;
case Stopping:
throw new RuntimeException("Invalid requested state in activity executor:" + activity.getRunState());
@@ -413,106 +334,40 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
}
- /**
- * Await a thread (aka motor/slot) entering a specific SlotState
- *
- * @param m motor instance
- * @param waitTime milliseconds to wait, total
- * @param pollTime polling interval between state checks
- * @param desiredRunStates any desired SlotState
- * @return true, if the desired SlotState was detected
- */
- private boolean awaitMotorState(Motor> m, int waitTime, int pollTime, RunState... desiredRunStates) {
- long startedAt = System.currentTimeMillis();
- while (System.currentTimeMillis() < (startedAt + waitTime)) {
- for (RunState desiredRunState : desiredRunStates) {
- if (desiredRunState == m.getSlotStateTracker().getSlotState()) {
- return true;
- }
- }
- try {
- Thread.sleep(pollTime);
- } catch (InterruptedException ignored) {
- }
- }
- logger.trace(() -> activityDef.getAlias() + "/Motor[" + m.getSlotId() + "] is now in state " + m.getSlotStateTracker().getSlotState());
- return false;
- }
-
- private boolean awaitAllRequiredMotorState(int waitTime, int pollTime, RunState... awaitingState) {
- long startedAt = System.currentTimeMillis();
- boolean awaited = false;
- while (!awaited && (System.currentTimeMillis() < (startedAt + waitTime))) {
- awaited = true;
- for (Motor motor : motors) {
- awaited = awaitMotorState(motor, waitTime, pollTime, awaitingState);
- if (!awaited) {
- logger.trace(() -> "failed awaiting motor " + motor.getSlotId() + " for state in " +
- Arrays.asList(awaitingState));
- break;
- }
- }
- }
- return awaited;
- }
-
- /**
- * Await a required thread (aka motor/slot) entering a specific SlotState
- *
- * @param m motor instance
- * @param waitTime milliseconds to wait, total
- * @param pollTime polling interval between state checks
- * @param awaitingState desired SlotState
- * @throws RuntimeException if the waitTime is used up and the desired state is not reached
- */
- private void awaitRequiredMotorState(Motor m, int waitTime, int pollTime, RunState... awaitingState) {
- RunState startingState = m.getSlotStateTracker().getSlotState();
- boolean awaitedRequiredState = awaitMotorState(m, waitTime, pollTime, awaitingState);
- if (!awaitedRequiredState) {
- String error = "Unable to await " + activityDef.getAlias() +
- "/Motor[" + m.getSlotId() + "]: from state " + startingState + " to " + m.getSlotStateTracker().getSlotState()
- + " after waiting for " + waitTime + "ms";
- RuntimeException e = new RuntimeException(error);
- logger.error(error);
- throw e;
- }
- logger.trace(() -> "motor " + m + " entered awaited state: " + Arrays.asList(awaitingState));
- }
-
- private synchronized void requestStopMotors() {
+ private void requestStopMotors() {
logger.info("stopping activity " + activity);
- activity.setRunState(RunState.Stopped);
+ activity.setRunState(RunState.Stopping);
motors.forEach(Motor::requestStop);
}
public boolean isRunning() {
- return motors.stream().anyMatch(m -> m.getSlotStateTracker().getSlotState() == RunState.Running);
+ return motors.stream().anyMatch(m -> m.getState().get() == RunState.Running);
}
public Activity getActivity() {
return activity;
}
- public synchronized void notifyException(Thread t, Throwable e) {
+ public void notifyException(Thread t, Throwable e) {
logger.debug(() -> "Uncaught exception in activity thread forwarded to activity executor: " + e.getMessage());
- this.stoppingException = new RuntimeException("Error in activity thread " + t.getName(), e);
- forceStopActivity(10000);
+ this.exception = new RuntimeException("Error in activity thread " + t.getName(), e);
+ this.requestStopMotors();
}
@Override
public synchronized void stopActivityWithReasonAsync(String reason) {
logger.info("Stopping activity " + this.activityDef.getAlias() + ": " + reason);
- this.stoppingException = new RuntimeException("Stopping activity " + this.activityDef.getAlias() + ": " + reason);
- logger.error("stopping with reason: " + stoppingException);
+ this.exception = new RuntimeException("Stopping activity " + this.activityDef.getAlias() + ": " + reason);
+ logger.error("stopping with reason: " + exception);
requestStopMotors();
}
@Override
public synchronized void stopActivityWithErrorAsync(Throwable throwable) {
- if (stoppingException == null) {
- this.stoppingException = new RuntimeException(throwable);
+ if (exception == null) {
+ this.exception = new RuntimeException(throwable);
logger.error("stopping on error: " + throwable.toString(), throwable);
} else {
if (activityDef.getParams().getOptionalBoolean("fullerrors").orElse(false)) {
@@ -531,9 +386,139 @@ public class ActivityThreadsManager implements ActivityController, ParameterMap.
@Override
- public synchronized ExecResult call() throws Exception {
- boolean stopped = awaitCompletion(Integer.MAX_VALUE);
- ExecResult result = new ExecResult(startedAt, stoppedAt, "", this.stoppingException);
+ public ExecutionResult call() throws Exception {
+
+ try {
+ // instantiate and configure fixtures that need to be present
+ // before threads start running such as metrics instruments
+ activity.initActivity();
+ awaitMotorsAtLeastRunning();
+ awaitActivityCompletion();
+ activity.shutdownActivity();
+ activity.closeAutoCloseables();
+ } catch (Exception e) {
+ this.exception = e;
+ }
+ ExecutionResult result = new ExecutionResult(startedAt, stoppedAt, "", exception);
return result;
}
+
+ /**
+ * This waits for at least one motor to be in running, finished or stopped state.
+ * A motor with enough cycles to read will go into a running state. A motor which has
+ * a short read immediately after being started will go into a finished state. A motor
+ * which has been stopped for some reason, like an error or a stop command will go into
+ * stopped state. All of these states are sufficient to signal that successful startup
+ * has been completed at least.
+ */
+ private void awaitMotorsAtLeastRunning() {
+ RunStateImage states = tally.awaitAny(RunState.Running, RunState.Stopped, RunState.Finished, RunState.Errored);
+ RunState maxState = states.getMaxState();
+ if (maxState==RunState.Errored) {
+ activity.setRunState(maxState);
+ throw new RuntimeException("Error in activity");
+ }
+ }
+
+ public void startActivity() {
+ // we need an executor service to run motor threads on
+ startMotorExecutorService();
+ startRunningActivityThreads();
+ awaitMotorsAtLeastRunning();
+ }
+
+ private boolean shutdownExecutorService(int secondsToWait) {
+
+ activitylogger.debug(() -> "Shutting down motor executor for (" + activity.getAlias() + ")");
+
+ boolean wasStopped = false;
+ try {
+ executorService.shutdown();
+ logger.trace(() -> "awaiting termination with timeout of " + secondsToWait + " seconds");
+ wasStopped = executorService.awaitTermination(secondsToWait, TimeUnit.SECONDS);
+ } catch (InterruptedException ie) {
+ logger.trace("interrupted while awaiting termination");
+ wasStopped = false;
+ logger.warn("while waiting termination of shutdown " + activity.getAlias() + ", " + ie.getMessage());
+ activitylogger.debug("REQUEST STOP/exception alias=(" + activity.getAlias() + ") wasstopped=" + wasStopped);
+ } catch (RuntimeException e) {
+ logger.trace("Received exception while awaiting termination: " + e.getMessage());
+ wasStopped = true;
+ exception = e;
+ } finally {
+ logger.trace(() -> "finally shutting down activity " + this.getActivity().getAlias());
+ this.stoppedAt = System.currentTimeMillis();
+ activity.setRunState(RunState.Stopped);
+ }
+
+ if (exception != null) {
+ logger.trace(() -> "an exception caused the activity to stop:" + exception.getMessage());
+ logger.warn("Setting ERROR on motor executor for activity '" + activity.getAlias() + "': " + exception.getMessage());
+ throw new RuntimeException(exception);
+ }
+
+ activitylogger.debug("motor executor for " + activity.getAlias() + ") wasstopped=" + wasStopped);
+
+ return wasStopped;
+ }
+
+ private void awaitActivityCompletion() {
+ RunStateImage state = tally.awaitNoneOther(RunState.Stopped, RunState.Finished, RunState.Errored);
+ RunState maxState = state.getMaxState();
+ activity.setRunState(maxState);
+ if (maxState==RunState.Errored) {
+ throw new RuntimeException("Error while waiting for activity completion:" + this.exception);
+ }
+ }
+
+ private void startMotorExecutorService() {
+ this.executorService = new ThreadPoolExecutor(
+ 0, Integer.MAX_VALUE,
+ 0L, TimeUnit.SECONDS,
+ new SynchronousQueue<>(),
+ new IndexedThreadFactory(activity.getAlias(), new ActivityExceptionHandler(this))
+ );
+ }
+
+
+ /**
+ *
True-up the number of motor instances known to the executor. Start all non-running motors.
+ * The protocol between the motors and the executor should be safe as long as each state change is owned by either
+ * the motor logic or the activity executor but not both, and strictly serialized as well. This is enforced by
+ * forcing start(...) to be serialized as well as using CAS on the motor states.
+ *
The startActivity method may be called to true-up the number of active motors in an activity executor after
+ * changes to threads.
+ */
+ private void startRunningActivityThreads() {
+
+ logger.info("starting activity " + activity.getAlias() + " for cycles " + activity.getCycleSummary());
+ Annotators.recordAnnotation(Annotation.newBuilder()
+ .session(sessionId)
+ .now()
+ .layer(Layer.Activity)
+ .label("alias", getActivityDef().getAlias())
+ .label("driver", getActivityDef().getActivityType())
+ .label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
+ .detail("params", getActivityDef().toString())
+ .build()
+ );
+
+ activitylogger.debug("START/before alias=(" + activity.getAlias() + ")");
+
+ try {
+ activity.setRunState(RunState.Starting);
+ this.startedAt = System.currentTimeMillis();
+ activity.onActivityDefUpdate(activityDef);
+ } catch (Exception e) {
+ this.exception = new RuntimeException("Error initializing activity '" + activity.getAlias() + "':\n" + e.getMessage(), e);
+ activitylogger.error(()->"error initializing activity '" + activity.getAlias() + "': " + exception);
+ throw new RuntimeException(exception);
+ }
+ adjustMotorCountToThreadParam(activity.getActivityDef());
+ tally.awaitAny(RunState.Running,RunState.Finished,RunState.Stopped);
+ activity.setRunState(RunState.Running);
+ activitylogger.debug("START/after alias=(" + activity.getAlias() + ")");
+ }
+
+
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityRuntimeInfo.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityRuntimeInfo.java
new file mode 100644
index 000000000..8e3d0ec53
--- /dev/null
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/activity/ActivityRuntimeInfo.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2022 nosqlbench
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.nosqlbench.engine.core.lifecycle.activity;
+
+import io.nosqlbench.engine.api.activityapi.core.Activity;
+import io.nosqlbench.engine.api.activityapi.core.RunState;
+import io.nosqlbench.engine.api.activityapi.core.progress.ProgressCapable;
+import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
+import io.nosqlbench.engine.core.lifecycle.ExecutionResult;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class ActivityRuntimeInfo implements ProgressCapable {
+
+ private final static Logger logger = LogManager.getLogger(ActivityRuntimeInfo.class);
+
+ private final Activity activity;
+ private final Future future;
+ private final ActivityExecutor executor;
+
+ private ExecutionResult result;
+
+ public ActivityRuntimeInfo(Activity activity, Future result, ActivityExecutor executor) {
+
+ this.activity = activity;
+ this.future = result;
+ this.executor = executor;
+ }
+
+ @Override
+ public ProgressMeterDisplay getProgressMeter() {
+ return this.activity.getProgressMeter();
+ }
+
+
+ public Future getFuture() {
+ return this.future;
+ }
+
+ /**
+ * Wait until the execution is complete and return the result.
+ * @param timeoutMillis
+ * @return null, or an ExecutionResult if the execution completed
+ */
+ public ExecutionResult awaitResult(long timeoutMillis) {
+ ExecutionResult result = null;
+ try {
+ result = future.get(timeoutMillis, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException te) {
+ } catch (InterruptedException ie) {
+ logger.warn("interrupted waiting for execution to complete");
+ } catch (ExecutionException e) {
+ throw new RuntimeException(e);
+// return new ExecutionResult(activity.getStartedAtMillis(),System.currentTimeMillis(),"",e);
+ }
+ return result;
+ }
+
+ public Activity getActivity() {
+ return this.activity;
+ }
+
+ public boolean isRunning() {
+ return executor.isRunning();
+ }
+
+ public RunState getRunState() {
+ return this.activity.getRunState();
+ }
+
+ public void stopActivity() {
+ this.executor.stopActivity();
+ }
+
+ public ActivityExecutor getActivityExecutor() {
+ return executor;
+ }
+}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/Scenario.java
similarity index 88%
rename from engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java
rename to engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/Scenario.java
index a087b444d..42f1a3545 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/Scenario.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.nosqlbench.engine.core.script;
+package io.nosqlbench.engine.core.lifecycle.scenario;
import com.codahale.metrics.MetricRegistry;
import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine;
@@ -26,11 +26,14 @@ import io.nosqlbench.api.metadata.SystemId;
import io.nosqlbench.engine.api.extensions.ScriptingPluginInfo;
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
import io.nosqlbench.engine.core.annotation.Annotators;
-import io.nosqlbench.engine.core.lifecycle.ActivityProgressIndicator;
-import io.nosqlbench.engine.core.lifecycle.ExecMetricsResult;
-import io.nosqlbench.engine.core.lifecycle.PolyglotScenarioController;
-import io.nosqlbench.engine.core.lifecycle.ScenarioController;
-import io.nosqlbench.engine.core.metrics.PolyglotMetricRegistryBindings;
+import io.nosqlbench.engine.core.lifecycle.activity.ActivityProgressIndicator;
+import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.bindings.PolyglotScenarioController;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.bindings.ActivityBindings;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.SandboxExtensionFinder;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.ScenarioContext;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.ScriptParams;
+import io.nosqlbench.engine.core.lifecycle.scenario.script.bindings.PolyglotMetricRegistryBindings;
import io.nosqlbench.nb.annotations.Maturity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -58,7 +61,7 @@ import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
-public class Scenario implements Callable {
+public class Scenario implements Callable {
private final String commandLine;
private final String reportSummaryTo;
@@ -71,9 +74,9 @@ public class Scenario implements Callable {
private Exception error;
private ScenarioMetadata scenarioMetadata;
- private ExecMetricsResult result;
+ private ExecutionMetricsResult result;
- public Optional getResultIfComplete() {
+ public Optional getResultIfComplete() {
return Optional.ofNullable(this.result);
}
@@ -213,7 +216,7 @@ public class Scenario implements Callable {
scriptEngine.put("scenario", new PolyglotScenarioController(scenarioController));
scriptEngine.put("metrics", new PolyglotMetricRegistryBindings(metricRegistry));
- scriptEngine.put("activities", new NashornActivityBindings(scenarioController));
+ scriptEngine.put("activities", new ActivityBindings(scenarioController));
for (ScriptingPluginInfo> extensionDescriptor : SandboxExtensionFinder.findAll()) {
if (!extensionDescriptor.isAutoLoading()) {
@@ -263,20 +266,26 @@ public class Scenario implements Callable {
);
logger.debug("Running control script for " + getScenarioName() + ".");
- scenarioController = new ScenarioController(this.scenarioName, minMaturity);
- initializeScriptingEngine(scenarioController);
- executeScenarioScripts();
-
- long awaitCompletionTime = 86400 * 365 * 1000L;
- logger.debug("Awaiting completion of scenario and activities for " + awaitCompletionTime + " millis.");
-
- scenarioController.awaitCompletion(awaitCompletionTime);
- //TODO: Ensure control flow covers controller shutdown in event of internal error.
+ scenarioController = new ScenarioController(this,minMaturity);
+ try {
+ initializeScriptingEngine(scenarioController);
+ executeScenarioScripts();
+ long awaitCompletionTime = 86400 * 365 * 1000L;
+ logger.debug("Awaiting completion of scenario and activities for " + awaitCompletionTime + " millis.");
+ scenarioController.awaitCompletion(awaitCompletionTime);
+ } catch (Exception e) {
+ this.error=e;
+ } finally {
+ scenarioController.shutdown();
+ }
Runtime.getRuntime().removeShutdownHook(scenarioShutdownHook);
scenarioShutdownHook.run();
}
+ public void notifyException(Thread t, Throwable e) {
+ this.error=new RuntimeException("in thread " + t.getName() + ", " +e, e);
+ }
private void executeScenarioScripts() {
for (String script : scripts) {
try {
@@ -375,35 +384,32 @@ public class Scenario implements Callable {
*
* The lifecycle of a scenario includes the lifecycles of all of the following:
*
- *
The scenario control script, executing within a graaljs context.
- *
The lifecycle of every activity which is started within the scenario.
+ *
The scenario control script, executing within a graaljs context.
+ *
The lifecycle of every activity which is started within the scenario.
*
*
* All of these run asynchronously within the scenario, however the same thread that calls
* the scenario is the one which executes the control script. A scenario ends when all
* of the following conditions are met:
*
- *
The scenario control script has run to completion, or experienced an exception.
- *
Each activity has run to completion, experienced an exception, or all
+ *
The scenario control script has run to completion, or experienced an exception.
+ *
Each activity has run to completion, experienced an exception, or all
*
*
* @return
*/
- public synchronized ExecMetricsResult call() {
+ public synchronized ExecutionMetricsResult call() {
if (result == null) {
try {
runScenario();
} catch (Exception e) {
- if (this.error!=null) {
- logger.debug("OVERLAPPING ERRORS: prior" + this.error.getMessage() + ", current:" + e.getMessage());
- }
- this.error = e;
+ this.error=e;
} finally {
- logger.debug((this.error == null ? "NORMAL" : "ERRORED") + " scenario run");
+ logger.debug((this.error==null ? "NORMAL" : "ERRORED") + " scenario run");
}
String iolog = scriptEnv.getTimedLog();
- this.result = new ExecMetricsResult(this.error, iolog, this.startedAtMillis, this.endedAtMillis);
+ this.result = new ExecutionMetricsResult(this.startedAtMillis, this.endedAtMillis, iolog, error);
result.reportMetricsSummaryToLog();
doReportSummaries(reportSummaryTo, result);
}
@@ -411,7 +417,7 @@ public class Scenario implements Callable {
return result;
}
- private void doReportSummaries(String reportSummaryTo, ExecMetricsResult result) {
+ private void doReportSummaries(String reportSummaryTo, ExecutionMetricsResult result) {
List fullChannels = new ArrayList<>();
List briefChannels = new ArrayList<>();
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
index bef6a8c2e..d0b2c4c4f 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenarioController.java
@@ -70,7 +70,7 @@ public class ScenarioController {
*/
public synchronized void start(ActivityDef activityDef) {
Annotators.recordAnnotation(Annotation.newBuilder()
- .session(sessionId)
+ .session(scenario.getScenarioName())
.now()
.layer(Layer.Activity)
.label("alias", activityDef.getAlias())
@@ -129,7 +129,7 @@ public class ScenarioController {
*/
public synchronized void run(ActivityDef activityDef, long timeoutMs) {
Annotators.recordAnnotation(Annotation.newBuilder()
- .session(sessionId)
+ .session(this.scenario.getScenarioName())
.now()
.layer(Layer.Activity)
.label("alias", activityDef.getAlias())
@@ -165,9 +165,8 @@ public class ScenarioController {
}
public boolean isRunningActivity(ActivityDef activityDef) {
-
- ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, false);
- return activityThreadsManager != null && activityThreadsManager.isRunning();
+ ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(activityDef.getAlias());
+ return (runtimeInfo != null && runtimeInfo.isRunning());
}
public boolean isRunningActivity(Map activityDefMap) {
@@ -184,7 +183,7 @@ public class ScenarioController {
*/
public synchronized void stop(ActivityDef activityDef) {
Annotators.recordAnnotation(Annotation.newBuilder()
- .session(sessionId)
+ .session(this.scenario.getScenarioName())
.now()
.layer(Layer.Activity)
.label("alias", activityDef.getAlias())
@@ -192,18 +191,14 @@ public class ScenarioController {
.detail("params", activityDef.toString())
.build());
- ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, false);
- if (activityThreadsManager == null) {
+ ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(activityDef.getAlias());
+ if (runtimeInfo == null) {
throw new RuntimeException("could not stop missing activity:" + activityDef);
}
- RunState runstate = activityThreadsManager.getActivity().getRunState();
- if (runstate != RunState.Running) {
- logger.warn("NOT stopping activity '" + activityThreadsManager.getActivity().getAlias() + "' because it is in state '" + runstate + "'");
- return;
- }
scenariologger.debug("STOP " + activityDef.getAlias());
- activityThreadsManager.stopActivity();
+
+ runtimeInfo.stopActivity();
}
/**
@@ -240,76 +235,6 @@ public class ScenarioController {
}
}
- /**
- * Modify one of the parameters in a defined activity. Any observing activity components will be notified of the
- * changes made to activity parameters.
- *
- * @param alias The name of an activity that is already known to the scenario.
- * @param param The parameter name
- * @param value a new parameter value
- */
- public synchronized void modify(String alias, String param, String value) {
- if (param.equals("alias")) {
- throw new InvalidParameterException("It is not allowed to change the name of an existing activity.");
- }
- ActivityThreadsManager activityThreadsManager = getActivityExecutor(alias);
- ParameterMap params = activityThreadsManager.getActivityDef().getParams();
- scenariologger.debug("SET (" + alias + "/" + param + ")=(" + value + ")");
- params.set(param, value);
- }
-
- /**
- * Apply any parameter changes to a defined activity, or start a new one.
- * This method is syntactical sugar for scripting. Each of the parameters in the map
- * is checked against existing values, and per-field modifications
- * are applied one at a time, only if the values have changed.
- *
- * @param appliedParams Map of new values.
- */
- public synchronized void apply(Map appliedParams) {
- String alias = appliedParams.get("alias");
-
- if (alias == null) {
- throw new BasicError("alias must be provided");
- }
-
- ActivityThreadsManager executor = activityExecutors.get(alias);
-
- if (executor == null) {
- logger.info("started scenario from apply:" + alias);
- start(appliedParams);
- return;
- }
-
- ParameterMap previousMap = executor.getActivityDef().getParams();
-
- for (String paramName : appliedParams.keySet()) {
- String appliedVal = appliedParams.get(paramName);
- Optional prevVal = previousMap.getOptionalString(paramName);
-
- if (!prevVal.isPresent() || !prevVal.get().equals(appliedVal)) {
- logger.info("applying new value to activity '" + alias + "': '" + prevVal.get() + "' -> '" + appliedVal + "'");
- previousMap.set(paramName, appliedVal);
- }
- }
- }
-
- /**
- * Get the activity executor associated with the given alias. This should be used to find activitytypes
- * which are presumed to be already defined.
- *
- * @param activityAlias The activity alias for the extant activity.
- * @return the associated ActivityExecutor
- * @throws RuntimeException a runtime exception if the named activity is not found
- */
- private ActivityThreadsManager getActivityExecutor(String activityAlias) {
- Optional executor =
- Optional.ofNullable(activityExecutors.get(activityAlias));
- return executor.orElseThrow(
- () -> new RuntimeException("ActivityExecutor for alias " + activityAlias + " not found.")
- );
-
- }
private List getMatchingAliases(String pattern) {
Pattern matcher;
@@ -320,52 +245,13 @@ public class ScenarioController {
matcher = Pattern.compile(pattern);
}
- List matching = activityExecutors.keySet().stream()
+ List matching = activityInfoMap.keySet().stream()
.filter(a -> Pattern.matches(pattern, a))
.peek(p -> logger.debug("MATCH " + pattern + " -> " + p))
.collect(Collectors.toList());
return matching;
}
- private ActivityThreadsManager getActivityExecutor(ActivityDef activityDef, boolean createIfMissing) {
- synchronized (activityExecutors) {
- ActivityThreadsManager executor = activityExecutors.get(activityDef.getAlias());
-
- if (executor == null && createIfMissing) {
- if (activityDef.getParams().containsKey("driver")) {
- ActivityType> activityType = new ActivityTypeLoader()
- .setMaturity(this.minMaturity)
- .load(activityDef)
- .orElseThrow(
- () -> new RuntimeException("Driver for '" + activityDef + "' was not found." +
- "\nYou can use --list-drivers to see what drivers are supported in this runtime." +
- ConfigSuggestions.suggestAlternates(
- new ActivityTypeLoader().getAllSelectors(), activityDef.getActivityType(), 4)
- .orElse("")
- )
- );
-
- executor = new ActivityThreadsManager(
- activityType.getAssembledActivity(
- activityDef,
- getActivityMap()
- ),
- this.sessionId
- );
- activityExecutors.put(activityDef.getAlias(), executor);
- } else {
- executor = new ActivityThreadsManager(
- new StandardActivityType(activityDef).getAssembledActivity(
- activityDef, getActivityMap()
- ), this.sessionId
- );
- }
-
- }
- return executor;
- }
- }
-
/**
* Wait for a bit. This is not the best approach, and will be replaced with a different system in the future.
*
@@ -394,29 +280,7 @@ public class ScenarioController {
* @return set of activity names
*/
public Set getAliases() {
- return activityExecutors.keySet();
- }
-
- /**
- * Return all the activity definitions that are known to this scenario.
- *
- * @return list of activity defs
- */
- public List getActivityDefs() {
- return activityExecutors.values().stream()
- .map(ActivityThreadsManager::getActivityDef)
- .collect(Collectors.toList());
- }
-
- /**
- * Get the named activity def, if it is known to this scenario.
- *
- * @param alias The name by which the activity is known to this scenario.
- * @return an ActivityDef instance
- * @throws RuntimeException if the alias is not known to the scenario
- */
- public ActivityDef getActivityDef(String alias) {
- return getActivityExecutor(alias).getActivityDef();
+ return activityInfoMap.keySet();
}
/**
@@ -427,8 +291,9 @@ public class ScenarioController {
* @param waitTimeMillis grace period during which an activity may cooperatively shut down
*/
public synchronized void forceStopScenario(int waitTimeMillis, boolean rethrow) {
+ logger.debug("force stopping scenario " + this.scenario.getScenarioName());
+ activityInfoMap.values().forEach(a -> a.getActivityExecutor().forceStopActivity(10000));
logger.debug("Scenario force stopped.");
- activityExecutors.values().forEach(a -> a.forceStopScenarioAndThrow(waitTimeMillis, rethrow));
}
// public synchronized void stopAll() {
@@ -446,31 +311,21 @@ public class ScenarioController {
public boolean awaitCompletion(long waitTimeMillis) {
logger.debug(() -> "awaiting completion");
boolean completed = true;
- long remaining = waitTimeMillis;
-
- List finishers = new ArrayList<>();
- for (ActivityThreadsManager ae : activityExecutors.values()) {
- ActivityFinisher finisher = new ActivityFinisher(ae, (int) remaining);
- finishers.add(finisher);
- finisher.start();
- }
-
- for (ActivityFinisher finisher : finishers) {
- try {
- logger.debug("joining finisher " + finisher.getName());
- finisher.join(waitTimeMillis);
- logger.debug("joined finisher " + finisher.getName());
- } catch (InterruptedException ignored) {
- }
- }
-
- for (ActivityFinisher finisher : finishers) {
- if (!finisher.getResult()) {
- logger.debug("finisher for " + finisher.getName() + " did not signal TRUE");
+ for (ActivityRuntimeInfo activityRuntimeInfo : this.activityInfoMap.values()) {
+ ExecutionResult activityResult = activityRuntimeInfo.awaitResult(waitTimeMillis);
+ if (activityResult == null) {
+ logger.error("Unable to retrieve activity result for " + activityRuntimeInfo.getActivity().getAlias());
completed = false;
+ } else {
+ if (activityResult.getException()!=null) {
+ if (activityResult.getException() instanceof RuntimeException e) {
+ throw e;
+ } else {
+ throw new RuntimeException(activityResult.getException());
+ }
+ }
}
}
-
return completed;
}
@@ -482,66 +337,98 @@ public class ScenarioController {
}
}
- public boolean await(Map activityDefMap) {
- return this.awaitActivity(activityDefMap);
+ public void await(Map activityDefMap) {
+ this.awaitActivity(activityDefMap);
}
public boolean awaitActivity(Map activityDefMap) {
ActivityDef ad = new ActivityDef(new ParameterMap(activityDefMap));
- return awaitActivity(ad);
+ return awaitActivity(ad, Long.MAX_VALUE);
}
public boolean await(String alias) {
- return this.awaitActivity(alias);
+ return this.awaitActivity(alias, Long.MAX_VALUE);
}
- public boolean awaitActivity(String alias) {
+ public boolean awaitActivity(String alias, long timeoutMs) {
ActivityDef toAwait = aliasToDef(alias);
- return awaitActivity(toAwait);
+ return awaitActivity(toAwait, Long.MAX_VALUE);
}
- public boolean await(ActivityDef activityDef) {
- return this.awaitActivity(activityDef);
+ public void await(ActivityDef activityDef, long timeoutMs) {
+ this.awaitActivity(activityDef, timeoutMs);
}
- public boolean awaitActivity(ActivityDef activityDef) {
- ActivityThreadsManager activityThreadsManager = getActivityExecutor(activityDef, false);
- if (activityThreadsManager == null) {
- throw new RuntimeException("Could not await missing activity: " + activityDef);
+ public boolean awaitActivity(ActivityDef activityDef, long timeoutMs) {
+ ActivityRuntimeInfo ari = this.activityInfoMap.get(activityDef.getAlias());
+ if (ari == null) {
+ throw new RuntimeException("Could not await missing activity: " + activityDef.getAlias());
}
scenariologger.debug("AWAIT/before alias=" + activityDef.getAlias());
- boolean finished = activityThreadsManager.awaitFinishedOrStopped(Integer.MAX_VALUE);
- scenariologger.debug("AWAIT/after completed=" + finished);
- return finished;
-
+ ExecutionResult result = null;
+ Future future=null;
+ try {
+ future = ari.getFuture();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ try {
+ result = future.get(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException e) {
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ return (result != null);
}
/**
* @return an unmodifyable String to executor map of all activities known to this scenario
*/
- public Map getActivityExecutorMap() {
- return Collections.unmodifiableMap(activityExecutors);
+ public Map getActivityExecutorMap() {
+ return Collections.unmodifiableMap(activityInfoMap);
+ }
+
+ public List getActivityDefs() {
+ return activityInfoMap.values().stream().map(ari -> ari.getActivity().getActivityDef()).toList();
}
public void reportMetrics() {
ActivityMetrics.reportTo(System.out);
}
- private Map getActivityMap() {
- Map activityMap = new HashMap();
- for (Map.Entry entry : activityExecutors.entrySet()) {
- activityMap.put(entry.getKey(), entry.getValue().getActivity());
- }
- return activityMap;
- }
-
public List getProgressMeters() {
List indicators = new ArrayList<>();
- for (ActivityThreadsManager ae : activityExecutors.values()) {
+ for (ActivityRuntimeInfo ae : activityInfoMap.values()) {
indicators.add(ae.getProgressMeter());
}
indicators.sort(Comparator.comparing(ProgressMeterDisplay::getStartTime));
return indicators;
}
+ public void notifyException(Thread t, Throwable e) {
+ logger.error("Uncaught exception in activity lifecycle thread:" + e, e);
+ scenario.notifyException(t,e);
+ throw new RuntimeException(e);
+ }
+
+ public ActivityDef getActivityDef(String alias) {
+ return activityInfoMap.get(alias).getActivity().getActivityDef();
+ }
+
+ public void shutdown() {
+ this.activitiesExecutor.shutdown();
+ try {
+ if (!this.activitiesExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
+ this.activitiesExecutor.shutdownNow();
+ if (!this.activitiesExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
+ throw new RuntimeException("Unable to shutdown activities executor");
+ }
+ }
+ } catch (Exception e) {
+
+ }
+ }
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java
index b644b84d1..3217a0910 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosExecutor.java
@@ -79,6 +79,7 @@ public class ScenariosExecutor {
* @return the final scenario-result map
*/
public ScenariosResults awaitAllResults(long timeout, long updateInterval) {
+ long waitFrom = System.currentTimeMillis();
if (updateInterval > timeout) {
throw new BasicError("timeout must be equal to or greater than updateInterval");
}
@@ -98,6 +99,7 @@ public class ScenariosExecutor {
} catch (InterruptedException ignored) {
}
}
+ logger.trace("waited " + (System.currentTimeMillis()-waitFrom) + " millis for scenarios");
updateAt = Math.min(timeoutAt, System.currentTimeMillis() + updateInterval);
}
@@ -193,10 +195,7 @@ public class ScenariosExecutor {
logger.debug("#stopScenario(name=" + scenarioName + ", rethrow="+ rethrow+")");
Optional pendingScenario = getPendingScenario(scenarioName);
if (pendingScenario.isPresent()) {
- ScenarioController controller = pendingScenario.get().getScenarioController();
- if (controller != null) {
- controller.forceStopScenario(0, rethrow);
- }
+ pendingScenario.get().getScenarioController().forceStopScenario(10000, true);
} else {
throw new RuntimeException("Unable to cancel scenario: " + scenarioName + ": not found");
}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java
index 2cd5e763b..6e601f8c8 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/lifecycle/scenario/ScenariosResults.java
@@ -41,8 +41,8 @@ public class ScenariosResults {
public String getExecutionSummary() {
String sb = "executions: " + scenarioResultMap.size() + " scenarios, " +
- scenarioResultMap.values().stream().filter(r -> r.getException().isEmpty()).count() + " normal, " +
- scenarioResultMap.values().stream().filter(r -> r.getException().isPresent()).count() + " errored";
+ scenarioResultMap.values().stream().filter(r -> r.getException()==null).count() + " normal, " +
+ scenarioResultMap.values().stream().filter(r -> r.getException()!=null).count() + " errored";
return sb;
}
@@ -72,7 +72,7 @@ public class ScenariosResults {
public boolean hasError() {
return this.scenarioResultMap.values().stream()
- .anyMatch(r -> r.getException().isPresent());
+ .anyMatch(r -> r.getException()!=null);
}
public int getSize() {
diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityThreadsManagerTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java
similarity index 71%
rename from engine-core/src/test/java/io/nosqlbench/engine/core/ActivityThreadsManagerTest.java
rename to engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java
index b82c1cd29..86f7d6165 100644
--- a/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityThreadsManagerTest.java
+++ b/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java
@@ -16,30 +16,35 @@
package io.nosqlbench.engine.core;
+import io.nosqlbench.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.engine.api.activityapi.core.*;
-import io.nosqlbench.engine.api.activityapi.output.OutputDispenser;
import io.nosqlbench.engine.api.activityapi.input.Input;
import io.nosqlbench.engine.api.activityapi.input.InputDispenser;
-import io.nosqlbench.api.engine.activityimpl.ActivityDef;
+import io.nosqlbench.engine.api.activityapi.output.OutputDispenser;
import io.nosqlbench.engine.api.activityimpl.CoreServices;
import io.nosqlbench.engine.api.activityimpl.SimpleActivity;
import io.nosqlbench.engine.api.activityimpl.action.CoreActionDispenser;
-import io.nosqlbench.engine.api.activityimpl.input.CoreInputDispenser;
import io.nosqlbench.engine.api.activityimpl.input.AtomicInput;
+import io.nosqlbench.engine.api.activityimpl.input.CoreInputDispenser;
import io.nosqlbench.engine.api.activityimpl.motor.CoreMotor;
import io.nosqlbench.engine.api.activityimpl.motor.CoreMotorDispenser;
-import io.nosqlbench.engine.core.lifecycle.ActivityThreadsManager;
-import io.nosqlbench.engine.core.lifecycle.ActivityTypeLoader;
-import org.apache.logging.log4j.Logger;
+import io.nosqlbench.engine.core.lifecycle.ExecutionResult;
+import io.nosqlbench.engine.core.lifecycle.activity.ActivityExecutor;
+import io.nosqlbench.engine.core.lifecycle.activity.ActivityTypeLoader;
import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import static org.assertj.core.api.Assertions.assertThat;
-public class ActivityThreadsManagerTest {
- private static final Logger logger = LogManager.getLogger(ActivityThreadsManagerTest.class);
+public class ActivityExecutorTest {
+ private static final Logger logger = LogManager.getLogger(ActivityExecutorTest.class);
@Test
public synchronized void testRestart() {
@@ -54,13 +59,30 @@ public class ActivityThreadsManagerTest {
a.setOutputDispenserDelegate(tdisp);
a.setInputDispenserDelegate(idisp);
a.setMotorDispenserDelegate(mdisp);
-
- ActivityThreadsManager ae = new ActivityThreadsManager(a, "test-restart");
- ad.setThreads(1);
- ae.startActivity();
- ae.stopActivity();
- ae.startActivity();
- ae.awaitCompletion(15000);
+ ExecutorService executor = Executors.newCachedThreadPool();
+ ActivityExecutor ae = new ActivityExecutor(a, "test-restart");
+ Future future = executor.submit(ae);
+ try {
+ System.out.println("ad.setThreads(1)");
+ ad.setThreads(1);
+ System.out.println("ae.startActivity()");
+ ae.startActivity();
+ System.out.println("ae.stopActivity()");
+ ae.stopActivity();
+ System.out.println("ae.startActivity()");
+ ae.startActivity();
+ System.out.println("ae.startActivity()");
+ ae.startActivity();
+ System.out.println("ExecutionResult executionResult = future.get();");
+ ExecutionResult executionResult = future.get();
+ System.out.println("System.out.print(executionResult);");
+ System.out.print(executionResult);
+ Thread.sleep(500L);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ System.out.print("ad.setThreads(1)");
+ executor.shutdown();
assertThat(idisp.getInput(10).getInputSegment(3)).isNull();
}
@@ -79,10 +101,20 @@ public class ActivityThreadsManagerTest {
a.setInputDispenserDelegate(idisp);
a.setMotorDispenserDelegate(mdisp);
- ActivityThreadsManager ae = new ActivityThreadsManager(a, "test-delayed-start");
- ad.setThreads(1);
- ae.startActivity();
- ae.awaitCompletion(15000);
+ ActivityExecutor ae = new ActivityExecutor(a, "test-delayed-start");
+ ExecutorService testExecutor = Executors.newCachedThreadPool();
+ Future future = testExecutor.submit(ae);
+
+ try {
+ ad.setThreads(1);
+ ae.startActivity();
+ ExecutionResult result = future.get();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ testExecutor.shutdownNow();
assertThat(idisp.getInput(10).getInputSegment(3)).isNull();
}
@@ -93,7 +125,7 @@ public class ActivityThreadsManagerTest {
Optional activityType = new ActivityTypeLoader().load(ad);
Input longSupplier = new AtomicInput(ad);
MotorDispenser> cmf = getActivityMotorFactory(
- ad, motorActionDelay(999), longSupplier
+ ad, motorActionDelay(999), longSupplier
);
Activity a = new SimpleActivity(ad);
InputDispenser idisp = new CoreInputDispenser(a);
@@ -104,15 +136,15 @@ public class ActivityThreadsManagerTest {
a.setInputDispenserDelegate(idisp);
a.setMotorDispenserDelegate(mdisp);
- ActivityThreadsManager ae = new ActivityThreadsManager(a, "test-new-executor");
+ ActivityExecutor ae = new ActivityExecutor(a, "test-new-executor");
ad.setThreads(5);
ae.startActivity();
- int[] speeds = new int[]{1,2000,5,2000,2,2000};
- for(int offset=0; offset
Date: Tue, 20 Dec 2022 23:11:26 -0600
Subject: [PATCH 15/19] test cleanup
---
.../io/nosqlbench/engine/core/ActivityExecutorTest.java | 8 --------
1 file changed, 8 deletions(-)
diff --git a/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java b/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java
index 86f7d6165..635c71a61 100644
--- a/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java
+++ b/engine-core/src/test/java/io/nosqlbench/engine/core/ActivityExecutorTest.java
@@ -63,20 +63,12 @@ public class ActivityExecutorTest {
ActivityExecutor ae = new ActivityExecutor(a, "test-restart");
Future future = executor.submit(ae);
try {
- System.out.println("ad.setThreads(1)");
ad.setThreads(1);
- System.out.println("ae.startActivity()");
ae.startActivity();
- System.out.println("ae.stopActivity()");
ae.stopActivity();
- System.out.println("ae.startActivity()");
ae.startActivity();
- System.out.println("ae.startActivity()");
ae.startActivity();
- System.out.println("ExecutionResult executionResult = future.get();");
ExecutionResult executionResult = future.get();
- System.out.println("System.out.print(executionResult);");
- System.out.print(executionResult);
Thread.sleep(500L);
} catch (Exception e) {
throw new RuntimeException(e);
From 4f4b4982c867eff63e0fe8b9d0ed08c40a862436 Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 23:11:55 -0600
Subject: [PATCH 16/19] templatize test logging level for logger setup and root
logger
---
engine-api/src/test/resources/log4j2-test.xml | 4 +-
engine-cli/src/test/resources/log4j2-test.xml | 4 +-
.../src/test/resources/log4j2-test.xml | 4 +-
.../src/test/resources/log4j2-test.xml | 4 +-
mvn-defaults/pom.xml | 13 ++++-
.../src/test/resources/log4j2-test.xml | 57 +++++++++++++++++++
nbr/src/test/resources/log4j2-test.xml | 57 +++++++++++++++++++
.../src/test/resources/log4j2-test.xml | 4 +-
.../src/test/resources/log4j2-test.xml | 4 +-
.../src/test/resources/log4j2-test.xml | 4 +-
10 files changed, 140 insertions(+), 15 deletions(-)
create mode 100644 nbr-examples/src/test/resources/log4j2-test.xml
create mode 100644 nbr/src/test/resources/log4j2-test.xml
diff --git a/engine-api/src/test/resources/log4j2-test.xml b/engine-api/src/test/resources/log4j2-test.xml
index 797a5780b..d3fa79da2 100644
--- a/engine-api/src/test/resources/log4j2-test.xml
+++ b/engine-api/src/test/resources/log4j2-test.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-
@@ -48,7 +48,7 @@
-
+
diff --git a/engine-cli/src/test/resources/log4j2-test.xml b/engine-cli/src/test/resources/log4j2-test.xml
index 797a5780b..d3fa79da2 100644
--- a/engine-cli/src/test/resources/log4j2-test.xml
+++ b/engine-cli/src/test/resources/log4j2-test.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-
@@ -48,7 +48,7 @@
-
+
diff --git a/engine-core/src/test/resources/log4j2-test.xml b/engine-core/src/test/resources/log4j2-test.xml
index 797a5780b..d3fa79da2 100644
--- a/engine-core/src/test/resources/log4j2-test.xml
+++ b/engine-core/src/test/resources/log4j2-test.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-
@@ -48,7 +48,7 @@
-
+
diff --git a/engine-rest/src/test/resources/log4j2-test.xml b/engine-rest/src/test/resources/log4j2-test.xml
index 3ee115d07..dc9a74051 100644
--- a/engine-rest/src/test/resources/log4j2-test.xml
+++ b/engine-rest/src/test/resources/log4j2-test.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-
@@ -48,7 +48,7 @@
-
+
diff --git a/mvn-defaults/pom.xml b/mvn-defaults/pom.xml
index 21b415e13..d74745189 100644
--- a/mvn-defaults/pom.xml
+++ b/mvn-defaults/pom.xml
@@ -23,6 +23,11 @@
pom
+
+ INFO
+
+ INFO
+
UTF-8UTF-8nosqlbench
@@ -463,6 +468,12 @@
+
+
+ src/test/resources
+ true
+
+ org.apache.maven.plugins
@@ -596,7 +607,7 @@
org.apache.ratapache-rat-plugin
- 0.13
+ 0.15verify
diff --git a/nbr-examples/src/test/resources/log4j2-test.xml b/nbr-examples/src/test/resources/log4j2-test.xml
new file mode 100644
index 000000000..d3fa79da2
--- /dev/null
+++ b/nbr-examples/src/test/resources/log4j2-test.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d %p %C{1.} [%t] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nbr/src/test/resources/log4j2-test.xml b/nbr/src/test/resources/log4j2-test.xml
new file mode 100644
index 000000000..d3fa79da2
--- /dev/null
+++ b/nbr/src/test/resources/log4j2-test.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d %p %C{1.} [%t] %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/virtdata-lang/src/test/resources/log4j2-test.xml b/virtdata-lang/src/test/resources/log4j2-test.xml
index 797a5780b..d3fa79da2 100644
--- a/virtdata-lang/src/test/resources/log4j2-test.xml
+++ b/virtdata-lang/src/test/resources/log4j2-test.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-
@@ -48,7 +48,7 @@
-
+
diff --git a/virtdata-lib-basics/src/test/resources/log4j2-test.xml b/virtdata-lib-basics/src/test/resources/log4j2-test.xml
index 797a5780b..d3fa79da2 100644
--- a/virtdata-lib-basics/src/test/resources/log4j2-test.xml
+++ b/virtdata-lib-basics/src/test/resources/log4j2-test.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-
@@ -48,7 +48,7 @@
-
+
diff --git a/virtdata-userlibs/src/test/resources/log4j2-test.xml b/virtdata-userlibs/src/test/resources/log4j2-test.xml
index 797a5780b..d3fa79da2 100644
--- a/virtdata-userlibs/src/test/resources/log4j2-test.xml
+++ b/virtdata-userlibs/src/test/resources/log4j2-test.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-
@@ -48,7 +48,7 @@
-
+
From 6c8782842da5c6ca78a060422a00e8595ed1a8cf Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Tue, 20 Dec 2022 23:52:37 -0600
Subject: [PATCH 17/19] change tests System.out calls to use logger directly
---
.../uniform/flowtypes/ChainingOp.java | 2 +-
.../tracking/LongTreeTrackerTest2.java | 23 +++++++++++--------
.../api/templating/CommandTemplateTest.java | 5 +++-
.../java/io/nosqlbench/nb/AggregateTests.java | 22 ++++++++++--------
.../optimizers/TestOptimoExperiments.java | 5 +++-
.../rest/services/openapi/OpenApiLoader.java | 5 +++-
.../services/openapi/OpenApiLoaderTest.java | 6 +++--
.../from_long/to_long/TriangularStepTest.java | 6 ++---
.../tests/long_long/SignedHashTest.java | 8 +++++--
.../tests/long_string/CombinationsTest.java | 5 +++-
.../RealDistributionsConcurrencyTests.java | 17 +++++++-------
.../RealDistributionsValuesTest.java | 13 +++++++----
.../IntegerDistributionsConcurrencyTest.java | 14 +++++------
.../IntegerDistributionsValuesTest.java | 13 +++++++----
.../virtdata/IntegratedComposerLogicTest.java | 3 +++
.../io/virtdata/IntegratedCurvesTest.java | 7 +++---
16 files changed, 94 insertions(+), 60 deletions(-)
diff --git a/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/flowtypes/ChainingOp.java b/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/flowtypes/ChainingOp.java
index 43c1aeed4..019001331 100644
--- a/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/flowtypes/ChainingOp.java
+++ b/adapters-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/flowtypes/ChainingOp.java
@@ -19,7 +19,7 @@ package io.nosqlbench.engine.api.activityimpl.uniform.flowtypes;
import java.util.function.Function;
/**
- *
ChainingOp: f(I) -> O
+ *
ChainingOp<I,O>: f(I) -> O<I,O>
*
* Run a function on the current cached result in the current thread and replace it
* with the result of the function. ChainingOps are one way of invoking
diff --git a/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/tracking/LongTreeTrackerTest2.java b/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/tracking/LongTreeTrackerTest2.java
index a8406f6a7..6dbc889d0 100644
--- a/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/tracking/LongTreeTrackerTest2.java
+++ b/engine-api/src/test/java/io/nosqlbench/engine/api/activityimpl/tracking/LongTreeTrackerTest2.java
@@ -18,12 +18,15 @@ package io.nosqlbench.engine.api.activityimpl.tracking;
import io.nosqlbench.engine.api.activityimpl.marker.longheap.LongTreeTracker;
import io.nosqlbench.engine.api.activityimpl.marker.longheap.LongTreeTrackerAtomic;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class LongTreeTrackerTest2 {
+ private final static Logger logger = LogManager.getLogger(LongTreeTrackerTest2.class);
// @Test
// public void testCoMask() {
@@ -96,21 +99,21 @@ public class LongTreeTrackerTest2 {
public void testApply() {
LongTreeTracker t = new LongTreeTracker(0L);
t.setCompleted(0);
- System.out.println(t);
+ logger.debug(t);
t.setCompleted(1);
- System.out.println(t);
+ logger.debug(t);
t.setCompleted(2);
- System.out.println(t);
+ logger.debug(t);
t.setCompleted(5);
- System.out.println(t);
+ logger.debug(t);
t.setCompleted(6);
- System.out.println(t);
+ logger.debug(t);
t.setCompleted(3);
- System.out.println(t);
+ logger.debug(t);
t.setCompleted(4);
- System.out.println(t);
+ logger.debug(t);
t.setCompleted(7);
- System.out.println(t);
+ logger.debug(t);
}
@Test
@@ -119,7 +122,7 @@ public class LongTreeTrackerTest2 {
for (int i = 0; i < 32 ; i++) {
t.setCompleted(i);
}
- System.out.println(t);
+ logger.debug(t);
assertThat(t.getImage()).isEqualTo(-2L);
}
@@ -141,7 +144,7 @@ public class LongTreeTrackerTest2 {
@Test
public void testBitString() {
LongTreeTracker t = new LongTreeTracker(2L);
- System.out.println(t);
+ logger.debug(t);
}
/**
diff --git a/engine-api/src/test/java/io/nosqlbench/engine/api/templating/CommandTemplateTest.java b/engine-api/src/test/java/io/nosqlbench/engine/api/templating/CommandTemplateTest.java
index 48a4a021d..1041452b9 100644
--- a/engine-api/src/test/java/io/nosqlbench/engine/api/templating/CommandTemplateTest.java
+++ b/engine-api/src/test/java/io/nosqlbench/engine/api/templating/CommandTemplateTest.java
@@ -21,6 +21,8 @@ import com.google.gson.GsonBuilder;
import io.nosqlbench.engine.api.activityconfig.StatementsLoader;
import io.nosqlbench.engine.api.activityconfig.yaml.OpTemplate;
import io.nosqlbench.engine.api.activityconfig.yaml.StmtsDocList;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import java.util.Map;
@@ -28,6 +30,7 @@ import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
public class CommandTemplateTest {
+ private final static Logger logger = LogManager.getLogger(CommandTemplateTest.class);
@Test
public void testCommandTemplate() {
@@ -53,7 +56,7 @@ public class CommandTemplateTest {
OpTemplate optpl = stmtsDocs.getStmts().get(0);
CommandTemplate ct = new CommandTemplate(optpl);
String format = gson.toJson(ct);
- System.out.println(format);
+ logger.debug(format);
}
diff --git a/engine-api/src/test/java/io/nosqlbench/nb/AggregateTests.java b/engine-api/src/test/java/io/nosqlbench/nb/AggregateTests.java
index 9d8df75b1..62956734f 100644
--- a/engine-api/src/test/java/io/nosqlbench/nb/AggregateTests.java
+++ b/engine-api/src/test/java/io/nosqlbench/nb/AggregateTests.java
@@ -18,6 +18,8 @@ package io.nosqlbench.nb;
import org.HdrHistogram.DoubleHistogram;
import org.HdrHistogram.DoubleRecorder;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import java.util.DoubleSummaryStatistics;
@@ -31,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* a proof, so we can get on with testing!
*/
public class AggregateTests {
+ private final static Logger logger = LogManager.getLogger(AggregateTests.class);
double[][] data = new double[][]{
{1, 1, 1, 1, 1, 1, 1, 1, 1, 91},
{15, 15, 15, 15, 15, 5, 5, 5, 5, 5},
@@ -62,8 +65,8 @@ public class AggregateTests {
aggstats.accept(series.getAverage());
}
- System.out.println("aggstats avg:" + aggstats.getAverage());
- System.out.println("allstats avg:" + allstats.getAverage());
+ logger.debug("aggstats avg:" + aggstats.getAverage());
+ logger.debug("allstats avg:" + allstats.getAverage());
assertThat(aggstats.getAverage()).isNotEqualTo(allstats.getAverage());
}
@@ -92,21 +95,21 @@ public class AggregateTests {
all.recordValue(v);
}
snapshots[i]=recorder.getIntervalHistogram();
- System.out.println(snapshot(snapshots[i],"ary[" + i + "]"));
+ logger.debug(snapshot(snapshots[i],"ary[" + i + "]"));
}
DoubleHistogram histoall = all.getIntervalHistogram();
- System.out.println(snapshot(histoall, "all"));
+ logger.debug(snapshot(histoall, "all"));
for (double pctile : new double[]{10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99, 99.9, 99.99}) {
DoubleSummaryStatistics avgOfInputs = new DoubleSummaryStatistics();
for (DoubleHistogram snapshot : snapshots) {
avgOfInputs.accept(snapshot.getValueAtPercentile(pctile));
}
- System.out.println("avg of " + pctile + " => " + String.format("%.3f",avgOfInputs.getAverage()) + " (min,max)=("+String.format("%.3f",avgOfInputs.getMin()) + "," +
+ logger.debug("avg of " + pctile + " => " + String.format("%.3f",avgOfInputs.getAverage()) + " (min,max)=("+String.format("%.3f",avgOfInputs.getMin()) + "," +
String.format("%.3f",avgOfInputs.getMax())+ ")");
- System.out.println("direct " + pctile + " => " + String.format("%.3f",histoall.getValueAtPercentile(pctile)));
- System.out.println();
+ logger.debug("direct " + pctile + " => " + String.format("%.3f",histoall.getValueAtPercentile(pctile)));
+
}
@@ -128,11 +131,10 @@ public class AggregateTests {
prototype[j]=r.nextDouble()*100;
}
- System.out.print("proto[" + i + "] = ");
+ logger.debug("proto[" + i + "] = ");
for (double v : prototype) {
- System.out.print(String.format("% 3.0f ",v));
+ logger.trace(String.format("% 3.0f ",v));
}
- System.out.println();
series[i]=resampleCurve(prototype,100);
}
diff --git a/engine-extensions/src/test/java/io/nosqlbench/optimizers/TestOptimoExperiments.java b/engine-extensions/src/test/java/io/nosqlbench/optimizers/TestOptimoExperiments.java
index 6a21cbd0e..9535297af 100644
--- a/engine-extensions/src/test/java/io/nosqlbench/optimizers/TestOptimoExperiments.java
+++ b/engine-extensions/src/test/java/io/nosqlbench/optimizers/TestOptimoExperiments.java
@@ -21,6 +21,8 @@ import org.apache.commons.math3.optim.*;
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType;
import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction;
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.BOBYQAOptimizer;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
@@ -52,6 +54,7 @@ import java.util.Random;
*/
public class TestOptimoExperiments {
+ private final static Logger logger = LogManager.getLogger(TestOptimoExperiments.class);
@Test
public void testNewAlgo() {
@@ -81,7 +84,7 @@ public class TestOptimoExperiments {
);
PointValuePair result = mo.optimize(od.toArray(new OptimizationData[0]));
- System.out.println(
+ logger.debug(
"point:" + Arrays.toString(result.getPoint()) +
" value=" + m.value(result.getPoint())
);
diff --git a/engine-rest/src/main/java/io/nosqlbench/engine/rest/services/openapi/OpenApiLoader.java b/engine-rest/src/main/java/io/nosqlbench/engine/rest/services/openapi/OpenApiLoader.java
index 2485d3e1f..1bc403b9f 100644
--- a/engine-rest/src/main/java/io/nosqlbench/engine/rest/services/openapi/OpenApiLoader.java
+++ b/engine-rest/src/main/java/io/nosqlbench/engine/rest/services/openapi/OpenApiLoader.java
@@ -27,6 +27,8 @@ import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.introspector.BeanAccess;
@@ -39,6 +41,7 @@ import java.util.stream.Collectors;
* .md#securityRequirementObject">OpenApi Spec 3.1.0
*/
public class OpenApiLoader {
+ private final static Logger logger = LogManager.getLogger(OpenApiLoader.class);
private static final OpenAPIParser parser = new OpenAPIParser();
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
@@ -91,7 +94,7 @@ public class OpenApiLoader {
yaml.setBeanAccess(BeanAccess.DEFAULT);
for (PathOp activeOp : activeOps) {
- System.out.println("yaml for op:" + yaml.dump(activeOp));
+ logger.debug("yaml for op:" + yaml.dump(activeOp));
pathops.put(activeOp.getCall(), activeOp);
}
diff --git a/engine-rest/src/test/java/io/nosqlbench/engine/rest/services/openapi/OpenApiLoaderTest.java b/engine-rest/src/test/java/io/nosqlbench/engine/rest/services/openapi/OpenApiLoaderTest.java
index 1ea5d0ce9..e4a2a30f1 100644
--- a/engine-rest/src/test/java/io/nosqlbench/engine/rest/services/openapi/OpenApiLoaderTest.java
+++ b/engine-rest/src/test/java/io/nosqlbench/engine/rest/services/openapi/OpenApiLoaderTest.java
@@ -16,10 +16,12 @@
package io.nosqlbench.engine.rest.services.openapi;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
public class OpenApiLoaderTest {
-
+ private final static Logger logger = LogManager.getLogger(OpenApiLoaderTest.class);
@Test
public void testYamlGenerator() {
String openidpath = "stargate.yaml";
@@ -28,7 +30,7 @@ public class OpenApiLoaderTest {
"}\n";
String result = OpenApiLoader.generateWorkloadFromFilepath(openidpath, filterJson);
- System.out.println(result);
+ logger.debug(result);
}
diff --git a/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangularStepTest.java b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangularStepTest.java
index 8a8ab8574..8887a53e5 100644
--- a/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangularStepTest.java
+++ b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangularStepTest.java
@@ -34,7 +34,7 @@ public class TriangularStepTest {
public void testStepExample1() {
TriangularStep e1 = new TriangularStep(100, 20);
int[] runLengths = this.rleStatsFor(e1, 0, 10000);
- System.out.println(Arrays.toString(runLengths));
+// System.out.println(Arrays.toString(runLengths));
assertThat(IntStream.of(runLengths).min().orElseThrow()).isEqualTo(80L);
assertThat(IntStream.of(runLengths).max().orElseThrow()).isEqualTo(120L);
}
@@ -43,7 +43,7 @@ public class TriangularStepTest {
public void testStepExample2() {
TriangularStep e1 = new TriangularStep(80, 10);
int[] runLengths = this.rleStatsFor(e1, 0, 10000);
- System.out.println(Arrays.toString(runLengths));
+// System.out.println(Arrays.toString(runLengths));
assertThat(IntStream.of(runLengths).min().orElseThrow()).isEqualTo(70L);
assertThat(IntStream.of(runLengths).max().orElseThrow()).isEqualTo(90L);
}
@@ -101,7 +101,7 @@ public class TriangularStepTest {
}
for (int count : counts) {
- System.out.println(count);
+// System.out.println(count);
histo[count-minval][FREQUENCY]++;
}
return histo;
diff --git a/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/tests/long_long/SignedHashTest.java b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/tests/long_long/SignedHashTest.java
index 3fe902c4f..16b29b2be 100644
--- a/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/tests/long_long/SignedHashTest.java
+++ b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/tests/long_long/SignedHashTest.java
@@ -17,11 +17,14 @@
package io.nosqlbench.virtdata.library.basics.tests.long_long;
import io.nosqlbench.virtdata.library.basics.shared.from_long.to_long.SignedHash;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class SignedHashTest {
+ private final static Logger logger = LogManager.getLogger(SignedHashTest.class);
@Test
public void testFunctionalResult() {
@@ -44,12 +47,13 @@ public class SignedHashTest {
SignedHash hash = new SignedHash();
for (int i = 0; i < 10; i++) {
long l = hash.applyAsLong(i) % 50L;
- System.out.println("i=" + i + " result=" + l);
+ logger.debug("i=" + i + " result=" + l);
+
}
for (int i = 0; i < 10; i++) {
long l = hash.applyAsLong(i+1000000L) % 50L;
- System.out.println("i=" + i + " result=" + l);
+ logger.debug("i=" + i + " result=" + l);
}
}
diff --git a/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/tests/long_string/CombinationsTest.java b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/tests/long_string/CombinationsTest.java
index bffcf56d2..2e0a27a72 100644
--- a/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/tests/long_string/CombinationsTest.java
+++ b/virtdata-lib-basics/src/test/java/io/nosqlbench/virtdata/library/basics/tests/long_string/CombinationsTest.java
@@ -17,12 +17,15 @@
package io.nosqlbench.virtdata.library.basics.tests.long_string;
import io.nosqlbench.virtdata.library.basics.shared.from_long.to_string.Combinations;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
public class CombinationsTest {
+ private final static Logger logger = LogManager.getLogger(CombinationsTest.class);
@Test
public void testSimplePrimes() {
@@ -38,7 +41,7 @@ public class CombinationsTest {
Combinations binaryByte = new Combinations("0-1;0-1;0-1;0-1;0-1;0-1;0-1;0-1;");
assertThat(binaryByte.apply(37)).isEqualTo("00100101");
for (int i = 0; i < 512; i++) {
- System.out.println("i:" + i + " = b:" + binaryByte.apply(i));
+ logger.debug("i:" + i + " = b:" + binaryByte.apply(i));
}
}
diff --git a/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/continuous/RealDistributionsConcurrencyTests.java b/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/continuous/RealDistributionsConcurrencyTests.java
index a34c625cf..591ec73a7 100644
--- a/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/continuous/RealDistributionsConcurrencyTests.java
+++ b/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/continuous/RealDistributionsConcurrencyTests.java
@@ -18,6 +18,8 @@ package io.nosqlbench.virtdata.library.curves4.continuous;
import io.nosqlbench.virtdata.core.bindings.DataMapper;
import io.nosqlbench.virtdata.core.bindings.VirtData;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
@@ -30,6 +32,7 @@ import java.util.concurrent.Future;
import static org.assertj.core.api.Assertions.assertThat;
public class RealDistributionsConcurrencyTests {
+ private final static Logger logger = LogManager.getLogger(RealDistributionsConcurrencyTests.class);
@Test
public void testConcurrentBinomialHashValues() {
@@ -73,8 +76,7 @@ public class RealDistributionsConcurrencyTests {
for (int i = 0; i < futures.size(); i++) {
try {
results.add(futures.get(i).get());
-// System.out.println(description + ": got results for thread " + i);
-// System.out.flush();
+ logger.trace(description + ": got results for thread " + i);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -83,7 +85,7 @@ public class RealDistributionsConcurrencyTests {
for (int vthread = 0; vthread < threads; vthread++) {
assertThat(results.get(vthread)).isEqualTo(values);
- System.out.println(description + ": verified values for thread " + vthread);
+ logger.debug(description + ": verified values for thread " + vthread);
}
@@ -107,8 +109,7 @@ public class RealDistributionsConcurrencyTests {
public double[] call() throws Exception {
double[] output = new double[size];
DataMapper mapper = VirtData.getMapper(mapperSpec, double.class);
-// System.out.println("resolved:" + mapper);
-// System.out.flush();
+ logger.trace("resolved:" + mapper);
synchronized (signal) {
signal.wait(10000);
@@ -116,9 +117,9 @@ public class RealDistributionsConcurrencyTests {
for (int i = 0; i < output.length; i++) {
output[i] = mapper.get(i);
-// if ((i % 100) == 0) {
-// System.out.println("wrote t:" + slot + ", iter:" + i + ", val:" + output[i]);
-// }
+ if ((i % 100) == 0) {
+ logger.trace("wrote t:" + slot + ", iter:" + i + ", val:" + output[i]);
+ }
}
return output;
}
diff --git a/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/continuous/RealDistributionsValuesTest.java b/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/continuous/RealDistributionsValuesTest.java
index c08a20a24..caf879a28 100644
--- a/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/continuous/RealDistributionsValuesTest.java
+++ b/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/continuous/RealDistributionsValuesTest.java
@@ -19,6 +19,8 @@ package io.nosqlbench.virtdata.library.curves4.continuous;
import io.nosqlbench.virtdata.library.curves4.continuous.long_double.Normal;
import io.nosqlbench.virtdata.library.curves4.continuous.long_double.Uniform;
import org.apache.commons.math4.stat.descriptive.DescriptiveStatistics;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Test;
@@ -29,12 +31,13 @@ import java.util.function.LongToDoubleFunction;
import static org.assertj.core.api.Assertions.assertThat;
public class RealDistributionsValuesTest {
+ private final static Logger logger = LogManager.getLogger(RealDistributionsValuesTest.class);
@Test
public void testComputedNormal() {
RunData runData = iterateMapperDouble(new Normal(10.0,2.0,"compute"), 1000000,1);
- System.out.println(runData);
+ logger.debug(runData);
assertThat(runData.getFractionalPercentile(0.5D))
.isCloseTo(10.0D, Offset.offset(0.01D));
assertThat(runData.getFractionalPercentile(0.4D))
@@ -46,7 +49,7 @@ public class RealDistributionsValuesTest {
@Test
public void testInterpolatedNormal() {
RunData runData = iterateMapperDouble(new Normal(10.0,2.0,"interpolate"), 1000000,1);
- System.out.println(runData);
+ logger.debug(runData);
assertThat(runData.getFractionalPercentile(0.5D))
.isCloseTo(10.0D, Offset.offset(0.01D));
assertThat(runData.getFractionalPercentile(0.4D))
@@ -64,7 +67,7 @@ public class RealDistributionsValuesTest {
.isCloseTo(50.0D, Offset.offset(1.0D));
assertThat(runData.getFractionalPercentile(0.78D))
.isCloseTo(78.0D, Offset.offset(1.0D));
- System.out.println(runData);
+ logger.debug(runData);
}
@Test
@@ -76,7 +79,7 @@ public class RealDistributionsValuesTest {
.isCloseTo(50.0D, Offset.offset(1.0D));
assertThat(runData.getFractionalPercentile(0.78D))
.isCloseTo(78.0D, Offset.offset(1.0D));
- System.out.println(runData);
+ logger.debug(runData);
}
@Test
@@ -92,7 +95,7 @@ public class RealDistributionsValuesTest {
assertThat(mapper.applyAsDouble(Long.MAX_VALUE)).isCloseTo(100.0D, Offset.offset(1.0D));
- System.out.println(runData);
+ logger.debug(runData);
}
private RunData iterateMapperDouble(LongToDoubleFunction mapper, int iterations, long funcstep) {
diff --git a/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/discrete/IntegerDistributionsConcurrencyTest.java b/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/discrete/IntegerDistributionsConcurrencyTest.java
index cbe439072..90ec8b7c0 100644
--- a/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/discrete/IntegerDistributionsConcurrencyTest.java
+++ b/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/discrete/IntegerDistributionsConcurrencyTest.java
@@ -19,6 +19,8 @@ package io.nosqlbench.virtdata.library.curves4.discrete;
import io.nosqlbench.virtdata.core.bindings.DataMapper;
import io.nosqlbench.virtdata.core.bindings.VirtData;
import org.apache.commons.statistics.distribution.BinomialDistribution;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Test;
@@ -33,6 +35,7 @@ import java.util.concurrent.Future;
import static org.assertj.core.api.Assertions.assertThat;
public class IntegerDistributionsConcurrencyTest {
+ private final static Logger logger = LogManager.getLogger(IntegerDistributionsConcurrencyTest.class);
@Test
public void testBinomialICDR() {
@@ -109,7 +112,6 @@ public class IntegerDistributionsConcurrencyTest {
try {
results[i] = futures.get(i).get();
System.out.println(description + ": got results for thread " + i);
- System.out.flush();
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -125,15 +127,14 @@ public class IntegerDistributionsConcurrencyTest {
for (int ithread = 0; ithread < threads; ithread++) {
System.out.print(results[ithread][i] + ",");
}
- System.out.println();
}
}
boolean equal = Arrays.equals(results[vthread],values);
if (!equal) {
- System.out.println("not equal!");
+ logger.debug("not equal!");
}
assertThat(results[vthread]).isEqualTo(values);
- System.out.println(description + ": verified values for thread " + vthread);
+ logger.debug(description + ": verified values for thread " + vthread);
}
@@ -157,8 +158,7 @@ public class IntegerDistributionsConcurrencyTest {
public long[] call() throws Exception {
long[] output = new long[size];
DataMapper mapper = VirtData.getMapper(mapperSpec, long.class);
-// System.out.println("resolved:" + mapper);
-// System.out.flush();
+// logger.debug("resolved:" + mapper);
synchronized (signal) {
signal.wait(10000);
@@ -167,7 +167,7 @@ public class IntegerDistributionsConcurrencyTest {
for (int i = 0; i < output.length; i++) {
output[i] = mapper.get(i);
// if ((i % 100) == 0) {
-// System.out.println("wrote t:" + slot + ", iter:" + i + ", val:" + output[i]);
+// logger.debug("wrote t:" + slot + ", iter:" + i + ", val:" + output[i]);
// }
}
return output;
diff --git a/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/discrete/IntegerDistributionsValuesTest.java b/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/discrete/IntegerDistributionsValuesTest.java
index 0ded14829..4c8bc3a6e 100644
--- a/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/discrete/IntegerDistributionsValuesTest.java
+++ b/virtdata-lib-curves4/src/test/java/io/nosqlbench/virtdata/library/curves4/discrete/IntegerDistributionsValuesTest.java
@@ -19,6 +19,8 @@ package io.nosqlbench.virtdata.library.curves4.discrete;
import io.nosqlbench.virtdata.library.curves4.continuous.long_double.Uniform;
import io.nosqlbench.virtdata.library.curves4.discrete.long_long.Zipf;
import org.apache.commons.math4.stat.descriptive.DescriptiveStatistics;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -31,13 +33,14 @@ import java.util.function.LongUnaryOperator;
import static org.assertj.core.api.Assertions.assertThat;
public class IntegerDistributionsValuesTest {
+ private final static Logger logger = LogManager.getLogger(IntegerDistributionsValuesTest.class);
@Disabled
@Test
public void testComputedZipf() {
RunData runData = iterateMapperLong(new Zipf(10000,2.0), 10000);
- System.out.println(runData);
+ logger.debug(runData);
assertThat(runData.getFractionalPercentile(0.6D))
.isCloseTo(1.0D, Offset.offset(0.0001D));
assertThat(runData.getFractionalPercentile(0.7D))
@@ -51,7 +54,7 @@ public class IntegerDistributionsValuesTest {
@Test
public void testInterpolatedZipf() {
RunData runData = iterateMapperLong(new Zipf(10000,2.0), 10000);
- System.out.println(runData);
+ logger.debug(runData);
assertThat(runData.getFractionalPercentile(0.6D))
.isCloseTo(1.0D, Offset.offset(0.0001D));
assertThat(runData.getFractionalPercentile(0.7D))
@@ -72,7 +75,7 @@ public class IntegerDistributionsValuesTest {
.isCloseTo(50.0D, Offset.offset(1.0D));
assertThat(runData.getFractionalPercentile(0.78D))
.isCloseTo(78.0D, Offset.offset(1.0D));
- System.out.println(runData);
+ logger.debug(runData);
}
@Test
@@ -84,7 +87,7 @@ public class IntegerDistributionsValuesTest {
.isCloseTo(50.0D, Offset.offset(1.0D));
assertThat(runData.getFractionalPercentile(0.78D))
.isCloseTo(78.0D, Offset.offset(1.0D));
- System.out.println(runData);
+ logger.debug(runData);
}
@Test
@@ -127,7 +130,7 @@ public class IntegerDistributionsValuesTest {
int readout = iterations/10;
for (int i = 0; i < iterations; i++) {
if ((i%readout)==0) {
- System.out.println("i="+i+"/"+iterations);
+ logger.debug("i="+i+"/"+iterations);
}
samples[i] = mapper.applyAsDouble(i);
}
diff --git a/virtdata-userlibs/src/test/java/io/virtdata/IntegratedComposerLogicTest.java b/virtdata-userlibs/src/test/java/io/virtdata/IntegratedComposerLogicTest.java
index ebdb9bcc9..21aa6384f 100644
--- a/virtdata-userlibs/src/test/java/io/virtdata/IntegratedComposerLogicTest.java
+++ b/virtdata-userlibs/src/test/java/io/virtdata/IntegratedComposerLogicTest.java
@@ -22,6 +22,8 @@ import io.nosqlbench.virtdata.library.basics.shared.from_long.to_long.Identity;
import io.nosqlbench.virtdata.library.basics.shared.from_long.to_string.NumberNameToString;
import io.nosqlbench.virtdata.library.basics.shared.from_long.to_string.Template;
import org.apache.commons.lang3.ClassUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import java.util.Optional;
@@ -33,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
public class IntegratedComposerLogicTest {
+ private final static Logger logger = LogManager.getLogger(IntegratedComposerLogicTest.class);
@Test
public void testPreferredReturnType() {
diff --git a/virtdata-userlibs/src/test/java/io/virtdata/IntegratedCurvesTest.java b/virtdata-userlibs/src/test/java/io/virtdata/IntegratedCurvesTest.java
index 283d734d2..544b39bac 100644
--- a/virtdata-userlibs/src/test/java/io/virtdata/IntegratedCurvesTest.java
+++ b/virtdata-userlibs/src/test/java/io/virtdata/IntegratedCurvesTest.java
@@ -19,6 +19,8 @@ package io.virtdata;
import io.nosqlbench.virtdata.core.bindings.DataMapper;
import io.nosqlbench.virtdata.core.bindings.VirtData;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Test;
@@ -27,15 +29,14 @@ import java.util.Locale;
import static org.assertj.core.api.Assertions.assertThat;
-//import org.apache.commons.math4.stat.descriptive.DescriptiveStatistics;
-
public class IntegratedCurvesTest {
+ private final static Logger logger = LogManager.getLogger(IntegratedComposerLogicTest.class);
@Test
public void testZipf() {
DataMapper mapper = VirtData.getMapper("Zipf(1000,2) -> long", long.class);
RunData runData = iterateMapperLong(mapper, 10000);
- System.out.println(runData);
+ logger.debug(runData);
assertThat(runData.getStats().getPercentile(0.1d)).isCloseTo(1.0, Offset.offset(0.01d));
assertThat(runData.getStats().getPercentile(1.0d)).isCloseTo(1.0, Offset.offset(0.01d));
From 6da3798bb1f6326159ff0566dfce10609ad16797 Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Wed, 21 Dec 2022 01:23:02 -0600
Subject: [PATCH 18/19] Update build.yml
diagnostics
---
.github/workflows/build.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 68ffdd494..c41f09f5f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -91,6 +91,8 @@ jobs:
NBDROID_NAME: ${{ secrets.NBDROID_NAME }}
NBDROID_TOKEN: ${{ secrets.NBDROID_TOKEN }}
run: |
+ set -x
+ find . -ls
rsync -av --delete -I --exclude '_index.md' drivers/ nosqlbench-build-docs/site/content/docs/drivers
rsync -av --delete -I --exclude '_index.md' bindings/ nosqlbench-build-docs/site/content/docs/bindings
echo "previewdocs.nosqlbench.io" > nosqlbench-build-docs/site/staticCNAME
From 301f1e2d279bdc26e14bed33e50c4f2284f3020e Mon Sep 17 00:00:00 2001
From: Jonathan Shook
Date: Wed, 21 Dec 2022 13:36:12 -0600
Subject: [PATCH 19/19] added missing category for TriangularStepFunction
---
.../basics/shared/from_long/to_long/TriangularStep.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangularStep.java b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangularStep.java
index c9bc86a9f..5597354fb 100644
--- a/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangularStep.java
+++ b/virtdata-lib-basics/src/main/java/io/nosqlbench/virtdata/library/basics/shared/from_long/to_long/TriangularStep.java
@@ -16,6 +16,8 @@
package io.nosqlbench.virtdata.library.basics.shared.from_long.to_long;
+import io.nosqlbench.virtdata.api.annotations.Categories;
+import io.nosqlbench.virtdata.api.annotations.Category;
import io.nosqlbench.virtdata.api.annotations.Example;
import io.nosqlbench.virtdata.api.annotations.ThreadSafeMapper;
@@ -38,6 +40,7 @@ import java.util.function.LongUnaryOperator;
* join the project or let us know.
*/
@ThreadSafeMapper
+@Categories({Category.experimental})
public class TriangularStep implements LongUnaryOperator {
private final Hash hasher = new Hash();