final CodeGenerator<Partitioner> cg = new CodeGenerator<Partitioner>(Partitioner.TEMPLATE_DEFINITION,
context.getFunctionRegistry());
final LogicalExpression materializedExpr = ExpressionTreeMaterializer.materialize(expr, incoming, collector);
if (collector.hasErrors()) {
throw new SchemaChangeException(String.format(
"Failure while trying to materialize incoming schema. Errors:\n %s.",
collector.toErrorString()));
}
// generate code to copy from an incoming value vector to the destination partition's outgoing value vector
JExpression inIndex = JExpr.direct("inIndex");
JExpression bucket = JExpr.direct("bucket");
JType outgoingVectorArrayType = cg.getModel().ref(ValueVector.class).array().array();
JType outgoingBatchArrayType = cg.getModel().ref(OutgoingRecordBatch.class).array();
// generate evaluate expression to determine the hash
CodeGenerator.HoldingContainer exprHolder = cg.addExpr(materializedExpr);
cg.getEvalBlock().decl(JType.parse(cg.getModel(), "int"), "bucket", exprHolder.getValue().mod(JExpr.lit(outgoing.length)));
// declare and assign the array of outgoing record batches
JVar outgoingBatches = cg.clazz.field(JMod.NONE,
outgoingBatchArrayType,
"outgoingBatches");
cg.getSetupBlock().assign(outgoingBatches, JExpr.direct("outgoing"));
// declare a two-dimensional array of value vectors; batch is first dimension, ValueVector is the second
JVar outgoingVectors = cg.clazz.field(JMod.NONE,
outgoingVectorArrayType,
"outgoingVectors");
// create 2d array and build initialization list. For example:
// outgoingVectors = new ValueVector[][] {
// new ValueVector[] {vv1, vv2},
// new ValueVector[] {vv3, vv4}
// });
JArray outgoingVectorInit = JExpr.newArray(cg.getModel().ref(ValueVector.class).array());
int fieldId = 0;
int batchId = 0;
for (OutgoingRecordBatch batch : outgoing) {
JArray outgoingVectorInitBatch = JExpr.newArray(cg.getModel().ref(ValueVector.class));
for (VectorWrapper<?> vv : batch) {
// declare outgoing value vector and assign it to the array
JVar outVV = cg.declareVectorValueSetupAndMember("outgoing[" + batchId + "]",
new TypedFieldId(vv.getField().getType(),
fieldId,
false));
// add vv to initialization list (e.g. { vv1, vv2, vv3 } )
outgoingVectorInitBatch.add(outVV);
++fieldId;
}
// add VV array to initialization list (e.g. new ValueVector[] { ... })
outgoingVectorInit.add(outgoingVectorInitBatch);
++batchId;
fieldId = 0;
}
// generate outgoing value vector 2d array initialization list.
cg.getSetupBlock().assign(outgoingVectors, outgoingVectorInit);
for (VectorWrapper<?> vvIn : incoming) {
// declare incoming value vectors
JVar incomingVV = cg.declareVectorValueSetupAndMember("incoming", new TypedFieldId(vvIn.getField().getType(),
fieldId,
vvIn.isHyper()));
// generate the copyFrom() invocation with explicit cast to the appropriate type
Class<?> vvType = TypeHelper.getValueVectorClass(vvIn.getField().getType().getMinorType(),
vvIn.getField().getType().getMode());
JClass vvClass = cg.getModel().ref(vvType);
// the following block generates calls to copyFrom(); e.g.:
// ((IntVector) outgoingVectors[bucket][0]).copyFrom(inIndex,
// outgoingBatches[bucket].getRecordCount(),
// vv1);
cg.getEvalBlock().add(
((JExpression) JExpr.cast(vvClass,
((JExpression)
outgoingVectors
.component(bucket))
.component(JExpr.lit(fieldId))))
.invoke("copyFrom")
.arg(inIndex)
.arg(((JExpression) outgoingBatches.component(bucket)).invoke("getRecordCount"))
.arg(incomingVV));
++fieldId;
}
// generate the OutgoingRecordBatch helper invocations
cg.getEvalBlock().add(((JExpression) outgoingBatches.component(bucket)).invoke("incRecordCount"));
cg.getEvalBlock().add(((JExpression) outgoingBatches.component(bucket)).invoke("flushIfNecessary"));
try {
// compile and setup generated code
// partitioner = context.getImplementationClassMultipleOutput(cg);
partitioner = context.getImplementationClass(cg);
partitioner.setup(context, incoming, outgoing);
} catch (ClassTransformationException | IOException e) {
throw new SchemaChangeException("Failure while attempting to load generated class", e);
}
}