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> { public abstract class BaseCqlStmtDispenser extends BaseOpDispenser<Cqld4CqlOp> {
private final LongFunction<Statement> stmtFunc;
private final int maxpages; private final int maxpages;
private final Cqld4OpMetrics metrics = new Cqld4OpMetrics(); private final Cqld4OpMetrics metrics = new Cqld4OpMetrics();
private final LongFunction<CqlSession> sessionFunc; private final LongFunction<CqlSession> sessionFunc;
@ -21,7 +20,6 @@ public abstract class BaseCqlStmtDispenser extends BaseOpDispenser<Cqld4CqlOp> {
public BaseCqlStmtDispenser(LongFunction<CqlSession> sessionFunc, ParsedOp op) { public BaseCqlStmtDispenser(LongFunction<CqlSession> sessionFunc, ParsedOp op) {
super(op); super(op);
this.sessionFunc = sessionFunc; this.sessionFunc = sessionFunc;
this.stmtFunc = this.getCommonStmtFunc(op);
this.maxpages = op.getStaticConfigOr("maxpages",1); this.maxpages = op.getStaticConfigOr("maxpages",1);
this.isRetryReplace = op.getStaticConfigOr("retryreplace",false); this.isRetryReplace = op.getStaticConfigOr("retryreplace",false);
} }
@ -37,41 +35,20 @@ public abstract class BaseCqlStmtDispenser extends BaseOpDispenser<Cqld4CqlOp> {
public LongFunction<CqlSession> getSessionFunc() { public LongFunction<CqlSession> getSessionFunc() {
return sessionFunc; 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 * All implementations of a CQL Statement Dispenser should be using the method
* provided by this function. This ensures that {@link Statement}-level attributes * provided by this function. This ensures that {@link Statement}-level attributes
* are handled uniformly and in one place. * 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 * This takes the base statement function and decorates it optionally with each
* additional qualified modifier, short-circuiting those which are not specified. * additional qualified modifier, short-circuiting those which are not specified.
* This allows default behavior to take precedence as well as avoids unnecessary calling * This allows default behavior to take precedence as well as avoids unnecessary calling
* overhead for implicit attributes. * overhead for implicit attributes. This should be called when the stmt function is
* @param op A parsed op template. * initialized within each dispenser, not for each time dispensing occurs.
* @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.
*/ */
private LongFunction<Statement> getCommonStmtFunc(ParsedOp op) { protected LongFunction<Statement> getEnhancedStmtFunc(LongFunction<Statement> basefunc, ParsedOp op) {
LongFunction<Statement> partial = getPartialStmtFunction(op); LongFunction<Statement> partial = basefunc;
partial = op.enhanceEnum(partial, "cl", DefaultConsistencyLevel.class, Statement::setConsistencyLevel); partial = op.enhanceEnum(partial, "cl", DefaultConsistencyLevel.class, Statement::setConsistencyLevel);
partial = op.enhanceEnum(partial, "scl", DefaultConsistencyLevel.class, Statement::setSerialConsistencyLevel); partial = op.enhanceEnum(partial, "scl", DefaultConsistencyLevel.class, Statement::setSerialConsistencyLevel);
partial = op.enhance(partial, "idempotent", Boolean.class, Statement::setIdempotent); 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 RSProcessors processors;
private final LongFunction<Statement> stmtFunc; private final LongFunction<Statement> stmtFunc;
private final ParsedTemplate stmtTpl;
private PreparedStatement preparedStmt; private PreparedStatement preparedStmt;
private CqlSession boundSession; 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); super(sessionFunc, cmd);
if (cmd.isDynamic("space")) { if (cmd.isDynamic("space")) {
throw new RuntimeException("Prepared statements and dynamic space values are not supported." + 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 would churn the prepared statement cache, defeating the purpose of prepared statements.");
} }
this.processors = processors; this.processors = processors;
stmtFunc = super.getStmtFunc(); this.stmtTpl = stmtTpl;
stmtFunc = createStmtFunc(cmd);
} }
@Override protected LongFunction<Statement> createStmtFunc(ParsedOp cmd) {
protected LongFunction<Statement> getPartialStmtFunction(ParsedOp cmd) {
LongFunction<Object[]> varbinder; LongFunction<Object[]> varbinder;
ParsedTemplate parsed = cmd.getStmtAsTemplate().orElseThrow(); varbinder = cmd.newArrayBinderFromBindPoints(stmtTpl.getBindPoints());
varbinder = cmd.newArrayBinderFromBindPoints(parsed.getBindPoints()); String preparedQueryString = stmtTpl.getPositionalStatement(s -> "?");
String preparedQueryString = parsed.getPositionalStatement(s -> "?");
boundSession = getSessionFunc().apply(0); boundSession = getSessionFunc().apply(0);
preparedStmt = boundSession.prepare(preparedQueryString); preparedStmt = boundSession.prepare(preparedQueryString);
@ -43,7 +43,7 @@ public class Cqld4PreparedStmtDispenser extends BaseCqlStmtDispenser {
Object[] apply = varbinder.apply(c); Object[] apply = varbinder.apply(c);
return preparedStmt.bind(apply); return preparedStmt.bind(apply);
}; };
return boundStmtFunc; return super.getEnhancedStmtFunc(boundStmtFunc, cmd);
} }
@Override @Override
@ -51,7 +51,7 @@ public class Cqld4PreparedStmtDispenser extends BaseCqlStmtDispenser {
return new Cqld4CqlPreparedStatement( return new Cqld4CqlPreparedStatement(
boundSession, boundSession,
(BoundStatement) getStmtFunc().apply(value), (BoundStatement) stmtFunc.apply(value),
getMaxPages(), getMaxPages(),
isRetryReplace(), isRetryReplace(),
processors processors

View File

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

View File

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

View File

@ -51,9 +51,7 @@ public class CqlD4PreparedStmtMapper implements OpMapper<Cqld4CqlOp> {
}); });
}); });
boolean prepared = cmd.getStaticConfigOr("prepared", true); return new Cqld4PreparedStmtDispenser(sessionFunc, cmd, stmtTpl, processors);
return new Cqld4PreparedStmtDispenser(sessionFunc, cmd, 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 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, 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. 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 __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 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. 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); return tmap.getStaticValue(field);
} }
public Optional<ParsedTemplate> getStmtAsTemplate() { // public Optional<ParsedTemplate> getStmtAsTemplate() {
return _opTemplate.getParsed(); // return _opTemplate.getParsed();
} // }
public Optional<ParsedTemplate> getAsTemplate(String fieldname) { public Optional<ParsedTemplate> getAsTemplate(String fieldname) {