Refactor ConfigModel Construction in StandardActivity (#2104)

* Refactor ConfigModel Construction in StandardActivity

* Tracking ConfigModel Param Classes

* ActivityDef ConfigMap and default ActivityDriver

* More complete config model for ActivityDef plus other small improvements

* Add NBAdvisor to StandardActivity

* NBAdvisor for Workload Params, Tags, and Bindings

* OF: Formatting

* Improve ActivityDef ConfigModel

* Refactor NBAdvisor output adding Debug level

* NBAdvisor output using fluent method

* Slight refactor and always fail condition

* SrInterpolator uses NBAdvisorPoint and NBAdvisorOutput improvements

* Check Cmd with NBAdvisor

* Add Advisor Name and Description to Logs

* Fix review comments
This commit is contained in:
Dave Fisher 2024-12-13 07:31:22 -08:00 committed by GitHub
parent 4f88f832a8
commit b6d437dcf0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 388 additions and 206 deletions

View File

@ -16,13 +16,14 @@
package io.nosqlbench.adapters.api.templating;
import io.nosqlbench.nb.api.advisor.NBAdvisorBuilder;
import io.nosqlbench.nb.api.advisor.NBAdvisorPoint;
import io.nosqlbench.nb.api.advisor.conditions.Conditions;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.advisor.NBAdvisorOutput;
import org.apache.commons.text.StrLookup;
import org.apache.commons.text.StringSubstitutor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Level;
import java.util.regex.Pattern;
import java.util.*;
@ -30,7 +31,8 @@ import java.util.function.Function;
public class StrInterpolator implements Function<String, String> {
private final static Logger logger = LogManager.getLogger(StrInterpolator.class);
private final NBAdvisorBuilder<String> advisorBuilder = new NBAdvisorBuilder<String>();
private NBAdvisorPoint<String> advisor;
private final MultiMap multimap = new MultiMap();
private final StringSubstitutor substitutor =
new StringSubstitutor(multimap, "<<", ">>", '\\')
@ -60,6 +62,8 @@ public class StrInterpolator implements Function<String, String> {
@Override
public String apply(String raw) {
advisor = advisorBuilder.build();
advisor.add(Conditions.DeprecatedWarning);
String[] lines = raw.split("\\R");
boolean endsWithNewline = raw.endsWith("\n");
int i = 0;
@ -76,6 +80,7 @@ public class StrInterpolator implements Function<String, String> {
if (endsWithNewline) {
results += System.lineSeparator();
}
advisor.setName("Workload", "Deprecated template format").logName().evaluate();
return results;
}
@ -165,7 +170,7 @@ public class StrInterpolator implements Function<String, String> {
// Process << ... >>
String after = substitutor.replace(line);
while (!after.equals(line)) {
NBAdvisorOutput.test("<<key:value>> deprecated in "+line);
advisor.validate("<<key:value>> in "+line);
line = after;
after = substitutor.replace(line);
}

View File

@ -2,13 +2,13 @@ package io.nosqlbench.nb.api.advisor;
/*
* Copyright (c) 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
@ -22,30 +22,25 @@ import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Level;
public class NBAdvisorOutput {
private final static Logger logger = LogManager.getLogger("ADVISOR");
private static final Logger logger = LogManager.getLogger("ADVISOR");
public static void test(String message) {
if (NBAdvisorLevel.get() == NBAdvisorLevel.enforce) {
output(Level.ERROR, message);
throw new NBAdvisorException(message, 2);
} else if (NBAdvisorLevel.get() == NBAdvisorLevel.validate) {
output(Level.WARN, message);
}
}
public static void render(Level level,String message) {
if (NBAdvisorLevel.get() == NBAdvisorLevel.validate) {
output(level, message);
}
}
public static void test(String message) {
if (NBAdvisorLevel.get() == NBAdvisorLevel.enforce) {
output(Level.ERROR, message);
throw new NBAdvisorException(message, 2);
}
output(Level.WARN, message);
}
public static void output(Level level,String message) {
if (level == Level.INFO) {
NBAdvisorOutput.logger.info(message);
} else if (level == Level.WARN) {
NBAdvisorOutput.logger.warn(message);
} else if (level == Level.ERROR) {
NBAdvisorOutput.logger.error(message);
}
logger.log(level,message);
}
}

View File

@ -28,14 +28,14 @@ public class NBAdvisorPoint<T> extends NBAdvisorPointOrBuilder<T> {
private final static Logger logger = LogManager.getLogger("ADVISOR");
private final String name;
private final String description;
private String name;
private String description;
private NBAdvisorLevel advisorLevel = NBAdvisorLevel.none;
private NBAdvisorCondition<T>[] conditions = new NBAdvisorCondition[0];
private List<Result<?>> resultLog = new ArrayList<Result<?>>();
public NBAdvisorPoint(String name) {
this(name, null);
this(name, "");
}
public NBAdvisorPoint(String name, String description) {
@ -44,6 +44,18 @@ public class NBAdvisorPoint<T> extends NBAdvisorPointOrBuilder<T> {
this.advisorLevel = NBAdvisorLevel.get();
}
public NBAdvisorPoint<T> add(NBAdvisorCondition<T> condition) {
_addArrayCondition(condition);
return this;
}
private void _addArrayCondition(NBAdvisorCondition<T> condition) {
NBAdvisorCondition<T>[] newConditions = new NBAdvisorCondition[conditions.length + 1];
System.arraycopy(conditions, 0, newConditions, 0, conditions.length);
newConditions[newConditions.length - 1] = condition;
conditions = newConditions;
}
public Result<T>[] validateAll(Collection<T> elements) {
List<Result<T>> buffer = new ArrayList<>();
for (T element : elements) {
@ -68,8 +80,27 @@ public class NBAdvisorPoint<T> extends NBAdvisorPointOrBuilder<T> {
return this.resultLog;
}
public NBAdvisorPoint<T> add(NBAdvisorCondition<T> condition) {
_addArrayCondition(condition);
public NBAdvisorPoint<T> evaluate() {
NBAdvisorResults advisorResults = new NBAdvisorResults(List.of(this));
advisorResults.evaluate();
return this;
}
public NBAdvisorPoint<T> clear() {
this.resultLog.clear();
return this;
}
public NBAdvisorPoint<T> setName(String name, String description) {
this.name = name;
this.description = description;
return this;
}
public NBAdvisorPoint<T> logName() {
if (resultLog.size() > 0) {
logger.info("Advisor: " + name + ": " + description);
}
return this;
}
@ -78,14 +109,6 @@ public class NBAdvisorPoint<T> extends NBAdvisorPointOrBuilder<T> {
return Arrays.stream(results).filter(Result::isError).map(Result::rendered).toArray(String[]::new);
}
private void _addArrayCondition(NBAdvisorCondition<T> condition) {
NBAdvisorCondition<T>[] newConditions = new NBAdvisorCondition[conditions.length + 1];
System.arraycopy(conditions, 0, newConditions, 0, conditions.length);
newConditions[newConditions.length - 1] = condition;
conditions = newConditions;
}
public static enum Status {
OK,
ERROR
@ -103,7 +126,7 @@ public class NBAdvisorPoint<T> extends NBAdvisorPointOrBuilder<T> {
public Level conditionLevel() {
return condition.level();
}
public String rendered() {
return switch (status) {
case OK -> "OK: " + condition.okMsg().apply(element);

View File

@ -2,13 +2,13 @@ package io.nosqlbench.nb.api.advisor;
/*
* Copyright (c) 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
@ -37,16 +37,6 @@ public class NBAdvisorResults {
return points.stream().flatMap(a -> a.getResultLog().stream()).toList();
}
public void render(Level level,String message) {
if (level == Level.INFO) {
logger.info(message);
} else if (level == Level.WARN) {
logger.warn(message);
} else if (level == Level.ERROR) {
logger.error(message);
}
}
public int evaluate() {
List<NBAdvisorPoint.Result<?>> results = getAdvisorResults();
Iterator<NBAdvisorPoint.Result<?>> iterator = results.iterator();
@ -59,23 +49,25 @@ public class NBAdvisorResults {
switch (NBAdvisorLevel.get()) {
case NBAdvisorLevel.none:
if ( level == Level.ERROR ) {
render(level, result.rendered());
NBAdvisorOutput.output(level, result.rendered());
count++;
terminate = true;
} else {
NBAdvisorOutput.output(Level.DEBUG, result.rendered());
}
break;
case NBAdvisorLevel.validate:
if ( level == Level.ERROR ) {
render(level, result.rendered());
NBAdvisorOutput.output(level, result.rendered());
count++;
terminate = true;
} else {
render(Level.INFO, result.rendered());
NBAdvisorOutput.output(level, result.rendered());
}
break;
case NBAdvisorLevel.enforce:
if ( level == Level.ERROR || level == Level.WARN ) {
render(level, result.rendered());
NBAdvisorOutput.output(level, result.rendered());
count++;
terminate = true;
}
@ -86,7 +78,7 @@ public class NBAdvisorResults {
String message = String.format("Advisor found %d actionable %s.",
count,
(count < 2 ? "error" : "errors"));
render(Level.ERROR, message);
NBAdvisorOutput.output(Level.ERROR, message);
throw new NBAdvisorException(message, 2);
}
return count;

View File

@ -18,7 +18,6 @@ package io.nosqlbench.nb.api.advisor.conditions;
*/
import io.nosqlbench.nb.api.advisor.NBAdvisorCondition;
import org.apache.logging.log4j.Level;
/**
@ -48,5 +47,9 @@ public class Conditions {
public static NoHyphens NoHyphensWarning = new NoHyphens(Level.WARN);
public static NoSpaces NoSpacesError = new NoSpaces(Level.ERROR);
public static NoSpaces NoSpacesWarning = new NoSpaces(Level.WARN);
public static ValidName ValidNameError = new ValidName(Level.ERROR);
public static ValidName ValidNameWarning = new ValidName(Level.WARN);
public static Deprecated DeprecatedError = new Deprecated(Level.ERROR);
public static Deprecated DeprecatedWarning = new Deprecated(Level.WARN);
}

View File

@ -0,0 +1,57 @@
package io.nosqlbench.nb.api.advisor.conditions;
/*
* Copyright (c) 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.
*/
import io.nosqlbench.nb.api.advisor.NBAdvisorCondition;
import org.apache.logging.log4j.Level;
import java.util.function.Function;
public class Deprecated implements NBAdvisorCondition<String> {
private final Level level;
public Deprecated(Level level) {
this.level = level;
}
@Override
public Function<String, String> okMsg() {
return string -> "Valid '" + string + "'";
}
@Override
public Function<String, String> errMsg() {
return string -> "Deprecated '" +string + "'";
}
@Override
public Level level() {
return level;
}
@Override
public String getName() {
return "failure";
}
@Override
public boolean test(String s) {
return true;
}
}

View File

@ -0,0 +1,62 @@
package io.nosqlbench.nb.api.advisor.conditions;
/*
* Copyright (c) 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.
*/
import io.nosqlbench.nb.api.advisor.NBAdvisorCondition;
import org.apache.logging.log4j.Level;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ValidName implements NBAdvisorCondition<String> {
private final static Pattern pattern = Pattern.compile("\\$\\{(?<name>[a-zA-Z_][a-zA-Z0-9_.]*)}");
private final Level level;
public ValidName(Level level) {
this.level = level;
}
@Override
public Function<String, String> okMsg() {
return string -> "String '" + string + "' is a valid name";
}
@Override
public Function<String, String> errMsg() {
return string -> "String '" +string + "' is not a valid name";
}
@Override
public Level level() {
return level;
}
@Override
public String getName() {
return "valid name";
}
@Override
public boolean test(String s) {
return pattern.matcher(s).matches();
}
}

View File

@ -66,6 +66,8 @@ public class NBBaseComponent extends NBBaseComponentMetrics implements NBCompone
labelsAdvisor.validateAll(componentSpecificLabelsOnly.asMap().keySet());
labelsAdvisor.validateAll(componentSpecificLabelsOnly.asMap().values());
labelsAdvisor.setName("Labels", "Check label names and values")
.logName();
NBAdvisorResults advisorResults = getAdvisorResults();
advisorResults.evaluate();

View File

@ -1,24 +0,0 @@
/*
* Copyright (c) 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.nb.api.config;
import io.nosqlbench.nb.api.labels.NBLabeledElement;
import javax.script.ScriptContext;
public interface LabeledScenarioContext extends ScriptContext, NBLabeledElement {
}

View File

@ -17,6 +17,8 @@
package io.nosqlbench.nb.api.config.standard;
import io.nosqlbench.nb.api.errors.BasicError;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.math.BigDecimal;
import java.util.*;
@ -24,7 +26,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class ConfigModel implements NBConfigModel {
private static final Logger logger = LogManager.getLogger("CONFIGMODEL");
private final Map<String, Param<?>> paramsByName = new LinkedHashMap<>();
private final List<Param<?>> params = new ArrayList<>();
private Param<?> lastAdded = null;
@ -47,10 +49,13 @@ public class ConfigModel implements NBConfigModel {
}
public <T> ConfigModel add(Param<T> param) {
this.params.add(param);
for (String name : param.getNames()) {
if (paramsByName.containsKey(name)) {
return this;
}
paramsByName.put(name, param);
}
this.params.add(param);
lastAdded = null;
return this;
}
@ -162,6 +167,7 @@ public class ConfigModel implements NBConfigModel {
Map<String, Param<?>> namedParams = getNamedParams();
for (String providedCfgField : sharedConfig.keySet()) {
if (namedParams.containsKey(providedCfgField)) {
namedParams.get(providedCfgField).addLayer("StandardActivity");
extracted.put(providedCfgField, sharedConfig.get(providedCfgField));
}
}
@ -178,21 +184,6 @@ public class ConfigModel implements NBConfigModel {
return matchConfig(cfg.getMap());
}
private void assertDistinctSynonyms(Map<String, ?> config) {
List<String> names = new ArrayList<>();
for (Param<?> param : getParams()) {
names.clear();
for (String s : param.getNames()) {
if (config.containsKey(s)) {
names.add(s);
}
}
if (names.size() > 1) {
throw new NBConfigError("Multiple names for the same parameter were provided: " + names);
}
}
}
@Override
public NBConfiguration apply(Map<String, ?> config) {
ConfigModel expanded = expand(this, config);
@ -230,6 +221,7 @@ public class ConfigModel implements NBConfigModel {
@Override
public void assertValidConfig(Map<String, ?> config) {
ConfigModel expanded = expand(this, config);
//expanded.print();
expanded.assertRequiredFields(config);
expanded.assertNoExtraneousFields(config);
expanded.assertDistinctSynonyms(config);
@ -238,7 +230,6 @@ public class ConfigModel implements NBConfigModel {
private ConfigModel expand(ConfigModel configModel, Map<String, ?> config) {
List<Param<?>> expanders = configModel.params.stream()
.filter(p -> p.getExpander() != null).toList();
for (Param<?> expandingParameter : expanders) {
for (String name : expandingParameter.getNames()) {
if (config.containsKey(name)) {
@ -275,7 +266,6 @@ public class ConfigModel implements NBConfigModel {
if (param.isRequired() && param.getDefaultValue() == null) {
boolean provided = false;
for (String name : param.getNames()) {
if (config.containsKey(name)) {
provided = true;
break;
@ -306,10 +296,8 @@ public class ConfigModel implements NBConfigModel {
"Unknown config parameter '" + configkey + "' in config model while configuring " + getOf().getSimpleName()
+ ", possible parameter names are " + this.paramsByName.keySet() + "."
);
ConfigSuggestions.getForParam(this, configkey)
.ifPresent(suggestion -> paramhelp.append(" ").append(suggestion));
throw new BasicError(paramhelp.toString());
}
}
@ -317,20 +305,42 @@ public class ConfigModel implements NBConfigModel {
}
}
private void assertDistinctSynonyms(Map<String, ?> config) {
List<String> names = new ArrayList<>();
for (Param<?> param : getParams()) {
names.clear();
for (String s : param.getNames()) {
if (config.containsKey(s)) {
names.add(s);
}
}
if (names.size() > 1) {
throw new NBConfigError("Multiple names for the same parameter were provided: " + names);
}
}
}
@Override
public ConfigModel add(NBConfigModel otherModel) {
String layer = otherModel.getOf().getSimpleName();
for (Param<?> param : otherModel.getParams()) {
param.addLayer(layer);
add(param);
}
return this;
}
@Override
public void log() {
logger.debug(() -> "ConfigModel: "+ofType);
for (Param<?> param : getParams()) logger.debug(() -> "ConfigModel: " + param);
}
@Override
public String toString() {
String sb = "[" +
params.stream().map(p -> p.getNames().get(0)).collect(Collectors.joining(",")) +
"]";
return sb;
}
}

View File

@ -73,4 +73,5 @@ public interface NBConfigModel {
NBConfigModel add(NBConfigModel otherModel);
void log();
}

View File

@ -16,6 +16,7 @@
package io.nosqlbench.nb.api.config.standard;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -35,6 +36,7 @@ public class Param<T> {
public boolean required;
private Pattern regex;
private final NBConfigModelExpander expander;
private List<String> layers;
public Param(
List<String> names,
@ -50,6 +52,7 @@ public class Param<T> {
this.required = required;
this.defaultValue = defaultValue;
this.expander = expander;
this.layers = new ArrayList<String>();
}
/**
@ -179,12 +182,13 @@ public class Param<T> {
@Override
public String toString() {
return "Element{" +
return "Param{" +
"names='" + names.toString() + '\'' +
", type=" + type +
", description='" + description + '\'' +
", required=" + required +
", defaultValue = " + defaultValue +
", layers = " + layers.toString() +
'}';
}
@ -232,6 +236,25 @@ public class Param<T> {
return regex;
}
public Param<T> addLayer(String layer) {
if (!containsLayer(layer)) {
this.layers.add(layer);
}
return this;
}
public List<String> getLayers() {
return layers;
}
public boolean hasLayers() {
return layers != null && !layers.isEmpty();
}
public boolean containsLayer(String layer) {
return layers.contains(layer);
}
public CheckResult<T> validate(Object value) {
if (value == null) {

View File

@ -17,6 +17,9 @@
package io.nosqlbench.nb.api.engine.activityimpl;
import io.nosqlbench.nb.api.components.core.NBNamedElement;
import io.nosqlbench.nb.api.config.standard.ConfigModel;
import io.nosqlbench.nb.api.config.standard.NBConfigModel;
import io.nosqlbench.nb.api.config.standard.Param;
import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.nb.api.labels.NBLabelSpec;
import io.nosqlbench.nb.api.labels.NBLabels;
@ -24,6 +27,9 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
@ -67,14 +73,14 @@ public class ActivityDef implements NBNamedElement {
this.parameterMap = parameterMap;
}
public static Optional<ActivityDef> parseActivityDefOptionally(String namedActivitySpec) {
try {
ActivityDef activityDef = parseActivityDef(namedActivitySpec);
return Optional.of(activityDef);
} catch (Exception e) {
return Optional.empty();
}
}
//public static Optional<ActivityDef> parseActivityDefOptionally(String namedActivitySpec) {
// try {
// ActivityDef activityDef = parseActivityDef(namedActivitySpec);
// return Optional.of(activityDef);
// } catch (Exception e) {
// return Optional.empty();
// }
//}
public static ActivityDef parseActivityDef(String namedActivitySpec) {
Optional<ParameterMap> activityParameterMap = ParameterMap.parseParams(namedActivitySpec);
@ -99,7 +105,12 @@ public class ActivityDef implements NBNamedElement {
return parameterMap.getOptionalString("alias").orElse(DEFAULT_ALIAS);
}
public String getActivityType() {
/**
* Return tbe Activity Driver Adapter Name
*
* @return the driver adapter name
*/
public String getActivityDriver() {
return parameterMap.getOptionalString("type", "driver").orElse(DEFAULT_ATYPE);
}
@ -193,7 +204,6 @@ public class ActivityDef implements NBNamedElement {
}
private void checkInvariants() {
if (getStartCycle() >= getEndCycle()) {
throw new InvalidParameterException("Start cycle must be strictly less than end cycle, but they are [" + getStartCycle() + ',' + getEndCycle() + ')');
@ -214,7 +224,9 @@ public class ActivityDef implements NBNamedElement {
if (this.parameterMap.containsKey(newName)) {
throw new BasicError("You have specified activity param '" + deprecatedName + "' in addition to the valid name '" + newName + "'. Remove '" + deprecatedName + "'.");
}
logger.warn("Auto replacing deprecated activity param '{}={}' with new '{}={}'.", deprecatedName, chars, newName, chars);
if (!newName.equals("driver")) {
logger.warn("Auto replacing deprecated activity param '{}={}' with new '{}={}'.", deprecatedName, chars, newName, chars);
}
parameterMap.put(newName, parameterMap.remove(deprecatedName));
} else {
throw new BasicError("Can't replace deprecated name with value of type " + deprecatedName.getClass().getCanonicalName());
@ -230,4 +242,31 @@ public class ActivityDef implements NBNamedElement {
return NBLabels.forKV();
}
public NBConfigModel getConfigModel() {
ConfigModel cfgmodel = ConfigModel.of(this.getClass());
Map<String, String> params = parameterMap.getStringStringMap();
params.forEach((k, v) -> {
cfgmodel.add(Param.defaultTo(k, v, "activity parameter found on command line"));
});
cfgmodel.add(Param.defaultTo(FIELD_ALIAS, DEFAULT_ALIAS).setDescription("The alias for the operations"));
cfgmodel.add(Param.defaultTo(FIELD_ATYPE, DEFAULT_ATYPE).setDescription("The default adapter type is 'stdout'"));
cfgmodel.add(Param.defaultTo(FIELD_CYCLES, DEFAULT_CYCLES).setDescription("The default number of cycles to test is '0'"));
cfgmodel.add(Param.defaultTo(FIELD_THREADS, DEFAULT_THREADS).setDescription("The default number of threads for testing is '1'"));
cfgmodel.add(Param.defaultTo(FIELD_RECYCLES, DEFAULT_RECYCLES).setDescription("The default number of recycles to test is '1'"));
cfgmodel.add(Param.optional("labels", String.class).setDescription("Metric labels for this activity"));
cfgmodel.add(Param.optional("tags", String.class).setDescription("Tags for selecting workload op templates"));
cfgmodel.add(Param.defaultTo("driver", DEFAULT_ATYPE).setDescription("The default adapter driver is 'stdout'"));
cfgmodel.add(Param.optional("workload", String.class).setDescription("The test workload"));
cfgmodel.add(Param.optional("yaml", String.class).setDescription("The test workload"));
cfgmodel.add(Param.defaultTo("async", 1,"Inflight Ops"));
cfgmodel.add(Param.defaultTo("maxtries", 10,"Maximum number of retries"));
cfgmodel.add(Param.defaultTo("interval", 1000,"Action interval"));
cfgmodel.add(Param.defaultTo("hdr_digits", 4,"HDR Digits"));
cfgmodel.add(Param.optional("errors").setDescription("Error handling method"));
cfgmodel.add(Param.optional("striderate").setDescription("Rate limiting stride"));
List<String> rates = Arrays.asList("cyclerate", "targetrate", "rate");
cfgmodel.add(Param.optional(rates, String.class, "Rate limit"));
return cfgmodel.asReadOnly();
}
}

View File

@ -207,12 +207,12 @@ public class TagFilter {
String filterkey2 = filterkey.substring(0, filterkey.length() - 1);
itemval = tags.get(filterkey2);
String message = "'" + filterkey + "' tags do not exist: try '" + filterkey2 + "'";
NBAdvisorOutput.test(message);
log.add("(☐, ) " + message);
NBAdvisorOutput.test(message);
filterkey = filterkey2;
}
}
String detail = "filter(" + filterkey +
((filterval != null) ? ":" + filterval : "") + ") " +
"tag(" + ((tags.containsKey(filterkey) ? filterkey : "") +

View File

@ -101,7 +101,7 @@ public class NBCLIScenarioPreprocessorTest {
@Test
public void testThatTemplateParamsAreExpandedAndNotRemovedOverride() {
NBCLIOptions opts = new NBCLIOptions(new String[]{"scenario_test", "template_test", "cycles-test=20"}, NBCLIOptions.Mode.ParseAllOptions);
NBCLIOptions opts = new NBCLIOptions(new String[]{"scenario_test", "template_test", "cycles_test=20"}, NBCLIOptions.Mode.ParseAllOptions);
List<Cmd> cmds = opts.getCommands();
assertThat(cmds.size()).isEqualTo(1);
assertThat(cmds.get(0).getArgMap()).isEqualTo(Map.of(
@ -109,7 +109,7 @@ public class NBCLIScenarioPreprocessorTest {
"alias", "with_template",
"container", "template_test",
"cycles", "20",
"cycles-test", "20",
"cycles_test", "20",
"driver", "stdout",
"labels", "workload:scenario_test,scenario:template_test",
"step", "with_template",
@ -119,14 +119,14 @@ public class NBCLIScenarioPreprocessorTest {
@Test
public void testThatUndefValuesAreUndefined() {
NBCLIOptions opts = new NBCLIOptions(new String[]{"scenario_test", "schema_only", "cycles-test=20"}, NBCLIOptions.Mode.ParseAllOptions);
NBCLIOptions opts = new NBCLIOptions(new String[]{"scenario_test", "schema_only", "cycles_test=20"}, NBCLIOptions.Mode.ParseAllOptions);
List<Cmd> cmds = opts.getCommands();
assertThat(cmds.size()).isEqualTo(1);
assertThat(cmds.get(0).getArgMap()).isEqualTo(Map.of(
"_impl", "run",
"alias", "schema",
"container", "schema_only",
"cycles-test", "20",
"cycles_test", "20",
"driver", "stdout",
"labels", "workload:scenario_test,scenario:schema_only",
"step", "schema",
@ -136,7 +136,7 @@ public class NBCLIScenarioPreprocessorTest {
NBCLIOptions opts1 = new NBCLIOptions(new String[]{"scenario_test", "schema_only", "doundef=20"}, NBCLIOptions.Mode.ParseAllOptions);
List<Cmd> cmds1 = opts1.getCommands();
assertThat(cmds1.size()).isEqualTo(1);
assertThat(cmds1.get(0).getArgValueOrNull("cycles-test")).isNull();
assertThat(cmds1.get(0).getArgValueOrNull("cycles_test")).isNull();
}
@Test
@ -150,7 +150,7 @@ public class NBCLIScenarioPreprocessorTest {
Path absolute = rel.toAbsolutePath();
assertThat(absolute).exists();
NBCLIOptions opts = new NBCLIOptions(new String[]{absolute.toString(), "schema_only", "cycles-test=20"}, NBCLIOptions.Mode.ParseAllOptions);
NBCLIOptions opts = new NBCLIOptions(new String[]{absolute.toString(), "schema_only", "cycles_test=20"}, NBCLIOptions.Mode.ParseAllOptions);
List<Cmd> cmds = opts.getCommands();
assertThat(cmds.size()).isGreaterThan(0);
}
@ -161,7 +161,7 @@ public class NBCLIScenarioPreprocessorTest {
//TODO: This might change?
String urlScenario = "https://raw.githubusercontent.com/nosqlbench/nosqlbench/main/engine-cli/src/test/resources/activities/scenario_test.yaml";
NBCLIOptions opts = new NBCLIOptions(new String[]{urlScenario, "schema_only", "cycles-test=20"}, NBCLIOptions.Mode.ParseAllOptions);
NBCLIOptions opts = new NBCLIOptions(new String[]{urlScenario, "schema_only", "cycles_test=20"}, NBCLIOptions.Mode.ParseAllOptions);
List<Cmd> cmds = opts.getCommands();
assertThat(cmds.size()).isGreaterThan(0);
}
@ -174,14 +174,14 @@ public class NBCLIScenarioPreprocessorTest {
@Test
public void testSubStepSelection() {
NBCLIOptions opts = new NBCLIOptions(new String[]{"scenario_test", "schema_only", "cycles-test=20"}, NBCLIOptions.Mode.ParseAllOptions);
NBCLIOptions opts = new NBCLIOptions(new String[]{"scenario_test", "schema_only", "cycles_test=20"}, NBCLIOptions.Mode.ParseAllOptions);
List<Cmd> cmds = opts.getCommands();
assertThat(cmds.size()).isEqualTo(1);
assertThat(cmds.get(0).getArgMap()).isEqualTo(Map.of(
"_impl", "run",
"alias", "schema",
"container", "schema_only",
"cycles-test", "20",
"cycles_test", "20",
"driver", "stdout",
"labels", "workload:scenario_test,scenario:schema_only",
"step", "schema",
@ -234,7 +234,7 @@ public class NBCLIScenarioPreprocessorTest {
.isThrownBy(() -> NBCLIScenarioPreprocessor.splitCommand(unclosedQuoteCmd))
.withMessageContaining("Unclosed quote found in scenario cmd");
}
@Test
public void testThatSuggestionsAreShownForDirectStepNameUsage() {
assertThatExceptionOfType(BasicError.class)

View File

@ -9,7 +9,7 @@ scenarios:
schema: run driver=stdout workload==scenario_test tags=block:"schema.*" doundef==undef
template_test:
with_template: run driver=stdout cycles=TEMPLATE(cycles-test,10)
with_template: run driver=stdout cycles=TEMPLATE(cycles_test,10)
duplicate_param:
schema: run driver=stdout workload==scenario_test threads=auto tags=block:"schema.*" threads=1 doundef==undef

View File

@ -97,7 +97,7 @@ public class SimpleActivity extends NBStatusComponent implements Activity, Invok
activityDef.getParams().set("alias", workloadOpt.get());
} else {
activityDef.getParams().set("alias",
activityDef.getActivityType().toUpperCase(Locale.ROOT)
activityDef.getActivityDriver().toUpperCase(Locale.ROOT)
+ nameEnumerator);
nameEnumerator++;
}
@ -540,7 +540,8 @@ public class SimpleActivity extends NBStatusComponent implements Activity, Invok
* @return The sequence of operations as determined by filtering and ratios
*/
@Deprecated(forRemoval = true)
protected <O> OpSequence<OpDispenser<? extends O>> createOpSequence(Function<OpTemplate, OpDispenser<? extends O>> opinit, boolean strict, DriverAdapter<?, ?> defaultAdapter) {
protected <O> OpSequence<OpDispenser<? extends O>> createOpSequence(Function<OpTemplate,
OpDispenser<? extends O>> opinit, boolean strict, DriverAdapter<?, ?> defaultAdapter) {
List<OpTemplate> stmts = loadOpTemplates(defaultAdapter);

View File

@ -27,12 +27,13 @@ import io.nosqlbench.adapters.api.activityimpl.uniform.Space;
import io.nosqlbench.adapters.api.activityimpl.uniform.decorators.SyntheticOpTemplateProvider;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.CycleOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import io.nosqlbench.nb.api.advisor.NBAdvisorPoint;
import io.nosqlbench.nb.api.advisor.conditions.Conditions;
import io.nosqlbench.nb.api.engine.metrics.instruments.MetricCategory;
import io.nosqlbench.nb.api.lifecycle.Shutdownable;
import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.nb.api.config.standard.*;
import io.nosqlbench.nb.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.nb.api.errors.OpConfigError;
import io.nosqlbench.nb.api.labels.NBLabels;
import io.nosqlbench.nb.api.components.events.NBEvent;
@ -67,10 +68,17 @@ public class StandardActivity<R extends java.util.function.LongFunction, S> exte
public StandardActivity(NBComponent parent, ActivityDef activityDef) {
super(parent, activityDef);
OpsDocList workload;
Optional<String> yaml_loc = activityDef.getParams().getOptionalString("yaml", "workload");
NBAdvisorPoint<String> paramsAdvisor = create().advisor(b -> b.name("Workload"));
paramsAdvisor.add(Conditions.ValidNameError);
List<DriverAdapter<CycleOp<?>, Space>> adapterlist = new ArrayList<>();
List<ParsedOp> pops = new ArrayList<>();
ConcurrentHashMap<String, OpMapper<? extends CycleOp<?>, ? extends Space>> mappers = new ConcurrentHashMap<>();
NBConfigModel activityModel = activityDef.getConfigModel();
String defaultDriverName = activityDef.getActivityDriver();
DriverAdapter<CycleOp<?>, Space> defaultAdapter = getDriverAdapter(defaultDriverName);
NBConfigModel yamlmodel;
OpsDocList workload;
Optional<String> yaml_loc = activityDef.getParams().getOptionalString("yaml", "workload");
if (yaml_loc.isPresent()) {
Map<String, Object> disposable = new LinkedHashMap<>(activityDef.getParams());
workload = OpsLoader.loadPath(yaml_loc.get(), disposable, "activities");
@ -78,88 +86,56 @@ public class StandardActivity<R extends java.util.function.LongFunction, S> exte
} else {
yamlmodel = ConfigModel.of(StandardActivity.class).asReadOnly();
}
Optional<String> defaultDriverName = activityDef.getParams().getOptionalString("driver");
Optional<DriverAdapter<?, ?>> defaultAdapter = defaultDriverName
.flatMap(name -> ServiceSelector.of(name, ServiceLoader.load(DriverAdapterLoader.class)).get())
.map(l -> l.load(this, NBLabels.forKV()));
if (defaultDriverName.isPresent() && defaultAdapter.isEmpty()) {
throw new BasicError("Unable to load '" + defaultDriverName.get() + "' driver adapter.\n"+
"Rebuild NB5 to include this driver adapter. "+
"Change '<activeByDefault>false</activeByDefault>' for the driver in "+
"'./nb-adapters/pom.xml' and './nb-adapters/nb-adapters-included/pom.xml' first.");
}
// HERE, op templates are loaded before drivers are loaded
List<OpTemplate> opTemplates = loadOpTemplates(defaultAdapter.orElse(null));
List<ParsedOp> pops = new ArrayList<>();
List<DriverAdapter<CycleOp<?>, Space>> adapterlist = new ArrayList<>();
yamlmodel.log();
NBConfigModel supersetConfig = ConfigModel.of(StandardActivity.class).add(yamlmodel);
Optional<String> defaultDriverOption = defaultDriverName;
ConcurrentHashMap<String, OpMapper<? extends CycleOp<?>, ? extends Space>> mappers = new ConcurrentHashMap<>();
//NBConfigModel supersetConfig = ConfigModel.of(StandardActivity.class).add(activityModel);
// Load the op templates
List<OpTemplate> opTemplates = loadOpTemplates(defaultAdapter);
for (OpTemplate ot : opTemplates) {
// ParsedOp incompleteOpDef = new ParsedOp(ot, NBConfiguration.empty(), List.of(), this);
logger.info(() -> "StandardActivity.opTemplate = "+ot);
String driverName = ot.getOptionalStringParam("driver", String.class)
.or(() -> ot.getOptionalStringParam("type", String.class))
.or(() -> defaultDriverOption)
.orElseThrow(() -> new OpConfigError("Unable to identify driver name for op template:\n" + ot));
// String driverName = ot.getOptionalStringParam("driver")
// .or(() -> activityDef.getParams().getOptionalString("driver"))
// .orElseThrow(() -> new OpConfigError("Unable to identify driver name for op template:\n" + ot));
// HERE
.orElse(defaultDriverName);
if (!adapters.containsKey(driverName)) {
DriverAdapter<CycleOp<?>,Space> adapter = Optional.of(driverName)
.flatMap(
name -> ServiceSelector.of(
name,
ServiceLoader.load(DriverAdapterLoader.class)
)
.get())
.map(
l -> l.load(
this,
NBLabels.forKV()
)
)
.orElseThrow(() -> new OpConfigError("driver adapter not present for name '" + driverName + "'"));
DriverAdapter<CycleOp<?>,Space> adapter =
defaultDriverName.equals(driverName) ? defaultAdapter : getDriverAdapter(driverName);
NBConfigModel combinedModel = yamlmodel;
//NBConfigModel combinedModel = activityModel;
NBConfiguration combinedConfig = combinedModel.matchConfig(activityDef.getParams());
if (adapter instanceof NBConfigurable configurable) {
NBConfigModel adapterModel = configurable.getConfigModel();
supersetConfig.add(adapterModel);
combinedModel = adapterModel.add(yamlmodel);
//combinedModel = adapterModel.add(activityModel);
combinedConfig = combinedModel.matchConfig(activityDef.getParams());
configurable.applyConfig(combinedConfig);
}
adapters.put(driverName, adapter);
mappers.put(driverName, adapter.getOpMapper());
}
paramsAdvisor.validateAll(ot.getParams().keySet());
paramsAdvisor.validateAll(ot.getTags().keySet());
//TO-DO - paramsAdvisor.validateAll(ot.getBindings().keySet());
supersetConfig.assertValidConfig(activityDef.getParams().getStringStringMap());
supersetConfig.log();
DriverAdapter<CycleOp<?>, Space> adapter = adapters.get(driverName);
adapterlist.add(adapter);
ParsedOp pop = new ParsedOp(ot, adapter.getConfiguration(), List.of(adapter.getPreprocessor()), this);
logger.info("StandardActivity.pop="+pop);
Optional<String> discard = pop.takeOptionalStaticValue("driver", String.class);
pops.add(pop);
}
logger.info(() -> "StandardActivity.opTemplate loop complete");
if (defaultDriverOption.isPresent()) {
long matchingDefault = mappers.keySet().stream().filter(n -> n.equals(defaultDriverOption.get())).count();
if (0 == matchingDefault) {
logger.warn("All op templates used a different driver than the default '{}'", defaultDriverOption.get());
}
paramsAdvisor.setName("Workload", "Check parameters, template, and binding names")
.logName().evaluate();
paramsAdvisor.clear().setName("Superset", "Check overall parameters");
paramsAdvisor.validateAll(supersetConfig.getNamedParams().keySet());
paramsAdvisor.logName().evaluate();
if (0 == mappers.keySet().stream().filter(n -> n.equals(defaultDriverName)).count()) {
logger.warn(() -> "All op templates used a different driver than the default '" + defaultDriverName + "'");
}
try {
@ -191,6 +167,17 @@ public class StandardActivity<R extends java.util.function.LongFunction, S> exte
);
}
private DriverAdapter<CycleOp<?>, Space> getDriverAdapter(String driverName) {
return Optional.of(driverName)
.flatMap(name -> ServiceSelector.of(name, ServiceLoader.load(DriverAdapterLoader.class)).get())
.map(l -> l.load(this, NBLabels.forKV())
)
.orElseThrow(() -> new OpConfigError("Unable to load '" + driverName + "' driver adapter.\n"+
"Rebuild NB5 to include this driver adapter. "+
"Change '<activeByDefault>false</activeByDefault>' for the driver in "+
"'./nb-adapters/pom.xml' and './nb-adapters/nb-adapters-included/pom.xml' first."));
}
@Override
public void initActivity() {
super.initActivity();
@ -217,7 +204,6 @@ public class StandardActivity<R extends java.util.function.LongFunction, S> exte
@Override
public synchronized void onActivityDefUpdate(ActivityDef activityDef) {
super.onActivityDefUpdate(activityDef);
for (DriverAdapter<?, ?> adapter : adapters.values()) {
if (adapter instanceof NBReconfigurable configurable) {
NBConfigModel cfgModel = configurable.getReconfigModel();
@ -279,7 +265,6 @@ public class StandardActivity<R extends java.util.function.LongFunction, S> exte
return super.getLabels();
}
@Override
public void onEvent(NBEvent event) {
switch (event) {
@ -295,5 +280,4 @@ public class StandardActivity<R extends java.util.function.LongFunction, S> exte
}
}
}

View File

@ -16,6 +16,8 @@
package io.nosqlbench.engine.cmdstream;
import io.nosqlbench.nb.api.advisor.NBAdvisorPoint;
import io.nosqlbench.nb.api.advisor.conditions.Conditions;
import io.nosqlbench.nb.api.errors.BasicError;
import jakarta.validation.constraints.NotNull;
import org.apache.logging.log4j.Logger;
@ -37,7 +39,6 @@ public class Cmd {
private final Map<String, CmdArg> cmdArgs;
private final String stepName;
public String getTargetContext() {
return targetContextName;
}
@ -86,6 +87,11 @@ public class Cmd {
// }
//
public Cmd(@NotNull String cmdTypeOrName, Map<String, CmdArg> argmap) {
NBAdvisorPoint<String> advisor = new NBAdvisorPoint<String>("Command","Check command arguments");
advisor.add(Conditions.ValidNameError);
advisor.validate(cmdTypeOrName);
advisor.validateAll(argmap.keySet());
advisor.logName().evaluate();
this.cmdType = CmdType.valueOfAnyCaseOrIndirect(cmdTypeOrName);
this.targetContextName = DEFAULT_TARGET_CONTEXT;
this.stepName = "";

View File

@ -421,11 +421,7 @@ public class ContainerActivitiesController extends NBBaseComponent {
}
try {
result = future.get(timeoutMs, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
} catch (ExecutionException | InterruptedException | TimeoutException e) {
throw new RuntimeException(e);
}
return null != result;

View File

@ -21,6 +21,8 @@ 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.advisor.NBAdvisorPoint;
import io.nosqlbench.nb.api.advisor.conditions.Conditions;
import io.nosqlbench.nb.api.annotations.Annotation;
import io.nosqlbench.nb.api.annotations.Layer;
import io.nosqlbench.nb.api.labels.NBLabels;
@ -50,6 +52,8 @@ public class NBBufferedContainer extends NBBaseComponent implements NBContainer
private Exception error;
private long endedAtMillis;
private final Map<String, String> vars = new LinkedHashMap<>();
private final List<NBAdvisorPoint<?>> advisors = new ArrayList<>();
private NBAdvisorPoint<String> paramsAdvisor;
public enum IOType {
connected,
@ -155,6 +159,10 @@ public class NBBufferedContainer extends NBBaseComponent implements NBContainer
private final static Pattern pattern = Pattern.compile("\\$\\{(?<name>[a-zA-Z_][a-zA-Z0-9_.]*)}");
private NBCommandParams interpolate(NBCommandParams params, Map<String, String> vars, String stepname) {
logger.debug("NBBufferedContainer.interpolate stepname=" + stepname);
paramsAdvisor = create().advisor(b -> b.name("Check params"));
paramsAdvisor.add(Conditions.ValidNameError);
paramsAdvisor.validateAll(vars.keySet());
Map<String, String> interpolated = new LinkedHashMap<>();
params.forEach((k, v) -> {
Matcher varmatcher = pattern.matcher(v);
@ -170,6 +178,9 @@ public class NBBufferedContainer extends NBBaseComponent implements NBContainer
varmatcher.appendTail(sb);
interpolated.put(k, sb.toString());
});
paramsAdvisor.validateAll(interpolated.keySet());
paramsAdvisor.setName("Container", "Check container and variable names")
.logName().evaluate();
return NBCommandParams.of(interpolated);
}
@ -190,9 +201,7 @@ public class NBBufferedContainer extends NBBaseComponent implements NBContainer
Object value = component.getAccessor().invoke(record);
results.put(stepname+"."+name,value.toString());
filtered.add(name);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@ -204,9 +213,7 @@ public class NBBufferedContainer extends NBBaseComponent implements NBContainer
try {
Object value = property.invoke(record);
results.put(stepname+"."+property.getName(),value.toString());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}