Merge pull request #1786 from nosqlbench/jshook/flowfix

Jshook/flowfix
This commit is contained in:
Jonathan Shook
2024-01-18 00:56:25 -06:00
committed by GitHub
21 changed files with 446 additions and 98 deletions

View File

@@ -95,7 +95,7 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
* for scenario encapsulation and concurrent testing.
*
* @param args
* Command Line Args
* Command Line Args
*/
public static void main(final String[] args) {
try {
@@ -158,17 +158,17 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
this.sessionName = SessionNamer.format(globalOptions.getSessionName(), sessionTime).replaceAll("SESSIONCODE", sessionCode);
NBCLI.loggerConfig
.setSessionName(sessionName)
.setConsoleLevel(globalOptions.getConsoleLogLevel())
.setConsolePattern(globalOptions.getConsoleLoggingPattern())
.setLogfileLevel(globalOptions.getScenarioLogLevel())
.setLogfilePattern(globalOptions.getLogfileLoggingPattern())
.setLoggerLevelOverrides(globalOptions.getLogLevelOverrides())
.setMaxLogs(globalOptions.getLogsMax())
.setLogsDirectory(globalOptions.getLogsDirectory())
.setAnsiEnabled(globalOptions.isEnableAnsi())
.setDedicatedVerificationLogger(globalOptions.isDedicatedVerificationLogger())
.activate();
.setSessionName(sessionName)
.setConsoleLevel(globalOptions.getConsoleLogLevel())
.setConsolePattern(globalOptions.getConsoleLoggingPattern())
.setLogfileLevel(globalOptions.getScenarioLogLevel())
.setLogfilePattern(globalOptions.getLogfileLoggingPattern())
.setLoggerLevelOverrides(globalOptions.getLogLevelOverrides())
.setMaxLogs(globalOptions.getLogsMax())
.setLogsDirectory(globalOptions.getLogsDirectory())
.setAnsiEnabled(globalOptions.isEnableAnsi())
.setDedicatedVerificationLogger(globalOptions.isDedicatedVerificationLogger())
.activate();
ConfigurationFactory.setConfigurationFactory(NBCLI.loggerConfig); // THIS should be the first time log4j2 is invoked!
NBCLI.logger = LogManager.getLogger("NBCLI"); // TODO: Detect if the logger config was already initialized (error)
@@ -208,15 +208,15 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
if (annotatorsConfig == null || annotatorsConfig.isBlank()) {
List<Map<String, String>> annotatorsConfigs = new ArrayList<>();
annotatorsConfigs.add(Map.of(
"type", "log",
"level", "info"
"type", "log",
"level", "info"
));
Gson gson = new GsonBuilder().create();
annotatorsConfig = gson.toJson(annotatorsConfigs);
}
final NBCLIOptions options = new NBCLIOptions(args,Mode.ParseAllOptions);
final NBCLIOptions options = new NBCLIOptions(args, Mode.ParseAllOptions);
NBCLI.logger = LogManager.getLogger("NBCLI");
NBIO.addGlobalIncludes(options.wantsIncludes());
@@ -277,18 +277,18 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
NBCLI.logger.debug(() -> "user requests to cat " + resourceToCat);
Optional<Content<?>> tocat = NBIO.classpath()
.searchPrefixes("activities")
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCat).extensionSet(RawOpsLoader.YAML_EXTENSIONS).first();
.searchPrefixes("activities")
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCat).extensionSet(RawOpsLoader.YAML_EXTENSIONS).first();
if (tocat.isEmpty()) tocat = NBIO.classpath()
.searchPrefixes().searchPrefixes(options.wantsIncludes())
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCat).first();
.searchPrefixes().searchPrefixes(options.wantsIncludes())
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCat).first();
final Content<?> data = tocat.orElseThrow(
() -> new BasicError("Unable to find " + resourceToCat +
" in classpath to cat out"));
() -> new BasicError("Unable to find " + resourceToCat +
" in classpath to cat out"));
System.out.println(data.get());
NBCLI.logger.info(() -> "Dumped internal resource '" + data.asPath() + "' to stdout");
@@ -300,19 +300,19 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
NBCLI.logger.debug(() -> "user requests to copy out " + resourceToCopy);
Optional<Content<?>> tocopy = NBIO.classpath()
.searchPrefixes("activities")
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCopy).extensionSet(RawOpsLoader.YAML_EXTENSIONS).first();
.searchPrefixes("activities")
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCopy).extensionSet(RawOpsLoader.YAML_EXTENSIONS).first();
if (tocopy.isEmpty()) tocopy = NBIO.classpath()
.searchPrefixes().searchPrefixes(options.wantsIncludes())
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCopy).first();
.searchPrefixes().searchPrefixes(options.wantsIncludes())
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCopy).first();
final Content<?> data = tocopy.orElseThrow(
() -> new BasicError(
"Unable to find " + resourceToCopy +
" in classpath to copy out")
() -> new BasicError(
"Unable to find " + resourceToCopy +
" in classpath to copy out")
);
final Path writeTo = Path.of(data.asPath().getFileName().toString());
@@ -350,7 +350,7 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
if (options.wantsTopicalHelp()) {
final Optional<String> helpDoc = MarkdownFinder.forHelpTopic(options.wantsTopicalHelpFor());
System.out.println(helpDoc.orElseThrow(
() -> new RuntimeException("No help could be found for " + options.wantsTopicalHelpFor())
() -> new RuntimeException("No help could be found for " + options.wantsTopicalHelpFor())
));
return NBCLI.EXIT_OK;
}
@@ -358,12 +358,12 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
NBCLI.logger.debug("initializing annotators with config:'{}'", annotatorsConfig);
Annotators.init(annotatorsConfig, options.getAnnotateLabelSpec());
Annotators.recordAnnotation(
Annotation.newBuilder()
.element(this)
.now()
.layer(Layer.Session)
.addDetail("cli", String.join("\n", args))
.build()
Annotation.newBuilder()
.element(this)
.now()
.layer(Layer.Session)
.addDetail("cli", String.join("\n", args))
.build()
);
// if ((null != reportPromPushTo) || (null != reportGraphiteTo) || (null != options.wantsReportCsvTo())) {
@@ -402,11 +402,11 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
NBCLI.logger.info(() -> "console logging level is " + options.getConsoleLogLevel());
Map<String, String> props = Map.of(
"summary", options.getReportSummaryTo(),
"logsdir", options.getLogsDirectory().toString(),
"progress", options.getProgressSpec(),
"prompush_cache", "prompush_cache.txt",
"heartbeat", String.valueOf(options.wantsHeartbeatIntervalMs())
"summary", options.getReportSummaryTo(),
"logsdir", options.getLogsDirectory().toString(),
"progress", options.getProgressSpec(),
"prompush_cache", "prompush_cache.txt",
"heartbeat", String.valueOf(options.wantsHeartbeatIntervalMs())
);
/**
* At this point, the command stream from the CLI should be handed into the session, and the session should
@@ -414,15 +414,15 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
*/
try (
NBSession session = new NBSession(
new NBBaseComponent(null,
options.getLabelMap()
.andDefault("jobname", "nosqlbench")
.andDefault("instance", "default")
),
sessionName,
props
)) {
NBSession session = new NBSession(
new NBBaseComponent(null,
options.getLabelMap()
.andDefault("jobname", "nosqlbench")
.andDefault("instance", "default")
),
sessionName,
props
)) {
options.wantsReportCsvTo().ifPresent(cfg -> {
MetricInstanceFilter filter = new MetricInstanceFilter();
@@ -450,6 +450,12 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
ExecutionResult sessionResult = session.apply(options.getCommands());
logger.info(sessionResult);
if (sessionResult.getException() instanceof RuntimeException rte) {
throw rte;
} else if (sessionResult.getException() instanceof Throwable t) {
throw new RuntimeException(t);
}
return sessionResult.getStatus().code;
}
// sessionResult.printSummary(System.out);

View File

@@ -27,14 +27,21 @@ import io.nosqlbench.nb.annotations.Service;
@Service(value= NBInvokableResolver.class,selector = "java")
public class NBJavaNativeResolver implements NBInvokableResolver {
@Override
public NBInvokableCommand resolve(Cmd cmd, NBBufferedContainer parent, String phaseName) {
public NBInvokableCommand resolve(Cmd cmd, NBBufferedContainer parent, String stepname) {
return switch (cmd.getCmdType()) {
case CmdType.indirect -> {
String implName = cmd.takeArgValue("_impl");
yield NBJavaCommandLoader.init(implName, parent, phaseName, cmd.getTargetContext());
String implName = cmd.getArgValue("_impl");
NBInvokableCommand invokable = NBJavaCommandLoader.init(implName, parent, stepname, cmd.getTargetContext());
cmd.takeArgValue("_impl");
yield invokable;
}
case CmdType.java -> NBJavaCommandLoader.init(cmd.getArgValue("class"), parent, phaseName, cmd.getTargetContext());
case CmdType.java -> NBJavaCommandLoader.init(cmd.getArgValue("class"), parent, stepname, cmd.getTargetContext());
default -> null;
};
}
@Override
public boolean verify(Cmd cmd) {
return NBJavaCommandLoader.oneExists(cmd.getArgValue("_impl")) != null;
}
}

View File

@@ -133,8 +133,12 @@ public class Cmd {
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(cmdType.toString());
sb.append(switch (cmdType) {
case indirect -> getArgs().containsKey("_impl") ? getArgs().get("_impl").getValue() : "[]";
default -> cmdType.name();
});
for (CmdArg value : getArgs().values()) {
if (value.getParam().name.startsWith("_impl")) continue;
sb.append(" ").append(value);
}
return sb.toString();

View File

@@ -39,9 +39,9 @@ public class NBJavaCommandLoader {
}
}
public static NBInvokableCommand init(String cmdSelector, NBComponent parent, String cmdAlias, String ctxName) {
public static NBInvokableCommand init(String cmdSelector, NBComponent parent, String stepName, String ctxName) {
NBCommandInfo cmdInfo = getSelector(cmdSelector).getOne();
NBInvokableCommand command = cmdInfo.create(parent, cmdAlias, ctxName);
NBInvokableCommand command = cmdInfo.create(parent, cmdSelector, ctxName);
return command;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2024 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.commands.fortesting;
import io.nosqlbench.engine.core.lifecycle.scenario.container.ContainerActivitiesController;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBBufferedContainer;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBCommandParams;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBBaseCommand;
import java.io.PrintWriter;
import java.io.Reader;
public class CMD_error extends NBBaseCommand {
public CMD_error(NBBufferedContainer parentComponent, String stepName, String targetScenario) {
super(parentComponent, stepName, targetScenario);
}
@Override
public Object invoke(NBCommandParams params, PrintWriter stdout, PrintWriter stderr, Reader stdin, ContainerActivitiesController controller) {
throw new RuntimeException("Command '" + this + "' throws ERROR.");
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 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.commands.fortesting;
import io.nosqlbench.engine.core.lifecycle.scenario.container.ContainerActivitiesController;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBBufferedContainer;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBCommandParams;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBBaseCommand;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
import io.nosqlbench.nb.api.labels.NBLabels;
import java.io.PrintWriter;
import java.io.Reader;
public class CMD_ok extends NBBaseCommand {
public CMD_ok(NBBufferedContainer parentComponent, String stepName, String targetScenario) {
super(parentComponent, stepName, targetScenario);
}
@Override
public Object invoke(NBCommandParams params, PrintWriter stdout, PrintWriter stderr, Reader stdin, ContainerActivitiesController controller) {
stdout.write("Command '" + this.toString() + "' says OK and exits with no object or exception.");
for (String pkey : params.keySet()) {
stdout.println("diagnostic 'ok' command setting key '" + pkey + " to " + params.get(pkey));
}
return params;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 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.commands.fortesting;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandInfo;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
import io.nosqlbench.nb.annotations.Service;
@Service(value = NBCommandInfo.class,selector = "test_error")
public class INFO_error extends NBCommandInfo {
@Override
public Class<? extends NBInvokableCommand> getType() {
return CMD_error.class;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 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.commands.fortesting;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandInfo;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
import io.nosqlbench.nb.annotations.Service;
@Service(value = NBCommandInfo.class,selector = "test_ok")
public class INFO_test_ok extends NBCommandInfo {
@Override
public Class<? extends NBInvokableCommand> getType() {
return CMD_ok.class;
}
}

View File

@@ -40,7 +40,7 @@ public abstract class NBCommandInfo {
cmdCtor = getType().getConstructor(NBBufferedContainer.class, String.class, String.class);
return cmdCtor.newInstance(parent, cmdName, ctxName);
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Unable to instantiate command via ctor(parent,name,ctx): " + e,e);
throw new RuntimeException("Unable to instantiate command via ctor(parent,name,ctx): " + e + (e.getCause()!=null ? "cause: " + e.getCause().toString() : ""),e);
}
}
}

View File

@@ -34,7 +34,7 @@ import java.util.Optional;
@Service(value = NBInvokableResolver.class, selector = "autojs")
public class NBAutoScriptResolver implements NBInvokableResolver {
@Override
public NBInvokableCommand resolve(Cmd cmd, NBBufferedContainer parent, String phaseName) {
public NBInvokableCommand resolve(Cmd cmd, NBBufferedContainer parent, String stepname) {
Optional<Content<?>> scriptfile = NBIO.local()
.searchPrefixes("scripts/auto")
@@ -47,11 +47,21 @@ public class NBAutoScriptResolver implements NBInvokableResolver {
Map<String, CmdArg> newArgs = new LinkedHashMap<>(cmd.getArgs());
newArgs.put("path",new CmdArg(new CmdParam("name",s->s,false),"=",pathOf.toString()));
Cmd reformattedCmd = new Cmd("script", newArgs);
return new NBScriptedCommand(parent, phaseName, cmd.getTargetContext()).add(reformattedCmd);
return new NBScriptedCommand(parent, stepname, cmd.getTargetContext()).add(reformattedCmd);
} else {
return null;
}
}
@Override
public boolean verify(Cmd cmd) {
return NBIO.local()
.searchPrefixes("scripts/auto")
.pathname(cmd.getArgValue("_impl"))
.extensionSet("js")
.first()
.isPresent();
}
}

View File

@@ -29,15 +29,35 @@ import java.util.function.Function;
public class NBCommandAssembly {
private static NBCoreInvokableResolver core_resolver = new NBCoreInvokableResolver();
private final static Logger logger = LogManager.getLogger(NBCommandAssembly.class);
public static NBCommandParams paramsFor(Cmd cmd) {
return switch (cmd.getCmdType()) {
case indirect, java, container -> {
Map<String, String> params = cmd.getArgMap();
params.remove("_impl");
yield NBCommandParams.of(params);
}
default -> NBCommandParams.of(Map.of());
};
}
public static record CommandInvocation(NBInvokableCommand command, NBCommandParams params, String containerName) {
}
public static List<CommandInvocation> assemble(List<Cmd> cmds, Function<String, NBBufferedContainer> ctxprovider) {
public static List<Cmd> assemble(List<Cmd> cmds, Function<String, NBBufferedContainer> ctxprovider) {
List<Cmd> mappedCmds = tagCommandsWithContext(cmds);
List<CommandInvocation> invocations = prepareMappedPhases(mappedCmds, ctxprovider);
return invocations;
NBCoreInvokableResolver core_resolver = new NBCoreInvokableResolver();
for (Cmd mappedCmd : mappedCmds) {
core_resolver.verify(mappedCmd);
}
return mappedCmds;
// List<CommandInvocation> invocations = prepareMappedPhases(mappedCmds, ctxprovider);
// return invocations;
}
private static List<Cmd> tagCommandsWithContext(List<Cmd> cmds) {
@@ -62,6 +82,40 @@ public class NBCommandAssembly {
return new ArrayList<>(tagged);
}
public static NBInvokableCommand resolve(Cmd cmd, Function<String, NBBufferedContainer> ctxProvider) {
try {
NBCommandParams params = switch (cmd.getCmdType()) {
case indirect, java, container -> NBCommandParams.of(cmd.getArgMap());
default -> NBCommandParams.of(Map.of());
};
String targetContext = cmd.getTargetContext();
NBInvokableCommand command = core_resolver.resolve(cmd, ctxProvider.apply(targetContext), cmd.getStepName());
return command;
} catch (Exception e) {
throw new UnresolvedCommand(cmd, e);
}
}
public static CommandInvocation assembleCommand(Cmd cmd, Function<String, NBBufferedContainer> ctxProvider) {
NBCommandParams params = switch (cmd.getCmdType()) {
case indirect, java, container -> NBCommandParams.of(cmd.getArgMap());
default -> NBCommandParams.of(Map.of());
};
String targetContext = cmd.getTargetContext();
NBInvokableCommand command = core_resolver.resolve(cmd, ctxProvider.apply(targetContext), cmd.getStepName());
if (command == null) {
throw new BasicError("Found zero commands for spec;" + cmd);
}
String containerName = cmd.getTargetContext();
// TODO, make this unnecessary by moving the impl out of the map to a dedicated cmd structure
params.remove("_impl");
return new CommandInvocation(command, params, containerName);
}
private static List<CommandInvocation> prepareMappedPhases(List<Cmd> mappedCmds, Function<String, NBBufferedContainer> ctxProvider) {
List<CommandInvocation> parameterizedInvocations = new ArrayList<>();
NBCoreInvokableResolver core_resolver = new NBCoreInvokableResolver();
@@ -73,7 +127,7 @@ public class NBCommandAssembly {
String targetContext = cmd.getTargetContext();
NBInvokableCommand command = core_resolver.resolve(cmd, ctxProvider.apply(targetContext), cmd.getStepName());
if (command==null) {
if (command == null) {
throw new BasicError("Found zero commands for spec;" + cmd);
}
String containerName = cmd.getTargetContext();

View File

@@ -45,6 +45,16 @@ public class NBCoreInvokableResolver implements NBInvokableResolver {
return null;
}
@Override
public boolean verify(Cmd cmd) {
for (NBInvokableResolver resolver : getResolvers().values()) {
if (resolver.verify(cmd)) {
return true;
}
}
return false;
}
private SequencedMap<String, NBInvokableResolver> getResolvers() {
if (this.resolvers == null || this.resolvers.isEmpty()) {
SequencedMap<String,NBInvokableResolver> resolverMap = new LinkedHashMap<>();

View File

@@ -21,6 +21,8 @@ import io.nosqlbench.engine.core.lifecycle.scenario.container.NBBufferedContaine
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
public interface NBInvokableResolver {
NBInvokableCommand resolve(Cmd cmd, NBBufferedContainer parent, String phaseName);
NBInvokableCommand resolve(Cmd cmd, NBBufferedContainer parent, String stepname);
boolean verify(Cmd cmd);
}

View File

@@ -25,10 +25,10 @@ import io.nosqlbench.nb.annotations.Service;
@Service(value = NBInvokableResolver.class, selector = "js")
public class NBScriptCommandResolver implements NBInvokableResolver {
@Override
public NBInvokableCommand resolve(Cmd cmd, NBBufferedContainer parent, String phaseName) {
public NBInvokableCommand resolve(Cmd cmd, NBBufferedContainer parent, String stepname) {
return switch (cmd.getCmdType()) {
case fragment, script->
new NBScriptedCommand(parent, phaseName, cmd.getTargetContext()).add(cmd);
new NBScriptedCommand(parent, stepname, cmd.getTargetContext()).add(cmd);
// case fragment ->
// new NBScriptedCommand(parent, phaseName, cmd.getTargetContext()).addScriptText(cmd.getArgValue("fragment"));
// case script ->
@@ -37,5 +37,8 @@ public class NBScriptCommandResolver implements NBInvokableResolver {
};
}
@Override
public boolean verify(Cmd cmd) {
return true;
}
}

View File

@@ -16,6 +16,7 @@
package io.nosqlbench.engine.core.lifecycle.session;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBCommandParams;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
import io.nosqlbench.nb.api.components.status.NBHeartbeatComponent;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
@@ -82,23 +83,22 @@ public class NBSession extends NBHeartbeatComponent implements Function<List<Cmd
// TODO: add container closing command
// TODO: inject container closing commands after the last command referencing each container
List<NBCommandAssembly.CommandInvocation> invocationCalls = NBCommandAssembly.assemble(cmds, this::getContext);
List<Cmd> assembledCommands = NBCommandAssembly.assemble(cmds, this::getContext);
ResultCollector collector = new ResultCollector();
// TODO: When a command is not successful, automatically break out of the command loop
try (ResultContext results = new ResultContext(collector).ok()) {
for (NBCommandAssembly.CommandInvocation invocation : invocationCalls) {
String targetContext = invocation.containerName();
String explanation = "in context '" + targetContext + "'";
try (NBInvokableCommand command = invocation.command()) {
explanation += " command '" + command.toString() + "'";
NBBufferedContainer container = getContext(targetContext);
NBCommandResult cmdResult = container.apply(command, invocation.params());
for (Cmd cmd : assembledCommands) {
String explanation = " in context " + cmd.getTargetContext() + ", command '" + cmd.toString() + "'";
try (NBInvokableCommand command = NBCommandAssembly.resolve(cmd,this::getContext)) {
NBCommandParams params = NBCommandAssembly.paramsFor(cmd);
NBBufferedContainer container = getContext(cmd.getTargetContext());
NBCommandResult cmdResult = container.apply(command, params);
results.apply(cmdResult);
if (cmdResult.hasException()) {
throw cmdResult.getException();
}
} catch (Exception e) {
String msg = "While running " + explanation + "', an error occurred: " + e.toString();
String msg = "While running " + explanation + ", an error occurred: " + e.toString();
results.error(e);
onError(e);
logger.error(msg);

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 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.session;
import io.nosqlbench.engine.cmdstream.Cmd;
import scala.concurrent.impl.FutureConvertersImpl;
public class UnresolvedCommand extends RuntimeException {
private final Cmd cmd;
public UnresolvedCommand(Cmd cmd, Throwable cause) {
super(cause);
this.cmd = cmd;
}
public String toString() {
final String helpmsg = """
Could not recognize command 'ARG'.
This means that all of the following searches for a compatible command failed:
1. commands: no scenario command named 'ARG' is known. (start, run, await, ...)
2. scripts: no auto script named './scripts/auto/ARG.js' in the local filesystem.
3. scripts: no auto script named 'scripts/auto/ARG.js' was found in the PROG binary.
4. workloads: no workload file named ARG[.yaml] was found in the local filesystem, even in include paths INCLUDES.
5. workloads: no workload file named ARG[.yaml] was bundled in PROG binary, even in include paths INCLUDES.
6. apps: no application named ARG was bundled in PROG.
You can discover available ways to invoke PROG by using the various --list-* commands:
[ --list-commands, --list-scripts, --list-workloads (and --list-scenarios), --list-apps ]
"""
.replaceAll("ARG", getCmdName())
.replaceAll("PROG", "nb5");
return super.toString() + "\nadditional diagnostics:\n" + helpmsg;
}
private String getCmdName() {
String impl = cmd.getArgMap().get("_impl");
if (impl!=null) return impl;
return cmd.toString();
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 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.session;
import io.nosqlbench.engine.cmdstream.Cmd;
import io.nosqlbench.engine.cmdstream.CmdArg;
import io.nosqlbench.nb.api.labels.NBLabeledElement;
import io.nosqlbench.nb.api.labels.NBLabels;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
public class NBSessionTest implements NBLabeledElement {
@Test
public void testThatSessionShortCircuitsCommandErrors() {
NBSession session = new NBSession(this, "session_name", Map.of());
Cmd c1 = new Cmd("test_ok", Map.of("test_ok", CmdArg.of("test_ok","key1","===","value1")));
Cmd c2 = new Cmd("test_error", Map.of());
Cmd c3 = new Cmd("test_ok", Map.of("test_ok", CmdArg.of("test_ok","key2","===","value2")));
List<Cmd> cmdStream = List.of(c1, c2, c3);
session.apply(cmdStream);
}
@Override
public NBLabels getLabels() {
return NBLabels.forKV("testing","session");
}
}

View File

@@ -23,15 +23,16 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* A service loader filter which works with {@link io.nosqlbench.nb.annotations.Service} to load a named service.
* This version requires the caller to provide the service loader instance, since it is now caller sensitive.
*
* <P>A service loader filter which works with {@link io.nosqlbench.nb.annotations.Service} to load a named service.
* This version requires the caller to provide the service loader instance, since it is now caller sensitive.</P>
* <p>
* Use it like this:<pre>{@code
* ResultValueFilterType filterType =
* ServiceSelector.of("core", ServiceLoader.load(ResultValueFilterType.class)).get();
* }</pre>
*
* @param <T> The service type
* @param <T>
* The service type
*/
public class ServiceSelector<T> implements Predicate<ServiceLoader.Provider<? extends T>> {
private final String name;
@@ -61,11 +62,13 @@ public class ServiceSelector<T> implements Predicate<ServiceLoader.Provider<? ex
public ServiceLoader.Provider<? extends T> getOneProvider() {
List<? extends ServiceLoader.Provider<? extends T>> providers = getAllProviders();
if (providers.size()==0 || providers.size()>1) {
throw new RuntimeException("You requested exactly one instance of a service by name '" + name + "', but got " +
(providers.stream().map(s -> s.getClass().getSimpleName())).collect(Collectors.joining(",")) + " (" + providers.stream().count() + ")");
if (providers.size() != 1) {
throw new RuntimeException(
"You requested exactly one instance of a service by name '" + name + "', but got " +
(providers.stream().map(s -> s.getClass().getSimpleName())).collect(Collectors.joining(",")) + " (" + providers.size() + ")"
);
}
return providers.get(0);
return providers.getFirst();
}
public T getOne() {
@@ -73,7 +76,7 @@ public class ServiceSelector<T> implements Predicate<ServiceLoader.Provider<? ex
}
public List<? extends ServiceLoader.Provider<? extends T>> getAllProviders() {
List<? extends ServiceLoader.Provider<? extends T>> providers = loader
return loader
.stream()
.peek(l -> {
if (l.type().getAnnotation(Service.class) == null) {
@@ -87,8 +90,8 @@ public class ServiceSelector<T> implements Predicate<ServiceLoader.Provider<? ex
.filter(l -> l.type().getAnnotation(Service.class) != null)
.filter(l -> l.type().getAnnotation(Service.class).selector().equals(name))
.toList();
return providers;
}
public List<? extends T> getAll() {
List<? extends ServiceLoader.Provider<? extends T>> providers = getAllProviders();
return providers.stream()
@@ -99,7 +102,7 @@ public class ServiceSelector<T> implements Predicate<ServiceLoader.Provider<? ex
public Optional<? extends T> get() {
List<? extends T> services = getAll();
if (services.size() == 1) {
return Optional.of(services.get(0));
return Optional.of(services.getFirst());
} else {
return Optional.empty();
}

View File

@@ -42,7 +42,7 @@ public class ComponentPulse extends UnstartedPeriodicTaskComponent {
LastReport.OnInterrupt
);
this.pulseOf = pulseOf;
String logsdir = getComponentProp("logsdir").orElseThrow();
String logsdir = getComponentProp("logsdir").orElse("logs");
String labelElement = pulseOf.getLabels().valueOf(fileNameLabel);
this.hbpath = Path.of(logsdir).resolve(labelElement +"_status.yaml");
this.linkpath = Path.of(logsdir).resolve("status.yaml");

View File

@@ -20,10 +20,13 @@ import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.labels.NBLabels;
import java.util.Map;
import java.util.Optional;
/**
* A <EM>live</EM> component is one which provides evidence that it is either
* in a healthy state or that it is not, via a heartbeat mechanism.
* A <EM>heartbeat</EM> component is one which provides evidence that it is either
* in a healthy state or that it is not, via a heartbeat mechanism. This requires
* that a component property 'heartbeat' is provides which is the millisecond interval
* between beats.
*/
public class NBHeartbeatComponent extends NBStatusComponent {
@@ -33,8 +36,12 @@ public class NBHeartbeatComponent extends NBStatusComponent {
public NBHeartbeatComponent(NBComponent parentComponent, NBLabels componentSpecificLabelsOnly, Map<String, String> props, String liveLabel) {
super(parentComponent, componentSpecificLabelsOnly, props);
// attaches, no further reference needed
new ComponentPulse(this, NBLabels.forKV(), liveLabel, Long.parseLong(getComponentProp("heartbeat").orElse("60000")));
getComponentProp("heartbeat")
.map(Long::parseLong)
.ifPresent(
// attaches, no further reference needed
hbmillis -> new ComponentPulse(this, NBLabels.forKV(), liveLabel, hbmillis)
);
}
}

View File

@@ -68,7 +68,7 @@ class ExitStatusIntegrationTests {
"driver=diag", "cyclerate=10", "not_a_thing", "cycles=100", "-vvv"
);
String stdout = String.join("\n", result.getStdoutData());
assertThat(stdout).contains("internal error: You requested exactly one instance of a service by name 'not_a_thing'");
assertThat(stdout).contains("You requested exactly one instance of a service by name 'not_a_thing'");
assertThat(result.exitStatus).isEqualTo(2);
}