mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
remainder of changes for scenario rework that need to be itemized
This commit is contained in:
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
@@ -14,8 +14,7 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -30,18 +29,14 @@
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
Runtime artifact for nosqlbench;
|
||||
This module ties the core libraries, provided drivers, and API into a single executable jar
|
||||
The engine API for nosqlbench;
|
||||
Provides the interfaces needed to build internal modules for the
|
||||
nosqlbench core engine
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.nosqlbench</groupId>
|
||||
<artifactId>engine-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- from core -->
|
||||
<dependency>
|
||||
<groupId>io.dropwizard.metrics</groupId>
|
||||
<artifactId>metrics-core</artifactId>
|
||||
@@ -58,21 +53,7 @@
|
||||
<artifactId>metrics-graphite</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- graalvm -->
|
||||
<dependency>
|
||||
<groupId>org.graalvm.js</groupId>
|
||||
<artifactId>js</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.graalvm.js</groupId>
|
||||
<artifactId>js-scriptengine</artifactId>
|
||||
@@ -83,16 +64,118 @@
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- only compile scope -->
|
||||
<!-- ^ from core -->
|
||||
<dependency>
|
||||
<groupId>io.nosqlbench</groupId>
|
||||
<artifactId>nb-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.nosqlbench</groupId>
|
||||
<artifactId>adapters-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.nosqlbench</groupId>
|
||||
<artifactId>nb-spectest</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.nosqlbench</groupId>
|
||||
<artifactId>nb-annotations</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.nosqlbench</groupId>
|
||||
<artifactId>virtdata-userlibs</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.graalvm.js</groupId>
|
||||
<artifactId>js</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>io.dropwizard.metrics</groupId>-->
|
||||
<!--<artifactId>metrics-jmx</artifactId>-->
|
||||
<!--<version>${metrics-version}</version>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
</dependency>
|
||||
<!-- test scope only -->
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>perftests</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<groups>perf</groups>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
<filtering>false</filtering> <!-- exclusion from defaults -->
|
||||
</testResource>
|
||||
<testResource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/test/resources</directory>
|
||||
<includes>
|
||||
<include>log4j2-test.xml</include>
|
||||
</includes>
|
||||
</testResource>
|
||||
</testResources>
|
||||
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenarios;
|
||||
|
||||
import io.nosqlbench.nb.api.errors.BasicError;
|
||||
|
||||
final class SCNamedParam {
|
||||
private final String name;
|
||||
private final String operator;
|
||||
private final String value;
|
||||
private String scenarioName;
|
||||
|
||||
public SCNamedParam(String name, String operator, String value) {
|
||||
this.name = name;
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean isReassignable() {
|
||||
return NBCLIScenarioPreprocessor.UNLOCKED.equals(operator);
|
||||
}
|
||||
|
||||
public boolean isFinalSilent() {
|
||||
return NBCLIScenarioPreprocessor.SILENT_LOCKED.equals(operator);
|
||||
}
|
||||
|
||||
public boolean isFinalVerbose() {
|
||||
return NBCLIScenarioPreprocessor.VERBOSE_LOCKED.equals(operator);
|
||||
}
|
||||
|
||||
|
||||
public SCNamedParam override(String value) {
|
||||
if (isReassignable()) {
|
||||
return new SCNamedParam(this.name, this.operator, value);
|
||||
} else if (isFinalSilent()) {
|
||||
return this;
|
||||
} else if (isFinalVerbose()) {
|
||||
throw new BasicError("Unable to reassign value for locked param '" + name + operator + value + "'");
|
||||
} else {
|
||||
throw new RuntimeException("impossible!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + (operator != null ? "=" : "") + (value != null ? value : "");
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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.cli;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Encapsulate Command parsing and structure for the NoSQLBench command line. Commands always have a name, sometimes
|
||||
* have a list of positional arguments, and sometimes have a map of named parameters. An example of a command tha thas
|
||||
* both would look like {@code script test.js p1=v1}
|
||||
*/
|
||||
public class Cmd {
|
||||
|
||||
private final static Logger logger = LogManager.getLogger(Cmd.class);
|
||||
|
||||
public enum CmdType {
|
||||
run(),
|
||||
start(),
|
||||
stop(Arg.of("alias_name")),
|
||||
forceStop(Arg.of("alias_name")),
|
||||
script(Arg.of("script_path", s -> s)),
|
||||
java(Arg.of("main_class",s->s)),
|
||||
await(Arg.of("alias_name")),
|
||||
waitMillis(Arg.of("millis_to_wait", Long::parseLong)),
|
||||
fragment(Arg.ofFreeform("script_fragment")),;
|
||||
|
||||
private final Arg<?>[] positional;
|
||||
|
||||
CmdType(Arg<?>... positional) {
|
||||
this.positional = positional;
|
||||
}
|
||||
|
||||
public String[] getPositionalArgNames() {
|
||||
String[] names = new String[positional.length];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
names[i] = positional[i].name;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public static CmdType valueOfAnyCase(String cmdname) {
|
||||
for (CmdType value : values()) {
|
||||
if (cmdname.equals(value.toString()) || cmdname.equalsIgnoreCase(value.toString())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return valueOf(cmdname); // let the normal exception take over in this case
|
||||
}
|
||||
|
||||
public Arg<?>[] getPositionalArgs() {
|
||||
return positional;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Arg<T> {
|
||||
public final String name;
|
||||
public final Function<String, T> converter;
|
||||
public final boolean freeform;
|
||||
|
||||
public Arg(String name, Function<String, T> converter, boolean freeform) {
|
||||
this.name = name;
|
||||
this.converter = converter;
|
||||
this.freeform = freeform;
|
||||
}
|
||||
|
||||
public static <T> Arg<T> of(String name, Function<String, T> converter) {
|
||||
return new Arg<>(name, converter, false);
|
||||
}
|
||||
|
||||
public static Arg<String> of(String name) {
|
||||
return new Arg<>(name, s -> s, false);
|
||||
}
|
||||
|
||||
public static Arg<String> ofFreeform(String name) {
|
||||
return new Arg<>(name, s -> s, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Map<String, String> cmdArgs;
|
||||
|
||||
public String getArg(String paramName) {
|
||||
return this.cmdArgs.get(paramName);
|
||||
}
|
||||
|
||||
private final CmdType cmdType;
|
||||
|
||||
public Cmd(CmdType cmdType, Map<String, String> cmdArgs) {
|
||||
this.cmdArgs = cmdArgs;
|
||||
this.cmdType = cmdType;
|
||||
}
|
||||
|
||||
public CmdType getCmdType() {
|
||||
return cmdType;
|
||||
}
|
||||
|
||||
public Map<String, String> getParams() {
|
||||
return cmdArgs;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(cmdType.toString());
|
||||
sb.append("(");
|
||||
if (getParams().size() > cmdType.positional.length) {
|
||||
sb.append(toJSONBlock(getParams(), false));
|
||||
} else {
|
||||
for (String value : getParams().values()) {
|
||||
String trimmed = ((value.startsWith("'") && value.endsWith("'"))
|
||||
|| (value.startsWith("\"")) && value.endsWith("\"")) ?
|
||||
value.substring(1, value.length() - 1) : value;
|
||||
sb.append("'").append(trimmed).append("'").append(",");
|
||||
}
|
||||
sb.setLength(sb.length() - 1);
|
||||
}
|
||||
sb.append(");");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static Cmd parseArg(LinkedList<String> arglist, PathCanonicalizer fixer) {
|
||||
|
||||
String cmdName = arglist.removeFirst();
|
||||
CmdType cmdType = CmdType.valueOfAnyCase(cmdName);
|
||||
|
||||
Map<String, String> params = new LinkedHashMap<>();
|
||||
|
||||
for (Arg<?> arg : cmdType.getPositionalArgs()) {
|
||||
|
||||
String nextarg = arglist.peekFirst();
|
||||
|
||||
if (nextarg == null) {
|
||||
throw new InvalidParameterException(
|
||||
"command '" + cmdName + " requires a value for " + arg.name
|
||||
+ ", but there were no remaining arguments after it.");
|
||||
} else if (arg.freeform) {
|
||||
logger.debug(() -> "freeform parameter:" + nextarg);
|
||||
} else if (nextarg.contains("=")) {
|
||||
throw new InvalidParameterException(
|
||||
"command '" + cmdName + "' requires a value for " + arg.name +
|
||||
", but a named parameter was found instead: " + nextarg);
|
||||
} else if (SessionCommandParser.RESERVED_WORDS.contains(nextarg)) {
|
||||
throw new InvalidParameterException(
|
||||
"command '" + cmdName + "' requires a value for " + arg.name
|
||||
+ ", but a reserved word was found instead: " + nextarg);
|
||||
}
|
||||
|
||||
logger.debug(() -> "cmd name:" + cmdName + ", positional " + arg.name + ": " + nextarg);
|
||||
params.put(arg.name, arg.converter.apply(arglist.removeFirst()).toString());
|
||||
}
|
||||
|
||||
while (arglist.size() > 0 &&
|
||||
!SessionCommandParser.RESERVED_WORDS.contains(arglist.peekFirst())
|
||||
&& arglist.peekFirst().contains("=")) {
|
||||
String arg = arglist.removeFirst();
|
||||
String[] assigned = arg.split("=", 2);
|
||||
String pname = assigned[0];
|
||||
String pval = assigned[1];
|
||||
|
||||
|
||||
if (pname.equals("yaml") || pname.equals("workload")) {
|
||||
pval = fixer.canonicalizePath(pval);
|
||||
}
|
||||
if (params.containsKey(pname)) {
|
||||
throw new InvalidParameterException("parameter '" + pname + "' is already set for '" + cmdType +"' command. For each command," +
|
||||
" a named parameter may only be set once. Multiple occurrences are disallowed to avoid errors or ambiguity.");
|
||||
}
|
||||
params.put(pname, pval);
|
||||
}
|
||||
|
||||
return new Cmd(cmdType, params);
|
||||
}
|
||||
|
||||
public static String toJSONBlock(Map<String, String> map, boolean oneline) {
|
||||
|
||||
int klen = map.keySet().stream().mapToInt(String::length).max().orElse(1);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
List<String> l = new ArrayList<>();
|
||||
for (Map.Entry<String, String> entries : map.entrySet()) {
|
||||
String key = entries.getKey();
|
||||
String value = sanitizeQuotes(entries.getValue());
|
||||
if (oneline) {
|
||||
l.add("'" + key + "':'" + value + "'");
|
||||
} else {
|
||||
l.add(" '" + key + "': " + " ".repeat(klen - key.length()) + "'" + value + "'");
|
||||
}
|
||||
}
|
||||
return "{" + (oneline ? "" : "\n") + String.join(",\n", l) + (oneline ? "}" : "\n}");
|
||||
}
|
||||
|
||||
private static String sanitizeQuotes(String value) {
|
||||
if (value.startsWith("'") && value.endsWith("'")) {
|
||||
return value.substring(1, value.length() - 1);
|
||||
}
|
||||
if (value.startsWith("\"") && value.endsWith("\"")) {
|
||||
return value.substring(1, value.length() - 1);
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
public static String toJSONParams(String varname, Map<String, String> map, boolean oneline) {
|
||||
return "// params.size==" + map.size() + "\n" + varname + "=" + toJSONBlock(map, oneline);
|
||||
}
|
||||
|
||||
public static List<Cmd> parseCmds (String...arglist){
|
||||
LinkedList<String> ll = new LinkedList<>(Arrays.asList(arglist));
|
||||
List<Cmd> cmds = new ArrayList<>();
|
||||
while (!ll.isEmpty()) {
|
||||
Cmd cmd = parseArg(ll, null);
|
||||
cmds.add(cmd);
|
||||
}
|
||||
return cmds;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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.cli;
|
||||
|
||||
import io.nosqlbench.api.content.Content;
|
||||
import io.nosqlbench.api.content.NBIO;
|
||||
import io.nosqlbench.engine.api.scenarios.NBCLIScenarioParser;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This parser will return a non-empty optional if there is no error.
|
||||
* If the optional is empty, then it means some part of the command structure
|
||||
* was not recognized.
|
||||
*/
|
||||
public class SessionCommandParser {
|
||||
// private final static Logger logger = LogManager.getLogger(SessionCommandParser.class);
|
||||
|
||||
private static final String FRAGMENT = "fragment";
|
||||
private static final String SCRIPT = "script";
|
||||
private static final String START = "start";
|
||||
private static final String RUN = "run";
|
||||
private static final String AWAIT = "await";
|
||||
private static final String STOP = "stop";
|
||||
private static final String FORCE_STOP = "forceStop";
|
||||
private static final String ACTIVITY = "activity";
|
||||
private static final String SCENARIO = "scenario";
|
||||
private static final String WAIT_MILLIS = "waitmillis";
|
||||
|
||||
private static final String JAVA_MAIN = "java";
|
||||
|
||||
public static final Set<String> RESERVED_WORDS = new HashSet<>() {{
|
||||
addAll(
|
||||
Arrays.asList(
|
||||
FRAGMENT, SCRIPT, START, RUN, AWAIT, STOP, FORCE_STOP, ACTIVITY, SCENARIO, WAIT_MILLIS
|
||||
)
|
||||
);
|
||||
}};
|
||||
|
||||
public static Optional<List<Cmd>> parse(
|
||||
LinkedList<String> arglist,
|
||||
String... includes
|
||||
) {
|
||||
boolean scriptCommands = false;
|
||||
boolean javaCommands = false;
|
||||
List<Cmd> cmdList = new LinkedList<>();
|
||||
PathCanonicalizer canonicalizer = new PathCanonicalizer(includes);
|
||||
while (arglist.peekFirst() != null) {
|
||||
String word = arglist.peekFirst();
|
||||
Cmd cmd;
|
||||
switch (word) {
|
||||
case JAVA_MAIN:
|
||||
cmd = Cmd.parseArg(arglist, canonicalizer);
|
||||
cmdList.add(cmd);
|
||||
javaCommands = true;
|
||||
break;
|
||||
case FRAGMENT:
|
||||
case SCRIPT:
|
||||
case START:
|
||||
case RUN:
|
||||
case AWAIT:
|
||||
case STOP:
|
||||
case FORCE_STOP:
|
||||
case WAIT_MILLIS:
|
||||
cmd = Cmd.parseArg(arglist, canonicalizer);
|
||||
cmdList.add(cmd);
|
||||
scriptCommands = true;
|
||||
break;
|
||||
default:
|
||||
Optional<Content<?>> scriptfile = NBIO.local()
|
||||
.searchPrefixes("scripts/auto")
|
||||
.pathname(word)
|
||||
.extensionSet("js")
|
||||
.first();
|
||||
|
||||
//Script
|
||||
if (scriptfile.isPresent()) {
|
||||
arglist.removeFirst();
|
||||
arglist.addFirst("scripts/auto/" + word);
|
||||
arglist.addFirst("script");
|
||||
cmd = Cmd.parseArg(arglist, canonicalizer);
|
||||
cmdList.add(cmd);
|
||||
} else if (NBCLIScenarioParser.isFoundWorkload(word, includes)) {
|
||||
NBCLIScenarioParser.parseScenarioCommand(arglist, RESERVED_WORDS, includes);
|
||||
} else {
|
||||
System.out.println("unrecognized Cmd: " + word); // instead of using logger due to init precedence
|
||||
return Optional.empty();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (javaCommands && scriptCommands) {
|
||||
throw new RuntimeException("combining java and javascript commands into one session is not yet supported.");
|
||||
}
|
||||
}
|
||||
return Optional.of(cmdList);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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.cmdstream;
|
||||
|
||||
import io.nosqlbench.engine.core.lifecycle.session.CmdParser;
|
||||
import io.nosqlbench.nb.api.errors.BasicError;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Encapsulate Command parsing and structure for the NoSQLBench command line. Commands always have a name, sometimes
|
||||
* have a list of positional arguments, and sometimes have a map of named parameters. An example of a command tha thas
|
||||
* both would look like {@code script test.js p1=v1}
|
||||
*/
|
||||
public class Cmd {
|
||||
|
||||
private final static Logger logger = LogManager.getLogger(Cmd.class);
|
||||
public static final String DEFAULT_TARGET_CONTEXT = "default";
|
||||
private final String targetContextName;
|
||||
|
||||
private final Map<String, CmdArg> cmdArgs;
|
||||
private final String stepName;
|
||||
|
||||
|
||||
public String getTargetContext() {
|
||||
return targetContextName;
|
||||
}
|
||||
|
||||
public Cmd forTargetContext(String contextName, String stepName) {
|
||||
return new Cmd(cmdType, cmdArgs, contextName, stepName);
|
||||
}
|
||||
|
||||
|
||||
public String getArgValueOrNull(String paramName) {
|
||||
CmdArg cmdArg = this.cmdArgs.get(paramName);
|
||||
if (cmdArg==null) {
|
||||
return null;
|
||||
}
|
||||
return cmdArg.getValue();
|
||||
|
||||
}
|
||||
public String getArgValue(String paramName) {
|
||||
CmdArg cmdArg = this.cmdArgs.get(paramName);
|
||||
if (cmdArg==null) {
|
||||
throw new BasicError("Could not get param value for undefined arg '" + paramName + "'");
|
||||
}
|
||||
return cmdArg.getValue();
|
||||
}
|
||||
|
||||
private final CmdType cmdType;
|
||||
|
||||
// public Cmd(@NotNull CmdType cmdType, Map<String, CmdArg> cmdArgs, String targetContextName, String stepName) {
|
||||
// this.cmdArgs = cmdArgs;
|
||||
// this.cmdType = cmdType;
|
||||
// this.targetContextName = targetContextName;
|
||||
// }
|
||||
|
||||
// public Cmd(String indirect, Map<String,String> args) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public Cmd(String cmdType, CmdArg... args) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
public Cmd(@NotNull String cmdTypeOrName, Map<String, CmdArg> argmap) {
|
||||
this.cmdType = CmdType.valueOfAnyCaseOrIndirect(cmdTypeOrName);
|
||||
this.targetContextName = DEFAULT_TARGET_CONTEXT;
|
||||
this.stepName = "";
|
||||
this.cmdArgs = new LinkedHashMap<>();
|
||||
if (this.cmdType == CmdType.indirect) {
|
||||
this.cmdArgs.put("_impl", new CmdArg(new CmdParam("_impl", s->s, false),"===",cmdTypeOrName));
|
||||
}
|
||||
cmdArgs.putAll(argmap);
|
||||
// if (!basket.isEmpty()) {
|
||||
// throw new BasicError("extraneous arguments provided for " + this + ": " + basket);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
public Cmd(@NotNull CmdType cmdType, Map<String, CmdArg> cmdArgMap) {
|
||||
this.cmdType = cmdType;
|
||||
this.stepName="NO-STEP";
|
||||
this.targetContextName = DEFAULT_TARGET_CONTEXT;
|
||||
this.cmdArgs = new LinkedHashMap<>();
|
||||
if (cmdType == CmdType.indirect && !cmdArgMap.containsKey("_impl")) {
|
||||
throw new RuntimeException("indirect cmd type is invalid without a '_impl' parameter.");
|
||||
}
|
||||
cmdArgs.putAll(cmdArgMap);
|
||||
}
|
||||
|
||||
public Cmd(@NotNull CmdType cmdType, Map<String, CmdArg> cmdArgMap, String targetContext, String stepName) {
|
||||
this.cmdType = cmdType;
|
||||
this.stepName=stepName;
|
||||
this.targetContextName = targetContext;
|
||||
this.cmdArgs = new LinkedHashMap<>();
|
||||
if (cmdType == CmdType.indirect && !cmdArgMap.containsKey("_impl")) {
|
||||
throw new RuntimeException("indirect cmd type is invalid without a '_impl' parameter.");
|
||||
}
|
||||
this.cmdArgs.putAll(cmdArgMap);
|
||||
}
|
||||
|
||||
public CmdType getCmdType() {
|
||||
return cmdType;
|
||||
}
|
||||
|
||||
// TODO: Since this replaced an implicit String, the types need to be disambiguated
|
||||
public Map<String, CmdArg> getArgs() {
|
||||
return cmdArgs;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(cmdType.toString());
|
||||
for (CmdArg value : getArgs().values()) {
|
||||
sb.append(" ").append(value);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String asScriptText() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getCmdType().toString());
|
||||
sb.append("(");
|
||||
if (this.cmdArgs.size() > getCmdType().getPositionalArgs().length) {
|
||||
sb.append(toJSONBlock(getArgMap(), false));
|
||||
} else {
|
||||
for (String value : getArgMap().values()) {
|
||||
String trimmed = ((value.startsWith("'") && value.endsWith("'"))
|
||||
|| (value.startsWith("\"")) && value.endsWith("\"")) ?
|
||||
value.substring(1, value.length() - 1) : value;
|
||||
sb.append("'").append(trimmed).append("'").append(",");
|
||||
}
|
||||
sb.setLength(sb.length() - 1);
|
||||
}
|
||||
sb.append(");");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
// public static Cmd parseArg(LinkedList<String> arglist, PathCanonicalizer fixer) {
|
||||
//
|
||||
// String cmdName = arglist.removeFirst();
|
||||
// CmdType cmdType = CmdType.valueOfAnyCaseOrIndirect(cmdName);
|
||||
//
|
||||
// Map<String, String> params = new LinkedHashMap<>();
|
||||
//
|
||||
// for (CmdParam<?> cmdParam : cmdType.getPositionalArgs()) {
|
||||
//
|
||||
// String nextarg = arglist.peekFirst();
|
||||
//
|
||||
// if (nextarg == null) {
|
||||
// throw new InvalidParameterException(
|
||||
// "command '" + cmdName + " requires a value for " + cmdParam.name
|
||||
// + ", but there were no remaining arguments after it.");
|
||||
// } else if (cmdParam.freeform) {
|
||||
// logger.debug(() -> "freeform parameter:" + nextarg);
|
||||
// } else if (nextarg.contains("=")) {
|
||||
// throw new InvalidParameterException(
|
||||
// "command '" + cmdName + "' requires a value for " + cmdParam.name +
|
||||
// ", but a named parameter was found instead: " + nextarg);
|
||||
// } else if (CmdType.anyMatches(nextarg)) {
|
||||
// throw new InvalidParameterException(
|
||||
// "command '" + cmdName + "' requires a value for " + cmdParam.name
|
||||
// + ", but a reserved word was found instead: " + nextarg);
|
||||
// }
|
||||
//
|
||||
// logger.debug(() -> "cmd name:" + cmdName + ", positional " + cmdParam.name + ": " + nextarg);
|
||||
// params.put(cmdParam.name, cmdParam.converter.apply(arglist.removeFirst()).toString());
|
||||
// }
|
||||
//
|
||||
// while (arglist.size() > 0 &&
|
||||
// !CmdType.anyMatches(arglist.peekFirst())
|
||||
// && arglist.peekFirst().contains("=")) {
|
||||
// String arg = arglist.removeFirst();
|
||||
// String[] assigned = arg.split("=", 2);
|
||||
// String pname = assigned[0];
|
||||
// String pval = assigned[1];
|
||||
//
|
||||
//
|
||||
// if (pname.equals("yaml") || pname.equals("workload")) {
|
||||
// pval = fixer.canonicalizePath(pval);
|
||||
// }
|
||||
// if (params.containsKey(pname)) {
|
||||
// throw new InvalidParameterException("parameter '" + pname + "' is already set for '" + cmdType + "' command. For each command," +
|
||||
// " a named parameter may only be set once. Multiple occurrences are disallowed to avoid errors or ambiguity.");
|
||||
// }
|
||||
// params.put(pname, pval);
|
||||
// }
|
||||
//
|
||||
// return new Cmd(cmdType, params);
|
||||
// }
|
||||
|
||||
public static String toJSONBlock(Map<String, String> map, boolean oneline) {
|
||||
|
||||
int klen = map.keySet().stream().mapToInt(String::length).max().orElse(1);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
List<String> l = new ArrayList<>();
|
||||
for (Map.Entry<String, String> entries : map.entrySet()) {
|
||||
String key = entries.getKey();
|
||||
String value = removeQuotes(entries.getValue());
|
||||
if (oneline) {
|
||||
l.add("'" + key + "':'" + value + "'");
|
||||
} else {
|
||||
l.add(" '" + key + "': " + " ".repeat(klen - key.length()) + "'" + value + "'");
|
||||
}
|
||||
}
|
||||
return "{" + (oneline ? "" : "\n") + String.join(",\n", l) + (oneline ? "}" : "\n}");
|
||||
}
|
||||
|
||||
private static String removeQuotes(String value) {
|
||||
if (value.startsWith("'") && value.endsWith("'")) {
|
||||
return value.substring(1, value.length() - 1);
|
||||
}
|
||||
if (value.startsWith("\"") && value.endsWith("\"")) {
|
||||
return value.substring(1, value.length() - 1);
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
public static String toJSONParams(String varname, Map<String, String> map, boolean oneline) {
|
||||
return "// params.size==" + map.size() + "\n" + varname + "=" + toJSONBlock(map, oneline);
|
||||
}
|
||||
|
||||
public Map<String, String> getArgMap() {
|
||||
LinkedHashMap<String, String> argmap = new LinkedHashMap<>();
|
||||
this.cmdArgs.forEach((k,v) -> {
|
||||
argmap.put(k,v.getValue());
|
||||
});
|
||||
return argmap;
|
||||
}
|
||||
|
||||
// public static List<Cmd> parseCmds(String... arglist) {
|
||||
// LinkedList<String> ll = new LinkedList<>(Arrays.asList(arglist));
|
||||
// List<Cmd> cmds = new ArrayList<>();
|
||||
// while (!ll.isEmpty()) {
|
||||
// Cmd cmd = parseArg(ll, null);
|
||||
// cmds.add(cmd);
|
||||
// }
|
||||
// return cmds;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.cmdstream;
|
||||
|
||||
import io.nosqlbench.engine.api.scenarios.NBCLIScenarioPreprocessor;
|
||||
import io.nosqlbench.engine.core.lifecycle.session.CmdParser;
|
||||
import io.nosqlbench.nb.api.errors.BasicError;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* An argument to a command is based on a defined parameter. You can not assign a typed argument value to a
|
||||
* command without first resolving the specific parameter.
|
||||
*/
|
||||
public class CmdArg {
|
||||
CmdParam param;
|
||||
private final String operator;
|
||||
private final String value;
|
||||
|
||||
private final static Set<String> OPERATORS = Set.of("=","==","===");
|
||||
public CmdArg(CmdParam param, String operator, String value) {
|
||||
if (!OPERATORS.contains(operator)) {
|
||||
throw new BasicError("You can't use the assignment operator '" + operator + "' with arguments to commands.");
|
||||
}
|
||||
this.param = param;
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static CmdArg of(String cmdName, String varname, String equals, String value) {
|
||||
CmdType type = CmdType.valueOfAnyCaseOrIndirect(cmdName);
|
||||
if (type==CmdType.indirect) {
|
||||
return new CmdArg(new CmdParam<String>(varname, s->s, false),equals,value);
|
||||
} else {
|
||||
return type.getNamedParam(varname).assign(equals,value);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isReassignable() {
|
||||
return NBCLIScenarioPreprocessor.UNLOCKED.equals(operator);
|
||||
}
|
||||
|
||||
public boolean isFinalSilent() {
|
||||
return NBCLIScenarioPreprocessor.SILENT_LOCKED.equals(operator);
|
||||
}
|
||||
|
||||
public boolean isFinalVerbose() {
|
||||
return NBCLIScenarioPreprocessor.VERBOSE_LOCKED.equals(operator);
|
||||
}
|
||||
|
||||
|
||||
public CmdArg override(String value) {
|
||||
if (isReassignable()) {
|
||||
return new CmdArg(this.param, this.operator, value);
|
||||
} else if (isFinalSilent()) {
|
||||
return this;
|
||||
} else if (isFinalVerbose()) {
|
||||
throw new BasicError("Unable to reassign value for locked param '" + param + operator + value + "'");
|
||||
} else {
|
||||
throw new RuntimeException("impossible!");
|
||||
}
|
||||
}
|
||||
|
||||
public CmdParam getParam() {
|
||||
return param;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getQuotedValue() {
|
||||
String quoted=value;
|
||||
for (char c :quoted.toCharArray()){
|
||||
if (CmdParser.SYMBOLS.indexOf(c)>=0) {
|
||||
quoted = "'" + quoted +"'";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return quoted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getParam().getName() + this.operator + getQuotedValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.cmdstream;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A CmdParam is used to define the valid names of arguments and their types.
|
||||
* These can be strictly type checked, or in some cases freeform where strings are
|
||||
* are used contextually.
|
||||
* @param <T> The base type of the argument when paired with this CmdParam
|
||||
*/
|
||||
public class CmdParam<T> {
|
||||
public final String name;
|
||||
public final Function<String, T> converter;
|
||||
public final boolean freeform;
|
||||
|
||||
public CmdParam(String name, Function<String, T> converter, boolean freeform) {
|
||||
this.name = name;
|
||||
this.converter = converter;
|
||||
this.freeform = freeform;
|
||||
}
|
||||
|
||||
public static <T> CmdParam<T> of(String name, Function<String, T> converter) {
|
||||
return new CmdParam<>(name, converter, false);
|
||||
}
|
||||
|
||||
public static CmdParam<String> of(String name) {
|
||||
return new CmdParam<>(name, s -> s, false);
|
||||
}
|
||||
|
||||
public static CmdParam<String> ofFreeform(String name) {
|
||||
return new CmdParam<>(name, s -> s, true);
|
||||
}
|
||||
|
||||
public CmdArg assign(String equals, String value) {
|
||||
return new CmdArg(this,equals, value);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.cmdstream;
|
||||
|
||||
/**
|
||||
* Command verbs define the names and possible parameters for valid commands.
|
||||
* One special type known as 'indirect' encodes verbs which are not directly mapped to specific
|
||||
* command implementations. This type is resolved based on the available commands in the runtime,
|
||||
* or an error is thrown.
|
||||
*/
|
||||
public enum CmdType {
|
||||
run(),
|
||||
start(),
|
||||
stop(CmdParam.of("activity")),
|
||||
forceStop(CmdParam.of("activity")),
|
||||
script(CmdParam.of("path", s -> s)),
|
||||
java(CmdParam.of("class", s -> s)),
|
||||
await(CmdParam.of("activity")),
|
||||
waitMillis(CmdParam.of("ms", Long::parseLong)),
|
||||
fragment(CmdParam.ofFreeform("fragment")),
|
||||
context(CmdParam.of("name")),
|
||||
indirect(CmdParam.of("indirect"));
|
||||
|
||||
private final CmdParam<?>[] positional;
|
||||
|
||||
CmdType(CmdParam<?>... positional) {
|
||||
this.positional = positional;
|
||||
}
|
||||
|
||||
public static boolean anyMatches(String s) {
|
||||
CmdType found = valueOfAnyCaseOrIndirect(s);
|
||||
return found != null;
|
||||
}
|
||||
|
||||
public String[] getPositionalArgNames() {
|
||||
String[] names = new String[positional.length];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
names[i] = positional[i].name;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public static CmdType valueOfAnyCaseOrIndirect(String cmdname) {
|
||||
for (CmdType value : values()) {
|
||||
if (cmdname.equals(value.toString()) || cmdname.equalsIgnoreCase(value.toString())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return indirect;
|
||||
}
|
||||
|
||||
public CmdParam<?>[] getPositionalArgs() {
|
||||
return positional;
|
||||
}
|
||||
|
||||
public CmdParam<?> getNamedParam(String varname) {
|
||||
for (CmdParam<?> cmdParam : positional) {
|
||||
if (cmdParam.name.equals(varname)) {
|
||||
return cmdParam;
|
||||
}
|
||||
}
|
||||
return new CmdParam<Object>(varname,s -> s, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.cmdstream;
|
||||
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandInfo;
|
||||
import io.nosqlbench.nb.annotations.ServiceSelector;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
public class NBJavaCommandLoader {
|
||||
public static Class<? extends NBInvokableCommand> oneExists(String cmdName) {
|
||||
ServiceLoader<NBCommandInfo> loader = ServiceLoader.load(NBCommandInfo.class);
|
||||
ServiceSelector<NBCommandInfo> selector = ServiceSelector.of(cmdName, loader);
|
||||
List<? extends ServiceLoader.Provider<? extends NBCommandInfo>> providers = selector.getAllProviders();
|
||||
if (providers.size()>1) {
|
||||
throw new RuntimeException("looking for an optional command for cmdName '" + cmdName +"' but found " + providers.size());
|
||||
}
|
||||
if (!providers.isEmpty()) {
|
||||
return providers.get(0).get().getType();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static NBInvokableCommand init(String cmdSelector, NBComponent parent, String cmdAlias, String ctxName) {
|
||||
NBCommandInfo cmdInfo = getSelector(cmdSelector).getOne();
|
||||
NBInvokableCommand command = cmdInfo.create(parent, cmdAlias, ctxName);
|
||||
return command;
|
||||
}
|
||||
|
||||
private static ServiceSelector<NBCommandInfo> getSelector(String cmdName) {
|
||||
ServiceLoader<NBCommandInfo> loader = ServiceLoader.load(NBCommandInfo.class);
|
||||
ServiceSelector<NBCommandInfo> selector = ServiceSelector.of(cmdName, loader);
|
||||
return selector;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# API notes; Commands
|
||||
|
||||
Commands have a very basic type model which facilitates parsing,
|
||||
configuring, overriding, and basic type checking.
|
||||
|
||||
* Cmd <-- This is a configured command, including:
|
||||
* CmdType <-- the type model for the command:
|
||||
* It's verb name, AKA a CmdType enum value.
|
||||
* It's valid parameters, their names and types, aka CmdArgs.
|
||||
* CmdArg <-- A named assignment as parameter name = argument value:
|
||||
* referencing a valid CmdArg from the command
|
||||
* assignment locks for template overrides and restrictions
|
||||
* The name of the context in which the command should be run
|
||||
|
||||
In short:
|
||||
|
||||
* cmd
|
||||
* CmdType enum type
|
||||
* String name
|
||||
* CmdParam[] params
|
||||
* arguments map <name, CmdArg>,
|
||||
* [param] reference
|
||||
* assigned value (the actual argument value to the related parameter)
|
||||
* mutability (unlocked | silent locked | verbose locked)
|
||||
* activity context name
|
||||
|
||||
A command stream consists of a sequence of commands, which is the basis for
|
||||
setting the logic for a session. NBSession is responsible for taking a sequence of commands
|
||||
and mapping them into NBInvokableCommands.
|
||||
|
||||
Prior to handing a sequence of commands over to a session, the named scenario preprocessor
|
||||
can evaluate a command line against a specified named scenario template. NBInvokableCommand
|
||||
resolution does not occur until the session has the command sequence. Thus, the work done by
|
||||
the named scenario preprocessor is limited to the exposed command types shown above.
|
||||
|
||||
@@ -18,12 +18,15 @@ package io.nosqlbench.engine.core.annotation;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.nosqlbench.api.config.standard.*;
|
||||
import io.nosqlbench.api.labels.NBLabelsFilter;
|
||||
import io.nosqlbench.api.labels.NBLabelsValidator;
|
||||
import io.nosqlbench.nb.api.config.standard.ConfigLoader;
|
||||
import io.nosqlbench.nb.api.config.standard.NBConfigurable;
|
||||
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
|
||||
import io.nosqlbench.nb.api.config.standard.NBMapConfigurable;
|
||||
import io.nosqlbench.nb.api.labels.NBLabelsFilter;
|
||||
import io.nosqlbench.nb.api.labels.NBLabelsValidator;
|
||||
import io.nosqlbench.nb.annotations.Service;
|
||||
import io.nosqlbench.api.annotations.Annotation;
|
||||
import io.nosqlbench.api.annotations.Annotator;
|
||||
import io.nosqlbench.nb.api.annotations.Annotation;
|
||||
import io.nosqlbench.nb.api.annotations.Annotator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
|
||||
package io.nosqlbench.engine.core.clientload;
|
||||
|
||||
import com.codahale.metrics.Gauge;
|
||||
import io.nosqlbench.api.engine.metrics.instruments.NBMetricGauge;
|
||||
import io.nosqlbench.api.labels.NBLabels;
|
||||
import io.nosqlbench.components.NBBaseComponent;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetricGauge;
|
||||
import io.nosqlbench.nb.api.labels.NBLabels;
|
||||
import io.nosqlbench.nb.api.components.NBBaseComponent;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -35,7 +34,7 @@ public class ClientSystemMetricChecker extends NBBaseComponent {
|
||||
private List<ClientMetric> clientMetrics;
|
||||
|
||||
public ClientSystemMetricChecker(NBComponent parent, NBLabels additionalLabels, int pollIntervalSeconds) {
|
||||
super(parent,additionalLabels);
|
||||
super(parent,additionalLabels.and("_type","client-metrics"));
|
||||
this.pollIntervalSeconds = pollIntervalSeconds;
|
||||
this.scheduler = Executors.newScheduledThreadPool(1);
|
||||
this.clientMetrics = new ArrayList<>();
|
||||
|
||||
@@ -20,13 +20,13 @@ import com.codahale.metrics.Counting;
|
||||
import com.codahale.metrics.Gauge;
|
||||
import com.codahale.metrics.MetricAttribute;
|
||||
import com.codahale.metrics.MetricFilter;
|
||||
import io.nosqlbench.api.engine.metrics.instruments.*;
|
||||
import io.nosqlbench.api.engine.metrics.reporters.ConsoleReporter;
|
||||
import io.nosqlbench.api.engine.metrics.reporters.Log4JMetricsReporter;
|
||||
import io.nosqlbench.components.NBCreators;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.components.NBComponentTraversal;
|
||||
import io.nosqlbench.components.NBFinders;
|
||||
import io.nosqlbench.nb.api.engine.metrics.instruments.*;
|
||||
import io.nosqlbench.nb.api.engine.metrics.reporters.ConsoleReporter;
|
||||
import io.nosqlbench.nb.api.engine.metrics.reporters.Log4JMetricsReporter;
|
||||
import io.nosqlbench.nb.api.components.NBCreators;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import io.nosqlbench.nb.api.components.NBComponentTraversal;
|
||||
import io.nosqlbench.nb.api.components.NBFinders;
|
||||
import io.nosqlbench.engine.core.metrics.NBMetricsSummary;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package io.nosqlbench.engine.core.lifecycle;
|
||||
|
||||
import io.nosqlbench.api.metadata.Indexed;
|
||||
import io.nosqlbench.nb.api.metadata.Indexed;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package io.nosqlbench.engine.core.lifecycle.activity;
|
||||
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioActivitiesController;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ContextActivitiesController;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -24,9 +24,9 @@ public class ActivitiesExceptionHandler implements Thread.UncaughtExceptionHandl
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(ActivitiesExceptionHandler.class);
|
||||
|
||||
private final ScenarioActivitiesController controller;
|
||||
private final ContextActivitiesController controller;
|
||||
|
||||
public ActivitiesExceptionHandler(ScenarioActivitiesController controller) {
|
||||
public ActivitiesExceptionHandler(ContextActivitiesController controller) {
|
||||
this.controller = controller;
|
||||
logger.debug(() -> "Activities exception handler starting up for executor '" + this.controller + "'");
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@ import io.nosqlbench.engine.api.activityapi.core.RunState;
|
||||
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
|
||||
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.context.ScenarioActivitiesController;
|
||||
import io.nosqlbench.nb.api.engine.metrics.PeriodicRunnable;
|
||||
import io.nosqlbench.nb.api.engine.util.Unit;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ContextActivitiesController;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -35,14 +35,14 @@ public class ActivitiesProgressIndicator implements Runnable {
|
||||
|
||||
private final static Logger logger = LogManager.getLogger("PROGRESS");
|
||||
private final String indicatorSpec;
|
||||
private final ScenarioActivitiesController sc;
|
||||
private final ContextActivitiesController sc;
|
||||
private PeriodicRunnable<ActivitiesProgressIndicator> runnable;
|
||||
private IndicatorMode indicatorMode = IndicatorMode.console;
|
||||
private final Set<String> seen = new HashSet<>();
|
||||
|
||||
private long intervalMillis = 1L;
|
||||
|
||||
public ActivitiesProgressIndicator(ScenarioActivitiesController sc, String indicatorSpec) {
|
||||
public ActivitiesProgressIndicator(ContextActivitiesController sc, String indicatorSpec) {
|
||||
this.sc = sc;
|
||||
this.indicatorSpec = indicatorSpec;
|
||||
start();
|
||||
|
||||
@@ -16,27 +16,27 @@
|
||||
package io.nosqlbench.engine.core.lifecycle.activity;
|
||||
|
||||
import com.codahale.metrics.Gauge;
|
||||
import io.nosqlbench.api.engine.metrics.instruments.NBMetricGauge;
|
||||
import io.nosqlbench.api.labels.NBLabeledElement;
|
||||
import io.nosqlbench.api.labels.NBLabels;
|
||||
import io.nosqlbench.components.NBComponentSubScope;
|
||||
import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetricGauge;
|
||||
import io.nosqlbench.nb.api.labels.NBLabeledElement;
|
||||
import io.nosqlbench.nb.api.labels.NBLabels;
|
||||
import io.nosqlbench.nb.api.components.NBComponentExecutionScope;
|
||||
import io.nosqlbench.engine.api.activityapi.core.*;
|
||||
import io.nosqlbench.engine.api.activityimpl.MotorState;
|
||||
import io.nosqlbench.api.annotations.Annotation;
|
||||
import io.nosqlbench.api.annotations.Layer;
|
||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.api.engine.activityimpl.ParameterMap;
|
||||
import io.nosqlbench.nb.api.annotations.Annotation;
|
||||
import io.nosqlbench.nb.api.annotations.Layer;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ParameterMap;
|
||||
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 io.nosqlbench.virtdata.userlibs.apps.valuechecker.IndexedThreadFactory;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -64,7 +64,7 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
|
||||
private static final Logger logger = LogManager.getLogger(ActivityExecutor.class);
|
||||
private static final Logger activitylogger = LogManager.getLogger("ACTIVITY");
|
||||
|
||||
private final List<Motor<?>> motors = new ArrayList<>();
|
||||
private final LinkedList<Motor<?>> motors = new LinkedList<>();
|
||||
private final Activity activity;
|
||||
private final ActivityDef activityDef;
|
||||
private final RunStateTally tally;
|
||||
@@ -242,7 +242,7 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
|
||||
* @param activityDef
|
||||
* the activityDef for this activity instance
|
||||
*/
|
||||
private void adjustMotorCountToThreadParam(ActivityDef activityDef) {
|
||||
private void adjustMotorCountToThreadParam(ActivityDef activityDef) { // TODO: Ensure that threads area allowed to complete their current op gracefully
|
||||
logger.trace(() -> ">-pre-adjust->" + getSlotStatus());
|
||||
|
||||
reduceActiveMotorCountDownToThreadParam(activityDef);
|
||||
@@ -274,6 +274,18 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
|
||||
if (activityDef.getThreads()==0) {
|
||||
logger.warn("setting threads to zero is not advised. At least one thread has to be active to keep the activity alive.");
|
||||
}
|
||||
// LinkedList<Motor<?>> toremove = new LinkedList<>();
|
||||
// while (activityDef.getThreads()>motors.size()) {
|
||||
// Motor<?> motor = motors.removeLast();
|
||||
// toremove.addFirst(motor);
|
||||
// }
|
||||
// for (Motor<?> motor : toremove) {
|
||||
// motor.requestStop();
|
||||
// }
|
||||
// for (Motor<?> motor : toremove) {
|
||||
// motor.removeState();
|
||||
// }
|
||||
//
|
||||
while (motors.size() > activityDef.getThreads()) {
|
||||
Motor motor = motors.get(motors.size() - 1);
|
||||
logger.trace(() -> "Stopping cycle motor thread:" + motor);
|
||||
@@ -379,7 +391,7 @@ public class ActivityExecutor implements NBLabeledElement, ParameterMap.Listener
|
||||
|
||||
@Override
|
||||
public ExecutionResult call() throws Exception {
|
||||
try (NBComponentSubScope scope = new NBComponentSubScope(activity)) {
|
||||
try (NBComponentExecutionScope scope = new NBComponentExecutionScope(activity)) {
|
||||
|
||||
shutdownHook = new ActivityExecutorShutdownHook(this);
|
||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package io.nosqlbench.engine.core.lifecycle.activity;
|
||||
|
||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import io.nosqlbench.engine.api.activityapi.core.Activity;
|
||||
import io.nosqlbench.engine.api.activityimpl.uniform.StandardActivityType;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@@ -18,13 +18,13 @@ package io.nosqlbench.engine.core.lifecycle.activity;
|
||||
|
||||
import io.nosqlbench.adapter.diag.DriverAdapterLoader;
|
||||
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.api.content.Content;
|
||||
import io.nosqlbench.api.content.NBIO;
|
||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.api.errors.BasicError;
|
||||
import io.nosqlbench.api.spi.SimpleServiceLoader;
|
||||
import io.nosqlbench.api.system.NBEnvironment;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import io.nosqlbench.nb.api.nbio.Content;
|
||||
import io.nosqlbench.nb.api.nbio.NBIO;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.nb.api.errors.BasicError;
|
||||
import io.nosqlbench.nb.api.spi.SimpleServiceLoader;
|
||||
import io.nosqlbench.nb.api.system.NBEnvironment;
|
||||
import io.nosqlbench.engine.api.activityapi.core.ActivityType;
|
||||
import io.nosqlbench.engine.api.activityimpl.uniform.StandardActivityType;
|
||||
import io.nosqlbench.nb.annotations.Maturity;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package io.nosqlbench.engine.core.lifecycle.process;
|
||||
|
||||
import io.nosqlbench.api.errors.BasicError;
|
||||
import io.nosqlbench.nb.api.errors.BasicError;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.graalvm.polyglot.PolyglotException;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package io.nosqlbench.engine.core.lifecycle.process;
|
||||
|
||||
import io.nosqlbench.api.Shutdownable;
|
||||
import io.nosqlbench.nb.api.lifecycle.Shutdownable;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package io.nosqlbench.engine.core.lifecycle.scenario.context;
|
||||
|
||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.proxy.ProxyObject;
|
||||
|
||||
@@ -28,11 +28,11 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class ActivityBindings implements Bindings, ProxyObject {
|
||||
|
||||
private final ScenarioActivitiesController scenario;
|
||||
private final ContextActivitiesController scenario;
|
||||
private final Map<String, Bindings> elementMap = new HashMap<String, Bindings>();
|
||||
|
||||
public ActivityBindings(ScenarioActivitiesController scenarioActivitiesController) {
|
||||
this.scenario = scenarioActivitiesController;
|
||||
public ActivityBindings(ContextActivitiesController contextActivitiesController) {
|
||||
this.scenario = contextActivitiesController;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenario.context;
|
||||
|
||||
import io.nosqlbench.engine.core.annotation.Annotators;
|
||||
import io.nosqlbench.engine.core.lifecycle.activity.ActivitiesProgressIndicator;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.ContextShutdownHook;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
|
||||
import io.nosqlbench.nb.api.annotations.Annotation;
|
||||
import io.nosqlbench.nb.api.annotations.Layer;
|
||||
import io.nosqlbench.nb.api.labels.NBLabels;
|
||||
import io.nosqlbench.nb.api.components.NBBaseComponent;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class NBBufferedCommandContext extends NBBaseComponent implements NBCommandContext {
|
||||
|
||||
private final static Logger logger = LogManager.getLogger(NBBufferedCommandContext.class);
|
||||
private final ContextActivitiesController controller;
|
||||
private final ActivitiesProgressIndicator activitiesProgressIndicator;
|
||||
private ContextShutdownHook contextShutdownHook;
|
||||
private long startedAtMillis;
|
||||
private Exception error;
|
||||
private long endedAtMillis;
|
||||
private final Map<String, Object> vars = new LinkedHashMap<>();
|
||||
|
||||
public enum IOType {
|
||||
connected,
|
||||
virtual,
|
||||
traced
|
||||
}
|
||||
|
||||
private final IOType iotype;
|
||||
private DiagWriter stdoutBuffer;
|
||||
private DiagWriter stderrBuffer;
|
||||
private DiagReader stdinBuffer;
|
||||
|
||||
public NBBufferedCommandContext(NBComponent parent, String name, IOType ioTypes) {
|
||||
super(parent, NBLabels.forKV("context",name));
|
||||
this.iotype = ioTypes;
|
||||
this.controller = new ContextActivitiesController(this);
|
||||
|
||||
switch (iotype) {
|
||||
case traced:
|
||||
stdoutBuffer = new DiagWriter(new InterjectingCharArrayWriter(" stdout "), new PrintWriter(System.out));
|
||||
stderrBuffer = new DiagWriter(new InterjectingCharArrayWriter(" stderr "), new PrintWriter(System.out));
|
||||
stdinBuffer = new DiagReader(new InputStreamReader(System.in), " stdin ");
|
||||
break;
|
||||
case virtual:
|
||||
stdoutBuffer = new DiagWriter(new InterjectingCharArrayWriter(" stdout "));
|
||||
stderrBuffer = new DiagWriter(new InterjectingCharArrayWriter(" stderr "));
|
||||
stdinBuffer = new DiagReader(new StringReader(""), " stdin ");
|
||||
break;
|
||||
case connected:
|
||||
stdoutBuffer = new DiagWriter(new PrintWriter(System.out));
|
||||
stderrBuffer = new DiagWriter(new PrintWriter(System.out));
|
||||
stdinBuffer = new DiagReader(new InputStreamReader(System.in));
|
||||
break;
|
||||
}
|
||||
|
||||
this.contextShutdownHook = new ContextShutdownHook(this);
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(this.contextShutdownHook);
|
||||
|
||||
Annotators.recordAnnotation(
|
||||
Annotation.newBuilder()
|
||||
.element(this)
|
||||
.now()
|
||||
.layer(Layer.Scenario)
|
||||
.build()
|
||||
);
|
||||
|
||||
this.activitiesProgressIndicator = new ActivitiesProgressIndicator(this.controller, "console:10s");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ContextActivitiesController controller() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter out() {
|
||||
return stdoutBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter err() {
|
||||
return stderrBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader in() {
|
||||
return stdinBuffer;
|
||||
}
|
||||
|
||||
public String getIOLog() {
|
||||
return this.stdoutBuffer.getTimedLog() + this.stderrBuffer.getTimedLog();
|
||||
}
|
||||
|
||||
public NBCommandContext asFixtures() {
|
||||
return (NBCommandContext) this;
|
||||
}
|
||||
|
||||
|
||||
public static ContextBuilderFacets.WantsName builder() {
|
||||
return new NBScenarioContextBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBCommandResult apply(NBInvokableCommand nbCmd, NBCommandParams nbCmdParams) {
|
||||
NBCommandResult safeCmdResult = nbCmd.invokeSafe(this, nbCmdParams);
|
||||
error=safeCmdResult.getException();
|
||||
if (error!=null) {
|
||||
try {
|
||||
controller.forceStopActivities(3000);
|
||||
} catch (final Exception eInner) {
|
||||
logger.debug(() -> "Found inner exception while forcing stop activities with rethrow=false: " + eInner);
|
||||
}
|
||||
// throw new RuntimeException(safeCmdResult.getException());
|
||||
}
|
||||
|
||||
Object object = safeCmdResult.getResultObject();
|
||||
String stepname = getLabels().valueOfOptional("step").orElse("unknownstep");
|
||||
if (object instanceof Map<?,?> map) {
|
||||
map.forEach((k,v) -> {
|
||||
logger.debug("setting command result for '" + stepname + "." + k + "' to '" + v.toString()+"'");
|
||||
getContainerVars().put(stepname+"."+k,v.toString());
|
||||
});
|
||||
getContainerVars().put(stepname+"._map",map);
|
||||
} else if (object instanceof List<?> list) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
getContainerVars().put(stepname+"."+String.valueOf(i),list.get(i));
|
||||
}
|
||||
getContainerVars().put(stepname+"._list",list);
|
||||
} else if (object instanceof Set<?> set) {
|
||||
getContainerVars().put(stepname+"._set",set);
|
||||
} else if (object != null && object.getClass().isArray()) {
|
||||
getContainerVars().put(stepname + "._array", object);
|
||||
} else if (object !=null) {
|
||||
getContainerVars().put(stepname + "._object", object);
|
||||
|
||||
// ignore
|
||||
// } else {
|
||||
//
|
||||
// RuntimeException error = new RuntimeException("Unrecognizable type to set context vars with:" + object.getClass().getCanonicalName());
|
||||
// logger.error(error);
|
||||
//// throw new RuntimeException("Unrecognizable type to set context vars with:" + object.getClass().getCanonicalName());
|
||||
} else {
|
||||
logger.debug("no object was provided to set the context result");
|
||||
}
|
||||
|
||||
return safeCmdResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doShutdown() {
|
||||
NBCommandContext.super.doShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getContainerVars() {
|
||||
return this.vars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeDetach() {
|
||||
// TODO, shutdown hooks need to be moved to context
|
||||
Runtime.getRuntime().removeShutdownHook(this.contextShutdownHook);
|
||||
final var retiringScenarioShutdownHook = this.contextShutdownHook;
|
||||
this.contextShutdownHook = null;
|
||||
retiringScenarioShutdownHook.run();
|
||||
this.logger.debug("removing context shutdown hook");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenario.context;
|
||||
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import os.CommandResult;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface NBCommandContext extends NBComponent, BiFunction<NBInvokableCommand,NBCommandParams, NBCommandResult> {
|
||||
// ScenarioPhaseParams params();
|
||||
ContextActivitiesController controller();
|
||||
PrintWriter out();
|
||||
PrintWriter err();
|
||||
Reader in();
|
||||
public static ContextBuilderFacets.WantsName builder() {
|
||||
return new NBScenarioContextBuilder();
|
||||
}
|
||||
|
||||
default void doShutdown() {
|
||||
};
|
||||
|
||||
Map<String,Object> getContainerVars();
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenario.context;
|
||||
|
||||
import io.nosqlbench.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.engine.core.lifecycle.session.NBSession;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* <P>An NBSceneFixtures instance represents the runtime fixtures needed to run a specific
|
||||
* scenario. It is instanced per execution and is not expected to be thread-safe nor
|
||||
* run more than once. This provides all of the required runtime support and IO boundaries
|
||||
* needed by a scenario.</P>
|
||||
*
|
||||
* <P>The properties on this context define the API used by any scenario logic,
|
||||
* whether implemented in script or directly. This should allow different
|
||||
* execution forms to read similarly, easing development and debugging of more advanced
|
||||
* scenarios.</P>
|
||||
*
|
||||
* <P>When using the fixtures within a context, they should be named <em>scene</em>
|
||||
* which suggests an episodic sequence of events.</P>
|
||||
*
|
||||
* <P>Within an execution context, scenario logic is expected to adhere to usage of
|
||||
* <i>scene.in</i>, <i>scene.out</i>, and <i>scene.error</i> instead of System.out, ...</P>
|
||||
*/
|
||||
public class NBDefaultSceneFixtures implements NBSceneFixtures {
|
||||
/*
|
||||
These are parameters which are passed into the script, named scenario, etc.
|
||||
*/
|
||||
private ScenarioParams params;
|
||||
/*
|
||||
* NBSession is the root component type in a NB process, and all CLI options which
|
||||
* affect global settings are expected to be properties on the session.
|
||||
*/
|
||||
private NBComponent session;
|
||||
|
||||
/*
|
||||
* ScenarioActivitiesController is the concurrency handling layer for activities within
|
||||
* a given scenario. A scenario doesn't complete unless until all activities
|
||||
* are complete or errored.
|
||||
*/
|
||||
private ScenarioActivitiesController controller;
|
||||
/*
|
||||
* Extensions provide additional scripting capabilities which are not provided by the
|
||||
* scripting or other runtimes, or new ways of tapping into extant features.
|
||||
*/
|
||||
|
||||
private PrintWriter out;
|
||||
private PrintWriter err;
|
||||
|
||||
private Reader in;
|
||||
|
||||
public NBDefaultSceneFixtures(ScenarioParams params, ScenarioActivitiesController controller, PrintWriter out, PrintWriter err, Reader in) {
|
||||
this.params = params;
|
||||
this.controller = controller;
|
||||
this.out = out;
|
||||
this.err = err;
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
// public static NBSceneFixtures ofDefault(String name) {
|
||||
// return new NBDefaultSceneFixtures(
|
||||
// new ScenarioParams(),
|
||||
// new NBSession(
|
||||
// new TestComponent("scene", name), "scene~"+name
|
||||
// ),
|
||||
// new ScenarioActivitiesController(),
|
||||
// new PrintWriter(System.out),
|
||||
// new PrintWriter(System.err),
|
||||
// new InputStreamReader(System.in)
|
||||
// );
|
||||
// }
|
||||
//
|
||||
|
||||
@Override
|
||||
public ScenarioParams params() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScenarioActivitiesController controller() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter out() {
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter err() {
|
||||
return err;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader in() {
|
||||
return in;
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenario.context;
|
||||
|
||||
import io.nosqlbench.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.api.filtering.TristateFilter;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.engine.api.scripting.DiagReader;
|
||||
import io.nosqlbench.engine.api.scripting.DiagWriter;
|
||||
import io.nosqlbench.engine.api.scripting.InterjectingCharArrayWriter;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Map;
|
||||
|
||||
public class NBSceneBuffer implements NBSceneFixtures {
|
||||
private final NBSceneFixtures fixtures;
|
||||
|
||||
public NBSceneBuffer params(Map<String,String> params) {
|
||||
return new NBSceneBuffer(
|
||||
new NBDefaultSceneFixtures(
|
||||
ScenarioParams.of(params),
|
||||
fixtures.controller(),
|
||||
fixtures.out(),
|
||||
fixtures.err(),
|
||||
fixtures.in())
|
||||
,iotype
|
||||
);
|
||||
}
|
||||
|
||||
public enum IOType {
|
||||
connected,
|
||||
virtual,
|
||||
traced
|
||||
}
|
||||
|
||||
private final IOType iotype;
|
||||
private DiagWriter stdoutBuffer;
|
||||
private DiagWriter stderrBuffer;
|
||||
private DiagReader stdinBuffer;
|
||||
|
||||
public NBSceneBuffer(NBSceneFixtures fixtures, IOType ioTypes) {
|
||||
this.iotype = ioTypes;
|
||||
this.fixtures = fixtures;
|
||||
|
||||
switch (iotype) {
|
||||
case traced:
|
||||
stdoutBuffer = new DiagWriter(new InterjectingCharArrayWriter(" stdout "), fixtures.out());
|
||||
stderrBuffer = new DiagWriter(new InterjectingCharArrayWriter(" stderr "), fixtures.err());
|
||||
stdinBuffer = new DiagReader(fixtures.in(), " stdin ");
|
||||
break;
|
||||
case virtual:
|
||||
stdoutBuffer = new DiagWriter(new InterjectingCharArrayWriter(" stdout "));
|
||||
stderrBuffer = new DiagWriter(new InterjectingCharArrayWriter(" stderr "));
|
||||
stdinBuffer = new DiagReader(new StringReader(""), " stdin ");
|
||||
break;
|
||||
case connected:
|
||||
stdoutBuffer = new DiagWriter(fixtures.out());
|
||||
stderrBuffer = new DiagWriter(fixtures.err());
|
||||
stdinBuffer = new DiagReader(fixtures.in());
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public NBSceneBuffer(NBSceneFixtures fixtures) {
|
||||
this(fixtures, IOType.traced);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScenarioParams params() {
|
||||
return fixtures.params();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScenarioActivitiesController controller() {
|
||||
return fixtures.controller();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter out() {
|
||||
return stdoutBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter err() {
|
||||
return stderrBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader in() {
|
||||
return stdinBuffer;
|
||||
}
|
||||
|
||||
public String getIOLog() {
|
||||
return this.stdoutBuffer.getTimedLog() + this.stderrBuffer.getTimedLog();
|
||||
}
|
||||
|
||||
public NBSceneFixtures asFixtures() {
|
||||
return (NBSceneFixtures) this;
|
||||
}
|
||||
|
||||
|
||||
public static SceneBuilderFacets.WantsController builder() {
|
||||
return new SceneBuilder();
|
||||
}
|
||||
|
||||
public static NBSceneBuffer traced(NBComponent component) {
|
||||
return builder().tracedIO().build(component);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenario.direct;
|
||||
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioActivitiesController;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneFixtures;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioParams;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBScenario;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
|
||||
public abstract class SCBaseScenario extends NBScenario {
|
||||
protected Reader stdin;
|
||||
protected PrintWriter stdout;
|
||||
protected Writer stderr;
|
||||
protected ScenarioActivitiesController controller;
|
||||
protected ScenarioParams params;
|
||||
|
||||
public SCBaseScenario(NBComponent parentComponent, String scenarioName) {
|
||||
super(parentComponent, scenarioName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void runScenario(NBSceneFixtures shell) {
|
||||
this.stdin = shell.in();
|
||||
this.stdout = shell.out();
|
||||
this.stderr = shell.err();
|
||||
this.controller = shell.controller();
|
||||
this.params = shell.params();
|
||||
try {
|
||||
invoke();
|
||||
} catch (Exception e) {
|
||||
stdout.println(e.toString());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this method, which emulates the scope
|
||||
* of previous scenario scripts. Within this method, local
|
||||
* fields will be available directly:
|
||||
* <UL>
|
||||
* <LI>component, an {@link NBComponent} - The NB component upon which all metrics or other services are attached.</LI>
|
||||
* <LI>stdin - a {@link Reader} representing the input buffer which would normally be {@link System#in}
|
||||
* <LI>stdout, stderr</LI>- a {@link PrintWriter}; This can be buffered virtually, attached to {@link System#out} and {@link System#err} or both for IO tracing.</LI>
|
||||
* <LI>controller - A dedicated {@link ScenarioActivitiesController} which can be used to define, start, top, and interact with activities.</LI>
|
||||
* <LI>params - The {@link ScenarioParams} which have been passed to this scenario.</LI>
|
||||
* <LI><EM>all component services</EM> as this scenario IS a component. This includes all implemented methods in any of the {@link NBComponent} sub-interfaces.</EM>
|
||||
* </LI>
|
||||
* </UL>
|
||||
*/
|
||||
public abstract void invoke();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenario.execution;
|
||||
|
||||
import io.nosqlbench.nb.api.annotations.Annotation;
|
||||
import io.nosqlbench.nb.api.annotations.Layer;
|
||||
import io.nosqlbench.nb.api.labels.NBLabels;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import io.nosqlbench.nb.api.components.NBComponentErrorHandler;
|
||||
import io.nosqlbench.engine.core.annotation.Annotators;
|
||||
import io.nosqlbench.engine.core.lifecycle.activity.ActivitiesProgressIndicator;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ContextActivitiesController;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandParams;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
|
||||
public abstract class NBBaseCommand extends NBInvokableCommand {
|
||||
|
||||
private final String targetScenario;
|
||||
protected Logger logger = LogManager.getLogger("COMMAND");
|
||||
|
||||
public NBBaseCommand(NBBufferedCommandContext parentComponent, String stepName, String targetScenario) {
|
||||
super(parentComponent, NBLabels.forKV("step", stepName));
|
||||
this.targetScenario = targetScenario;
|
||||
}
|
||||
|
||||
public NBBaseCommand(NBBufferedCommandContext parentComponent, String commandLabel) {
|
||||
this(parentComponent, commandLabel, "_testing_");
|
||||
}
|
||||
|
||||
public String getScenarioName() {
|
||||
return getLabels().asMap().get("scenario");
|
||||
}
|
||||
|
||||
public String getTargetScenario() {
|
||||
return this.targetScenario;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object apply(NBBufferedCommandContext sctx, NBCommandParams params) {
|
||||
return invoke(params, sctx.out(), sctx.err(), sctx.in(), sctx.controller());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SCENARIO (" + this.getClass().getSuperclass().getSimpleName() + ") { scenarioName: " + getScenarioName() + " }";
|
||||
}
|
||||
|
||||
public abstract Object invoke(
|
||||
NBCommandParams params,
|
||||
PrintWriter stdout,
|
||||
PrintWriter stderr,
|
||||
Reader stdin,
|
||||
ContextActivitiesController controller
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenario.execution;
|
||||
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Implement this stub service to identify {@link NBInvokableCommand}s which can be loaded in the runtime.
|
||||
* Each concrete implementation of NBCommandInfo needs to be annotated with
|
||||
* <pre>{@code
|
||||
* @Service(value = NBCommandInfo.class, selector = "<cmdname>")
|
||||
* }</pre>
|
||||
*/
|
||||
public abstract class NBCommandInfo {
|
||||
private final static Logger logger = LogManager.getLogger(NBCommandInfo.class);
|
||||
public abstract Class<? extends NBInvokableCommand> getType();
|
||||
public NBInvokableCommand create(NBComponent parent, String cmdName, String ctxName) {
|
||||
Constructor<? extends NBInvokableCommand> cmdCtor;
|
||||
try {
|
||||
cmdCtor = getType().getConstructor(NBBufferedCommandContext.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenario.execution;
|
||||
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandParams;
|
||||
import io.nosqlbench.nb.api.components.NBBaseComponent;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import io.nosqlbench.nb.api.labels.NBLabels;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public abstract class NBInvokableCommand extends NBBaseComponent implements BiFunction<NBBufferedCommandContext, NBCommandParams, Object> {
|
||||
private static final Logger logger = LogManager.getLogger(NBInvokableCommand.class);
|
||||
|
||||
public NBInvokableCommand(NBBufferedCommandContext parentComponent, NBLabels componentSpecificLabelsOnly) {
|
||||
super(parentComponent, componentSpecificLabelsOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Object apply(NBBufferedCommandContext nbBufferedCommandContext, NBCommandParams nbCommandParams);
|
||||
|
||||
public NBCommandResult invokeSafe(NBBufferedCommandContext context, NBCommandParams params) {
|
||||
Object resultObject = null;
|
||||
Exception exception = null;
|
||||
long startAt = System.currentTimeMillis();
|
||||
NBCommandResult result = null;
|
||||
try {
|
||||
logger.debug("invoking command: " + this);
|
||||
resultObject=apply(context, params);
|
||||
logger.debug("cmd produced: " + (resultObject==null ? "NULL" : resultObject.toString()));
|
||||
} catch (Exception e) {
|
||||
exception = e;
|
||||
logger.error("error in command (stack trace follows): " + this.description() + ": " + exception);
|
||||
exception.printStackTrace(System.out);
|
||||
} finally {
|
||||
long endAt = System.currentTimeMillis();
|
||||
result = new NBCommandResult(context, startAt, endAt, exception);
|
||||
if (resultObject!=null) {
|
||||
result.setResultObject(resultObject);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.scenario.execution;
|
||||
|
||||
import io.nosqlbench.api.annotations.Annotation;
|
||||
import io.nosqlbench.api.annotations.Layer;
|
||||
import io.nosqlbench.api.labels.NBLabels;
|
||||
import io.nosqlbench.api.metadata.ScenarioMetadata;
|
||||
import io.nosqlbench.api.metadata.SystemId;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.components.NBBaseComponent;
|
||||
import io.nosqlbench.components.NBComponentErrorHandler;
|
||||
import io.nosqlbench.engine.core.annotation.Annotators;
|
||||
import io.nosqlbench.engine.core.lifecycle.activity.ActivitiesProgressIndicator;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioActivitiesController;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneBuffer;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneFixtures;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.script.NBScriptedScenario;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* This is the core logic of every NB scenario.
|
||||
* <OL>
|
||||
* <LI>NBScenario creates a generic execution context.</LI>
|
||||
* <LI>This context is functionally applied to (executed by) a specific implementation.</LI>
|
||||
* <LI>Activities associated with the scenario are completed or errored.</LI>
|
||||
* <LI>A result is composited from the data in the component tree.</LI>
|
||||
* </OL>
|
||||
*/
|
||||
public abstract class NBScenario extends NBBaseComponent
|
||||
implements
|
||||
Function<NBSceneBuffer, ScenarioResult>,
|
||||
NBComponentErrorHandler {
|
||||
|
||||
protected Logger logger = LogManager.getLogger("SCENARIO");
|
||||
private long startedAtMillis, endedAtMillis;
|
||||
|
||||
private ScenarioMetadata scenarioMetadata;
|
||||
|
||||
private ScenarioActivitiesController scenarioActivitiesController;
|
||||
private Exception error;
|
||||
private String progressInterval = "console:10s";
|
||||
private ActivitiesProgressIndicator activitiesProgressIndicator;
|
||||
|
||||
public NBScenario(NBComponent parentComponent, String scenarioName) {
|
||||
super(parentComponent, NBLabels.forKV("scenario",scenarioName));
|
||||
}
|
||||
|
||||
public String getScenarioName() {
|
||||
return getLabels().asMap().get("scenario");
|
||||
}
|
||||
|
||||
public void forceStopScenario(int i, boolean b) {
|
||||
scenarioActivitiesController.forceStopScenario(i,b);
|
||||
}
|
||||
|
||||
// public Map<String, String> getParams() {
|
||||
// return this.params;
|
||||
// }
|
||||
|
||||
public ScenarioActivitiesController getActivitiesController() {
|
||||
return this.scenarioActivitiesController;
|
||||
}
|
||||
|
||||
public enum State {
|
||||
Scheduled,
|
||||
Running,
|
||||
Errored,
|
||||
Interrupted,
|
||||
Finished
|
||||
}
|
||||
|
||||
private ScenarioShutdownHook scenarioShutdownHook;
|
||||
private State state;
|
||||
|
||||
/**
|
||||
* This should be the only way to get a ScenarioResult for a Scenario.
|
||||
* <p>
|
||||
* The lifecycle of a scenario includes the lifecycles of all of the following:
|
||||
* <OL>
|
||||
* <LI>The scenario control script, executing within a graaljs context.</LI>
|
||||
* <LI>The lifecycle of every activity which is started within the scenario.</LI>
|
||||
* </OL>
|
||||
* <p>
|
||||
* 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:
|
||||
* <UL>
|
||||
* <LI>The scenario control script has run to completion, or experienced an exception.</LI>
|
||||
* <LI>Each activity has run to completion, experienced an exception, or all</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public final ScenarioResult apply(NBSceneBuffer sctx) {
|
||||
this.scenarioActivitiesController =sctx.controller();
|
||||
|
||||
this.scenarioShutdownHook = new ScenarioShutdownHook(this);
|
||||
Runtime.getRuntime().addShutdownHook(this.scenarioShutdownHook);
|
||||
|
||||
this.state = NBScriptedScenario.State.Running;
|
||||
this.startedAtMillis = System.currentTimeMillis();
|
||||
Annotators.recordAnnotation(
|
||||
Annotation.newBuilder()
|
||||
.element(this)
|
||||
.now()
|
||||
.layer(Layer.Scenario)
|
||||
.build()
|
||||
);
|
||||
|
||||
if (!"disabled".equals(progressInterval) && progressInterval!=null && !progressInterval.isEmpty())
|
||||
this.activitiesProgressIndicator = new ActivitiesProgressIndicator(scenarioActivitiesController, this.progressInterval);
|
||||
|
||||
ScenarioResult result = null;
|
||||
try {
|
||||
runScenario(sctx.asFixtures());
|
||||
final long awaitCompletionTime = 86400 * 365 * 1000L;
|
||||
this.logger.debug("Awaiting completion of scenario and activities for {} millis.", awaitCompletionTime);
|
||||
this.scenarioActivitiesController.awaitCompletion(awaitCompletionTime);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
scenarioActivitiesController.forceStopScenario(3000, false);
|
||||
} catch (final Exception eInner) {
|
||||
this.logger.debug("Found inner exception while forcing stop with rethrow=false: {}", eInner);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.error = e;
|
||||
} finally {
|
||||
this.scenarioActivitiesController.shutdown();
|
||||
this.endedAtMillis = System.currentTimeMillis();
|
||||
result = new ScenarioResult(
|
||||
sctx,
|
||||
startedAtMillis,
|
||||
endedAtMillis,
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Runtime.getRuntime().removeShutdownHook(this.scenarioShutdownHook);
|
||||
final var retiringScenarioShutdownHook = this.scenarioShutdownHook;
|
||||
this.scenarioShutdownHook = null;
|
||||
retiringScenarioShutdownHook.run();
|
||||
this.logger.debug("removing scenario shutdown hook");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public void notifyException(final Thread t, final Throwable e) {
|
||||
error = new RuntimeException("in thread " + t.getName() + ", " + e, e);
|
||||
}
|
||||
|
||||
protected abstract void runScenario(NBSceneFixtures sctx);
|
||||
|
||||
public void finish() {
|
||||
this.logger.debug("finishing scenario");
|
||||
this.endedAtMillis = System.currentTimeMillis(); //TODO: Make only one endedAtMillis assignment
|
||||
if (State.Running == this.state) state = State.Finished;
|
||||
|
||||
if (null != scenarioShutdownHook) {
|
||||
// If this method was called while the shutdown hook is defined, then it means
|
||||
// that the scenario was ended before the hook was uninstalled normally.
|
||||
state = State.Interrupted;
|
||||
this.logger.warn("Scenario was interrupted by process exit, shutting down");
|
||||
} else
|
||||
this.logger.info(
|
||||
"Scenario completed successfully, with {} logical activities.",
|
||||
scenarioActivitiesController.getActivityExecutorMap().size()
|
||||
);
|
||||
|
||||
this.logger.info(() -> "scenario state: " + state);
|
||||
|
||||
// We report the scenario state via annotation even for short runs
|
||||
final Annotation annotation = Annotation.newBuilder()
|
||||
.element(this)
|
||||
.interval(startedAtMillis, this.endedAtMillis)
|
||||
.layer(Layer.Scenario)
|
||||
.addDetail("event", "stop-scenario")
|
||||
.build();
|
||||
|
||||
Annotators.recordAnnotation(annotation);
|
||||
|
||||
}
|
||||
|
||||
private synchronized ScenarioMetadata getScenarioMetadata() {
|
||||
if (null == this.scenarioMetadata) scenarioMetadata = new ScenarioMetadata(
|
||||
startedAtMillis,
|
||||
getScenarioName(),
|
||||
SystemId.getNodeId(),
|
||||
SystemId.getNodeFingerprint()
|
||||
);
|
||||
return this.scenarioMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SCENARIO (" + this.getClass().getSuperclass().getSimpleName()+") { scenarioName: "+getScenarioName()+" }";
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package io.nosqlbench.engine.core.lifecycle.scenario.execution;
|
||||
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -1,284 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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.scenario.execution;
|
||||
|
||||
import io.nosqlbench.api.errors.BasicError;
|
||||
import io.nosqlbench.api.labels.NBLabels;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.components.NBBaseComponent;
|
||||
import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.IndexedThreadFactory;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.*;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.script.ScenarioExceptionHandler;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ScenariosExecutor extends NBBaseComponent {
|
||||
|
||||
private final Logger logger = LogManager.getLogger("SCENARIOS");
|
||||
private final LinkedHashMap<String, SubmittedScenario> submitted = new LinkedHashMap<>();
|
||||
|
||||
private final ExecutorService executor;
|
||||
private final String name;
|
||||
private RuntimeException stoppingException;
|
||||
|
||||
public ScenariosExecutor(NBComponent parent, String name, int threads) {
|
||||
super(parent, NBLabels.forKV("executor","name"));
|
||||
executor = new ThreadPoolExecutor(1, threads,
|
||||
0L, TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingQueue<>(),
|
||||
new IndexedThreadFactory("scenarios", new ScenarioExceptionHandler(this)));
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public synchronized void execute(NBScenario scenario, Map<String,String> params) {
|
||||
if (submitted.get(scenario.getScenarioName()) != null) {
|
||||
throw new BasicError("Scenario " + scenario.getScenarioName() + " is already defined. Remove it first to reuse the name.");
|
||||
}
|
||||
|
||||
NBSceneBuffer bufferedContext = getNbSceneBuffer(params);
|
||||
Future<ScenarioResult> future = executor.submit(
|
||||
() -> scenario.apply(bufferedContext) // combine basic execution data with trace
|
||||
);
|
||||
SubmittedScenario s = new SubmittedScenario(scenario, future);
|
||||
submitted.put(s.getName(), s);
|
||||
// TODO at this point, bufferedContext holds all the trace, make it visible in results
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private NBSceneBuffer getNbSceneBuffer(Map<String, String> params) {
|
||||
return NBSceneBuffer.builder()
|
||||
.tracedIO()
|
||||
.params(params)
|
||||
.build(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down all running scenarios and awaits all results.
|
||||
*
|
||||
* @return the final scenario-result map.
|
||||
*/
|
||||
public ScenariosResults awaitAllResults() {
|
||||
return awaitAllResults(Long.MAX_VALUE / 2, 10000); // half max value, to avoid overflow
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down all running scenarios and awaits all results.
|
||||
*
|
||||
* @param timeout how long to wait for the results to complete
|
||||
* @param updateInterval how frequently to log status while waiting
|
||||
* @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");
|
||||
}
|
||||
long timeoutAt = System.currentTimeMillis() + timeout;
|
||||
|
||||
executor.shutdown();
|
||||
try {
|
||||
while (!executor.awaitTermination(timeout, TimeUnit.MILLISECONDS)) {
|
||||
if (System.currentTimeMillis()>=timeoutAt) {
|
||||
throw new RuntimeException("executor still running scenarios after awaiting all results for " + timeout
|
||||
+ "ms. isTerminated:" + executor.isTerminated() + " isShutdown:" + executor.isShutdown());
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
|
||||
// while (!executor.isShutdown() && System.currentTimeMillis() < timeoutAt) {
|
||||
// long waitedAt = System.currentTimeMillis();
|
||||
// long updateAt = Math.min(timeoutAt, waitedAt + updateInterval);
|
||||
// while (!executor.isShutdown() && System.currentTimeMillis() < timeoutAt) {
|
||||
// while (!executor.isShutdown() && System.currentTimeMillis() < updateAt) {
|
||||
// try {
|
||||
// long timeRemaining = updateAt - System.currentTimeMillis();
|
||||
// if (executor.awaitTermination(timeRemaining, TimeUnit.MILLISECONDS)) {
|
||||
// logger.info("executor shutdown during await");
|
||||
// }
|
||||
// } catch (InterruptedException ignored) {
|
||||
// }
|
||||
// }
|
||||
// logger.trace(() -> "waited " + (System.currentTimeMillis()-waitFrom) + " millis for scenarios");
|
||||
// updateAt = Math.min(timeoutAt, System.currentTimeMillis() + updateInterval);
|
||||
// }
|
||||
//
|
||||
// logger.debug("scenarios executor shutdown after " + (System.currentTimeMillis() - waitedAt) + "ms.");
|
||||
// }
|
||||
//
|
||||
// if (!executor.isShutdown()) {
|
||||
// throw new RuntimeException("executor still runningScenarios after awaiting all results for " + timeout
|
||||
// + "ms. isTerminated:" + executor.isTerminated() + " isShutdown:" + executor.isShutdown());
|
||||
// }
|
||||
Map<NBScenario, ScenarioResult> scenarioResultMap = new LinkedHashMap<>();
|
||||
getAsyncResultStatus()
|
||||
.entrySet()
|
||||
.forEach(
|
||||
es -> scenarioResultMap.put(
|
||||
es.getKey(),
|
||||
es.getValue().orElse(null)
|
||||
)
|
||||
);
|
||||
return new ScenariosResults(this, scenarioResultMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of scenarios which have been submitted, in order
|
||||
*/
|
||||
public List<String> getPendingScenarios() {
|
||||
return new ArrayList<>(
|
||||
submitted.values().stream()
|
||||
.map(SubmittedScenario::getName)
|
||||
.collect(Collectors.toCollection(ArrayList::new)));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns a map of all pending scenario names and optional results.
|
||||
* All submitted scenarios are included. Those which are still pending
|
||||
* are returned with an empty option.</p>
|
||||
*
|
||||
* <p>Results may be exceptional. If {@link ExecutionMetricsResult#getException()} is present,
|
||||
* then the result did not complete normally.</p>
|
||||
*
|
||||
* @return map of async results, with incomplete results as Optional.empty()
|
||||
*/
|
||||
public Map<NBScenario, Optional<ScenarioResult>> getAsyncResultStatus() {
|
||||
|
||||
Map<NBScenario, Optional<ScenarioResult>> optResults = new LinkedHashMap<>();
|
||||
|
||||
for (SubmittedScenario submittedScenario : submitted.values()) {
|
||||
Future<ScenarioResult> resultFuture = submittedScenario.getResultFuture();
|
||||
|
||||
Optional<ScenarioResult> 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");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
optResults.put(submittedScenario.getScenario(), oResult);
|
||||
|
||||
}
|
||||
|
||||
return optResults;
|
||||
}
|
||||
|
||||
public Optional<NBScenario> getPendingScenario(String scenarioName) {
|
||||
return Optional.ofNullable(submitted.get(scenarioName)).map(SubmittedScenario::getScenario);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of a pending or completed scenario. If the scenario has run to
|
||||
* completion, then the Optional will be present. If the scenario threw an
|
||||
* exception, or there was an error accessing the future, then the result will
|
||||
* contain the exception. If the callable for the scenario was cancelled, then the
|
||||
* result will contain an exception stating such.
|
||||
* <p>
|
||||
* If the scenario is still pending, then the optional will be empty.
|
||||
*
|
||||
* @param scenarioName the scenario name of interest
|
||||
* @return an optional result
|
||||
*/
|
||||
public Optional<Future<ScenarioResult>> getPendingResult(String scenarioName) {
|
||||
return Optional.ofNullable(submitted.get(scenarioName)).map(s -> s.resultFuture);
|
||||
}
|
||||
|
||||
public synchronized void stopScenario(String scenarioName) {
|
||||
this.stopScenario(scenarioName, false);
|
||||
}
|
||||
|
||||
public synchronized void stopScenario(String scenarioName, boolean rethrow) {
|
||||
logger.debug("#stopScenario(name=" + scenarioName + ", rethrow="+ rethrow+")");
|
||||
Optional<NBScenario> pendingScenario = getPendingScenario(scenarioName);
|
||||
if (pendingScenario.isPresent()) {
|
||||
pendingScenario.get().forceStopScenario(10000, true);
|
||||
} else {
|
||||
throw new RuntimeException("Unable to cancel scenario: " + scenarioName + ": not found");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void deleteScenario(String scenarioName) {
|
||||
stopScenario(scenarioName, false);
|
||||
|
||||
Optional<NBScenario> pendingScenario = getPendingScenario(scenarioName);
|
||||
if (pendingScenario.isPresent()) {
|
||||
submitted.remove(scenarioName);
|
||||
logger.info(() -> "cancelled scenario " + scenarioName);
|
||||
} else {
|
||||
throw new RuntimeException("Unable to cancel scenario: " + scenarioName + ": not found");
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public synchronized void shutdownNow() {
|
||||
if (!executor.isShutdown()) {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
private static class SubmittedScenario {
|
||||
private final NBScenario scenario;
|
||||
private final Future<ScenarioResult> resultFuture;
|
||||
|
||||
SubmittedScenario(NBScenario scenario, Future<ScenarioResult> resultFuture) {
|
||||
this.scenario = scenario;
|
||||
this.resultFuture = resultFuture;
|
||||
}
|
||||
|
||||
public NBScenario getScenario() {
|
||||
return scenario;
|
||||
}
|
||||
|
||||
Future<ScenarioResult> getResultFuture() {
|
||||
return resultFuture;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return scenario.getScenarioName();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void notifyException(Thread t, Throwable e) {
|
||||
logger.debug(() -> "Scenario executor uncaught exception: " + e.getMessage());
|
||||
this.stoppingException = new RuntimeException("Error in scenario thread " + t.getName(), e);
|
||||
}
|
||||
|
||||
public ScenarioResult run(NBScenario scenario, Map<String,String> params) {
|
||||
return scenario.apply(getNbSceneBuffer(params));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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.scenario.execution;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ScenariosResults {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(ScenariosResults.class);
|
||||
private final String scenariosExecutorName;
|
||||
private final Map<NBScenario, ScenarioResult> scenarioResultMap = new LinkedHashMap<>();
|
||||
|
||||
|
||||
public ScenariosResults(ScenariosExecutor scenariosExecutor) {
|
||||
this.scenariosExecutorName = scenariosExecutor.getName();
|
||||
}
|
||||
|
||||
public ScenariosResults(ScenariosExecutor scenariosExecutor, Map<NBScenario, ScenarioResult> map) {
|
||||
this.scenariosExecutorName = scenariosExecutor.getName();
|
||||
scenarioResultMap.putAll(map);
|
||||
}
|
||||
|
||||
public String getExecutionSummary() {
|
||||
String sb = "executions: " + scenarioResultMap.size() + " scenarios, " +
|
||||
scenarioResultMap.values().stream().filter(r -> r.getException()==null).count() + " normal, " +
|
||||
scenarioResultMap.values().stream().filter(r -> r.getException()!=null).count() + " errored";
|
||||
return sb;
|
||||
}
|
||||
|
||||
public ScenarioResult getOne() {
|
||||
if (this.scenarioResultMap.size() != 1) {
|
||||
throw new RuntimeException("getOne found " + this.scenarioResultMap.size() + " results instead of 1.");
|
||||
}
|
||||
return scenarioResultMap.values().stream().findFirst().orElseThrow(
|
||||
() -> new RuntimeException("Missing result."));
|
||||
}
|
||||
|
||||
public void reportToLog() {
|
||||
for (Map.Entry<NBScenario, ScenarioResult> entry : this.scenarioResultMap.entrySet()) {
|
||||
NBScenario scenario = entry.getKey();
|
||||
ScenarioResult oresult = entry.getValue();
|
||||
|
||||
logger.info(() -> "results for scenario: " + scenario);
|
||||
|
||||
// if (oresult != null) {
|
||||
// oresult.reportElapsedMillisToLog();
|
||||
// } else {
|
||||
// logger.error(scenario.getScenarioName() + ": incomplete (missing result)");
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasError() {
|
||||
return this.scenarioResultMap.values().stream()
|
||||
.anyMatch(r -> r.getException()!=null);
|
||||
}
|
||||
|
||||
public Optional<Exception> getAnyError() {
|
||||
return this.scenarioResultMap.values().stream()
|
||||
.map(ScenarioResult::getException).filter(Objects::nonNull).findFirst();
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return this.scenarioResultMap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return scenarioResultMap.values().stream().map(Object::toString).collect(Collectors.joining("\n"));
|
||||
}
|
||||
}
|
||||
@@ -16,33 +16,37 @@
|
||||
|
||||
package io.nosqlbench.engine.core.lifecycle.scenario.script;
|
||||
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneBuffer;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneFixtures;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandContext;
|
||||
|
||||
import javax.script.SimpleScriptContext;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
|
||||
public class BufferedScriptContext extends SimpleScriptContext {
|
||||
private final NBSceneFixtures fixtures;
|
||||
|
||||
public BufferedScriptContext(NBSceneFixtures fixtures) {
|
||||
this.fixtures = fixtures;
|
||||
Reader reader;
|
||||
Writer writer;
|
||||
Writer errorWriter;
|
||||
|
||||
public BufferedScriptContext(Writer writer, Writer errorWriter,Reader reader) {
|
||||
this.writer = writer;
|
||||
this.errorWriter = errorWriter;
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader getReader() { // stdin
|
||||
return fixtures.in();
|
||||
return this.reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer getWriter() { // stdout
|
||||
return fixtures.out();
|
||||
return this.writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Writer getErrorWriter() { // stderr
|
||||
return fixtures.err();
|
||||
return this.errorWriter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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.scenario.script;
|
||||
|
||||
import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine;
|
||||
import io.nosqlbench.engine.cmdstream.BasicScriptBuffer;
|
||||
import io.nosqlbench.engine.cmdstream.Cmd;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBBaseCommand;
|
||||
import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.activity.ActivitiesProgressIndicator;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandParams;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ContextActivitiesController;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Engine.Builder;
|
||||
import org.graalvm.polyglot.EnvironmentAccess;
|
||||
import org.graalvm.polyglot.HostAccess;
|
||||
import org.graalvm.polyglot.PolyglotAccess;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
|
||||
import javax.script.*;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.util.*;
|
||||
|
||||
public class NBScriptedCommand extends NBBaseCommand {
|
||||
private final Invocation invocation = Invocation.EXECUTE_SCRIPT;
|
||||
private final BasicScriptBuffer buffer;
|
||||
|
||||
private Exception error;
|
||||
|
||||
private ExecutionMetricsResult result;
|
||||
private BufferedScriptContext context;
|
||||
private GraalJSScriptEngine _engine;
|
||||
|
||||
public Optional<ExecutionMetricsResult> getResultIfComplete() {
|
||||
return Optional.ofNullable(result);
|
||||
}
|
||||
|
||||
public NBScriptedCommand add(BasicScriptBuffer otherBuf) {
|
||||
this.buffer.add(otherBuf);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public enum Invocation {
|
||||
RENDER_SCRIPT,
|
||||
EXECUTE_SCRIPT
|
||||
}
|
||||
|
||||
// private final List<String> scripts = new ArrayList<>();
|
||||
|
||||
private ActivitiesProgressIndicator activitiesProgressIndicator;
|
||||
private String progressInterval = "console:1m";
|
||||
// private ScenarioScriptShell scriptEnv;
|
||||
private final String phaseName;
|
||||
private NBCommandParams scenarioScenarioParams;
|
||||
private final Engine engine = Engine.Graalvm;
|
||||
private long startedAtMillis = -1L;
|
||||
private long endedAtMillis = -1L;
|
||||
|
||||
public enum Engine {
|
||||
Graalvm
|
||||
}
|
||||
|
||||
public NBScriptedCommand(
|
||||
NBBufferedCommandContext parentComponent,
|
||||
String phaseName,
|
||||
String targetScenario
|
||||
) {
|
||||
super(parentComponent, phaseName, targetScenario);
|
||||
this.phaseName = phaseName;
|
||||
this.progressInterval = progressInterval;
|
||||
this.buffer = new BasicScriptBuffer();
|
||||
}
|
||||
|
||||
public static NBScriptedCommand ofScripted(String name, Map<String, String> params, NBBufferedCommandContext parent, Invocation invocation) {
|
||||
return new NBScriptedCommand(parent, name, "default");
|
||||
}
|
||||
public NBScriptedCommand add(Cmd... cmds) {
|
||||
this.buffer.add(cmds);
|
||||
return this;
|
||||
}
|
||||
|
||||
// public NBScriptedCommand addScriptText(final String scriptText) {
|
||||
// this.scripts.add(scriptText);
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
|
||||
// public NBScriptedCommand addScriptFiles(final String... args) {
|
||||
// for (final String scriptFile : args) {
|
||||
// final Path scriptPath = Paths.get(scriptFile);
|
||||
// byte[] bytes = new byte[0];
|
||||
// try {
|
||||
// bytes = Files.readAllBytes(scriptPath);
|
||||
// } catch (final IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// final ByteBuffer bb = ByteBuffer.wrap(bytes);
|
||||
// final Charset utf8 = StandardCharsets.UTF_8;
|
||||
// final String scriptData = utf8.decode(bb).toString();
|
||||
// this.addScriptText(scriptData);
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
|
||||
private BufferedScriptContext initializeScriptContext(PrintWriter stdout, PrintWriter stderr, Reader stdin, ContextActivitiesController controller) {
|
||||
BufferedScriptContext ctx = new BufferedScriptContext(stdout, stderr, stdin);
|
||||
ctx.getBindings(ScriptContext.ENGINE_SCOPE).put("this", this);
|
||||
ctx.getBindings(ScriptContext.ENGINE_SCOPE).put("context", context);
|
||||
ctx.getBindings(ScriptContext.ENGINE_SCOPE).put("controller", controller);
|
||||
ctx.getBindings(ScriptContext.ENGINE_SCOPE).put("stdout", stdout);
|
||||
ctx.getBindings(ScriptContext.ENGINE_SCOPE).put("stderr", stderr);
|
||||
ctx.getBindings(ScriptContext.ENGINE_SCOPE).put("stdin", stdin);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
private GraalJSScriptEngine initializeScriptingEngine() {
|
||||
if (_engine == null) {
|
||||
final Context.Builder contextSettings = Context.newBuilder("js")
|
||||
.allowHostAccess(HostAccess.ALL)
|
||||
.allowNativeAccess(true)
|
||||
.allowCreateThread(true)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowHostClassLookup(s -> true)
|
||||
.allowHostClassLoading(true)
|
||||
.allowCreateProcess(true)
|
||||
.allowAllAccess(true)
|
||||
.allowEnvironmentAccess(EnvironmentAccess.INHERIT)
|
||||
.allowPolyglotAccess(PolyglotAccess.ALL)
|
||||
.option("js.ecmascript-version", "2022")
|
||||
.option("js.nashorn-compat", "true");
|
||||
|
||||
final Builder engineBuilder = org.graalvm.polyglot.Engine.newBuilder();
|
||||
engineBuilder.option("engine.WarnInterpreterOnly", "false");
|
||||
final org.graalvm.polyglot.Engine polyglotEngine = engineBuilder.build();
|
||||
this._engine = GraalJSScriptEngine.create(polyglotEngine, contextSettings);
|
||||
}
|
||||
return this._engine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(NBCommandParams params, PrintWriter stdout, PrintWriter stderr, Reader stdin, ContextActivitiesController controller) {
|
||||
try {
|
||||
this.logger.debug("Initializing scripting engine for {}.", phaseName);
|
||||
GraalJSScriptEngine engine = this.initializeScriptingEngine();
|
||||
this.context = this.initializeScriptContext(stdout, stderr, stdin, controller);
|
||||
this.logger.debug("Running control script for {}.", phaseName);
|
||||
engine.setContext(context);
|
||||
engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("params", params);
|
||||
|
||||
Object resultObject = null;
|
||||
|
||||
// for (final String script : this.scripts) {
|
||||
// if ((engine instanceof Compilable compilableEngine)) {
|
||||
// this.logger.debug("Using direct script compilation");
|
||||
// final CompiledScript compiled = compilableEngine.compile(script);
|
||||
// this.logger.debug("-> invoking main scenario script (compiled)");
|
||||
// resultObject = compiled.eval(this.context);
|
||||
// this.logger.debug("<- scenario script completed (compiled)");
|
||||
// } else {
|
||||
this.logger.debug("-> invoking main scenario script (interpreted)");
|
||||
// engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("this", this);
|
||||
// engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("params", params);
|
||||
// engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("context", context);
|
||||
// engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("controller", controller);
|
||||
// engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("stdout", stdout);
|
||||
// engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("stderr", stderr);
|
||||
// engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE).put("stdin", stdin);
|
||||
resultObject = engine.eval(buffer.getParsedScript());
|
||||
this.logger.debug("<- scenario control script completed (interpreted)");
|
||||
// }
|
||||
return resultObject;
|
||||
// }
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
this.endedAtMillis = System.currentTimeMillis();
|
||||
// this.logger.debug("{} scenario run", null == this.error ? "NORMAL" : "ERRORED");
|
||||
}
|
||||
// return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if ((null == o) || (this.getClass() != o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
final NBScriptedCommand scenario = (NBScriptedCommand) o;
|
||||
return Objects.equals(this.phaseName, scenario.phaseName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (null != this.phaseName) ? phaseName.hashCode() : 0;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return description();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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.scenario.script;
|
||||
|
||||
import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.engine.core.lifecycle.ExecutionMetricsResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.activity.ActivitiesProgressIndicator;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneFixtures;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioParams;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBScenario;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.script.bindings.PolyglotScenarioController;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Engine.Builder;
|
||||
import org.graalvm.polyglot.EnvironmentAccess;
|
||||
import org.graalvm.polyglot.HostAccess;
|
||||
import org.graalvm.polyglot.PolyglotAccess;
|
||||
|
||||
import javax.script.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
|
||||
public class NBScriptedScenario extends NBScenario {
|
||||
private final Invocation invocation = Invocation.EXECUTE_SCRIPT;
|
||||
|
||||
private Exception error;
|
||||
|
||||
private ExecutionMetricsResult result;
|
||||
private BufferedScriptContext context;
|
||||
|
||||
public Optional<ExecutionMetricsResult> getResultIfComplete() {
|
||||
return Optional.ofNullable(result);
|
||||
}
|
||||
|
||||
|
||||
public enum Invocation {
|
||||
RENDER_SCRIPT,
|
||||
EXECUTE_SCRIPT
|
||||
}
|
||||
|
||||
private final List<String> scripts = new ArrayList<>();
|
||||
private ScriptEngine scriptEngine;
|
||||
|
||||
private ActivitiesProgressIndicator activitiesProgressIndicator;
|
||||
private String progressInterval = "console:1m";
|
||||
// private ScenarioScriptShell scriptEnv;
|
||||
private final String scenarioName;
|
||||
private ScenarioParams scenarioScenarioParams;
|
||||
private final Engine engine = Engine.Graalvm;
|
||||
private long startedAtMillis = -1L;
|
||||
private long endedAtMillis = -1L;
|
||||
|
||||
public enum Engine {
|
||||
Graalvm
|
||||
}
|
||||
|
||||
public NBScriptedScenario(
|
||||
final String scenarioName,
|
||||
NBComponent parentComponent
|
||||
) {
|
||||
super(parentComponent, scenarioName);
|
||||
this.scenarioName = scenarioName;
|
||||
this.progressInterval = progressInterval;
|
||||
}
|
||||
|
||||
public static NBScriptedScenario ofScripted(String name, Map<String, String> params, NBComponent parent, Invocation invocation) {
|
||||
return new NBScriptedScenario(name, parent);
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
|
||||
public NBScriptedScenario addScriptText(final String scriptText) {
|
||||
this.scripts.add(scriptText);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public NBScriptedScenario addScriptFiles(final String... args) {
|
||||
for (final String scriptFile : args) {
|
||||
final Path scriptPath = Paths.get(scriptFile);
|
||||
byte[] bytes = new byte[0];
|
||||
try {
|
||||
bytes = Files.readAllBytes(scriptPath);
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
final ByteBuffer bb = ByteBuffer.wrap(bytes);
|
||||
final Charset utf8 = StandardCharsets.UTF_8;
|
||||
final String scriptData = utf8.decode(bb).toString();
|
||||
this.addScriptText(scriptData);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private BufferedScriptContext initializeScriptContext(NBSceneFixtures fixtures) {
|
||||
BufferedScriptContext ctx = new BufferedScriptContext(fixtures);
|
||||
// this.scriptEngine.setContext(ctx);
|
||||
ctx.getBindings(ScriptContext.ENGINE_SCOPE).put("scenario", new PolyglotScenarioController(fixtures.controller()));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
private void initializeScriptingEngine() {
|
||||
final Context.Builder contextSettings = Context.newBuilder("js")
|
||||
.allowHostAccess(HostAccess.ALL)
|
||||
.allowNativeAccess(true)
|
||||
.allowCreateThread(true)
|
||||
.allowIO(true)
|
||||
.allowHostClassLookup(s -> true)
|
||||
.allowHostClassLoading(true)
|
||||
.allowCreateProcess(true)
|
||||
.allowAllAccess(true)
|
||||
.allowEnvironmentAccess(EnvironmentAccess.INHERIT)
|
||||
.allowPolyglotAccess(PolyglotAccess.ALL)
|
||||
.option("js.ecmascript-version", "2022")
|
||||
.option("js.nashorn-compat", "true");
|
||||
|
||||
final Builder engineBuilder = org.graalvm.polyglot.Engine.newBuilder();
|
||||
engineBuilder.option("engine.WarnInterpreterOnly", "false");
|
||||
final org.graalvm.polyglot.Engine polyglotEngine = engineBuilder.build();
|
||||
scriptEngine = GraalJSScriptEngine.create(polyglotEngine, contextSettings);
|
||||
}
|
||||
|
||||
protected final void runScenario(NBSceneFixtures shell) {
|
||||
try {
|
||||
this.logger.debug("Initializing scripting engine for {}.", scenarioName);
|
||||
this.initializeScriptingEngine();
|
||||
this.context = this.initializeScriptContext(shell);
|
||||
this.logger.debug("Running control script for {}.", scenarioName);
|
||||
this.executeScenarioScripts();
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
this.endedAtMillis = System.currentTimeMillis();
|
||||
// this.logger.debug("{} scenario run", null == this.error ? "NORMAL" : "ERRORED");
|
||||
}
|
||||
// String iolog = error != null ? error.toString() : this.scriptEnv.getTimedLog();
|
||||
// result = new ExecutionMetricsResult(startedAtMillis, endedAtMillis, iolog, this.error);
|
||||
// this.result.reportMetricsSummaryToLog();
|
||||
}
|
||||
|
||||
private void executeScenarioScripts() throws ScriptException {
|
||||
for (final String script : this.scripts) {
|
||||
if ((scriptEngine instanceof Compilable compilableEngine)) {
|
||||
this.logger.debug("Using direct script compilation");
|
||||
final CompiledScript compiled = compilableEngine.compile(script);
|
||||
this.logger.debug("-> invoking main scenario script (compiled)");
|
||||
compiled.eval(this.context);
|
||||
this.logger.debug("<- scenario script completed (compiled)");
|
||||
} else {
|
||||
this.logger.debug("-> invoking main scenario script (interpreted)");
|
||||
this.scriptEngine.eval(script);
|
||||
this.logger.debug("<- scenario control script completed (interpreted)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if ((null == o) || (this.getClass() != o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
final NBScriptedScenario scenario = (NBScriptedScenario) o;
|
||||
return Objects.equals(this.scenarioName, scenario.scenarioName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (null != this.scenarioName) ? scenarioName.hashCode() : 0;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "name:'" + scenarioName + '\'';
|
||||
}
|
||||
|
||||
// public void addScenarioScriptParams(final ScriptParams scenarioScriptParams) {
|
||||
// this.scenarioScriptParams = scenarioScriptParams;
|
||||
// }
|
||||
|
||||
// public void addScenarioScriptParams(final Map<String, String> scriptParams) {
|
||||
// this.addScenarioScriptParams(new ScriptParams() {{
|
||||
// this.putAll(scriptParams);
|
||||
// }});
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,32 +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.scenario.script;
|
||||
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.ScenariosExecutor;
|
||||
|
||||
public class ScenarioExceptionHandler implements Thread.UncaughtExceptionHandler {
|
||||
private final ScenariosExecutor scenariosExecutor;
|
||||
|
||||
public ScenarioExceptionHandler(ScenariosExecutor scenariosExecutor) {
|
||||
this.scenariosExecutor = scenariosExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
scenariosExecutor.notifyException(t, e);
|
||||
}
|
||||
}
|
||||
@@ -15,12 +15,12 @@
|
||||
*/
|
||||
package io.nosqlbench.engine.core.lifecycle.scenario.script;
|
||||
|
||||
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBSceneFixtures;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScriptEnvBuffer;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandContext;
|
||||
|
||||
public class ScenarioScriptShell extends ScriptEnvBuffer {
|
||||
|
||||
public ScenarioScriptShell(NBSceneFixtures fixtures) {
|
||||
public ScenarioScriptShell(NBCommandContext fixtures) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package io.nosqlbench.engine.core.lifecycle.scenario.script.bindings;
|
||||
|
||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioActivitiesController;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ContextActivitiesController;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.graalvm.polyglot.Value;
|
||||
@@ -29,9 +29,9 @@ public class PolyglotScenarioController {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger("SCENARIO/POLYGLOT");
|
||||
|
||||
private final ScenarioActivitiesController controller;
|
||||
private final ContextActivitiesController controller;
|
||||
|
||||
public PolyglotScenarioController(ScenarioActivitiesController inner) {
|
||||
public PolyglotScenarioController(ContextActivitiesController inner) {
|
||||
this.controller = inner;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package io.nosqlbench.engine.core.lifecycle.session;
|
||||
|
||||
import io.nosqlbench.engine.cli.Cmd;
|
||||
import io.nosqlbench.engine.cmdstream.Cmd;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -59,8 +59,8 @@ public class CmdParamsBuffer {
|
||||
* @param cmd The command containing the new params to merge in
|
||||
*/
|
||||
private void combineGlobalParams(Map<String, String> scriptParams, Cmd cmd) {
|
||||
for (String newkey : cmd.getParams().keySet()) {
|
||||
String newvalue = cmd.getParams().get(newkey);
|
||||
for (String newkey : cmd.getArgs().keySet()) {
|
||||
String newvalue = cmd.getArgs().get(newkey).getValue();
|
||||
|
||||
if (scriptParams.containsKey(newkey)) {
|
||||
logger.warn("command '" + cmd.getCmdType() + "' overwrote param '" + newkey + " as " + newvalue);
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.errors.BasicError;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* <P>Take zero or more strings containing combined argv and return
|
||||
* a single {@link Cmd} list containing zero or more commands.</P>
|
||||
* <p>
|
||||
* {@see <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/wordexp.html">POSIX wordexp</a>},
|
||||
* of which this is a shallow substitute.</P>
|
||||
*/
|
||||
public class CmdParser {
|
||||
public final static String SYMBOLS = "`~!@#$%^&*(){}[]|+?!";
|
||||
|
||||
public static List<Cmd> parse(String... strings) {
|
||||
List<Cmd> cmds = new LinkedList<>();
|
||||
for (String string : strings) {
|
||||
cmds.addAll(parseCmdString(string));
|
||||
}
|
||||
return cmds;
|
||||
}
|
||||
|
||||
private record parameter(String name, String op, String value) {}
|
||||
private record command(String name){}
|
||||
private final static Pattern combinedPattern =
|
||||
Pattern.compile("(?<varname>[a-zA-Z_][a-zA-Z0-9_.-]+)(?<operator>=+)(?<value>.+)|(?<command>[a-zA-Z_][a-zA-Z0-9_.]+)",Pattern.DOTALL);
|
||||
private final static Pattern commandName =Pattern.compile("^$");
|
||||
public static LinkedList<Cmd> parseArgvCommands(LinkedList<String> args) {
|
||||
LinkedList<Record> cmdstructs = new LinkedList<>();
|
||||
LinkedList<Cmd> cmds = new LinkedList<>();
|
||||
|
||||
while (args.size()>0) {
|
||||
String arg=args.peekFirst();
|
||||
Matcher matcher = combinedPattern.matcher(arg);
|
||||
if (matcher.matches()) {
|
||||
args.removeFirst();
|
||||
String command = matcher.group("command");
|
||||
String varname = matcher.group("varname");
|
||||
String operator = matcher.group("operator");
|
||||
String value = matcher.group("value");
|
||||
cmdstructs.add(command!=null ? new command(command) : new parameter(varname,operator,value));
|
||||
} else {
|
||||
break;
|
||||
// throw new BasicError("Unable to parse arg as a command or an assignment: '"+arg+"'");
|
||||
}
|
||||
}
|
||||
while (!cmdstructs.isEmpty()) {
|
||||
if (cmdstructs.peekFirst() instanceof command cmd) {
|
||||
cmdstructs.removeFirst();
|
||||
Map<String,CmdArg> params = new LinkedHashMap<>();
|
||||
while (cmdstructs.peekFirst() instanceof parameter param) {
|
||||
cmdstructs.removeFirst();
|
||||
params.put(param.name(),CmdArg.of(cmd.name(),param.name(),param.op(),param.value()));
|
||||
}
|
||||
cmds.add(new Cmd(cmd.name(),params));
|
||||
} else {
|
||||
throw new BasicError("first word in argv is not a command: '" + cmdstructs.peekFirst() + "'");
|
||||
}
|
||||
}
|
||||
return cmds;
|
||||
}
|
||||
|
||||
public static enum PS {
|
||||
barename_start, barename, equals, barevalue, dquote, squote, end
|
||||
}
|
||||
|
||||
private static List<? extends Cmd> parseCmdString(String line) {
|
||||
List<Cmd> cmds = new LinkedList<>();
|
||||
LinkedHashMap<String, CmdArg> args = new LinkedHashMap<>();
|
||||
String cmdName = null;
|
||||
String varname = null, equals = null, value = null;
|
||||
StringBuilder buf = new StringBuilder(1024);
|
||||
PS state = PS.barename_start;
|
||||
int pos = -1;
|
||||
while (state != PS.end) {
|
||||
char at = 0;
|
||||
CharType type;
|
||||
if (++pos >= line.length()) {
|
||||
type = CharType.EOI;
|
||||
} else {
|
||||
at = line.charAt(pos);
|
||||
type = CharType.of(at);
|
||||
}
|
||||
if (type == CharType.unknown) throw new BasicError("Unknown character class for '" + at + "'");
|
||||
state = switch (state) {
|
||||
case barename_start -> switch (type) {
|
||||
case space -> PS.barename_start;
|
||||
case alpha, underscore -> {
|
||||
buf.setLength(0);
|
||||
buf.append(at);
|
||||
yield PS.barename;
|
||||
}
|
||||
case EOI -> {
|
||||
if (cmdName != null) {
|
||||
cmds.add(new Cmd(cmdName, args));
|
||||
}
|
||||
yield PS.end;
|
||||
}
|
||||
default -> PS_error(at, pos, state, type);
|
||||
};
|
||||
case barename -> switch (type) {
|
||||
case alpha, numeric, underscore, dot -> {
|
||||
buf.append(at);
|
||||
yield PS.barename;
|
||||
}
|
||||
case space -> {
|
||||
if (cmdName != null) cmds.add(new Cmd(cmdName, args));
|
||||
args = new LinkedHashMap<>();
|
||||
cmdName = buf.toString().trim();
|
||||
buf.setLength(0);
|
||||
yield PS.barename_start;
|
||||
}
|
||||
case EOI -> {
|
||||
cmds.add(new Cmd(buf.toString().trim(), args));
|
||||
yield PS.end;
|
||||
}
|
||||
case equals -> {
|
||||
if (cmdName == null)
|
||||
PS_error(at, pos, state, type, "parameter found while no command has been specified");
|
||||
varname = buf.toString();
|
||||
buf.setLength(0);
|
||||
buf.append(at);
|
||||
yield PS.equals;
|
||||
}
|
||||
default -> PS_error(at, pos, state, type);
|
||||
};
|
||||
case barevalue -> switch (type) {
|
||||
case space -> {
|
||||
value = buf.toString();
|
||||
args.put(varname, CmdArg.of(cmdName, varname, equals, value));
|
||||
varname = null;
|
||||
equals = null;
|
||||
buf.setLength(0);
|
||||
yield PS.barename_start;
|
||||
}
|
||||
case EOI -> {
|
||||
value = buf.toString();
|
||||
args.put(varname, CmdArg.of(cmdName, varname, equals, value));
|
||||
cmds.add(new Cmd(cmdName, args));
|
||||
varname = null;
|
||||
equals = null;
|
||||
buf.setLength(0);
|
||||
yield PS.end;
|
||||
}
|
||||
default -> {
|
||||
buf.append(at);
|
||||
yield PS.barevalue;
|
||||
}
|
||||
};
|
||||
case dquote -> switch (type) {
|
||||
case dquote -> {
|
||||
value = buf.toString();
|
||||
args.put(varname, CmdArg.of(cmdName, varname, equals, value));
|
||||
|
||||
varname = null;
|
||||
equals = null;
|
||||
buf.setLength(0);
|
||||
|
||||
yield PS.barename_start;
|
||||
}
|
||||
case EOI ->
|
||||
PS_error(at, pos, state, type, "reached end of input while reading double-quoted value");
|
||||
default -> {
|
||||
buf.append(at);
|
||||
yield PS.dquote;
|
||||
}
|
||||
};
|
||||
case squote -> switch (type) {
|
||||
case squote -> {
|
||||
|
||||
value = buf.toString();
|
||||
args.put(varname, CmdArg.of(cmdName, varname, equals, value));
|
||||
varname = null;
|
||||
equals = null;
|
||||
buf.setLength(0);
|
||||
yield PS.barename_start;
|
||||
}
|
||||
case EOI ->
|
||||
PS_error(at, pos, state, type, "reached end of input while reading single-quoted value");
|
||||
default -> {
|
||||
buf.append(at);
|
||||
yield PS.squote;
|
||||
}
|
||||
};
|
||||
case equals -> switch (type) {
|
||||
case equals -> {
|
||||
buf.append(at);
|
||||
yield PS.equals;
|
||||
}
|
||||
case dquote -> {
|
||||
equals = buf.toString();
|
||||
buf.setLength(0);
|
||||
yield PS.dquote;
|
||||
}
|
||||
case squote -> {
|
||||
equals = buf.toString();
|
||||
buf.setLength(0);
|
||||
yield PS.squote;
|
||||
}
|
||||
case alpha, numeric, underscore, symbol -> {
|
||||
equals = buf.toString();
|
||||
buf.setLength(0);
|
||||
buf.append(at);
|
||||
yield PS.barevalue;
|
||||
}
|
||||
default -> PS_error(at, pos, state, type);
|
||||
};
|
||||
case end ->
|
||||
throw new RuntimeException("Invalid fallthrough to end state. This should have been skipped");
|
||||
};
|
||||
}
|
||||
return cmds;
|
||||
|
||||
}
|
||||
|
||||
private static PS PS_error(char at, int pos, PS state, CharType type, String... msg) {
|
||||
throw new BasicError("invalid char '" + at + "' at position " + pos + " in parser state '" + state + "'"
|
||||
+ (type != null ? " for type '" + type.name() + "'" : "")
|
||||
+ ((msg.length > 0) ? " " + String.join(", ", Arrays.asList(msg)) : ""));
|
||||
}
|
||||
|
||||
private static enum CharType {
|
||||
alpha,
|
||||
numeric,
|
||||
squote,
|
||||
dquote,
|
||||
equals,
|
||||
underscore,
|
||||
space,
|
||||
dot,
|
||||
newline,
|
||||
symbol,
|
||||
EOI,
|
||||
unknown;
|
||||
|
||||
static CharType of(char c) {
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) return alpha;
|
||||
if ((c >= '0' && c <= '9')) return numeric;
|
||||
if (c == '_') return underscore;
|
||||
if (c == '.') return dot;
|
||||
if (c == '=') return equals;
|
||||
if (c == '\'') return squote;
|
||||
if (c == '"') return dquote;
|
||||
if (c == ' ' || c == '\t') return space;
|
||||
if (c == '\n' || c == '\r') return newline;
|
||||
if (SYMBOLS.indexOf(c) >= 0) return symbol;
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.engine.cmdstream.CmdParam;
|
||||
import io.nosqlbench.engine.cmdstream.CmdType;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.script.NBScriptedCommand;
|
||||
import io.nosqlbench.nb.annotations.Service;
|
||||
import io.nosqlbench.nb.api.nbio.Content;
|
||||
import io.nosqlbench.nb.api.nbio.NBIO;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service(value = NBInvokableResolver.class, selector = "autojs")
|
||||
public class NBAutoScriptResolver implements NBInvokableResolver {
|
||||
@Override
|
||||
public NBInvokableCommand resolve(Cmd cmd, NBBufferedCommandContext parent, String phaseName) {
|
||||
|
||||
Optional<Content<?>> scriptfile = NBIO.local()
|
||||
.searchPrefixes("scripts/auto")
|
||||
.pathname(cmd.getArgValue("_impl"))
|
||||
.extensionSet("js")
|
||||
.first();
|
||||
|
||||
if (scriptfile.isPresent()) {
|
||||
Path pathOf = scriptfile.get().asPath();
|
||||
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);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.*;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandParams;
|
||||
import io.nosqlbench.nb.api.errors.BasicError;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class NBCommandAssembly {
|
||||
|
||||
private final static Logger logger = LogManager.getLogger(NBCommandAssembly.class);
|
||||
|
||||
public static record CommandInvocation(NBInvokableCommand command, NBCommandParams params, String contextName) {
|
||||
}
|
||||
|
||||
public static List<CommandInvocation> assemble(List<Cmd> cmds, Function<String, NBBufferedCommandContext> ctxprovider) {
|
||||
List<Cmd> mappedCmds = tagCommandsWithContext(cmds);
|
||||
List<CommandInvocation> invocations = prepareMappedPhases(mappedCmds, ctxprovider);
|
||||
return invocations;
|
||||
}
|
||||
|
||||
private static List<Cmd> tagCommandsWithContext(List<Cmd> cmds) {
|
||||
LinkedList<Cmd> tagged = new LinkedList<>();
|
||||
String contextName = Cmd.DEFAULT_TARGET_CONTEXT;
|
||||
for (Cmd cmd : cmds) {
|
||||
|
||||
if (cmd.getArgs().containsKey("context")) {
|
||||
String ctx = cmd.getArgs().remove("context").getValue();
|
||||
String step = cmd.getArgs().containsKey("step") ? cmd.getArgs().remove("step").getValue() : "no-step";
|
||||
tagged.add(cmd.forTargetContext(ctx, step));
|
||||
} else if (cmd.getCmdType() == CmdType.context) {
|
||||
contextName = cmd.getArgValue("context_name");
|
||||
if (contextName.equals(Cmd.DEFAULT_TARGET_CONTEXT)) {
|
||||
logger.warn("You are explicitly setting the scenario name to " + Cmd.DEFAULT_TARGET_CONTEXT + "'. This is likely an error. " +
|
||||
"This is the default scenario name, and if you are using different scenario names you should pick something that is different and specific.");
|
||||
}
|
||||
} else {
|
||||
tagged.add(cmd.forTargetContext(contextName, null));
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(tagged);
|
||||
}
|
||||
|
||||
private static List<CommandInvocation> prepareMappedPhases(List<Cmd> mappedCmds, Function<String, NBBufferedCommandContext> ctxProvider) {
|
||||
List<CommandInvocation> parameterizedInvocations = new ArrayList<>();
|
||||
NBCoreInvokableResolver core_resolver = new NBCoreInvokableResolver();
|
||||
String basename = "phase_";
|
||||
int count = 0;
|
||||
for (Cmd cmd : mappedCmds) {
|
||||
count++;
|
||||
String phaseName = basename + count;
|
||||
|
||||
NBCommandParams params = switch (cmd.getCmdType()) {
|
||||
case indirect, java, context -> NBCommandParams.of(cmd.getArgMap());
|
||||
default -> NBCommandParams.of(Map.of());
|
||||
};
|
||||
|
||||
String targetContext = cmd.getTargetContext();
|
||||
NBInvokableCommand command = core_resolver.resolve(cmd, ctxProvider.apply(targetContext), phaseName);
|
||||
if (command==null) {
|
||||
throw new BasicError("Found zero commands for spec;" + cmd);
|
||||
}
|
||||
String contextName = cmd.getTargetContext();
|
||||
parameterizedInvocations.add(new CommandInvocation(command, params, contextName));
|
||||
}
|
||||
return parameterizedInvocations;
|
||||
}
|
||||
|
||||
// private static NBBaseCommand buildJavascriptCommand(List<Cmd> cmds, String targetScenario, NBBufferedCommandContext parent, String phaseName) {
|
||||
//// boolean dryrun;
|
||||
//// NBScriptedScenario.Invocation invocation = dryrun ?
|
||||
//// NBScriptedScenario.Invocation.RENDER_SCRIPT :
|
||||
//// NBScriptedScenario.Invocation.EXECUTE_SCRIPT;
|
||||
//
|
||||
// final ScriptBuffer buffer = new BasicScriptBuffer().add(cmds.toArray(new Cmd[0]));
|
||||
// final String scriptData = buffer.getParsedScript();
|
||||
//
|
||||
// final NBCommandParams cmdParams = new NBCommandParams();
|
||||
// cmdParams.putAll(buffer.getCombinedParams());
|
||||
//
|
||||
// final NBScriptedCommand cmd = new NBScriptedCommand(parent, phaseName, targetScenario);
|
||||
//
|
||||
// cmd.addScriptText(scriptData);
|
||||
// return cmd;
|
||||
// }
|
||||
|
||||
// private static NBBaseCommand buildJavaCommand(List<Cmd> cmds, NBComponent parent, String phaseName) {
|
||||
// if (cmds.size() != 1) {
|
||||
// throw new RuntimeException("java phases require exactly 1 java command");
|
||||
// }
|
||||
// Cmd javacmd = cmds.get(0);
|
||||
// NBBaseCommand cmd = (NBBaseCommand) NBJavaCommandLoader.init(javacmd.getArgValue("_impl"), parent, phaseName, javacmd.getTargetContext());
|
||||
// return cmd;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandParams;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
|
||||
import io.nosqlbench.nb.api.config.standard.TestComponent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class NBCommandInvoker {
|
||||
private final static Logger logger = LogManager.getLogger(NBCommandInvoker.class);
|
||||
|
||||
public static NBCommandResult invoke(NBInvokableCommand command, NBCommandParams params) {
|
||||
return invoke(createContext(),command,params);
|
||||
}
|
||||
|
||||
public static NBCommandResult invoke(NBBufferedCommandContext context, NBInvokableCommand command) {
|
||||
return invoke(context, command, NBCommandParams.of(Map.of()));
|
||||
}
|
||||
|
||||
private static NBBufferedCommandContext createContext() {
|
||||
return NBCommandContext.builder().name("testing").build(TestComponent.EMPTY_COMPONENT);
|
||||
}
|
||||
|
||||
public static NBCommandResult invoke(NBBufferedCommandContext context, NBInvokableCommand command, NBCommandParams params) {
|
||||
return command.invokeSafe(context,params);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.CmdType;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
|
||||
import io.nosqlbench.nb.annotations.Service;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This is the core wrapper around any resolvers for NB commands.
|
||||
* Call it directly and it will invoke all others in the runtime as long as they
|
||||
* are registered as a service for SPI.
|
||||
*/
|
||||
public class NBCoreInvokableResolver implements NBInvokableResolver {
|
||||
private final static String[] precedence = new String[]{"js", "java", "autojs"};
|
||||
private SequencedMap<String,NBInvokableResolver> resolvers = new LinkedHashMap<>();
|
||||
|
||||
@Override
|
||||
public NBInvokableCommand resolve(Cmd cmd, NBBufferedCommandContext parent, String phaseName) {
|
||||
for (NBInvokableResolver resolver : getResolvers().values()) {
|
||||
NBInvokableCommand loadedCommand = resolver.resolve(cmd, parent, phaseName);
|
||||
if (loadedCommand!=null) {
|
||||
return loadedCommand;
|
||||
}
|
||||
}
|
||||
// if (cmd.getCmdType() == CmdType.indirect) {
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
private SequencedMap<String, NBInvokableResolver> getResolvers() {
|
||||
if (this.resolvers == null || this.resolvers.isEmpty()) {
|
||||
SequencedMap<String,NBInvokableResolver> resolverMap = new LinkedHashMap<>();
|
||||
ServiceLoader<NBInvokableResolver> resolvers = ServiceLoader.load(NBInvokableResolver.class);
|
||||
for (NBInvokableResolver resolver : resolvers) {
|
||||
String selector = resolver.getClass().getAnnotation(Service.class).selector();
|
||||
resolverMap.put(selector,resolver);
|
||||
}
|
||||
for (int i = precedence.length-1; i >= 0; i--) {
|
||||
if (resolverMap.containsKey(precedence[i])) {
|
||||
NBInvokableResolver resolver = resolverMap.remove(precedence[i]);
|
||||
resolverMap.putFirst(precedence[i],resolver);
|
||||
}
|
||||
}
|
||||
this.resolvers = resolverMap;
|
||||
}
|
||||
return this.resolvers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.BasicScriptBuffer;
|
||||
import io.nosqlbench.engine.cmdstream.Cmd;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBInvokableCommand;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.script.NBScriptedCommand;
|
||||
import io.nosqlbench.nb.annotations.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service(value = NBInvokableResolver.class, selector = "js")
|
||||
public class NBScriptCommandResolver implements NBInvokableResolver {
|
||||
@Override
|
||||
public NBInvokableCommand resolve(Cmd cmd, NBBufferedCommandContext parent, String phaseName) {
|
||||
return switch (cmd.getCmdType()) {
|
||||
case run, await, forceStop, stop, start, waitMillis, fragment, script->
|
||||
new NBScriptedCommand(parent, phaseName, cmd.getTargetContext()).add(cmd);
|
||||
// case fragment ->
|
||||
// new NBScriptedCommand(parent, phaseName, cmd.getTargetContext()).addScriptText(cmd.getArgValue("fragment"));
|
||||
// case script ->
|
||||
// new NBScriptedCommand(parent, phaseName, cmd.getTargetContext()).addScriptFiles(cmd.getArgValue("path"));
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -16,32 +16,24 @@
|
||||
|
||||
package io.nosqlbench.engine.core.lifecycle.session;
|
||||
|
||||
import io.nosqlbench.api.engine.metrics.instruments.NBFunctionGauge;
|
||||
import io.nosqlbench.api.engine.metrics.instruments.NBMetricGauge;
|
||||
import io.nosqlbench.api.labels.NBLabeledElement;
|
||||
import io.nosqlbench.api.labels.NBLabels;
|
||||
import io.nosqlbench.components.NBComponent;
|
||||
import io.nosqlbench.components.NBBaseComponent;
|
||||
import io.nosqlbench.components.NBComponentSubScope;
|
||||
import io.nosqlbench.components.decorators.NBTokenWords;
|
||||
import io.nosqlbench.engine.cli.BasicScriptBuffer;
|
||||
import io.nosqlbench.engine.cli.Cmd;
|
||||
import io.nosqlbench.engine.cli.ScriptBuffer;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.nb.api.engine.metrics.instruments.NBFunctionGauge;
|
||||
import io.nosqlbench.nb.api.engine.metrics.instruments.NBMetricGauge;
|
||||
import io.nosqlbench.nb.api.labels.NBLabeledElement;
|
||||
import io.nosqlbench.nb.api.labels.NBLabels;
|
||||
import io.nosqlbench.nb.api.components.NBBaseComponent;
|
||||
import io.nosqlbench.nb.api.components.decorators.NBTokenWords;
|
||||
import io.nosqlbench.engine.cmdstream.Cmd;
|
||||
import io.nosqlbench.engine.core.clientload.*;
|
||||
import io.nosqlbench.engine.core.lifecycle.ExecutionResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.process.NBCLIErrorHandler;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.ScenarioParams;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBScenario;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.ScenariosExecutor;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.ScenariosResults;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.script.NBScriptedScenario;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandResult;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
@@ -55,20 +47,33 @@ public class NBSession extends NBBaseComponent implements Function<List<Cmd>, Ex
|
||||
private final String sessionName;
|
||||
private final ClientSystemMetricChecker clientMetricChecker;
|
||||
|
||||
private final Map<String, NBBufferedCommandContext> contexts = new ConcurrentHashMap<>();
|
||||
|
||||
public enum STATUS {
|
||||
OK,
|
||||
WARNING,
|
||||
ERROR
|
||||
}
|
||||
|
||||
private NBBufferedCommandContext getContext(String name) {
|
||||
return contexts.computeIfAbsent(
|
||||
name,
|
||||
n -> NBCommandContext.builder().name(n).build(this)
|
||||
);
|
||||
}
|
||||
|
||||
public NBSession(
|
||||
NBLabeledElement labelContext,
|
||||
String sessionName
|
||||
) {
|
||||
super(null, labelContext.getLabels().and("session", sessionName));
|
||||
super(
|
||||
null,
|
||||
labelContext.getLabels()
|
||||
.and("session", sessionName)
|
||||
);
|
||||
this.sessionName = sessionName;
|
||||
|
||||
this.clientMetricChecker = new ClientSystemMetricChecker(this, NBLabels.forKV(),10);
|
||||
this.clientMetricChecker = new ClientSystemMetricChecker(this, NBLabels.forKV(), 10);
|
||||
registerLoadAvgMetrics();
|
||||
registerMemInfoMetrics();
|
||||
// registerDiskStatsMetrics();
|
||||
@@ -78,109 +83,55 @@ public class NBSession extends NBBaseComponent implements Function<List<Cmd>, Ex
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes on scenario names:
|
||||
* <UL>
|
||||
* <LI>If none are provided, then all cmds are implicitly allocated to the "default" scenario.</LI>
|
||||
* <LI>If the name "default" is provided directly, then this is considered an error.</LI>
|
||||
* <LI>Otherwise, the most recently set scenario name is the one in which all following commands are run.</LI>
|
||||
* <LI></LI>
|
||||
* </UL>
|
||||
*
|
||||
* @param cmds
|
||||
* the function argument
|
||||
* @return
|
||||
*/
|
||||
public ExecutionResult apply(List<Cmd> cmds) {
|
||||
|
||||
if (cmds.isEmpty()) {
|
||||
logger.info("No commands provided.");
|
||||
}
|
||||
|
||||
Map<String, String> params = new CmdParamsBuffer(cmds).getGlobalParams();
|
||||
|
||||
// TODO: add context closing command
|
||||
// TODO: inject context closing commands after the last command referencing each context
|
||||
List<NBCommandAssembly.CommandInvocation> invocationCalls = NBCommandAssembly.assemble(cmds, this::getContext);
|
||||
ResultCollector collector = new ResultCollector();
|
||||
|
||||
try (ResultContext results = new ResultContext(collector)) {
|
||||
final ScenariosExecutor scenariosExecutor = new ScenariosExecutor(this, "executor-" + sessionName, 1);
|
||||
|
||||
NBScenario scenario;
|
||||
if (cmds.get(0).getCmdType().equals(Cmd.CmdType.java)) {
|
||||
scenario = buildJavaScenario(cmds);
|
||||
} else {
|
||||
scenario = buildJavacriptScenario(cmds);
|
||||
try (ResultContext results = new ResultContext(collector).ok()) {
|
||||
for (NBCommandAssembly.CommandInvocation invocation : invocationCalls) {
|
||||
try {
|
||||
String targetContext = invocation.contextName();
|
||||
NBBufferedCommandContext context = getContext(targetContext);
|
||||
NBCommandResult cmdResult = context.apply(invocation.command(), invocation.params());
|
||||
results.apply(cmdResult);
|
||||
} catch (Exception e) {
|
||||
String msg = "While running command '" + invocation.command() + "' in context '" + invocation.contextName() + "', an error occurred: " + e.toString();
|
||||
logger.error(msg);
|
||||
results.error(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
try (NBComponentSubScope scope = new NBComponentSubScope(scenario)) {
|
||||
scenariosExecutor.execute(scenario, params);
|
||||
// this.doReportSummaries(this.reportSummaryTo, this.result);
|
||||
} catch (Exception e) {
|
||||
results.error(e);
|
||||
}
|
||||
final ScenariosResults scenariosResults = scenariosExecutor.awaitAllResults();
|
||||
logger.debug(() -> "Total of " + scenariosResults.getSize() + " result object returned from ScenariosExecutor");
|
||||
|
||||
// logger.info(scenariosResults.getExecutionSummary());
|
||||
|
||||
if (scenariosResults.hasError()) {
|
||||
results.error(scenariosResults.getAnyError().orElseThrow());
|
||||
final Exception exception = scenariosResults.getOne().getException();
|
||||
logger.warn(scenariosResults.getExecutionSummary());
|
||||
NBCLIErrorHandler.handle(exception, true);
|
||||
System.err.println(exception.getMessage()); // TODO: make this consistent with ConsoleLogging sequencing
|
||||
}
|
||||
|
||||
results.output(scenariosResults.getExecutionSummary());
|
||||
results.ok();
|
||||
|
||||
}
|
||||
|
||||
for (String ctxName : contexts.keySet()) {
|
||||
NBBufferedCommandContext ctx = contexts.get(ctxName);
|
||||
logger.debug("awaiting end of activities in context '" + ctxName + "':" +
|
||||
ctx.controller().getActivityDefs().stream().map(ActivityDef::getAlias).toList());
|
||||
ctx.controller().shutdown();
|
||||
ctx.controller().awaitCompletion(Long.MAX_VALUE);
|
||||
logger.debug("completed");
|
||||
}
|
||||
|
||||
return collector.toExecutionResult();
|
||||
}
|
||||
|
||||
|
||||
private NBScenario buildJavacriptScenario(List<Cmd> cmds) {
|
||||
// boolean dryrun;
|
||||
// NBScriptedScenario.Invocation invocation = dryrun ?
|
||||
// NBScriptedScenario.Invocation.RENDER_SCRIPT :
|
||||
// NBScriptedScenario.Invocation.EXECUTE_SCRIPT;
|
||||
|
||||
final ScriptBuffer buffer = new BasicScriptBuffer().add(cmds.toArray(new Cmd[0]));
|
||||
final String scriptData = buffer.getParsedScript();
|
||||
|
||||
final ScenarioParams scenarioParams = new ScenarioParams();
|
||||
scenarioParams.putAll(buffer.getCombinedParams());
|
||||
|
||||
final NBScriptedScenario scenario = new NBScriptedScenario(sessionName, this);
|
||||
|
||||
scenario.addScriptText(scriptData);
|
||||
return scenario;
|
||||
}
|
||||
|
||||
private NBScenario buildJavaScenario(List<Cmd> cmds) {
|
||||
if (cmds.size() != 1) {
|
||||
throw new RuntimeException("java scenarios require exactly 1 java command");
|
||||
}
|
||||
Cmd javacmd = cmds.get(0);
|
||||
String mainClass = javacmd.getArg("main_class");
|
||||
|
||||
// This doesn't work as expected; The newest service loader docs are vague about Provider and no-args ctor requirements
|
||||
// and the code suggests that you still have to have one unless you are in a named module
|
||||
// SimpleServiceLoader<NBScenario> loader = new SimpleServiceLoader<>(NBScenario.class, Maturity.Any);
|
||||
// List<SimpleServiceLoader.Component<? extends NBScenario>> namedProviders = loader.getNamedProviders(mainClass);
|
||||
// SimpleServiceLoader.Component<? extends NBScenario> provider = namedProviders.get(0);
|
||||
// Class<? extends NBScenario> type = provider.provider.type();
|
||||
|
||||
Class<NBScenario> type;
|
||||
try {
|
||||
type = (Class<NBScenario>) Class.forName(mainClass);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
Constructor<? extends NBScenario> constructor = type.getConstructor(NBComponent.class, String.class);
|
||||
NBScenario scenario = constructor.newInstance(this, sessionName);
|
||||
return scenario;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void registerLoadAvgMetrics() {
|
||||
LoadAvgReader reader = new LoadAvgReader();
|
||||
if (!reader.fileExists())
|
||||
@@ -203,18 +154,18 @@ public class NBSession extends NBBaseComponent implements Function<List<Cmd>, Ex
|
||||
if (!reader.fileExists())
|
||||
return;
|
||||
|
||||
NBMetricGauge memTotalGauge = create().gauge("mem_total",reader::getMemTotalkB);
|
||||
NBMetricGauge memUsedGauge = create().gauge("mem_used",reader::getMemUsedkB);
|
||||
NBMetricGauge memFreeGauge = create().gauge("mem_free",reader::getMemFreekB);
|
||||
NBMetricGauge memAvailableGauge = create().gauge("mem_avaialble",reader::getMemAvailablekB);
|
||||
NBMetricGauge memCachedGauge = create().gauge("mem_cache",reader::getMemCachedkB);
|
||||
NBMetricGauge memTotalGauge = create().gauge("mem_total", reader::getMemTotalkB);
|
||||
NBMetricGauge memUsedGauge = create().gauge("mem_used", reader::getMemUsedkB);
|
||||
NBMetricGauge memFreeGauge = create().gauge("mem_free", reader::getMemFreekB);
|
||||
NBMetricGauge memAvailableGauge = create().gauge("mem_avaialble", reader::getMemAvailablekB);
|
||||
NBMetricGauge memCachedGauge = create().gauge("mem_cache", reader::getMemCachedkB);
|
||||
NBMetricGauge memBufferedGauge = create().gauge("mem_buffered", reader::getMemBufferskB);
|
||||
// add checking for percent memory used at some given time; TODO: Modify percent threshold
|
||||
clientMetricChecker.addRatioMetricToCheck(memUsedGauge, memTotalGauge, 90.0, false);
|
||||
|
||||
NBMetricGauge swapTotalGauge = create().gauge("swap_total", reader::getSwapTotalkB);
|
||||
NBMetricGauge swapFreeGauge = create().gauge("swap_free",reader::getSwapFreekB);
|
||||
NBMetricGauge swapUsedGauge = create().gauge("swap_used",reader::getSwapUsedkB);
|
||||
NBMetricGauge swapFreeGauge = create().gauge("swap_free", reader::getSwapFreekB);
|
||||
NBMetricGauge swapUsedGauge = create().gauge("swap_used", reader::getSwapUsedkB);
|
||||
}
|
||||
|
||||
private void registerDiskStatsMetrics() {
|
||||
@@ -223,9 +174,9 @@ public class NBSession extends NBBaseComponent implements Function<List<Cmd>, Ex
|
||||
return;
|
||||
|
||||
for (String device : reader.getDevices()) {
|
||||
create().gauge(device +"_transactions", () ->reader.getTransactionsForDevice(device));
|
||||
create().gauge(device +"_kB_read", () -> reader.getKbReadForDevice(device));
|
||||
create().gauge(device+"_kB_written", () -> reader.getKbWrittenForDevice(device));
|
||||
create().gauge(device + "_transactions", () -> reader.getTransactionsForDevice(device));
|
||||
create().gauge(device + "_kB_read", () -> reader.getKbReadForDevice(device));
|
||||
create().gauge(device + "_kB_written", () -> reader.getKbWrittenForDevice(device));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,10 +185,10 @@ public class NBSession extends NBBaseComponent implements Function<List<Cmd>, Ex
|
||||
if (!reader.fileExists())
|
||||
return;
|
||||
for (String iface : reader.getInterfaces()) {
|
||||
create().gauge(iface+"_rx_bytes",() -> reader.getBytesReceived(iface));
|
||||
create().gauge(iface+"_rx_packets",() -> reader.getPacketsReceived(iface));
|
||||
create().gauge(iface+"_tx_bytes",() -> reader.getBytesTransmitted(iface));
|
||||
create().gauge(iface+"_tx_packets",() -> reader.getPacketsTransmitted(iface));
|
||||
create().gauge(iface + "_rx_bytes", () -> reader.getBytesReceived(iface));
|
||||
create().gauge(iface + "_rx_packets", () -> reader.getPacketsReceived(iface));
|
||||
create().gauge(iface + "_tx_bytes", () -> reader.getBytesTransmitted(iface));
|
||||
create().gauge(iface + "_tx_packets", () -> reader.getPacketsTransmitted(iface));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +197,7 @@ public class NBSession extends NBBaseComponent implements Function<List<Cmd>, Ex
|
||||
if (!reader.fileExists())
|
||||
return;
|
||||
NBMetricGauge cpuUserGauge = create().gauge("cpu_user", reader::getUserTime);
|
||||
NBMetricGauge cpuSystemGauge = create().gauge("cpu_system",reader::getSystemTime);
|
||||
NBMetricGauge cpuSystemGauge = create().gauge("cpu_system", reader::getSystemTime);
|
||||
NBMetricGauge cpuIdleGauge = create().gauge("cpu_idle", reader::getIdleTime);
|
||||
NBMetricGauge cpuIoWaitGauge = create().gauge("cpu_iowait", reader::getIoWaitTime);
|
||||
NBMetricGauge cpuTotalGauge = create().gauge("cpu_total", reader::getTotalTime);
|
||||
|
||||
@@ -17,14 +17,16 @@
|
||||
package io.nosqlbench.engine.core.lifecycle.session;
|
||||
|
||||
import io.nosqlbench.engine.core.lifecycle.ExecutionResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandResult;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ResultContext implements AutoCloseable {
|
||||
private final Consumer<ResultContext> receiver;
|
||||
private ExecutionResult.Status status;
|
||||
|
||||
ResultContext(Consumer<ResultContext> receiver) {
|
||||
public ResultContext(Consumer<ResultContext> receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
@@ -33,12 +35,15 @@ public class ResultContext implements AutoCloseable {
|
||||
public final StringBuilder buf = new StringBuilder();
|
||||
private long stopMillis;
|
||||
|
||||
public void error(Exception error) {
|
||||
public ResultContext error(Exception error) {
|
||||
this.error = error;
|
||||
error();
|
||||
return this;
|
||||
}
|
||||
|
||||
public void output(CharSequence cs) {
|
||||
public ResultContext output(CharSequence cs) {
|
||||
buf.append(cs);
|
||||
return this;
|
||||
}
|
||||
public String output() {
|
||||
return buf.toString();
|
||||
@@ -60,11 +65,13 @@ public class ResultContext implements AutoCloseable {
|
||||
return new ExecutionResult(this.startMillis,this.stopMillis,buf.toString(), error);
|
||||
}
|
||||
|
||||
public void ok() {
|
||||
public ResultContext ok() {
|
||||
this.status= ExecutionResult.Status.OK;
|
||||
return this;
|
||||
}
|
||||
public void error() {
|
||||
public ResultContext error() {
|
||||
this.status= ExecutionResult.Status.ERROR;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long startMillis() {
|
||||
@@ -78,4 +85,15 @@ public class ResultContext implements AutoCloseable {
|
||||
public Exception getException() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public ResultContext apply(Supplier<ExecutionResult> resultSource) {
|
||||
ExecutionResult executionResult = resultSource.get();
|
||||
if (executionResult.getException()!=null) {
|
||||
this.error(executionResult.getException());
|
||||
output(executionResult.getIOLog());
|
||||
} else {
|
||||
this.ok();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package io.nosqlbench.engine.core.logging;
|
||||
|
||||
import io.nosqlbench.api.logging.NBLogLevel;
|
||||
import io.nosqlbench.nb.api.logging.NBLogLevel;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
@@ -198,10 +198,10 @@ public class LoggerConfig extends ConfigurationFactory {
|
||||
LayoutComponentBuilder logfileLayout = builder.newLayout("PatternLayout")
|
||||
.addAttribute("pattern", logfilePattern);
|
||||
|
||||
String filebase = getSessionName().replaceAll("\\s", "_");
|
||||
String logfilePath = loggerDir.resolve(filebase + ".log").toString();
|
||||
|
||||
String logfilePath = loggerDir.resolve(getFileBase() + ".log").toString();
|
||||
this.logfileLocation = logfilePath;
|
||||
String archivePath = loggerDir.resolve(filebase + "-TIMESTAMP.log.gz").toString()
|
||||
String archivePath = loggerDir.resolve(getFileBase() + "-TIMESTAMP.log.gz").toString()
|
||||
.replaceAll("TIMESTAMP", "%d{MM-dd-yy}");
|
||||
|
||||
ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
|
||||
@@ -218,8 +218,12 @@ public class LoggerConfig extends ConfigurationFactory {
|
||||
builder.add(logsAppenderBuilder);
|
||||
|
||||
if (isDedicatedVerificationLoggerEnabled) {
|
||||
var verificationLogfilePath = loggerDir.resolve(filebase + "_verification.log").toString();
|
||||
addResultVerificationLoggingChannel(builder, verificationLogfilePath);
|
||||
attachAuxLogger(builder, "VERIFY", fileLevel);
|
||||
}
|
||||
// TODO: build stop-words transcoder, add padding to end of alphabet, substitute stopwords
|
||||
|
||||
if (fileLevel.isInRange(Level.INFO,Level.TRACE)) {
|
||||
attachAuxLogger(builder, "RUNTIME", fileLevel);
|
||||
}
|
||||
|
||||
rootBuilder.add(
|
||||
@@ -256,6 +260,10 @@ public class LoggerConfig extends ConfigurationFactory {
|
||||
return builtConfig;
|
||||
}
|
||||
|
||||
private String getFileBase() {
|
||||
return getSessionName().replaceAll("\\s", "_");
|
||||
}
|
||||
|
||||
private String getSessionName() {
|
||||
return sessionName;
|
||||
}
|
||||
@@ -381,22 +389,23 @@ public class LoggerConfig extends ConfigurationFactory {
|
||||
return this;
|
||||
}
|
||||
|
||||
private void addResultVerificationLoggingChannel(ConfigurationBuilder<BuiltConfiguration> builder, String verificationLogfilePath) {
|
||||
var appenderName = "RESULTVERIFYLOG";
|
||||
private void attachAuxLogger(ConfigurationBuilder<BuiltConfiguration> builder, String loggerName, Level fileLevel) {
|
||||
String appenderName = loggerName+(("_APPENDER").toUpperCase());
|
||||
String fileName = loggerDir.resolve(getFileBase() + "_"+loggerName+".log").toString().toLowerCase();
|
||||
var appender = builder
|
||||
.newAppender(appenderName, FileAppender.PLUGIN_NAME)
|
||||
.addAttribute("append", false)
|
||||
.addAttribute("fileName", verificationLogfilePath)
|
||||
.addAttribute("fileName", fileName)
|
||||
.add(builder
|
||||
.newLayout("PatternLayout")
|
||||
.addAttribute("pattern", "%d %p %C{1.} [%t] %m%n")
|
||||
);
|
||||
var logger = builder
|
||||
.newLogger("VERIFY", Level.INFO)
|
||||
.newLogger(loggerName, fileLevel)
|
||||
.add(builder.newAppenderRef(appenderName))
|
||||
.addAttribute("additivity", false);
|
||||
|
||||
builder.add(appender);
|
||||
builder.add(logger);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
package io.nosqlbench.engine.core.metadata;
|
||||
|
||||
import io.nosqlbench.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.api.content.Content;
|
||||
import io.nosqlbench.api.content.NBIO;
|
||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.api.errors.BasicError;
|
||||
import io.nosqlbench.nb.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.nb.api.nbio.Content;
|
||||
import io.nosqlbench.nb.api.nbio.NBIO;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.nb.api.errors.BasicError;
|
||||
import io.nosqlbench.engine.api.activityapi.core.ActivityType;
|
||||
import io.nosqlbench.engine.core.lifecycle.activity.ActivityTypeLoader;
|
||||
import io.nosqlbench.nb.annotations.Service;
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
package io.nosqlbench.engine.core.metrics;
|
||||
|
||||
import io.nosqlbench.api.config.standard.*;
|
||||
import io.nosqlbench.nb.annotations.Service;
|
||||
import io.nosqlbench.api.annotations.Annotation;
|
||||
import io.nosqlbench.api.annotations.Annotator;
|
||||
import io.nosqlbench.nb.api.annotations.Annotation;
|
||||
import io.nosqlbench.nb.api.annotations.Annotator;
|
||||
import io.nosqlbench.nb.api.config.standard.*;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package io.nosqlbench.engine.core;
|
||||
|
||||
import io.nosqlbench.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.nb.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.engine.api.activityapi.core.*;
|
||||
import io.nosqlbench.engine.api.activityapi.input.Input;
|
||||
import io.nosqlbench.engine.api.activityapi.input.InputDispenser;
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package io.nosqlbench.engine.core;
|
||||
|
||||
import io.nosqlbench.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.nb.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
|
||||
import io.nosqlbench.engine.api.activityapi.core.Action;
|
||||
import io.nosqlbench.engine.api.activityapi.core.Activity;
|
||||
import io.nosqlbench.engine.api.activityapi.core.Motor;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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;
|
||||
|
||||
import io.nosqlbench.engine.cmdstream.Cmd;
|
||||
import io.nosqlbench.engine.cmdstream.CmdArg;
|
||||
import io.nosqlbench.engine.cmdstream.CmdParam;
|
||||
import io.nosqlbench.engine.core.lifecycle.session.NBCommandInvoker;
|
||||
import io.nosqlbench.engine.core.lifecycle.session.NBSession;
|
||||
import io.nosqlbench.nb.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.nb.api.components.NBComponent;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBBufferedCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandContext;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.context.NBCommandParams;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.script.NBScriptedCommand;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class NBBaseCommandTest {
|
||||
private final Logger logger = LogManager.getLogger(NBBaseCommandTest.class);
|
||||
|
||||
@Test
|
||||
public void shouldLoadScriptText() {
|
||||
NBBufferedCommandContext ctx = NBCommandContext.builder().name("testing").build(NBComponent.EMPTY_COMPONENT);
|
||||
NBScriptedCommand cmd = NBScriptedCommand.ofScripted("testing", Map.of(),ctx, NBScriptedCommand.Invocation.EXECUTE_SCRIPT);
|
||||
cmd.add(new Cmd("fragment",Map.of(
|
||||
"fragment",new CmdArg(new CmdParam("fragment",s->s,false),"=","print('loaded script environment...');")
|
||||
)));
|
||||
|
||||
try {
|
||||
NBCommandResult result = NBCommandInvoker.invoke(ctx,cmd);
|
||||
assertThat(result.getIOLog()).contains("loaded script environment...");
|
||||
} catch (Exception e) {
|
||||
logger.debug(() -> "Scenario run encountered an exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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;
|
||||
|
||||
import io.nosqlbench.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.ScenarioResult;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.ScenariosExecutor;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.script.NBScriptedScenario;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class NBScenarioTest {
|
||||
private final Logger logger = LogManager.getLogger(NBScenarioTest.class);
|
||||
|
||||
@Test
|
||||
public void shouldLoadScriptText() {
|
||||
NBScriptedScenario scenario = NBScriptedScenario.ofScripted("testing", Map.of(),new TestComponent(), NBScriptedScenario.Invocation.EXECUTE_SCRIPT);
|
||||
scenario.addScriptText("print('loaded script environment...');\n");
|
||||
try {
|
||||
ScenariosExecutor executor = new ScenariosExecutor(TestComponent.INSTANCE, "test", 1);
|
||||
executor.execute(scenario,Map.of());
|
||||
ScenarioResult result = executor.awaitAllResults().getOne();
|
||||
assertThat(result.getIOLog()).contains("loaded script environment...");
|
||||
} catch (Exception e) {
|
||||
logger.debug(() -> "Scenario run encountered an exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.CmdType;
|
||||
import io.nosqlbench.nb.api.errors.BasicError;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
// test for dots and underscores in names
|
||||
class CmdParserTest {
|
||||
|
||||
@Test
|
||||
public void testSingleCommand() {
|
||||
List<Cmd> cmds = CmdParser.parse("testcmd42");
|
||||
assertThat(cmds).hasSize(1);
|
||||
assertThat(cmds.get(0).getCmdType()).isEqualTo(CmdType.indirect);
|
||||
assertThat(cmds.get(0).getArgValue("_impl")).isEqualTo("testcmd42");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleCommandWithArgs() {
|
||||
List<Cmd> cmds = CmdParser.parse("testcmd43 param1=value1");
|
||||
assertThat(cmds).hasSize(1);
|
||||
assertThat(cmds.get(0).getCmdType()).isEqualTo(CmdType.indirect);
|
||||
assertThat(cmds.get(0).getArgValue("_impl")).isEqualTo("testcmd43");
|
||||
assertThat(cmds.get(0).getArgValue("param1")).isEqualTo("value1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleDquotedArg() {
|
||||
List<Cmd> cmds = CmdParser.parse("testcmd44 param1=\"value1\"");
|
||||
assertThat(cmds).hasSize(1);
|
||||
assertThat(cmds.get(0).getCmdType()).isEqualTo(CmdType.indirect);
|
||||
assertThat(cmds.get(0).getArgValue("_impl")).isEqualTo("testcmd44");
|
||||
assertThat(cmds.get(0).getArgValue("param1")).isEqualTo("value1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpecialSymbolValue() {
|
||||
List<Cmd> cmds = CmdParser.parse("start param1="+ CmdParser.SYMBOLS+ " param2='"+ CmdParser.SYMBOLS+ "' param3=\""+ CmdParser.SYMBOLS+ "\"");
|
||||
assertThat(cmds).hasSize(1);
|
||||
assertThat(cmds.get(0).getCmdType()).isEqualTo(CmdType.start);
|
||||
assertThat(cmds.get(0).getArgValue("param1")).isEqualTo(CmdParser.SYMBOLS);
|
||||
assertThat(cmds.get(0).getArgValue("param2")).isEqualTo(CmdParser.SYMBOLS);
|
||||
assertThat(cmds.get(0).getArgValue("param3")).isEqualTo(CmdParser.SYMBOLS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCatchesShortReadErrors() {
|
||||
assertThrows(BasicError.class,() -> CmdParser.parse("start param1=\"shortread"),
|
||||
"an error should be thrown if end of input is reached in the middle of a double-quoted value.");
|
||||
assertThrows(BasicError.class,() -> CmdParser.parse("start param1='shortread"),
|
||||
"an error should be thrown if end of input is reached in the middle of a single-quoted value.");
|
||||
assertThrows(BasicError.class,() -> CmdParser.parse("param1=value1"),
|
||||
"an error should be thrown if a named parameter is specified without a prior command.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThatSymbolsAreQuotedInStringForm() {
|
||||
List<Cmd> cmds = CmdParser.parse("start param1=value1 param2='~should be quoted'");
|
||||
assertThat(cmds.size()).isEqualTo(1);
|
||||
assertThat(cmds.get(0).getCmdType()).isEqualTo(CmdType.start);
|
||||
assertThat(cmds.get(0).getArgValue("param1")).isEqualTo("value1");
|
||||
assertThat(cmds.get(0).getArgValue("param2")).isEqualTo("~should be quoted");
|
||||
assertThat(cmds.get(0).toString()).isEqualTo("start param1=value1 param2='~should be quoted'");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicArgvParser() {
|
||||
LinkedList<Cmd> cmds = CmdParser.parseArgvCommands(new LinkedList<>(List.of("_cmd4", "param1=value1")));
|
||||
assertThat(cmds.size()).isEqualTo(1);
|
||||
assertThat(cmds.get(0).getCmdType()).isEqualTo(CmdType.indirect);
|
||||
assertThat(cmds.get(0).getArgValue("_impl")).isEqualTo("_cmd4");
|
||||
assertThat(cmds.get(0).getArgValue("param1")).isEqualTo("value1");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,8 +17,8 @@
|
||||
package io.nosqlbench.engine.core.metrics;
|
||||
|
||||
import com.codahale.metrics.Timer;
|
||||
import io.nosqlbench.api.labels.NBLabels;
|
||||
import io.nosqlbench.api.engine.metrics.DeltaHdrHistogramReservoir;
|
||||
import io.nosqlbench.nb.api.labels.NBLabels;
|
||||
import io.nosqlbench.nb.api.engine.metrics.DeltaHdrHistogramReservoir;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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.script;
|
||||
|
||||
import io.nosqlbench.api.config.standard.TestComponent;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.ScenariosExecutor;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.execution.ScenariosResults;
|
||||
import io.nosqlbench.engine.core.lifecycle.scenario.script.NBScriptedScenario;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ScenariosExecutorTest {
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void testAwaitOnTime() {
|
||||
ScenariosExecutor e = new ScenariosExecutor(new TestComponent("id","test-await-on-time"),ScenariosExecutorTest.class.getSimpleName(), 1);
|
||||
NBScriptedScenario scenario = NBScriptedScenario.ofScripted("testing", Map.of(),new TestComponent("scripted-scenario","scripted-scenario"), NBScriptedScenario.Invocation.EXECUTE_SCRIPT);
|
||||
scenario.addScriptText("load('classpath:scripts/asyncs.js');\nsetTimeout(\"print('waited')\",5000);\n");
|
||||
e.execute(scenario,Map.of());
|
||||
ScenariosResults scenariosResults = e.awaitAllResults();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user