naming: use ParsedOp instead of ParsedCommand

This commit is contained in:
Jonathan Shook 2021-09-13 09:43:19 -05:00
parent 9763dd0be7
commit 828ec0252d
15 changed files with 42 additions and 545 deletions

View File

@ -9,7 +9,7 @@ import io.nosqlbench.adapter.cqld4.processors.CqlFieldCaptureProcessor;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import io.nosqlbench.engine.api.activityimpl.OpMapper;
import io.nosqlbench.engine.api.activityimpl.uniform.DriverSpaceCache;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.nb.api.config.params.ParamsParser;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.errors.BasicError;
@ -30,7 +30,7 @@ public class Cqld4OpMapper implements OpMapper<Cqld4Op> {
this.cache = cache;
}
public OpDispenser<Cqld4Op> apply(ParsedCommand cmd) {
public OpDispenser<Cqld4Op> apply(ParsedOp cmd) {
ParsedTemplate stmtTpl = cmd.getStmtAsTemplate().orElseThrow(() -> new BasicError(
"No statement was found in the op template:" + cmd

View File

@ -3,15 +3,15 @@ package io.nosqlbench.adapter.cqld4.opdispensers;
import com.datastax.oss.driver.api.core.CqlSession;
import io.nosqlbench.adapter.cqld4.Cqld4Op;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.nb.api.errors.BasicError;
public class CqlD4PreparedBatchOpDispenser implements OpDispenser<Cqld4Op> {
private final CqlSession session;
private final ParsedCommand cmd;
private final ParsedOp cmd;
public CqlD4PreparedBatchOpDispenser(CqlSession session, ParsedCommand cmd) {
public CqlD4PreparedBatchOpDispenser(CqlSession session, ParsedOp cmd) {
this.session = session;
this.cmd = cmd;
}

View File

@ -3,13 +3,13 @@ package io.nosqlbench.adapter.cqld4.opdispensers;
import com.datastax.oss.driver.api.core.CqlSession;
import io.nosqlbench.adapter.cqld4.Cqld4Op;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
public class Cqld4BatchStatementDispenser implements OpDispenser<Cqld4Op> {
private final CqlSession session;
private final ParsedCommand cmd;
private final ParsedOp cmd;
public Cqld4BatchStatementDispenser(CqlSession session, ParsedCommand cmd) {
public Cqld4BatchStatementDispenser(CqlSession session, ParsedOp cmd) {
this.session = session;
this.cmd = cmd;
}

View File

@ -8,7 +8,7 @@ import io.nosqlbench.adapter.cqld4.Cqld4OpMetrics;
import io.nosqlbench.adapter.cqld4.optypes.Cqld4PreparedStatement;
import io.nosqlbench.adapter.cqld4.RSProcessors;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.virtdata.core.templates.ParsedTemplate;
import java.util.function.LongFunction;
@ -24,7 +24,7 @@ public class Cqld4PreparedStmtDispenser implements OpDispenser<Cqld4Op> {
private final Cqld4OpMetrics metrics;
private final RSProcessors processors;
public Cqld4PreparedStmtDispenser(CqlSession session, ParsedCommand cmd, RSProcessors processors) {
public Cqld4PreparedStmtDispenser(CqlSession session, ParsedOp cmd, RSProcessors processors) {
this.session = session;
this.processors = processors;

View File

@ -6,17 +6,17 @@ import io.nosqlbench.adapter.cqld4.Cqld4Op;
import io.nosqlbench.adapter.cqld4.Cqld4OpMetrics;
import io.nosqlbench.adapter.cqld4.optypes.Cqld4SimpleCqlStatement;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
public class Cqld4SimpleCqlStmtDispenser implements OpDispenser<Cqld4Op> {
private final CqlSession session;
private final ParsedCommand cmd;
private final ParsedOp cmd;
private final int maxpages;
private final boolean retryreplace;
private final Cqld4OpMetrics metrics;
public Cqld4SimpleCqlStmtDispenser(CqlSession session, ParsedCommand cmd) {
public Cqld4SimpleCqlStmtDispenser(CqlSession session, ParsedOp cmd) {
this.session = session;
this.cmd = cmd;
this.maxpages = cmd.getStaticConfigOr("maxpages",1);

View File

@ -1,7 +1,7 @@
package io.nosqlbench.engine.api.activityimpl;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import java.util.function.Function;
@ -39,7 +39,7 @@ import java.util.function.Function;
* </hr>
* <h2>Implementation Strategy</h2>
* <p>
* A view of an op template is provided in the {@link ParsedCommand} API. This allows
* A view of an op template is provided in the {@link ParsedOp} API. This allows
* you to examine the fields provided by users. It also lets you see which
* of these fields are defined as dynamic and which are simply static values.
* When multiple types of operations are supported for a driver adapter, you must decide
@ -62,16 +62,16 @@ import java.util.function.Function;
* to hold all the details for executing an operation,
* generally something that implements {@link Runnable}.
*/
public interface OpMapper<T extends Op> extends Function<ParsedCommand, OpDispenser<T>> {
public interface OpMapper<T extends Op> extends Function<ParsedOp, OpDispenser<T>> {
/**
* Interrogate the parsed command, and provide a new
*
* @param cmd The {@link ParsedCommand} which is the parsed version of the user-provided op template.
* @param cmd The {@link ParsedOp} which is the parsed version of the user-provided op template.
* This contains all the fields provided by the user, as well as explicit knowledge of
* which ones are static and dynamic.
* @return An OpDispenser which can be used to synthesize real operations.
*/
@Override
OpDispenser<T> apply(ParsedCommand cmd);
OpDispenser<T> apply(ParsedOp cmd);
}

View File

@ -3,7 +3,7 @@ package io.nosqlbench.engine.api.activityimpl.uniform;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import io.nosqlbench.engine.api.activityimpl.OpMapper;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import java.util.Map;
@ -36,7 +36,7 @@ public interface DriverAdapter<R extends Op, S> {
* <p>
* <H2>Op Mapping</H2>
* An Op Mapper is a function which can look at the parsed
* fields in a {@link ParsedCommand} and create an OpDispenser.
* fields in a {@link ParsedOp} and create an OpDispenser.
* An OpDispenser is a function that will produce a special
* type {@link R} that this DriverAdapter implements as its
* op implementation.</p>
@ -63,7 +63,7 @@ public interface DriverAdapter<R extends Op, S> {
* <p>
* <H2>A note on implementation strategy:</H2>
* Generally speaking, implementations of this method should interrogate the op fields
* in the ParsedCommand and return an OpDispenser that matches the user's intentions.
* in the ParsedOp and return an OpDispenser that matches the user's intentions.
* This can be based on something explicit, like the value of a {@code type} field,
* or it can be based on whether certain fields are present or not. Advanced implementations
* might take into account which fields are provided as static values and which are

View File

@ -1,438 +0,0 @@
package io.nosqlbench.engine.api.templating;
import io.nosqlbench.engine.api.activityconfig.yaml.OpTemplate;
import io.nosqlbench.engine.api.templating.binders.ArrayBinder;
import io.nosqlbench.engine.api.templating.binders.ListBinder;
import io.nosqlbench.engine.api.templating.binders.OrderedMapBinder;
import io.nosqlbench.nb.api.config.standard.NBConfigError;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.config.standard.NBTypeConverter;
import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.nb.api.errors.OpConfigError;
import io.nosqlbench.virtdata.core.bindings.DataMapper;
import io.nosqlbench.virtdata.core.bindings.VirtData;
import io.nosqlbench.virtdata.core.templates.BindPoint;
import io.nosqlbench.virtdata.core.templates.CapturePoint;
import io.nosqlbench.virtdata.core.templates.ParsedTemplate;
import io.nosqlbench.virtdata.core.templates.StringBindings;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.*;
import java.util.function.Function;
import java.util.function.LongFunction;
/**
* Parse an OpTemplate into a ParsedCommand, which can dispense object maps
*/
public class ParsedCommand implements LongFunction<Map<String, ?>> {
private final static Logger logger = LogManager.getLogger(ParsedCommand.class);
/**
* The fields which are statically assigned
**/
private final Map<String, Object> statics = new LinkedHashMap<>();
/**
* The fields which are dynamic, and must be realized via functions.
* This map contains keys which identify the field names, and values, which may be null or undefined.
*/
private final Map<String, LongFunction<?>> dynamics = new LinkedHashMap<>();
/**
* The names of payload values in the result of the operation which should be saved.
* The keys in this map represent the name of the value as it would be found in the native
* representation of a result. If the values are defined, then each one represents the name
* that the found value should be saved as instead of the original name.
*/
private final List<List<CapturePoint>> captures = new ArrayList<>();
private final int mapsize;
/**
* A prototype of the fully generated map, to be used as the starting point
* when rendering the full map with dynamic values.
*/
private final LinkedHashMap<String, Object> protomap = new LinkedHashMap<>();
private final OpTemplate ot;
private final NBConfiguration acfg;
/**
* Create a parsed command from an Op template.
*
* @param ot An OpTemplate representing an operation to be performed in a native driver.
* @param acfg The activity configuration, used for reading config parameters
*/
public ParsedCommand(OpTemplate ot, NBConfiguration acfg) {
this(ot, acfg, List.of());
}
/**
* Create a parsed command from an Op template. This version is exactly like
* {@link ParsedCommand(OpTemplate,NBConfiguration)} except that it allows
* preprocessors. Preprocessors are all applied to the the op template before
* it is applied to the parsed command fields, allowing you to combine or destructure
* fields from more tha one representation into a single canonical representation
* for processing.
*
* @param ot The OpTemplate as provided by a user via YAML, JSON, or API (data structure)
* @param acfg The activity configuration, used to resolve nested config parameters
* @param preprocessors Map->Map transformers.
*/
public ParsedCommand(OpTemplate ot, NBConfiguration acfg, List<Function<Map<String, Object>, Map<String, Object>>> preprocessors) {
this.ot = ot;
this.acfg = acfg;
Map<String, Object> map = ot.getOp().orElseThrow();
for (Function<Map<String, Object>, Map<String, Object>> preprocessor : preprocessors) {
map = preprocessor.apply(map);
}
applyTemplateFields(map, ot.getBindings());
mapsize = statics.size() + dynamics.size();
}
// For now, we only allow bind points to reference bindings, not other op template
// fields. This seems like the saner and less confusing approach, so implementing
// op field references should be left until it is requested if at all
private void applyTemplateFields(Map<String, Object> map, Map<String, String> bindings) {
map.forEach((k, v) -> {
if (v instanceof CharSequence) {
ParsedTemplate pt = ParsedTemplate.of(((CharSequence) v).toString(), bindings);
this.captures.add(pt.getCaptures());
switch (pt.getType()) {
case literal:
statics.put(k, ((CharSequence) v).toString());
protomap.put(k, ((CharSequence) v).toString());
break;
case bindref:
String spec = pt.asBinding().orElseThrow().getBindspec();
Optional<DataMapper<Object>> mapper = VirtData.getOptionalMapper(spec);
dynamics.put(k, mapper.orElseThrow());
protomap.put(k, null);
break;
case concat:
StringBindings sb = new StringBindings(pt);
dynamics.put(k, sb);
protomap.put(k, null);
break;
}
} else {
// Eventually, nested and mixed static dynamic structure could be supported, but
// it would be complex to implement and also not that efficient, so let's just copy
// structure for now
statics.put(k, v);
protomap.put(k, v);
}
});
}
public String getName() {
return ot.getName();
}
public Map<String, Object> getStaticPrototype() {
return statics;
}
public Map<String, LongFunction<?>> getDynamicPrototype() {
return dynamics;
}
@Override
public Map<String, Object> apply(long value) {
LinkedHashMap<String, Object> map = new LinkedHashMap<>(protomap);
dynamics.forEach((k, v) -> {
map.put(k, v.apply(value));
});
return map;
}
public boolean isDefinedDynamic(String field) {
return dynamics.containsKey(field);
}
/**
* @param field The field name to look for in the static field map.
* @return true if and only if the named field is present in the static field map.
*/
public boolean isDefinedStatic(String field) {
return statics.containsKey(field);
}
public boolean isDefinedStatic(String field, Class<?> type) {
return statics.containsKey(field) && type.isAssignableFrom(field.getClass());
}
/**
* @param fields Names of fields to look for in the static field map.
* @return true if and only if all provided field names are present in the static field map.
*/
public boolean isDefinedStaticAll(String... fields) {
for (String field : fields) {
if (!statics.containsKey(field)) {
return false;
}
}
return true;
}
/**
* Get the static value for the provided name, cast to the required type.
*
* @param field Name of the field to get
* @param classOfT The type of the field to return. If actual type is not compatible to a cast to this type, then a
* casting error will be thrown.
* @param <T> The parameter type of the return type, used at compile time only to qualify asserted return type
* @return A value of type T, or null
*/
public <T> T getStaticValue(String field, Class<T> classOfT) {
return (T) statics.get(field);
}
/**
* Get the static value for the provided name, cast to the required type, where the type is inferred
* from the calling context.
*
* @param field Name of the field to get
* @param <T> The parameter type of the return type. used at compile time only to quality return type.
* @return A value of type T, or null
*/
public <T> T getStaticValue(String field) {
return (T) statics.get(field);
}
public Optional<ParsedTemplate> getStmtAsTemplate() {
return ot.getParsed();
}
/**
* Get the named static field value, or return the provided default, but throw an exception if
* the named field is dynamic.
*
* @param name The name of the field value to return.
* @param defaultValue A value to return if the named value is not present in static nor dynamic fields.
* @param <T> The type of the field to return.
* @return The value
* @throws RuntimeException if the field name is only present in the dynamic fields.
*/
public <T> T getStaticValueOr(String name, T defaultValue) {
if (statics.containsKey(name)) {
return (T) statics.get(name);
} else if (dynamics.containsKey(name)) {
throw new BasicError("static field '" + name + "' was defined dynamically. This may be supportable if the driver developer" +
"updates the op mapper to support this field as a dynamic field, but it is not yet supported.");
} else {
return defaultValue;
}
}
/**
* Get the specified parameter by the user using the defined field which is closest to the op
* template. This is the standard way of getting parameter values which can be specified at the
* op template, op param, or activity level.
*
* @param name The name of the configuration param
* @param defaultValue the default value to return if the value is not defined anywhere in
* (op fields, op params, activity params)
* @param <T> The type of the value to return
* @return A configuration value
* @throws io.nosqlbench.nb.api.config.standard.NBConfigError if the named field is defined dynamically,
* as in this case, it is presumed that the parameter is not supported unless it is defined statically.
*/
public <T> T getStaticConfigOr(String name, T defaultValue) {
if (statics.containsKey(name)) {
return NBTypeConverter.convertOr(statics.get(name), defaultValue);
} else if (ot.getParams().containsKey(name)) {
return NBTypeConverter.convertOr(ot.getParams().get(name), defaultValue);
} else if (acfg.getMap().containsKey(name)) {
return NBTypeConverter.convertOr(acfg.get("name"), defaultValue);
} else if (dynamics.containsKey(name)) {
throw new NBConfigError("static config field '" + name + "' was defined dynamically. This may be supportable if the driver developer" +
"updates the op mapper to support this field as a dynamic field, but it is not yet supported.");
} else {
return defaultValue;
}
}
public <T> Optional<T> getOptionalStaticConfig(String name, Class<T> type) {
if (statics.containsKey(name)) {
return Optional.of(NBTypeConverter.convert(statics.get(name), type));
} else if (ot.getParams().containsKey(name)) {
return Optional.of(NBTypeConverter.convert(ot.getParams().get(name), type));
} else if (acfg.getMap().containsKey(name)) {
return Optional.of(NBTypeConverter.convert(acfg.get("name"), type));
} else if (dynamics.containsKey("name")) {
throw new NBConfigError("static config field '" + name + "' was defined dynamically. This may be supportable if the driver developer" +
"updates the op mapper to support this field as a dynamic field, but it is not yet supported.");
} else {
return Optional.empty();
}
}
/**
* Works exactly like {@link #getStaticConfigOr(String, Object)}, except that dynamic values
* at the op field level will be generated on a per-input basis. This is a shortcut method for
* allowing configuration values to be accessed dynamically where it makes sense.
*/
public <T> T getConfigOr(String name, T defaultValue, long input) {
if (statics.containsKey(name)) {
return NBTypeConverter.convertOr(statics.get(name), defaultValue);
} else if (dynamics.containsKey(name)) {
return NBTypeConverter.convertOr(dynamics.get(name).apply(input), defaultValue);
} else if (ot.getParams().containsKey(name)) {
return NBTypeConverter.convertOr(ot.getParams().get(name), defaultValue);
} else if (acfg.getMap().containsKey(name)) {
return NBTypeConverter.convertOr(acfg.get("name"), defaultValue);
} else return defaultValue;
}
/**
* Return an optional value for the named field. This is an {@link Optional} form of {@link #getStaticValue}.
*
* @param field Name of the field to get
* @param classOfT The type of field to return. If the actual type is not compatible to a cast to this type,
* then a casting error will be thrown.
* @param <T> The parameter type of the return
* @return An optional value, empty unless the named value is defined in the static field map.
*/
public <T> Optional<T> getStaticValueOptionally(String field, Class<T> classOfT) {
return Optional.ofNullable(getStaticValue(field, classOfT));
}
public <T> Optional<T> getStaticValueOptionally(String field) {
return Optional.ofNullable(getStaticValue(field));
}
/**
* Get the named field value for a given long input. This uses parameter type inference -- The casting
* to the return type will be based on the type of any assignment or casting on the caller's side.
* Thus, if the actual type is not compatable to a cast to the needed return type, a casting error will
* be thrown.
*
* @param field The name of the field to get.
* @param input The seed value, or cycle value for which to generate the value.
* @param <T> The parameter type of the returned value. Inferred from usage context.
* @return The value.
*/
public <T> T get(String field, long input) {
if (statics.containsKey(field)) {
return (T) statics.get(field);
}
if (dynamics.containsKey(field)) {
return (T) dynamics.get(field).apply(input);
}
return null;
}
/**
* Get the map of all fields for the given input cycle.
*
* @param l seed value, cycle number, input...
* @return A map of named objects
*/
public Map<String, Object> getMap(long l) {
return apply(l);
}
public Set<String> getDefinedNames() {
HashSet<String> nameSet = new HashSet<>(statics.keySet());
nameSet.addAll(dynamics.keySet());
return nameSet;
}
public <V> LongFunction<V> getAsFunctionOr(String name, V defaultValue) {
if (isDefinedStatic(name)) {
V value = getStaticValue(name);
return l -> value;
} else if (isDefinedDynamic(name)) {
return l -> get(name, l);
} else {
return l -> defaultValue;
}
}
public boolean isDefined(String field) {
return statics.containsKey(field) || dynamics.containsKey(field);
}
public boolean isDefinedAll(String... fields) {
for (String field : fields) {
if (!statics.containsKey(field) && !dynamics.containsKey(field)) {
return false;
}
}
return true;
}
public void requireStaticFields(String... fields) {
for (String field : fields) {
if (!statics.containsKey(field)) {
Set<String> missing = new HashSet<>();
for (String readoutfield : fields) {
if (!statics.containsKey(readoutfield)) {
missing.add(readoutfield);
}
}
throw new OpConfigError("Fields " + missing + " are required to be defined with static values for this type of operation.");
}
}
}
public LongFunction<List<Object>> newListBinder(String... fields) {
return new ListBinder(this, fields);
}
public LongFunction<List<Object>> newListBinder(List<String> fields) {
return new ListBinder(this, fields);
}
public LongFunction<Map<String, Object>> newOrderedMapBinder(String... fields) {
return new OrderedMapBinder(this, fields);
}
public LongFunction<Object[]> newArrayBinder(String... fields) {
return new ArrayBinder(this, fields);
}
public LongFunction<Object[]> newArrayBinder(List<String> fields) {
return new ArrayBinder(this, fields);
}
public LongFunction<Object[]> newArrayBinderFromBindPoints(List<BindPoint> bindPoints) {
return new ArrayBinder(bindPoints);
}
public LongFunction<?> getMapper(String field) {
LongFunction<?> mapper = dynamics.get(field);
return mapper;
}
public int getSize() {
return this.mapsize;
}
public boolean isUndefined(String field) {
return !(statics.containsKey(field) || dynamics.containsKey(field));
}
// ParsedCommand parseField(String srcField, Function<String,Map<String,Object>> parser) {
//
// String field = Optional.ofNullable(statics.get(srcField))
// .filter(o -> o instanceof CharSequence)
// .map(Object::toString)
// .orElseThrow();
//
// Map<String, Object> newFields = parser.apply(field);
// apply(newFields)
//
// }
}

View File

@ -1,6 +1,6 @@
package io.nosqlbench.engine.api.templating.binders;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.nb.api.errors.OpConfigError;
import io.nosqlbench.virtdata.core.bindings.DataMapper;
import io.nosqlbench.virtdata.core.bindings.VirtData;
@ -17,7 +17,7 @@ public class ArrayBinder implements LongFunction<Object[]> {
private final LongFunction<?>[] mapperary;
private final int[] dindexes;
public ArrayBinder(ParsedCommand cmd, String[] fields) {
public ArrayBinder(ParsedOp cmd, String[] fields) {
this.protoary = new Object[fields.length];
this.mapperary = new LongFunction<?>[fields.length];
int[] indexes = new int[fields.length];
@ -25,7 +25,7 @@ public class ArrayBinder implements LongFunction<Object[]> {
for (int i = 0; i < fields.length; i++) {
String field = fields[i];
if (cmd.isDefinedStatic(field)) {
if (cmd.isStatic(field)) {
protoary[i] = cmd.getStaticValue(field);
} else if (cmd.isDefinedDynamic(field)) {
mapperary[i] = cmd.getMapper(field);
@ -37,7 +37,7 @@ public class ArrayBinder implements LongFunction<Object[]> {
this.dindexes = Arrays.copyOf(indexes, nextIndex);
}
public ArrayBinder(ParsedCommand cmd, List<String> fields) {
public ArrayBinder(ParsedOp cmd, List<String> fields) {
this(cmd, fields.toArray(new String[0]));
}

View File

@ -1,6 +1,6 @@
package io.nosqlbench.engine.api.templating.binders;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.nb.api.errors.OpConfigError;
import java.util.ArrayList;
@ -14,7 +14,7 @@ public class ListBinder implements LongFunction<List<Object>> {
private final ArrayList<LongFunction<?>> mapperlist;
private final int[] dindexes;
public ListBinder(ParsedCommand cmd, String... fields) {
public ListBinder(ParsedOp cmd, String... fields) {
this.protolist = new ArrayList<>(fields.length);
this.mapperlist = new ArrayList<>(fields.length);
int[] indexes = new int[fields.length];
@ -22,7 +22,7 @@ public class ListBinder implements LongFunction<List<Object>> {
for (int i = 0; i < fields.length; i++) {
String field = fields[i];
if (cmd.isDefinedStatic(field)) {
if (cmd.isStatic(field)) {
protolist.add(cmd.getStaticValue(field));
mapperlist.add(null);
} else if (cmd.isDefinedDynamic(field)) {
@ -36,7 +36,7 @@ public class ListBinder implements LongFunction<List<Object>> {
this.dindexes = Arrays.copyOf(indexes,lastIndex);
}
public ListBinder(ParsedCommand cmd, List<String> fields) {
public ListBinder(ParsedOp cmd, List<String> fields) {
this(cmd,fields.toArray(new String[0]));
}

View File

@ -1,6 +1,6 @@
package io.nosqlbench.engine.api.templating.binders;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.nb.api.errors.OpConfigError;
import java.util.HashMap;
@ -13,9 +13,9 @@ public class OrderedMapBinder implements LongFunction<Map<String, Object>> {
private final Map<String,Object> protomap = new LinkedHashMap<>();
private final Map<String,LongFunction<?>> bindermap = new HashMap<>();
public OrderedMapBinder(ParsedCommand cmd, String... fields) {
public OrderedMapBinder(ParsedOp cmd, String... fields) {
for (String field : fields) {
if (cmd.isDefinedStatic(field)) {
if (cmd.isStatic(field)) {
protomap.put(field,cmd.getStaticValue(field));
} else if (cmd.isDefinedDynamic(field)) {
bindermap.put(field,cmd.getMapper(field));

View File

@ -61,7 +61,7 @@ which is the same across all driver types that can be used with NoSQLBench.
The Op Templates which are provided by users are normalized by NoSQLBench into a standard
representation that is used within the op mapping and synthesis steps. This representation is
provided by the ParsedCommand and ParsedTemplate APIs. The User-Facing construct is _Op Template_,
provided by the ParsedOp and ParsedTemplate APIs. The User-Facing construct is _Op Template_,
while the developer building driver adapters only sees _Parsed Commands_ and a fully-normalized API.
## Effective Op Mapping
@ -74,9 +74,9 @@ constructor. Op Mappers may need access to the activity's parameters or the acti
These can be provided from the DriverAdapter base type when needed.
Assuming you provide the activity params and the space cache to an OpMapper implementation, when
it's `apply(ParsedCommand cmd)` method is called, you have access to a few levels of information:
it's `apply(ParsedOp cmd)` method is called, you have access to a few levels of information:
1. The ParsedCommand -- representing the specific details of an operation to be performed:
1. The ParsedOp -- representing the specific details of an operation to be performed:
* op field names
* static field values - literal values or any non-string collection type (map, set, list)
* dynamic field values - Any type which contains a string template or a single binding
@ -142,12 +142,12 @@ Activites have configuration at various levels:
5. op template fields
Op template fields (seen by the NB driver developer through the
ParsedCommand API) are properly meant to specify a distinct type of operation
ParsedOp API) are properly meant to specify a distinct type of operation
by its defined properties, no less or more. However, users will sometimes
put op params into the op template alongside the op fields. This is *OK*.
*The rule of thumb is to ensure that a named field can only be used as an
op field or an op param but not both.* Each ParsedCommand has access to
op field or an op param but not both.* Each ParsedOp has access to
all of the layers above, and should be used to extract out the fields
which are properly configuration level data before the fields are used
for op mapping. By using this technique, op fields can be configured from any convenient

View File

@ -1,65 +0,0 @@
package io.nosqlbench.engine.api.templating;
import io.nosqlbench.engine.api.activityconfig.yaml.OpData;
import io.nosqlbench.nb.api.config.standard.ConfigModel;
import io.nosqlbench.nb.api.config.standard.Param;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import java.util.function.LongFunction;
import static org.assertj.core.api.Assertions.assertThat;
public class ParsedCommandTest {
ParsedCommand pc = new ParsedCommand(
new OpData().applyFields(
Map.of(
"op", Map.of(
"stmt", "test",
"dyna1", "{dyna1}",
"dyna2", "{{NumberNameToString()}}",
"identity", "{{Identity()}}"
),
"bindings", Map.of(
"dyna1", "NumberNameToString()"
)
)
),
ConfigModel.of(ParsedCommandTest.class)
.add(Param.defaultTo("testcfg","testval"))
.asReadOnly()
.apply(Map.of())
);
@Test
public void testParsedCommand() {
Map<String, Object> m1 = pc.apply(0);
assertThat(m1).containsEntry("stmt", "test");
assertThat(m1).containsEntry("dyna1","zero");
assertThat(m1).containsEntry("dyna2","zero");
assertThat(m1).containsEntry("identity", 0L);
}
@Test
public void testNewListBinder() {
LongFunction<List<Object>> lb = pc.newListBinder("dyna1", "identity", "dyna2", "identity");
List<Object> objects = lb.apply(1);
assertThat(objects).isEqualTo(List.of("one",1L,"one",1L));
}
@Test
public void testNewMapBinder() {
LongFunction<Map<String, Object>> mb = pc.newOrderedMapBinder("dyna1", "identity", "dyna2");
Map<String, Object> objects = mb.apply(2);
assertThat(objects).isEqualTo(Map.<String,Object>of("dyna1","two","identity",2L,"dyna2","two"));
}
@Test
public void testNewAryBinder() {
LongFunction<Object[]> ab = pc.newArrayBinder("dyna1", "dyna1", "identity", "identity");
Object[] objects = ab.apply(3);
assertThat(objects).isEqualTo(new Object[]{"three","three",3L,3L});
}
}

View File

@ -21,7 +21,7 @@ import io.nosqlbench.engine.api.activityimpl.input.ProgressCapable;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.engine.api.metrics.ActivityMetrics;
import io.nosqlbench.engine.api.templating.CommandTemplate;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.engine.api.templating.StrInterpolator;
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
import io.nosqlbench.nb.api.errors.BasicError;
@ -427,11 +427,11 @@ public class SimpleActivity implements Activity, ProgressCapable {
}
protected <O extends Op> OpSequence<OpDispenser<O>> createOpSourceFromCommands(
Function<ParsedCommand, OpDispenser<O>> opinit,
Function<ParsedOp, OpDispenser<O>> opinit,
NBConfiguration cfg,
List<Function<Map<String, Object>, Map<String, Object>>> parsers
) {
Function<OpTemplate, ParsedCommand> f = t -> new ParsedCommand(t, cfg, parsers);
Function<OpTemplate, ParsedOp> f = t -> new ParsedOp(t, cfg, parsers);
Function<OpTemplate, OpDispenser<O>> opTemplateOFunction = f.andThen(opinit);
return createOpSequence(opTemplateOFunction);
}

View File

@ -7,7 +7,7 @@ import io.nosqlbench.engine.api.activityimpl.ActivityDef;
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
import io.nosqlbench.engine.api.activityimpl.SimpleActivity;
import io.nosqlbench.engine.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.engine.api.templating.ParsedCommand;
import io.nosqlbench.engine.api.templating.ParsedOp;
import io.nosqlbench.nb.api.errors.OpConfigError;
import java.util.List;
@ -33,7 +33,7 @@ public class StandardActivity<R extends Op,S> extends SimpleActivity {
this.adapter = adapter;
try {
Function<ParsedCommand, OpDispenser<R>> opmapper = adapter.getOpMapper();
Function<ParsedOp, OpDispenser<R>> opmapper = adapter.getOpMapper();
Function<Map<String, Object>, Map<String, Object>> preprocessor = adapter.getPreprocessor();
sequence = createOpSourceFromCommands(opmapper, adapter.getConfiguration(), List.of(preprocessor));
opsource= OpSource.of(sequence);