mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
additional improvements to cqld4 driver
This commit is contained in:
parent
05b3a50ec9
commit
e7668610c3
@ -3,8 +3,8 @@ package io.nosqlbench.adapter.cqld4;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import io.nosqlbench.adapter.cqld4.opdispensers.CqlD4PreparedBatchOpDispenser;
|
||||
import io.nosqlbench.adapter.cqld4.opdispensers.Cqld4BatchStatementDispenser;
|
||||
import io.nosqlbench.adapter.cqld4.opdispensers.Cqld4PreparedOpDispenser;
|
||||
import io.nosqlbench.adapter.cqld4.opdispensers.Cqld4SimpleCqlStatementDispenser;
|
||||
import io.nosqlbench.adapter.cqld4.opdispensers.Cqld4PreparedStmtDispenser;
|
||||
import io.nosqlbench.adapter.cqld4.opdispensers.Cqld4SimpleCqlStmtDispenser;
|
||||
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
|
||||
import io.nosqlbench.engine.api.activityimpl.OpMapper;
|
||||
import io.nosqlbench.engine.api.activityimpl.uniform.DriverSpaceCache;
|
||||
@ -32,11 +32,11 @@ public class Cqld4OpMapper implements OpMapper<Cqld4Op> {
|
||||
if (prepared && batch) {
|
||||
return new CqlD4PreparedBatchOpDispenser(session, cmd, cfg);
|
||||
} else if (prepared) {
|
||||
return new Cqld4PreparedOpDispenser(session, cmd, cfg);
|
||||
return new Cqld4PreparedStmtDispenser(session, cmd);
|
||||
} else if (batch) {
|
||||
return new Cqld4BatchStatementDispenser(session, cmd, cfg);
|
||||
} else {
|
||||
return new Cqld4SimpleCqlStatementDispenser(session, cmd, cfg);
|
||||
return new Cqld4SimpleCqlStmtDispenser(session, cmd, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,21 +0,0 @@
|
||||
package io.nosqlbench.adapter.cqld4;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Maintain a cache of objects to use in a CQLD4 context.
|
||||
*/
|
||||
public class Cqld4SpaceCache {
|
||||
private final ConcurrentHashMap<String, Cqld4Space> clientscopes = new ConcurrentHashMap<>();
|
||||
private final Cqld4DriverAdapter adapter;
|
||||
|
||||
public Cqld4SpaceCache(Cqld4DriverAdapter adapter) {
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
public Cqld4Space getSpace(String name) {
|
||||
return clientscopes.computeIfAbsent(name, newName -> {
|
||||
return new Cqld4Space(adapter);
|
||||
});
|
||||
}
|
||||
}
|
@ -7,36 +7,28 @@ import io.nosqlbench.adapter.cqld4.Cqld4Op;
|
||||
import io.nosqlbench.adapter.cqld4.optypes.Cqld4PreparedStatement;
|
||||
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
|
||||
import io.nosqlbench.engine.api.templating.ParsedCommand;
|
||||
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
|
||||
import io.nosqlbench.virtdata.core.templates.ParsedTemplate;
|
||||
|
||||
import java.util.function.LongFunction;
|
||||
|
||||
public class Cqld4PreparedOpDispenser implements OpDispenser<Cqld4Op> {
|
||||
public class Cqld4PreparedStmtDispenser implements OpDispenser<Cqld4Op> {
|
||||
|
||||
private final CqlSession session;
|
||||
private final ParsedCommand cmd;
|
||||
private final NBConfiguration cfg;
|
||||
|
||||
private final LongFunction<Object[]> varbinder;
|
||||
private final PreparedStatement preparedStmt;
|
||||
|
||||
public Cqld4PreparedOpDispenser(CqlSession session, ParsedCommand cmd, NBConfiguration cfg) {
|
||||
public Cqld4PreparedStmtDispenser(CqlSession session, ParsedCommand cmd) {
|
||||
|
||||
this.session = session;
|
||||
this.cmd = cmd;
|
||||
this.cfg = cfg;
|
||||
// if (cmd.isDefinedDynamic("stmt")) {
|
||||
// throw new OpConfigError("You must have a static template to create prepared statements. (Do not make the stmt field a binding itself)");
|
||||
// }
|
||||
|
||||
ParsedTemplate parsed = cmd.getStmtAsTemplate().orElseThrow();
|
||||
String preparedQueryString = parsed.getPositionalStatement(s -> "?");
|
||||
|
||||
varbinder = cmd.newArrayBinderFromBindPoints(parsed.getBindPoints());
|
||||
preparedStmt = session.prepare(preparedQueryString);
|
||||
|
||||
String preparedQueryString = parsed.getPositionalStatement(s -> "?");
|
||||
preparedStmt = session.prepare(preparedQueryString);
|
||||
}
|
||||
|
||||
// TODO: Explain in the dev guide that apply in the op dispenser should do all the "bind" level stuff
|
||||
@Override
|
||||
public Cqld4Op apply(long value) {
|
||||
Object[] parameters = varbinder.apply(value);
|
@ -8,13 +8,13 @@ import io.nosqlbench.engine.api.activityimpl.OpDispenser;
|
||||
import io.nosqlbench.engine.api.templating.ParsedCommand;
|
||||
import io.nosqlbench.nb.api.config.standard.NBConfiguration;
|
||||
|
||||
public class Cqld4SimpleCqlStatementDispenser implements OpDispenser<Cqld4Op> {
|
||||
public class Cqld4SimpleCqlStmtDispenser implements OpDispenser<Cqld4Op> {
|
||||
|
||||
private final CqlSession session;
|
||||
private final ParsedCommand cmd;
|
||||
private final NBConfiguration cfg;
|
||||
|
||||
public Cqld4SimpleCqlStatementDispenser(CqlSession session, ParsedCommand cmd, NBConfiguration cfg) {
|
||||
public Cqld4SimpleCqlStmtDispenser(CqlSession session, ParsedCommand cmd, NBConfiguration cfg) {
|
||||
this.session = session;
|
||||
this.cmd = cmd;
|
||||
this.cfg = cfg;
|
@ -17,15 +17,46 @@ import java.util.function.LongFunction;
|
||||
* static and dynamic elements of the operation together.
|
||||
* In most cases, implementations of OpDispenser will be constructed
|
||||
* within the logic of an {@link OpMapper} which is responsible for
|
||||
* determine the type of OpDispenser to use as associated with a specific
|
||||
* type {@code (<T>)}.
|
||||
* determining the type of OpDispenser to use as associated with a specific
|
||||
* type {@code (<T>)}. The OpMapper is called for each type of operation
|
||||
* that is active during activity initialization. It's primary responsibility
|
||||
* is figuring out what types of {@link OpDispenser}s to create based
|
||||
* on the op templates provided by users. Once the activity is initialized,
|
||||
* a set of op dispensers is held as live dispensers to use as needed
|
||||
* to synthesize new operations from generated data in real time.
|
||||
* </p>
|
||||
*
|
||||
* <hr/>
|
||||
* <h2>Implementation Strategy</h2>
|
||||
* <p>OpDispenser implementations are intended to be implemented
|
||||
* for each type of distinct operation that is supported by a
|
||||
* {@link io.nosqlbench.engine.api.activityimpl.uniform.DriverAdapter}.
|
||||
* That is not to say that an OpDispenser can't be responsible for
|
||||
* producing multiple types of operations. Operations which are similar
|
||||
* in what they need and how they are constructed make sense to be implemented
|
||||
* in the same op dispenser. Those which need different construction
|
||||
* logic or fundamentally different types of field values should be implemented
|
||||
* separately. The rule of thumb is to ensure that op construction patterns
|
||||
* are easy to understand at the mapping level ({@link OpMapper}),
|
||||
* and streamlined for fast execution at the synthesis level ({@link OpDispenser}).
|
||||
*
|
||||
* @param <T> The parameter type of the actual operation which will be used
|
||||
* to hold all the details for executing an operation,
|
||||
* generally something that implements {@link Runnable}.
|
||||
* something that implements {@link Runnable}.
|
||||
*/
|
||||
public interface OpDispenser<T> extends LongFunction<T> {
|
||||
@Override
|
||||
|
||||
/**
|
||||
* The apply method in an op dispenser should do all of the work of
|
||||
* creating an operation that is executable by some other caller.
|
||||
* The value produced by the apply method should not require
|
||||
* additional processing if a caller wants to execute the operation
|
||||
* multiple times, as for retries.
|
||||
*
|
||||
* @param value The cycle number which serves as the seed for any
|
||||
* generated op fields to be bound into an operation.
|
||||
* @return an executable operation
|
||||
*/
|
||||
@Override
|
||||
T apply(long value);
|
||||
}
|
||||
|
@ -8,23 +8,42 @@ import java.util.function.Function;
|
||||
* <p>
|
||||
* <h2>Synopsis</h2>
|
||||
* An OpMapper is responsible for converting parsed op templates
|
||||
* into dispensers of operations. the intention of the user,
|
||||
* into dispensers of operations based on the intention of the user.
|
||||
*
|
||||
* Op Templates as expressed as a set of field values, some literal, and
|
||||
* some virtualized (to be generated per-cycle). The op template is
|
||||
* parsed into a {@link ParsedCommand}.
|
||||
* some dynamic, to be generated based on a specific cycle value.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <h2>Concepts</h2>
|
||||
* The OpMapper is a function (the op mapper) that returns another function (the op synthesizer).
|
||||
* The returned function is then used to create actual operations in some executable form.
|
||||
* The difference
|
||||
* between the OpMapper and the OpDispenser is this: The OpMapper is responsible for
|
||||
* identifying exactly what type of operation the user intends, according to the rules
|
||||
* op construction documented by the driver maintainer. The OpDispenser is responsible
|
||||
* for efficiently dispensing objects of a given type which can be used to execute an
|
||||
* operation. In short, mapping op templates to the users' intention must happen first, and
|
||||
* then building an operation efficiently with that specific knowledge can happen after.
|
||||
* The OpMapper is basically a function that returns another function. The responsibility
|
||||
* for creating executable operations is shared between the {@link OpMapper} and the
|
||||
* {@link OpDispenser}. The logic needed to determine the type of an operation intended
|
||||
* by the user (mapping) is different from the logic you use to construct that specific
|
||||
* type of operation once you know the intent (dispensing). If you look at a example
|
||||
* of doing these together in code, there is always a point at which you know what is
|
||||
* needed to construct an operation. If you draw a line at this point, it represents
|
||||
* the separation of responsibilities between op mappers and op dispensers.
|
||||
* </p>
|
||||
*
|
||||
* <p>This separation of responsibilities serves as both a conceptual clarification as
|
||||
* well as a way to optimize runtime behavior. In the NoSQLBench model, all of the first step
|
||||
* (mapping, the responsibility of this class) occurs at initialization time of an activity.
|
||||
* This means that mapping logic can be as clear, readable, type-safe and obvious as
|
||||
* possible without any negative effect on the later phase. In fact, clarity and obviousness
|
||||
* at this level serves to keep implementations of the next phase much more straight-forward
|
||||
* and streamlined, since all that is left to do is assemble the known elements together
|
||||
* into an executable operation.</p>
|
||||
*
|
||||
* </hr>
|
||||
* <h2>Implementation Strategy</h2>
|
||||
* <p>
|
||||
* A view of an op template is provided in the {@link ParsedCommand} 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
|
||||
* on a distinct signature
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
|
@ -417,7 +417,7 @@ public class SimpleActivity implements Activity, ProgressCapable {
|
||||
* @param <O>
|
||||
* @return
|
||||
*/
|
||||
protected <O> OpSequence<OpDispenser<O>> createOpSequenceFromCommands(Function<CommandTemplate, OpDispenser<O>> opinit) {
|
||||
protected <O extends Runnable> OpSequence<OpDispenser<O>> createOpSequenceFromCommands(Function<CommandTemplate, OpDispenser<O>> opinit) {
|
||||
Function<OpTemplate, CommandTemplate> f = CommandTemplate::new;
|
||||
Function<OpTemplate, OpDispenser<O>> opTemplateOFunction = f.andThen(opinit);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user