fix initializion order bug in CQL op mapping

This commit is contained in:
Jonathan Shook 2022-02-16 16:05:17 -06:00
parent 195986465b
commit 3df691b1f8
7 changed files with 25 additions and 52 deletions

View File

@ -12,7 +12,6 @@ import java.util.function.LongFunction;
public abstract class BaseCqlStmtDispenser extends BaseOpDispenser<Cqld4CqlOp> {
private final LongFunction<Statement> stmtFunc;
private final int maxpages;
private final Cqld4OpMetrics metrics = new Cqld4OpMetrics();
private final LongFunction<CqlSession> sessionFunc;
@ -21,7 +20,6 @@ public abstract class BaseCqlStmtDispenser extends BaseOpDispenser<Cqld4CqlOp> {
public BaseCqlStmtDispenser(LongFunction<CqlSession> sessionFunc, ParsedOp op) {
super(op);
this.sessionFunc = sessionFunc;
this.stmtFunc = this.getCommonStmtFunc(op);
this.maxpages = op.getStaticConfigOr("maxpages",1);
this.isRetryReplace = op.getStaticConfigOr("retryreplace",false);
}
@ -37,41 +35,20 @@ public abstract class BaseCqlStmtDispenser extends BaseOpDispenser<Cqld4CqlOp> {
public LongFunction<CqlSession> getSessionFunc() {
return sessionFunc;
}
/**
* Implement this method to define a statement function, considering only
* the functionality that is specific to that statement type.
* Do not implement decorators which apply to {@link Statement} as these are
* applied uniformly internal to the logic of {@link #getStmtFunc()}.
* @param op The parsed op template
* @return A statement function
*/
protected abstract LongFunction<Statement> getPartialStmtFunction(ParsedOp op);
/**
* All implementations of a CQL Statement Dispenser should be using the method
* provided by this function. This ensures that {@link Statement}-level attributes
* are handled uniformly and in one place.
* @return A function which produces a statement, fully ready to execute, with all
* cross-type attributes handled consistently.
*/
public LongFunction<Statement> getStmtFunc() {
return stmtFunc;
}
/**
* Any {@link Statement}-level attributes need to be handled here.
* This is the initializer for the {@link #getStmtFunc()}} accessor method.
*
* This takes the base statement function and decorates it optionally with each
* additional qualified modifier, short-circuiting those which are not specified.
* This allows default behavior to take precedence as well as avoids unnecessary calling
* overhead for implicit attributes.
* @param op A parsed op template.
* @return A function which is used to construct {@link Statement} objects, ready to run.
* However, this method is hidden to ensure that it is used only as a one-time initializer
* at construction time.
* overhead for implicit attributes. This should be called when the stmt function is
* initialized within each dispenser, not for each time dispensing occurs.
*/
private LongFunction<Statement> getCommonStmtFunc(ParsedOp op) {
LongFunction<Statement> partial = getPartialStmtFunction(op);
protected LongFunction<Statement> getEnhancedStmtFunc(LongFunction<Statement> basefunc, ParsedOp op) {
LongFunction<Statement> partial = basefunc;
partial = op.enhanceEnum(partial, "cl", DefaultConsistencyLevel.class, Statement::setConsistencyLevel);
partial = op.enhanceEnum(partial, "scl", DefaultConsistencyLevel.class, Statement::setSerialConsistencyLevel);
partial = op.enhance(partial, "idempotent", Boolean.class, Statement::setIdempotent);

View File

@ -16,26 +16,26 @@ public class Cqld4PreparedStmtDispenser extends BaseCqlStmtDispenser {
private final RSProcessors processors;
private final LongFunction<Statement> stmtFunc;
private final ParsedTemplate stmtTpl;
private PreparedStatement preparedStmt;
private CqlSession boundSession;
public Cqld4PreparedStmtDispenser(LongFunction<CqlSession> sessionFunc, ParsedOp cmd, RSProcessors processors) {
public Cqld4PreparedStmtDispenser(LongFunction<CqlSession> sessionFunc, ParsedOp cmd, ParsedTemplate stmtTpl, RSProcessors processors) {
super(sessionFunc, cmd);
if (cmd.isDynamic("space")) {
throw new RuntimeException("Prepared statements and dynamic space values are not supported." +
" This would churn the prepared statement cache, defeating the purpose of prepared statements.");
}
this.processors = processors;
stmtFunc = super.getStmtFunc();
this.stmtTpl = stmtTpl;
stmtFunc = createStmtFunc(cmd);
}
@Override
protected LongFunction<Statement> getPartialStmtFunction(ParsedOp cmd) {
protected LongFunction<Statement> createStmtFunc(ParsedOp cmd) {
LongFunction<Object[]> varbinder;
ParsedTemplate parsed = cmd.getStmtAsTemplate().orElseThrow();
varbinder = cmd.newArrayBinderFromBindPoints(parsed.getBindPoints());
String preparedQueryString = parsed.getPositionalStatement(s -> "?");
varbinder = cmd.newArrayBinderFromBindPoints(stmtTpl.getBindPoints());
String preparedQueryString = stmtTpl.getPositionalStatement(s -> "?");
boundSession = getSessionFunc().apply(0);
preparedStmt = boundSession.prepare(preparedQueryString);
@ -43,7 +43,7 @@ public class Cqld4PreparedStmtDispenser extends BaseCqlStmtDispenser {
Object[] apply = varbinder.apply(c);
return preparedStmt.bind(apply);
};
return boundStmtFunc;
return super.getEnhancedStmtFunc(boundStmtFunc, cmd);
}
@Override
@ -51,7 +51,7 @@ public class Cqld4PreparedStmtDispenser extends BaseCqlStmtDispenser {
return new Cqld4CqlPreparedStatement(
boundSession,
(BoundStatement) getStmtFunc().apply(value),
(BoundStatement) stmtFunc.apply(value),
getMaxPages(),
isRetryReplace(),
processors

View File

@ -18,12 +18,12 @@ public class Cqld4RawStmtDispenser extends BaseCqlStmtDispenser {
public Cqld4RawStmtDispenser(LongFunction<CqlSession> sessionFunc, LongFunction<String> targetFunction, ParsedOp cmd) {
super(sessionFunc, cmd);
this.targetFunction=targetFunction;
this.stmtFunc = super.getStmtFunc();
this.stmtFunc = createStmtFunc(cmd);
}
@Override
protected LongFunction<Statement> getPartialStmtFunction(ParsedOp cmd) {
return l -> new SimpleStatementBuilder(targetFunction.apply(l)).build();
protected LongFunction<Statement> createStmtFunc(ParsedOp cmd) {
LongFunction<Statement> basefunc = l -> new SimpleStatementBuilder(targetFunction.apply(l)).build();
return super.getEnhancedStmtFunc(basefunc,cmd);
}
@Override

View File

@ -16,12 +16,11 @@ public class Cqld4SimpleCqlStmtDispenser extends BaseCqlStmtDispenser {
public Cqld4SimpleCqlStmtDispenser(LongFunction<CqlSession> sessionFunc, LongFunction<String> targetFunction, ParsedOp cmd) {
super(sessionFunc,cmd);
this.targetFunction=targetFunction;
this.stmtFunc = super.getStmtFunc();
this.stmtFunc =createStmtFunc(cmd);
}
@Override
protected LongFunction<Statement> getPartialStmtFunction(ParsedOp op) {
return l -> SimpleStatement.newInstance(targetFunction.apply(l));
protected LongFunction<Statement> createStmtFunc(ParsedOp op) {
return super.getEnhancedStmtFunc(l -> SimpleStatement.newInstance(targetFunction.apply(l)),op);
}
@Override

View File

@ -51,9 +51,7 @@ public class CqlD4PreparedStmtMapper implements OpMapper<Cqld4CqlOp> {
});
});
boolean prepared = cmd.getStaticConfigOr("prepared", true);
return new Cqld4PreparedStmtDispenser(sessionFunc, cmd, processors);
return new Cqld4PreparedStmtDispenser(sessionFunc, cmd, stmtTpl, processors);
}
}

View File

@ -133,7 +133,6 @@ names for the classic form have not changed.
Like all driver adapters, the CQLd4 driver has the ability to use multiple low-level
driver instances for the purposes of advanced testing. To take advantage of this,
simply set a `space` parameter in your op templates, with a dynamic value.
__WARNING__: If you use the driver cache feature, be aware that creating a large
number of driver instances will be very expensive. Generally driver instances are meant
to be initialized and then shared throughout the life-cycle of an application process.

View File

@ -151,9 +151,9 @@ public class ParsedOp implements LongFunction<Map<String, ?>>, StaticFieldReader
return tmap.getStaticValue(field);
}
public Optional<ParsedTemplate> getStmtAsTemplate() {
return _opTemplate.getParsed();
}
// public Optional<ParsedTemplate> getStmtAsTemplate() {
// return _opTemplate.getParsed();
// }
public Optional<ParsedTemplate> getAsTemplate(String fieldname) {