From f7bf1a0276f336bcff145a254f6234c2a9b19d04 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Fri, 9 Jul 2021 15:35:21 -0500 Subject: [PATCH] improvements to cqld4 --- .../adapter/cqld4/Cqld4DriverAdapter.java | 5 +- .../adapter/cqld4/Cqld4OpMapper.java | 16 +---- .../driver/direct/DirectCallAdapter.java | 5 +- .../driver/direct/DirectOpMapper.java | 9 ++- .../activityimpl/uniform/DriverAdapter.java | 67 +++++++++++++++---- .../engine/api/templating/ParsedCommand.java | 24 +++++-- 6 files changed, 83 insertions(+), 43 deletions(-) diff --git a/driver-cqld4/src/main/java/io/nosqlbench/adapter/cqld4/Cqld4DriverAdapter.java b/driver-cqld4/src/main/java/io/nosqlbench/adapter/cqld4/Cqld4DriverAdapter.java index 616803fc3..47abcf903 100644 --- a/driver-cqld4/src/main/java/io/nosqlbench/adapter/cqld4/Cqld4DriverAdapter.java +++ b/driver-cqld4/src/main/java/io/nosqlbench/adapter/cqld4/Cqld4DriverAdapter.java @@ -1,9 +1,8 @@ package io.nosqlbench.adapter.cqld4; -import io.nosqlbench.engine.api.activityimpl.OpDispenser; +import io.nosqlbench.engine.api.activityimpl.OpMapper; import io.nosqlbench.engine.api.activityimpl.uniform.BaseDriverAdapter; import io.nosqlbench.engine.api.activityimpl.uniform.DriverAdapter; -import io.nosqlbench.engine.api.templating.ParsedCommand; import io.nosqlbench.nb.annotations.Service; import java.util.function.Function; @@ -14,7 +13,7 @@ public class Cqld4DriverAdapter extends BaseDriverAdapter { private Cqld4SpaceCache sessionCache; @Override - public Function> getOpMapper() { + public OpMapper getOpMapper() { return new Cqld4OpMapper(getSpaceCache()); } diff --git a/driver-cqld4/src/main/java/io/nosqlbench/adapter/cqld4/Cqld4OpMapper.java b/driver-cqld4/src/main/java/io/nosqlbench/adapter/cqld4/Cqld4OpMapper.java index 07960d809..8a6648ca6 100644 --- a/driver-cqld4/src/main/java/io/nosqlbench/adapter/cqld4/Cqld4OpMapper.java +++ b/driver-cqld4/src/main/java/io/nosqlbench/adapter/cqld4/Cqld4OpMapper.java @@ -9,7 +9,6 @@ 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.nb.api.errors.BasicError; public class Cqld4OpMapper implements OpMapper { @@ -22,18 +21,9 @@ public class Cqld4OpMapper implements OpMapper { public OpDispenser apply(ParsedCommand cmd) { - // if session field = static string, else ... - - boolean prepared = cmd.getStaticValueOr("prepared",false); - boolean batch = cmd.getStaticValueOr("boolean",false); - - if (cmd.isDefinedDynamic("session")) { - throw new BasicError("This driver adapter does not support dynamic sessions."); - } - // If it did, we would use something like this instead... - // LongFunction session = cmd.getAsFunctionOr("session", "default"); - - Cqld4Space cqld4Space = cache.get(cmd.getStaticValueOr("session", "default")); + Cqld4Space cqld4Space = cache.get(cmd.getStaticConfigOr("space", "default")); + boolean prepared = cmd.getStaticConfigOr("prepared",true); + boolean batch = cmd.getStaticConfigOr("boolean",false); CqlSession session = cqld4Space.getSession(); if (prepared && batch) { diff --git a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallAdapter.java b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallAdapter.java index b1936d82d..af9fada5a 100644 --- a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallAdapter.java +++ b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallAdapter.java @@ -1,9 +1,8 @@ package io.nosqlbench.driver.direct; -import io.nosqlbench.engine.api.activityimpl.OpDispenser; +import io.nosqlbench.engine.api.activityimpl.OpMapper; import io.nosqlbench.engine.api.activityimpl.uniform.BaseDriverAdapter; import io.nosqlbench.engine.api.activityimpl.uniform.DriverAdapter; -import io.nosqlbench.engine.api.templating.ParsedCommand; import io.nosqlbench.nb.annotations.Service; import java.util.List; @@ -29,7 +28,7 @@ public class DirectCallAdapter extends BaseDriverAdapter { } @Override - public Function> getOpMapper() { + public OpMapper getOpMapper() { return new DirectOpMapper(); } } diff --git a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectOpMapper.java b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectOpMapper.java index 7e2420a40..5629e4ec7 100644 --- a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectOpMapper.java +++ b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectOpMapper.java @@ -1,18 +1,21 @@ package io.nosqlbench.driver.direct; import io.nosqlbench.engine.api.activityimpl.OpDispenser; +import io.nosqlbench.engine.api.activityimpl.OpMapper; import io.nosqlbench.engine.api.templating.ParsedCommand; import io.nosqlbench.nb.api.errors.OpConfigError; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.*; -import java.util.function.Function; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.function.LongFunction; import java.util.stream.Collectors; -public class DirectOpMapper implements Function> { +public class DirectOpMapper implements OpMapper { @Override public OpDispenser apply(ParsedCommand cmd) { diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/DriverAdapter.java b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/DriverAdapter.java index 0e9202537..853f59e1e 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/DriverAdapter.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/activityimpl/uniform/DriverAdapter.java @@ -2,6 +2,7 @@ package io.nosqlbench.engine.api.activityimpl.uniform; import io.nosqlbench.engine.api.activityapi.core.ActivityType; import io.nosqlbench.engine.api.activityimpl.OpDispenser; +import io.nosqlbench.engine.api.activityimpl.OpMapper; import io.nosqlbench.engine.api.templating.ParsedCommand; import java.util.Map; @@ -18,28 +19,63 @@ import java.util.function.Function; *

* * @param The type of Runnable operation which will be used to wrap - * all operations for this driver adapter. This allows you to - * add context or features common to all operations of this - * type. + * all operations for this driver adapter. This allows you to + * add context or features common to all operations of this + * type. * @param The type of context space used by this driver to hold - * cached instances of clients, session, or other native driver - * esoterica. This is the shared state which might be needed - * during construction of R type operations, or even for individual - * operations. + * cached instances of clients, session, or other native driver + * esoterica. This is the shared state which might be needed + * during construction of R type operations, or even for individual + * operations. */ public interface DriverAdapter { /** + *

+ *

Op Mapping

* An Op Mapper is a function which can look at the parsed * fields in a {@link ParsedCommand} and create an OpDispenser. - * An OpDispenser is a function that will produce an special + * An OpDispenser is a function that will produce a special * type {@link R} that this DriverAdapter implements as its - * op implementation. + * op implementation.

+ * + *

+ * The function that is returned is responsible for creating another function. + * This might seem counter-intuitive but it is very intentional because + * of these design constraints: + *

    + *
  • Mapping op semantics to a type of operation must be very clear + * and flexible. Performance is not important at this layer because this is all done + * during initialization time for an activity.
  • + *
  • Synthesizing executable operations from a known type of operational template + * must be done very efficiently. This part is done during activity execution, so + * having the details of how you are going to create an op for execution already + * sorted out is important.
  • + *
+ * + * To clarify the distinction between these two phases, the first is canonically + * called op mapping in the documentation. The second is called + * op synthesis. + *

+ * + *

+ *

A note on implementation strategy

+ * Generally speaking, implementations of this method should interrogate the op fields + * in the ParsedCommand 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 + * specified as bindings. In any case, the op mapping phase is meant to qualify and + * pre-check that the fields provided are valid and specific for a given type of operation. + * What happens within {@link OpDispenser} implementations, however, should do + * as little qualification of field value as possible, focusing simply on constructing + * the type of operation for which they are designed. + *

* * @return a synthesizer function for {@link R} op generation */ - Function> getOpMapper(); + OpMapper getOpMapper(); /** * The preprocessor function allows the driver adapter to remap @@ -47,19 +83,21 @@ public interface DriverAdapter { * At this level, the transform is applied once to the input map * (once per op template) to yield the map that is provided to * {@link io.nosqlbench.engine.api.activityimpl.OpMapper} implementations. + * * @return A function to pre-process the op template fields. */ - default Function,Map> getPreprocessor() { - return f->f; + default Function, Map> getPreprocessor() { + return f -> f; } /** * When a driver needs to identify an error uniquely for the purposes of * routing it to the correct error handler, or naming it in logs, or naming * metrics, override this method in your activity. + * * @return A function that can reliably and safely map an instance of Throwable to a stable name. */ - default Function getErrorNameMapper() { + default Function getErrorNameMapper() { return t -> t.getClass().getSimpleName(); } @@ -75,7 +113,7 @@ public interface DriverAdapter { * * @return A function which can initialize a new S */ - default Function getSpaceInitializer() { + default Function getSpaceInitializer() { return n -> null; } @@ -84,6 +122,7 @@ public interface DriverAdapter { * of a DriverAdapter which are not operations. These are generally * things needed by operations, or things needed during the * construction of operations. + * * @return A cache of named objects */ DriverSpaceCache getSpaceCache(); diff --git a/engine-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedCommand.java b/engine-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedCommand.java index 955af12c2..d1ccd470b 100644 --- a/engine-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedCommand.java +++ b/engine-api/src/main/java/io/nosqlbench/engine/api/templating/ParsedCommand.java @@ -25,11 +25,6 @@ public class ParsedCommand implements LongFunction> { private final static Logger logger = LogManager.getLogger(ParsedCommand.class); - /** - * the name of this operation - **/ - private final String name; - /** * The fields which are statically assigned **/ @@ -50,6 +45,7 @@ public class ParsedCommand implements LongFunction> { private final List> captures = new ArrayList<>(); private final int mapsize; private final LinkedHashMap protomap = new LinkedHashMap<>(); + private final OpTemplate ot; /** * Create a parsed command from an Op template. The op template is simply the normalized view of @@ -62,7 +58,7 @@ public class ParsedCommand implements LongFunction> { } public ParsedCommand(OpTemplate ot, List, Map>> preprocessors) { - this.name = ot.getName(); + this.ot = ot; Map map = ot.getOp().orElseThrow(); for (Function, Map> preprocessor : preprocessors) { @@ -104,7 +100,7 @@ public class ParsedCommand implements LongFunction> { } public String getName() { - return name; + return ot.getName(); } public Map getStaticMap() { @@ -199,6 +195,20 @@ public class ParsedCommand implements LongFunction> { } } + public T getStaticConfigOr(String name, T defaultValue) { + + if (statics.containsKey(name)) { + return (T) statics.get(name); + } else if (ot.getParams().containsKey(name)) { + return (T) ot.getParams().get(name); + } else if (dynamics.containsKey(name)) { + throw new BasicError("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; + } + } + /** * Return an optional value for the named field. This is an {@link Optional} form of {@link #getStaticValue}.