muttakin2301/ccr_train_1000 huggingface dataset:
Code review comment: nit: possibly just make this the same exception as above? (New types are going to be added without this list being updated, this different wording could lead to user confusion.)

Code before review:
void validateJavaUdfZetaSqlType(Type type) {
switch (type.getKind()) {
case TYPE_INT64:
case TYPE_DOUBLE:
case TYPE_BOOL:
case TYPE_STRING:
case TYPE_BYTES:
break;
case TYPE_NUMERIC:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_DATETIME:
case TYPE_TIMESTAMP:
case TYPE_ARRAY:
case TYPE_STRUCT:
throw new UnsupportedOperationException(
"ZetaSQL type not allowed in Java UDF: " + type.getKind().name());
default:
throw new UnsupportedOperationException("Unknown ZetaSQL type: " + type.getKind().name());
}
}

Line under review: throw new UnsupportedOperationException("Unknown ZetaSQL type: " + type.getKind().name());

Code after addressing the review:
void validateJavaUdfZetaSqlType(Type type) {
switch (type.getKind()) {
case TYPE_INT64:
case TYPE_DOUBLE:
case TYPE_BOOL:
case TYPE_STRING:
case TYPE_BYTES:
break;
case TYPE_NUMERIC:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_DATETIME:
case TYPE_TIMESTAMP:
case TYPE_ARRAY:
case TYPE_STRUCT:
default:
throw new UnsupportedOperationException(
"ZetaSQL type not allowed in Java UDF: " + type.getKind().name());
}
}
Code review comment: Consider matching every value as switch expression on enum is exhaustive, i.e. not matching a value is a compile error if there isn't a `default` clause.

Code before review:
private static Object decodePayload(Inspector entry) {
return switch (entry.type()) {
case STRING -> entry.asString();
case LONG -> entry.asLong();
case BOOL -> entry.asBool();
case DOUBLE -> entry.asDouble();
case DATA -> entry.asData();
default -> null;
};
}

Line under review: default -> null;

Code after addressing the review:
private static Object decodePayload(Inspector entry) {
return switch (entry.type()) {
case STRING -> entry.asString();
case LONG -> entry.asLong();
case BOOL -> entry.asBool();
case DOUBLE -> entry.asDouble();
case DATA -> entry.asData();
default -> null;
};
}
Code review comment: Fixed. ApplicationDispatcherBootstrap now returns "unknown" JobResult in case job result can no longer be retrieved after fail-over.

Code before review:
public void testDuplicateJobSubmissionWithTerminatedJobId() throws Throwable {
final JobID testJobID = new JobID(0, 2);
final Configuration configurationUnderTest = getConfiguration();
configurationUnderTest.set(
PipelineOptionsInternal.PIPELINE_FIXED_JOB_ID, testJobID.toHexString());
configurationUnderTest.set(
HighAvailabilityOptions.HA_MODE, HighAvailabilityMode.ZOOKEEPER.name());
final TestingDispatcherGateway.Builder dispatcherBuilder =
new TestingDispatcherGateway.Builder()
.setSubmitFunction(
jobGraph -> {
final CompletableFuture<Acknowledge> submit =
new CompletableFuture<>();
submit.completeExceptionally(
new DuplicateJobSubmissionException(testJobID, true));
return submit;
})
.setRequestJobStatusFunction(
jobId -> CompletableFuture.completedFuture(JobStatus.FINISHED))
.setRequestJobResultFunction(
jobId ->
CompletableFuture.completedFuture(
createSuccessfulJobResult(jobId)));
final CompletableFuture<Void> applicationFuture =
runApplication(dispatcherBuilder, configurationUnderTest, 1);
applicationFuture.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}

Line under review: CompletableFuture.completedFuture(

Code after addressing the review:
public void testDuplicateJobSubmissionWithTerminatedJobId() throws Throwable {
final JobID testJobID = new JobID(0, 2);
final Configuration configurationUnderTest = getConfiguration();
configurationUnderTest.set(
PipelineOptionsInternal.PIPELINE_FIXED_JOB_ID, testJobID.toHexString());
configurationUnderTest.set(
HighAvailabilityOptions.HA_MODE, HighAvailabilityMode.ZOOKEEPER.name());
final TestingDispatcherGateway.Builder dispatcherBuilder =
new TestingDispatcherGateway.Builder()
.setSubmitFunction(
jobGraph ->
FutureUtils.completedExceptionally(
DuplicateJobSubmissionException
.ofGloballyTerminated(testJobID)))
.setRequestJobStatusFunction(
jobId -> CompletableFuture.completedFuture(JobStatus.FINISHED))
.setRequestJobResultFunction(
jobId ->
CompletableFuture.completedFuture(
createSuccessfulJobResult(jobId)));
final CompletableFuture<Void> applicationFuture =
runApplication(dispatcherBuilder, configurationUnderTest, 1);
applicationFuture.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
Code review comment: @g2vinay: Let's try reusing the `randomByteBufferFlux`.

Code before review:
public Mono<Void> runAsync() {
return dataLakeFileAsyncClient.append(createRandomByteBufferFlux(options.getSize()), 0, options.getSize());
}

Line under review: return dataLakeFileAsyncClient.append(createRandomByteBufferFlux(options.getSize()), 0, options.getSize());

Code after addressing the review:
public Mono<Void> runAsync() {
return dataLakeFileAsyncClient.append(byteBufferFlux, 0, options.getSize());
}
Code review comment: value and type. I will change it.

Code before review:
private void checkUniqueness(BLangConstant constant) {
if (constant.symbol.kind == SymbolKind.CONSTANT) {
String nameString = constant.name.value;
BLangConstantValue value = constant.symbol.value;
String valueNType;
if (value == null) {
valueNType = String.valueOf(value);
} else {
valueNType = String.valueOf(value) + value.type.getKind().typeName();
}
if (constantMap.containsKey(nameString)) {
if (!valueNType.equals(constantMap.get(nameString))) {
dlog.error(constant.name.pos, DiagnosticErrorCode.ALREADY_INITIALIZED_SYMBOL, nameString);
}
} else {
constantMap.put(nameString, valueNType);
}
}
}

Line under review: String valueNType;

Code after addressing the review:
private void checkUniqueness(BLangConstant constant) {
if (constant.symbol.kind == SymbolKind.CONSTANT) {
String nameString = constant.name.value;
BLangConstantValue value = constant.symbol.value;
if (constantMap.containsKey(nameString)) {
BLangConstantValue lastValue = constantMap.get(nameString);
if (!value.equals(lastValue)) {
if (lastValue == null) {
dlog.error(constant.name.pos, DiagnosticErrorCode.ALREADY_INITIALIZED_SYMBOL, nameString);
} else {
dlog.error(constant.name.pos, DiagnosticErrorCode.ALREADY_INITIALIZED_SYMBOL_WITH_ANOTHER,
nameString, lastValue);
}
}
} else {
constantMap.put(nameString, value);
}
}
}
Code review comment: Could we risk upgrading the package left out?

Code before review:
public void testInstall() {
TaskContext taskContext = mock(TaskContext.class);
TestCommandSupplier commandSupplier = new TestCommandSupplier(taskContext);
commandSupplier.expectCommand("yum list installed package-1", 0, "");
commandSupplier.expectCommand("yum list installed package-2", 1, "");
commandSupplier.expectCommand(
"yum install --assumeyes --enablerepo=repo-name package-1 package-2",
0,
"");
Yum yum = new Yum(taskContext, commandSupplier);
yum.install("package-1", "package-2")
.enableRepo("repo-name")
.converge();
commandSupplier.verifyInvocations();
}

Line under review: "yum install --assumeyes --enablerepo=repo-name package-1 package-2",

Code after addressing the review:
public void testInstall() {
TaskContext taskContext = mock(TaskContext.class);
TestCommandSupplier commandSupplier = new TestCommandSupplier(taskContext);
commandSupplier.expectCommand("yum list installed package-1", 0, "");
commandSupplier.expectCommand("yum list installed package-2", 1, "");
commandSupplier.expectCommand(
"yum install --assumeyes --enablerepo=repo-name package-1 package-2",
0,
"");
Yum yum = new Yum(taskContext, commandSupplier);
yum.install("package-1", "package-2")
.enableRepo("repo-name")
.converge();
commandSupplier.verifyInvocations();
}
Code review comment: Maybe it would be a good idea to log on `info` if we fall back to another key if `fallbackKey.isDeprecated == false`. That way, the user knows from which option it has read the value.

Code before review:
public boolean contains(ConfigOption<?> configOption) {
synchronized (this.confData){
if (this.confData.containsKey(configOption.key())) {
return true;
}
else if (configOption.hasFallbackKeys()) {
for (FallbackKey fallbackKey : configOption.fallbackKeys()) {
if (this.confData.containsKey(fallbackKey.getKey())) {
if (fallbackKey.isDeprecated()) {
LOG.warn("Config uses deprecated configuration key '{}' instead of proper key '{}'",
fallbackKey.getKey(), configOption.key());
}
return true;
}
}
}
return false;
}
}

Line under review: if (fallbackKey.isDeprecated()) {

Code after addressing the review:
public boolean contains(ConfigOption<?> configOption) {
synchronized (this.confData){
if (this.confData.containsKey(configOption.key())) {
return true;
}
else if (configOption.hasFallbackKeys()) {
for (FallbackKey fallbackKey : configOption.fallbackKeys()) {
if (this.confData.containsKey(fallbackKey.getKey())) {
loggingFallback(fallbackKey, configOption);
return true;
}
}
}
return false;
}
}
Code review comment: means aggregation functions only use one column

Code before review:
public boolean check(OptExpression input, OptimizerContext context) {
LogicalAggregationOperator aggregate = (LogicalAggregationOperator) input.getOp();
LogicalRepeatOperator repeatOperator = (LogicalRepeatOperator) input.inputAt(0).getOp();
if (aggregate.getType() != AggType.GLOBAL || repeatOperator.getRepeatColumnRef().size() <= 3
|| repeatOperator.hasPushDown()) {
return false;
}
if (!aggregate.getAggregations().values().stream()
.allMatch(agg -> SUPPORT_AGGREGATE_FUNCTIONS.contains(agg.getFnName()) &&
!agg.isDistinct() && agg.getUsedColumns().cardinality() <= 1)) {
return false;
}
List<ColumnRefOperator> allRepeatRefs = repeatOperator.getRepeatColumnRef()
.get(repeatOperator.getRepeatColumnRef().size() - 1);
for (List<ColumnRefOperator> refs : repeatOperator.getRepeatColumnRef()) {
if (refs.stream().anyMatch(ref -> !allRepeatRefs.contains(ref))) {
return false;
}
}
return true;
}

Line under review: return false;

Code after addressing the review:
public boolean check(OptExpression input, OptimizerContext context) {
LogicalAggregationOperator aggregate = (LogicalAggregationOperator) input.getOp();
LogicalRepeatOperator repeatOperator = (LogicalRepeatOperator) input.inputAt(0).getOp();
if (aggregate.getType() != AggType.GLOBAL || repeatOperator.getRepeatColumnRef().size() <= 3
|| repeatOperator.hasPushDown()) {
return false;
}
if (!aggregate.getAggregations().values().stream()
.allMatch(agg -> SUPPORT_AGGREGATE_FUNCTIONS.contains(agg.getFnName()) &&
!agg.isDistinct() && agg.getUsedColumns().cardinality() <= 1)) {
return false;
}
List<ColumnRefOperator> allRepeatRefs = repeatOperator.getRepeatColumnRef()
.get(repeatOperator.getRepeatColumnRef().size() - 1);
Set<ColumnRefOperator> checkRefs = new HashSet<>(allRepeatRefs);
for (int i = 0; i < repeatOperator.getRepeatColumnRef().size() - 1; i++) {
List<ColumnRefOperator> refs = repeatOperator.getRepeatColumnRef().get(i);
if (refs.stream().anyMatch(ref -> !allRepeatRefs.contains(ref))) {
return false;
}
refs.forEach(checkRefs::remove);
}
checkRefs.addAll(repeatOperator.getOutputGrouping());
return !checkRefs.containsAll(aggregate.getGroupingKeys());
}
Code review comment: Because in this commit there is no `createAndSetUpSlotPool(Clock clock)` method in `SlotPoolImpl` related test cases. In future commits, I replace all the `createAndSetUpSlotPool` with `SlotPoolBuilder`.

Code before review:
public void testDiscardIdleSlotIfReleasingFailed() throws Exception {
final ManualClock clock = new ManualClock();
try (TestingSlotPoolImpl slotPool = createSlotPoolImpl(clock)) {
setupSlotPool(slotPool, resourceManagerGateway, mainThreadExecutor);
final AllocationID expiredAllocationId = new AllocationID();
final SlotOffer slotToExpire = new SlotOffer(expiredAllocationId, 0, ResourceProfile.ANY);
OneShotLatch freeSlotLatch = new OneShotLatch();
taskManagerGateway.setFreeSlotFunction((AllocationID allocationId, Throwable cause) -> {
freeSlotLatch.trigger();
return FutureUtils.completedExceptionally(new TimeoutException("Test failure"));
});
assertThat(slotPool.registerTaskManager(taskManagerLocation.getResourceID()), Matchers.is(true));
assertThat(slotPool.offerSlot(taskManagerLocation, taskManagerGateway, slotToExpire), Matchers.is(true));
clock.advanceTime(timeout.toMilliseconds() + 1, TimeUnit.MILLISECONDS);
slotPool.triggerCheckIdleSlot();
freeSlotLatch.await();
CompletableFuture<PhysicalSlot> future = requestNewAllocatedSlot(
slotPool,
new SlotRequestId()
);
try {
future.get(10L, TimeUnit.MILLISECONDS);
fail("Expected to fail with a timeout.");
} catch (TimeoutException ignored) {
assertEquals(0, slotPool.getAvailableSlots().size());
}
}
}

Line under review: setupSlotPool(slotPool, resourceManagerGateway, mainThreadExecutor);

Code after addressing the review:
public void testDiscardIdleSlotIfReleasingFailed() throws Exception {
final ManualClock clock = new ManualClock();
try (TestingSlotPoolImpl slotPool = createAndSetUpSlotPool(resourceManagerGateway, clock, TIMEOUT)) {
final AllocationID expiredAllocationId = new AllocationID();
final SlotOffer slotToExpire = new SlotOffer(expiredAllocationId, 0, ResourceProfile.ANY);
OneShotLatch freeSlotLatch = new OneShotLatch();
taskManagerGateway.setFreeSlotFunction((AllocationID allocationId, Throwable cause) -> {
freeSlotLatch.trigger();
return FutureUtils.completedExceptionally(new TimeoutException("Test failure"));
});
assertThat(slotPool.registerTaskManager(taskManagerLocation.getResourceID()), Matchers.is(true));
assertThat(slotPool.offerSlot(taskManagerLocation, taskManagerGateway, slotToExpire), Matchers.is(true));
clock.advanceTime(TIMEOUT.toMilliseconds() + 1, TimeUnit.MILLISECONDS);
slotPool.triggerCheckIdleSlot();
freeSlotLatch.await();
final CompletableFuture<PhysicalSlot> allocatedSlotFuture = requestNewAllocatedSlot(
slotPool,
new SlotRequestId());
try {
allocatedSlotFuture.get(10L, TimeUnit.MILLISECONDS);
fail("Expected to fail with a timeout.");
} catch (TimeoutException ignored) {
assertEquals(0, slotPool.getAvailableSlots().size());
}
}
}
Code review comment: Ok, It's about ones' design thinking, you can keep your style.

Code before review:
public static List<SqlNode> convertOrderByItems(final Collection<OrderByItemSegment> orderByItems) {
List<SqlNode> sqlNodes = Lists.newArrayList();
for (OrderByItemSegment orderByItemSegment : orderByItems) {
Optional<SqlNode> optional = Optional.empty();
if (orderByItemSegment instanceof ColumnOrderByItemSegment) {
optional = new ColumnOrderByItemSqlNodeConverter().convert((ColumnOrderByItemSegment) orderByItemSegment);
} else if (orderByItemSegment instanceof ExpressionOrderByItemSegment) {
throw new UnsupportedOperationException("unsupported ExpressionOrderByItemSegment");
} else if (orderByItemSegment instanceof IndexOrderByItemSegment) {
throw new UnsupportedOperationException("unsupported IndexOrderByItemSegment");
} else if (orderByItemSegment instanceof TextOrderByItemSegment) {
throw new UnsupportedOperationException("unsupported TextOrderByItemSegment");
}
if (optional.isPresent()) {
sqlNodes.add(optional.get());
}
}
return sqlNodes;
}

Line under review: List<SqlNode> sqlNodes = Lists.newArrayList();

Code after addressing the review:
public static List<SqlNode> convertOrderByItems(final Collection<OrderByItemSegment> orderByItems) {
List<SqlNode> sqlNodes = Lists.newArrayList();
for (OrderByItemSegment orderByItemSegment : orderByItems) {
Optional<SqlNode> optional = Optional.empty();
if (orderByItemSegment instanceof ColumnOrderByItemSegment) {
optional = new ColumnOrderByItemSqlNodeConverter().convert((ColumnOrderByItemSegment) orderByItemSegment);
} else if (orderByItemSegment instanceof ExpressionOrderByItemSegment) {
throw new UnsupportedOperationException("unsupported ExpressionOrderByItemSegment");
} else if (orderByItemSegment instanceof IndexOrderByItemSegment) {
throw new UnsupportedOperationException("unsupported IndexOrderByItemSegment");
} else if (orderByItemSegment instanceof TextOrderByItemSegment) {
throw new UnsupportedOperationException("unsupported TextOrderByItemSegment");
}
if (optional.isPresent()) {
sqlNodes.add(optional.get());
}
}
return sqlNodes;
}
Code review comment: Nope. The mailbox executes the writer.

Code before review:
public void write(IN element, Context context) throws IOException, InterruptedException {
sinkContextAdapter.updateTimestamp(context);
RawMessage<byte[]> message = serializationSchema.serialize(element, sinkContextAdapter);
List<String> availableTopics = metadataListener.availableTopics();
String topic = topicRouter.route(element, message, availableTopics, sinkContextAdapter);
TypedMessageBuilder<?> builder = createMessageBuilder(topic, deliveryGuarantee);
if (sinkConfiguration.isEnableSchemaEvolution()) {
((TypedMessageBuilder<IN>) builder).value(element);
} else {
((TypedMessageBuilder<byte[]>) builder).value(message.getValue());
}
message.supplement(builder);
if (deliveryGuarantee == DeliveryGuarantee.NONE) {
builder.sendAsync();
} else if (deliveryGuarantee == DeliveryGuarantee.AT_LEAST_ONCE) {
pendingMessages.acquire();
CompletableFuture<MessageId> sender = builder.sendAsync();
sender.whenComplete(
(id, ex) -> {
pendingMessages.release();
if (ex != null) {
mailboxExecutor.execute(
() -> {
throw new FlinkRuntimeException(
"Failed to send data to Pulsar " + topic, ex);
},
"Failed to send message to Pulsar");
} else {
LOG.debug("Sent message to Pulsar {} with message id {}", topic, id);
}
});
}
}

Line under review: }

Code after addressing the review:
public void write(IN element, Context context) throws IOException, InterruptedException {
PulsarMessage<?> message = serializationSchema.serialize(element, sinkContext);
String key = message.getKey();
List<String> availableTopics = metadataListener.availableTopics();
String topic = topicRouter.route(element, key, availableTopics, sinkContext);
TypedMessageBuilder<?> builder = createMessageBuilder(topic, context, message);
long deliverAt = messageDelayer.deliverAt(element, sinkContext);
if (deliverAt > 0) {
builder.deliverAt(deliverAt);
}
if (deliveryGuarantee == DeliveryGuarantee.NONE) {
builder.sendAsync();
} else {
requirePermits();
mailboxExecutor.execute(
() -> enqueueMessageSending(topic, builder),
"Failed to send message to Pulsar");
}
}
Code review comment: non synchronized access to `childTokenSourceList` may cause concurrency access failure.

Code before review:
public void cancel() {
if (this.cancellationRequested.compareAndSet(false, true)) {
for (LinkedCancellationTokenSource childTokenSource : this.childTokenSourceList) {
childTokenSource.close();
}
childTokenSourceList.clear();
}
}

Line under review: childTokenSourceList.clear();

Code after addressing the review:
public void cancel() {
synchronized (this) {
if (this.cancellationRequested.compareAndSet(false, true)) {
for (LinkedCancellationTokenSource childTokenSource : this.childTokenSourceList) {
childTokenSource.close();
}
childTokenSourceList.clear();
}
}
}
Code review comment: Can't we just use something like `container.beanManager().getEvent().select(new TypeLiteral<AtomicReference<String>>(){}).fire(msg);` instead?

Code before review:
public void testObserverNotification() {
ArcContainer container = Arc.container();
ReferenceWrapper msg = new ReferenceWrapper();
RequestFoo.DESTROYED.set(false);
container.beanManager().getEvent().select(ReferenceWrapper.class).fire(msg);
String fooId1 = msg.getReference().get();
assertNotNull(fooId1);
assertTrue(RequestFoo.DESTROYED.get());
RequestFoo.DESTROYED.set(false);
msg.getReference().set(null);
ManagedContext requestContext = container.requestContext();
assertFalse(requestContext.isActive());
try {
requestContext.activate();
String fooId2 = container.instance(RequestFoo.class).get().getId();
assertNotEquals(fooId1, fooId2);
container.beanManager().getEvent().select(ReferenceWrapper.class).fire(msg);
assertEquals(fooId2, msg.getReference().get());
} finally {
requestContext.terminate();
}
assertTrue(RequestFoo.DESTROYED.get());
}

Line under review: container.beanManager().getEvent().select(ReferenceWrapper.class).fire(msg);

Code after addressing the review:
public void testObserverNotification() {
ArcContainer container = Arc.container();
AtomicReference<String> msg = new AtomicReference<>();
RequestFoo.DESTROYED.set(false);
container.beanManager().getEvent().select(new TypeLiteral<AtomicReference<String>>() {
}).fire(msg);
String fooId1 = msg.get();
assertNotNull(fooId1);
assertTrue(RequestFoo.DESTROYED.get());
RequestFoo.DESTROYED.set(false);
msg.set(null);
ManagedContext requestContext = container.requestContext();
assertFalse(requestContext.isActive());
try {
requestContext.activate();
String fooId2 = container.instance(RequestFoo.class).get().getId();
assertNotEquals(fooId1, fooId2);
container.beanManager().getEvent().select(new TypeLiteral<AtomicReference<String>>() {
}).fire(msg);
assertEquals(fooId2, msg.get());
} finally {
requestContext.terminate();
}
assertTrue(RequestFoo.DESTROYED.get());
}
Code review comment: How i atomicity ensured here? WOuldn't you need to hold at least a read lock to read this.lastDatabaseAccount and locationCache atomically?

Code before review:
private List<String> getEffectivePreferredRegions() {
if (this.connectionPolicy.getPreferredRegions() != null && !this.connectionPolicy.getPreferredRegions().isEmpty()) {
return this.connectionPolicy.getPreferredRegions();
}
if (this.latestDatabaseAccount == null) {
return Collections.emptyList();
}
return this.locationCache.getEffectivePreferredLocations();
}


Code after addressing the review:
private List<String> getEffectivePreferredRegions() {
if (this.connectionPolicy.getPreferredRegions() != null && !this.connectionPolicy.getPreferredRegions().isEmpty()) {
return this.connectionPolicy.getPreferredRegions();
}
this.databaseAccountReadLock.lock();
try {
if (this.latestDatabaseAccount == null) {
return Collections.emptyList();
}
return this.locationCache.getEffectivePreferredLocations();
} finally {
this.databaseAccountReadLock.unlock();
}
}
Code review comment: We'd better to wrap the requiredParams and SQL template string by a individual class rather  than hard code it in every single method.

Code before review:
public static String buildStatsMinValueSql(Map<String, String> params) throws InvalidFormatException {
Set<String> requiredParams = Sets.newHashSet("table", "column");
if (checkParams(requiredParams, params)) {
return processTemplate(MIN_VALUE_SQL, params);
} else {
throw new InvalidFormatException("Wrong parameter format. need params: " + requiredParams);
}
}

Line under review: Set<String> requiredParams = Sets.newHashSet("table", "column");

Code after addressing the review:
public static String buildStatsMinValueSql(Map<String, String> params) throws InvalidFormatException {
Set<String> requiredParams = getTemplateParams(MIN_VALUE_SQL);
if (checkParams(requiredParams, params)) {
return processTemplate(MIN_VALUE_SQL, params);
} else {
throw new InvalidFormatException("Wrong parameter format. need params: " + requiredParams);
}
}
Code review comment: You are right, currently HBase connector only support atomic types as columns (HBase qualifier).

Code before review:
private HBaseTableSchema validateTableSchema(TableSchema schema) {
HBaseTableSchema hbaseSchema = new HBaseTableSchema();
String[] fieldNames = schema.getFieldNames();
TypeInformation[] fieldTypes = schema.getFieldTypes();
for (int i = 0; i < fieldNames.length; i++) {
String name = fieldNames[i];
TypeInformation<?> type = fieldTypes[i];
if (type instanceof RowTypeInfo) {
RowTypeInfo familyType = (RowTypeInfo) type;
String[] qualifierNames = familyType.getFieldNames();
TypeInformation[] qualifierTypes = familyType.getFieldTypes();
for (int j = 0; j < familyType.getArity(); j++) {
Class clazz = qualifierTypes[j].getTypeClass();
if (LocalDateTime.class.equals(clazz)) {
clazz = Timestamp.class;
} else if (LocalDate.class.equals(clazz)) {
clazz = Date.class;
} else if (LocalTime.class.equals(clazz)) {
clazz = Time.class;
}
hbaseSchema.addColumn(name, qualifierNames[j], clazz);
}
} else {
hbaseSchema.setRowKey(name, type.getTypeClass());
}
}
return hbaseSchema;
}

Line under review: clazz = Timestamp.class;

Code after addressing the review:
private HBaseTableSchema validateTableSchema(TableSchema schema) {
HBaseTableSchema hbaseSchema = new HBaseTableSchema();
String[] fieldNames = schema.getFieldNames();
TypeInformation[] fieldTypes = schema.getFieldTypes();
for (int i = 0; i < fieldNames.length; i++) {
String name = fieldNames[i];
TypeInformation<?> type = fieldTypes[i];
if (type instanceof RowTypeInfo) {
RowTypeInfo familyType = (RowTypeInfo) type;
String[] qualifierNames = familyType.getFieldNames();
TypeInformation[] qualifierTypes = familyType.getFieldTypes();
for (int j = 0; j < familyType.getArity(); j++) {
Class clazz = qualifierTypes[j].getTypeClass();
if (LocalDateTime.class.equals(clazz)) {
clazz = Timestamp.class;
} else if (LocalDate.class.equals(clazz)) {
clazz = Date.class;
} else if (LocalTime.class.equals(clazz)) {
clazz = Time.class;
}
hbaseSchema.addColumn(name, qualifierNames[j], clazz);
}
} else {
hbaseSchema.setRowKey(name, type.getTypeClass());
}
}
return hbaseSchema;
}
Code review comment: Sorry, I missed this on the first pass. We want `RuntimeException` to be passed through without modification if possible. I believe this will work: ``` if (e.getCause() instanceof RuntimeException) {   throw (RuntimeException) e.getCause(); } throw new RuntimeException(e); ```

Code before review:
private void outputRow(TimestampedFuture c, OutputReceiver<Row> r) throws InterruptedException {
final Value v;
try {
v = c.future().get();
} catch (ExecutionException e) {
throw new RuntimeException(checkArgumentNotNull(e.getCause()));
}
if (!v.isNull()) {
Row row = ZetaSqlBeamTranslationUtils.toBeamRow(v, outputSchema, verifyRowValues);
r.outputWithTimestamp(row, c.timestamp());
}
}

Line under review: throw new RuntimeException(checkArgumentNotNull(e.getCause()));

Code after addressing the review:
private void outputRow(TimestampedFuture c, OutputReceiver<Row> r) throws InterruptedException {
final Value v;
try {
v = c.future().get();
} catch (ExecutionException e) {
throw extractException(e);
}
if (!v.isNull()) {
Row row = ZetaSqlBeamTranslationUtils.toBeamRow(v, outputSchema, verifyRowValues);
r.outputWithTimestamp(row, c.timestamp());
}
}
Code review comment: Can you extract these if condition to new private method?

Code before review:
private SqlNode convertSQLStatement(final ExplainStatement deleteStatement) {
return deleteStatement.getStatement().map(each -> {
if (each instanceof SelectStatement) {
return new SelectStatementConverter().convert((SelectStatement) each);
} else if (each instanceof DeleteStatement) {
return new DeleteStatementConverter().convert((DeleteStatement) each);
}
return null;
}).orElseThrow(IllegalStateException::new);
}

Line under review: if (each instanceof SelectStatement) {

Code after addressing the review:
private SqlNode convertSQLStatement(final ExplainStatement deleteStatement) {
return deleteStatement.getStatement().map(this::convertSqlNode).orElseThrow(IllegalStateException::new);
}
Code review comment: EXECUTE COMMAND need return binary row format

Code before review:
private void initQueryOptions(ConnectContext context) {
this.queryOptions = context.getSessionVariable().toThrift();
this.queryOptions.setEnablePipelineEngine(SessionVariable.enablePipelineEngine());
this.queryOptions.setBeExecVersion(Config.be_exec_version);
this.queryOptions.setQueryTimeout(context.getExecTimeout());
this.queryOptions.setExecutionTimeout(context.getExecTimeout());
this.queryOptions.setEnableScanNodeRunSerial(context.getSessionVariable().isEnableScanRunSerial());
this.queryOptions.setMysqlRowBinaryFormat(
context.getCommand() == MysqlCommand.COM_STMT_EXECUTE);
}

Line under review: this.queryOptions.setMysqlRowBinaryFormat(

Code after addressing the review:
private void initQueryOptions(ConnectContext context) {
this.queryOptions = context.getSessionVariable().toThrift();
this.queryOptions.setEnablePipelineEngine(SessionVariable.enablePipelineEngine());
this.queryOptions.setBeExecVersion(Config.be_exec_version);
this.queryOptions.setQueryTimeout(context.getExecTimeout());
this.queryOptions.setExecutionTimeout(context.getExecTimeout());
this.queryOptions.setEnableScanNodeRunSerial(context.getSessionVariable().isEnableScanRunSerial());
this.queryOptions.setMysqlRowBinaryFormat(
context.getCommand() == MysqlCommand.COM_STMT_EXECUTE);
}
Code review comment: ```suggestion         assertThatFuture(allocatedFuture).eventuallySucceeds(); ``` The test is succeeding even with the production code change not being applied. We're getting into the right code path for this test, but we're not asserting the returned future correctly as far as I can see.  (hint: You have to statically import `FlinkAssertions.assertThatFuture` for the above code change to work)

Code before review:
void testAllocationUpdatesIgnoredIfSlotRemoved() throws Exception {
final FineGrainedTaskManagerTracker taskManagerTracker =
new FineGrainedTaskManagerTracker();
final CompletableFuture<
Tuple6<
SlotID,
JobID,
AllocationID,
ResourceProfile,
String,
ResourceManagerId>>
requestFuture = new CompletableFuture<>();
final CompletableFuture<Acknowledge> responseFuture = new CompletableFuture<>();
final TestingTaskExecutorGateway taskExecutorGateway =
new TestingTaskExecutorGatewayBuilder()
.setRequestSlotFunction(
tuple6 -> {
requestFuture.complete(tuple6);
return responseFuture;
})
.createTestingTaskExecutorGateway();
final TaskExecutorConnection taskExecutorConnection =
new TaskExecutorConnection(ResourceID.generate(), taskExecutorGateway);
taskManagerTracker.addTaskManager(
taskExecutorConnection, ResourceProfile.ANY, ResourceProfile.ANY);
final ResourceTracker resourceTracker = new DefaultResourceTracker();
final JobID jobId = new JobID();
final SlotStatusSyncer slotStatusSyncer =
new DefaultSlotStatusSyncer(TASK_MANAGER_REQUEST_TIMEOUT);
slotStatusSyncer.initialize(
taskManagerTracker,
resourceTracker,
ResourceManagerId.generate(),
EXECUTOR_RESOURCE.getExecutor());
final CompletableFuture<Void> allocatedFuture =
slotStatusSyncer.allocateSlot(
taskExecutorConnection.getInstanceID(),
jobId,
"address",
ResourceProfile.ANY);
final AllocationID allocationId = requestFuture.get().f2;
assertThat(resourceTracker.getAcquiredResources(jobId))
.contains(ResourceRequirement.create(ResourceProfile.ANY, 1));
assertThat(taskManagerTracker.getAllocatedOrPendingSlot(allocationId))
.hasValueSatisfying(
slot -> {
assertThat(slot.getJobId()).isEqualTo(jobId);
assertThat(slot.getState()).isEqualTo(SlotState.PENDING);
});
taskManagerTracker.removeTaskManager(taskExecutorConnection.getInstanceID());
assertThat(taskManagerTracker.getAllocatedOrPendingSlot(allocationId)).isEmpty();
responseFuture.complete(Acknowledge.get());
assertThat(allocatedFuture).isNotCompletedExceptionally();
}

Line under review: assertThat(allocatedFuture).isNotCompletedExceptionally();

Code after addressing the review:
void testAllocationUpdatesIgnoredIfSlotRemoved() throws Exception {
testSlotAllocation(
(slotStatusSyncer, taskManagerTracker, instanceID, allocationId) -> {
taskManagerTracker.removeTaskManager(instanceID);
assertThat(taskManagerTracker.getAllocatedOrPendingSlot(allocationId))
.isEmpty();
});
}
Code review comment: Here a trailing WS is not required AFAIU.

Code before review:
public ImportDeclarationNode transform(ImportDeclarationNode importDeclarationNode) {
Token importKeyword = formatToken(importDeclarationNode.importKeyword(), 0, 0);
if (importDeclarationNode.orgName().isPresent()) {
ImportOrgNameNode orgName = formatNode(importDeclarationNode.orgName().get(), 0, 0);
importDeclarationNode = importDeclarationNode.modify().withOrgName(orgName).apply();
}
SeparatedNodeList<IdentifierToken> moduleNames = formatSeparatedNodeList(importDeclarationNode.moduleName(),
0, 0, 0, 0, 0, 0);
if (importDeclarationNode.version().isPresent()) {
ImportVersionNode version = formatNode(importDeclarationNode.version().get(), 0, 0);
importDeclarationNode = importDeclarationNode.modify().withVersion(version).apply();
}
if (importDeclarationNode.prefix().isPresent()) {
ImportPrefixNode prefix = formatNode(importDeclarationNode.prefix().get(), 0, 0);
importDeclarationNode = importDeclarationNode.modify().withPrefix(prefix).apply();
}
Token semicolon = formatToken(importDeclarationNode.semicolon(), 0, 1);
return importDeclarationNode.modify()
.withImportKeyword(importKeyword)
.withModuleName(moduleNames)
.withSemicolon(semicolon)
.apply();
}

Line under review: ImportPrefixNode prefix = formatNode(importDeclarationNode.prefix().get(), 0, 0);

Code after addressing the review:
public ImportDeclarationNode transform(ImportDeclarationNode importDeclarationNode) {
Token importKeyword = formatToken(importDeclarationNode.importKeyword(), 1, 0);
boolean hasOrgName = importDeclarationNode.orgName().isPresent();
boolean hasVersion = importDeclarationNode.version().isPresent();
boolean hasPrefix = importDeclarationNode.prefix().isPresent();
if (hasOrgName) {
ImportOrgNameNode orgName = formatNode(importDeclarationNode.orgName().get(), 0, 0);
importDeclarationNode = importDeclarationNode.modify().withOrgName(orgName).apply();
}
SeparatedNodeList<IdentifierToken> moduleNames = formatSeparatedNodeList(importDeclarationNode.moduleName(),
0, 0, 0, 0, (hasVersion || hasPrefix) ? 1 : 0, 0);
if (hasVersion) {
ImportVersionNode version = formatNode(importDeclarationNode.version().get(), hasPrefix ? 1 : 0, 0);
importDeclarationNode = importDeclarationNode.modify().withVersion(version).apply();
}
if (hasPrefix) {
ImportPrefixNode prefix = formatNode(importDeclarationNode.prefix().get(), 0, 0);
importDeclarationNode = importDeclarationNode.modify().withPrefix(prefix).apply();
}
Token semicolon = formatToken(importDeclarationNode.semicolon(), this.trailingWS, this.trailingNL);
return importDeclarationNode.modify()
.withImportKeyword(importKeyword)
.withModuleName(moduleNames)
.withSemicolon(semicolon)
.apply();
}
Code review comment: If we can return `false` from the calling methods (ie `hasQualifiedIdentifier` and `hasBacktickExpr`) whenever `peek(lookahead.offset).kind == SyntaxKind.BACKTIC_CONTENT` then we can simplify this by removing the `Lookahead` class

Code before review:
private boolean isValidBacktickContentSequence(ReferenceGenre refGenre) {
boolean hasMatch;
Lookahead lookahead = new Lookahead();
switch (refGenre) {
case SPECIAL_KEY:
hasMatch = hasQualifiedIdentifier(lookahead);
break;
case FUNCTION_KEY:
hasMatch = hasBacktickExpr(lookahead, true);
break;
case NO_KEY:
hasMatch = hasBacktickExpr(lookahead, false);
break;
default:
throw new IllegalStateException("Unsupported backtick reference genre");
}
return hasMatch && peek(lookahead.offset).kind == SyntaxKind.BACKTICK_TOKEN;
}

Line under review: return hasMatch && peek(lookahead.offset).kind == SyntaxKind.BACKTICK_TOKEN;

Code after addressing the review:
private boolean isValidBacktickContentSequence(ReferenceGenre refGenre) {
boolean hasMatch;
Lookahead lookahead = new Lookahead();
switch (refGenre) {
case SPECIAL_KEY:
hasMatch = hasQualifiedIdentifier(lookahead);
break;
case FUNCTION_KEY:
hasMatch = hasBacktickExpr(lookahead, true);
break;
case NO_KEY:
hasMatch = hasBacktickExpr(lookahead, false);
break;
default:
throw new IllegalStateException("Unsupported backtick reference genre");
}
return hasMatch && peek(lookahead.offset).kind == SyntaxKind.BACKTICK_TOKEN;
}
Code review comment: Please use each to replace tableHintLimitedContext.

Code before review:
public ASTNode visitWithTableHint(final WithTableHintContext ctx) {
WithTableHintSegment withTableHintSegment = new WithTableHintSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex());
if (null != ctx.tableHintLimited()) {
Collection<TableHintLimitedSegment> tableHintLimitedSegments = new LinkedList<>();
for (TableHintLimitedContext tableHintLimitedContext : ctx.tableHintLimited()) {
tableHintLimitedSegments.add((TableHintLimitedSegment) visit(tableHintLimitedContext));
}
withTableHintSegment.getTableHintLimitedSegments().addAll(tableHintLimitedSegments);
}
return withTableHintSegment;
}

Line under review: for (TableHintLimitedContext tableHintLimitedContext : ctx.tableHintLimited()) {

Code after addressing the review:
public ASTNode visitWithTableHint(final WithTableHintContext ctx) {
WithTableHintSegment result = new WithTableHintSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex());
if (null != ctx.tableHintLimited()) {
Collection<TableHintLimitedSegment> tableHintLimitedSegments = new LinkedList<>();
for (TableHintLimitedContext each : ctx.tableHintLimited()) {
tableHintLimitedSegments.add((TableHintLimitedSegment) visit(each));
}
result.getTableHintLimitedSegments().addAll(tableHintLimitedSegments);
}
return result;
}
Code review comment: ```suggestion 			Objects.equals(checkPointType, that.checkpointType) && ```

Code before review:
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CheckpointStatistics that = (CheckpointStatistics) o;
return id == that.id &&
savepoint == that.savepoint &&
triggerTimestamp == that.triggerTimestamp &&
latestAckTimestamp == that.latestAckTimestamp &&
stateSize == that.stateSize &&
duration == that.duration &&
alignmentBuffered == that.alignmentBuffered &&
numSubtasks == that.numSubtasks &&
numAckSubtasks == that.numAckSubtasks &&
status == that.status &&
Objects.equals(checkPointType, that.checkPointType) &&
Objects.equals(checkpointStatisticsPerTask, that.checkpointStatisticsPerTask);
}

Line under review: Objects.equals(checkPointType, that.checkPointType) &&

Code after addressing the review:
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CheckpointStatistics that = (CheckpointStatistics) o;
return id == that.id &&
savepoint == that.savepoint &&
triggerTimestamp == that.triggerTimestamp &&
latestAckTimestamp == that.latestAckTimestamp &&
stateSize == that.stateSize &&
duration == that.duration &&
alignmentBuffered == that.alignmentBuffered &&
processedData == processedData &&
persistedData == that.persistedData &&
numSubtasks == that.numSubtasks &&
numAckSubtasks == that.numAckSubtasks &&
status == that.status &&
Objects.equals(checkpointType, that.checkpointType) &&
Objects.equals(checkpointStatisticsPerTask, that.checkpointStatisticsPerTask);
}
Code review comment: This should be in an `else` block of `if (errorAfter` above.  See the .NET version:  https://github.com/Azure/azure-sdk-for-net/blob/main/common/Perf/Azure.Sample.Perf/Event/MockEventProcessor.cs#L131

Code before review:
private void process(int partition) {
MockEventContext mockEventContext = mockEventContexts[partition];
if (maxEventsPerSecond > 0) {
while (process) {
long elapsedTime = (System.nanoTime() - startTime);
if (errorAfter != null && !errorRaised
&& (errorAfter.compareTo(Duration.ofNanos(elapsedTime)) < 0)) {
errorLock.lock();
if (!errorRaised) {
processError(partition, new IllegalStateException("Test Exception"));
errorRaised = true;
}
}
int eventsSent = eventsRaised[partition];
double targetEventsSent = ((double) (elapsedTime / 1_000_000_000))
* maxEventsPerSecondPerPartition;
if (eventsSent < targetEventsSent) {
processEvent.accept(mockEventContext);
eventsRaised[partition]++;
} else {
try {
Thread.sleep((long) ((1 / maxEventsPerSecondPerPartition) * 1000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
} else {
while (process) {
if (errorAfter != null && !errorRaised
&& (errorAfter.compareTo(Duration.ofNanos((System.nanoTime() - startTime))) < 0)) {
errorLock.lock();
if (!errorRaised) {
processError(partition, new IllegalStateException("Test Exception"));
errorRaised = true;
}
}
processEvent.accept(mockEventContext);
eventsRaised[partition]++;
}
}
}

Line under review: processEvent.accept(mockEventContext);

Code after addressing the review:
private void process(int partition) {
MockEventContext mockEventContext = mockEventContexts[partition];
if (maxEventsPerSecond > 0) {
while (process) {
long elapsedTime = (System.nanoTime() - startTime);
if (errorAfter != null && !errorRaised
&& (errorAfter.compareTo(Duration.ofNanos(elapsedTime)) < 0)) {
errorLock.lock();
try {
if (!errorRaised) {
processError(partition, new IllegalStateException("Test Exception"));
errorRaised = true;
}
} finally {
errorLock.unlock();
}
} else {
int eventsSent = eventsRaised[partition];
double targetEventsSent = ((double) (elapsedTime / 1_000_000_000))
* maxEventsPerSecondPerPartition;
if (eventsSent < targetEventsSent) {
processEvent.accept(mockEventContext);
eventsRaised[partition]++;
} else {
try {
Thread.sleep((long) ((1 / maxEventsPerSecondPerPartition) * 1000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
} else {
while (process) {
if (errorAfter != null && !errorRaised
&& (errorAfter.compareTo(Duration.ofNanos((System.nanoTime() - startTime))) < 0)) {
errorLock.lock();
try {
if (!errorRaised) {
processError(partition, new IllegalStateException("Test Exception"));
errorRaised = true;
}
} finally {
errorLock.unlock();
}
} else {
processEvent.accept(mockEventContext);
eventsRaised[partition]++;
}
}
}
}
Code review comment: nit: "a bit" is a little confusing since it's just waiting  ditto below

Code before review:
public void testScheduledBudgetRefresh() throws InterruptedException {
CountDownLatch redistributeBudgetLatch = new CountDownLatch(1);
Runnable redistributeBudget = redistributeBudgetLatch::countDown;
GetWorkBudgetRefresher budgetRefresher = createBudgetRefresher(redistributeBudget);
budgetRefresher.start();
redistributeBudgetLatch.await();
assertThat(redistributeBudgetLatch.getCount()).isEqualTo(0);
}


Code after addressing the review:
public void testScheduledBudgetRefresh() throws InterruptedException {
CountDownLatch redistributeBudgetLatch = new CountDownLatch(1);
Runnable redistributeBudget = redistributeBudgetLatch::countDown;
GetWorkBudgetRefresher budgetRefresher = createBudgetRefresher(redistributeBudget);
budgetRefresher.start();
redistributeBudgetLatch.await();
assertThat(redistributeBudgetLatch.getCount()).isEqualTo(0);
}
Code review comment: My bad. It is a kind of unnecessary condition. Will remove. Thanks.

Code before review:
private void updateSymbolType(BLangConstant constant) {
if (constant.symbol.kind == SymbolKind.CONSTANT && constant.symbol.type.getKind() != TypeKind.FINITE &&
constant.symbol.value != null) {
BFiniteType finiteType = checkType(constant, constant.symbol.value.value, constant.symbol.type,
constant.symbol.pos);
if (finiteType != null) {
constant.symbol.type = finiteType;
}
}
}

Line under review: if (constant.symbol.kind == SymbolKind.CONSTANT && constant.symbol.type.getKind() != TypeKind.FINITE &&

Code after addressing the review:
private void updateSymbolType(BLangConstant constant) {
BConstantSymbol symbol = constant.symbol;
if (symbol.type.getKind() != TypeKind.FINITE && symbol.value != null) {
BType singletonType = checkType(constant.expr, constant, symbol.value.value, symbol.type, symbol.pos);
if (singletonType != null) {
symbol.type = singletonType;
}
}
}
Code review comment: These shouldn't be equal in any case, though ;)

Code before review:
public void createFromActiveSession() {
PrepareResult result = deployApp(testApp);
long sessionId = applicationRepository.createSessionFromExisting(applicationId(),
new SilentDeployLogger(),
false,
timeoutBudget);
long originalSessionId = result.sessionId();
ApplicationMetaData originalApplicationMetaData = getApplicationMetaData(applicationId(), originalSessionId);
ApplicationMetaData applicationMetaData = getApplicationMetaData(applicationId(), sessionId);
assertNotEquals(sessionId, originalSessionId);
assertEquals(applicationMetaData.getApplicationName(), originalApplicationMetaData.getApplicationName());
assertEquals(applicationMetaData.getPreviousActiveGeneration(), originalApplicationMetaData.getGeneration().longValue());
assertNotEquals(applicationMetaData.getGeneration(), originalApplicationMetaData.getApplicationName());
assertEquals(applicationMetaData.getDeployedByUser(), originalApplicationMetaData.getDeployedByUser());
}

Line under review: assertNotEquals(applicationMetaData.getGeneration(), originalApplicationMetaData.getApplicationName());

Code after addressing the review:
public void createFromActiveSession() {
PrepareResult result = deployApp(testApp);
long sessionId = applicationRepository.createSessionFromExisting(applicationId(),
new SilentDeployLogger(),
false,
timeoutBudget);
long originalSessionId = result.sessionId();
ApplicationMetaData originalApplicationMetaData = getApplicationMetaData(applicationId(), originalSessionId);
ApplicationMetaData applicationMetaData = getApplicationMetaData(applicationId(), sessionId);
assertNotEquals(sessionId, originalSessionId);
assertEquals(applicationMetaData.getApplicationName(), originalApplicationMetaData.getApplicationName());
assertEquals(applicationMetaData.getPreviousActiveGeneration(), originalApplicationMetaData.getGeneration().longValue());
assertNotEquals(applicationMetaData.getGeneration(), originalApplicationMetaData.getGeneration());
assertEquals(applicationMetaData.getDeployedByUser(), originalApplicationMetaData.getDeployedByUser());
}
Code review comment: this method is no longer used 

Code before review:
void testExceptionHistoryWithTaskFailure() throws Exception {
final Exception expectedException = new Exception("Expected Local Exception");
BiConsumer<AdaptiveScheduler, List<ExecutionAttemptID>> testLogic =
(scheduler, attemptIds) -> {
final ExecutionAttemptID attemptId = attemptIds.get(1);
scheduler.updateTaskExecutionState(
new TaskExecutionStateTransition(
new TaskExecutionState(
attemptId, ExecutionState.FAILED, expectedException)));
};
final Iterable<RootExceptionHistoryEntry> actualExceptionHistory =
new ExceptionHistoryTester(singleThreadMainThreadExecutor)
.withTestLogic(testLogic)
.run();
assertThat(actualExceptionHistory).hasSize(1);
final RootExceptionHistoryEntry failure = actualExceptionHistory.iterator().next();
assertThat(failure.getException().deserializeError(classLoader))
.isEqualTo(expectedException);
}

Line under review: };

Code after addressing the review:
void testExceptionHistoryWithTaskFailure() throws Exception {
final Exception expectedException = new Exception("Expected Local Exception");
BiConsumer<AdaptiveScheduler, List<ExecutionAttemptID>> testLogic =
(scheduler, attemptIds) -> {
final ExecutionAttemptID attemptId = attemptIds.get(1);
scheduler.updateTaskExecutionState(
new TaskExecutionStateTransition(
new TaskExecutionState(
attemptId, ExecutionState.FAILED, expectedException)));
};
final Iterable<RootExceptionHistoryEntry> actualExceptionHistory =
new ExceptionHistoryTester(singleThreadMainThreadExecutor)
.withTestLogic(testLogic)
.run();
assertThat(actualExceptionHistory).hasSize(1);
final RootExceptionHistoryEntry failure = actualExceptionHistory.iterator().next();
assertThat(failure.getException().deserializeError(classLoader))
.isEqualTo(expectedException);
}