muttakin2301/ccr_train_1000 huggingface dataset:
Code review comment: We don't in any place doing this currently, given this is happening during shutdown maybe it's best we don't?

Code before review:
public static ExecutorService addShutdownHookSafely(ExecutorService executorService, Duration shutdownTimeout) {
if (executorService == null) {
return null;
}
Objects.requireNonNull(shutdownTimeout, "'shutdownTimeout' cannot be null.");
if (shutdownTimeout.isZero() || shutdownTimeout.isNegative()) {
throw new IllegalArgumentException("'shutdownTimeout' must be a non-zero positive duration.");
}
long timeoutNanos = shutdownTimeout.toNanos();
Thread shutdownThread = new Thread(() -> {
try {
executorService.shutdown();
if (!executorService.awaitTermination(timeoutNanos / 2, TimeUnit.NANOSECONDS)) {
executorService.shutdownNow();
executorService.awaitTermination(timeoutNanos / 2, TimeUnit.NANOSECONDS);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
executorService.shutdown();
}
});
if (shutdownHookAccessHelper) {
java.security.AccessController.doPrivileged((java.security.PrivilegedAction<Void>) () -> {
Runtime.getRuntime().addShutdownHook(shutdownThread);
return null;
});
} else {
Runtime.getRuntime().addShutdownHook(shutdownThread);
}
return executorService;
}

Line under review: Thread.currentThread().interrupt();

Code after addressing the review:
public static ExecutorService addShutdownHookSafely(ExecutorService executorService, Duration shutdownTimeout) {
if (executorService == null) {
return null;
}
Objects.requireNonNull(shutdownTimeout, "'shutdownTimeout' cannot be null.");
if (shutdownTimeout.isZero() || shutdownTimeout.isNegative()) {
throw new IllegalArgumentException("'shutdownTimeout' must be a non-zero positive duration.");
}
long timeoutNanos = shutdownTimeout.toNanos();
Thread shutdownThread = new Thread(() -> {
try {
executorService.shutdown();
if (!executorService.awaitTermination(timeoutNanos / 2, TimeUnit.NANOSECONDS)) {
executorService.shutdownNow();
executorService.awaitTermination(timeoutNanos / 2, TimeUnit.NANOSECONDS);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
executorService.shutdown();
}
});
if (ShutdownHookAccessHelperHolder.shutdownHookAccessHelper) {
java.security.AccessController.doPrivileged((java.security.PrivilegedAction<Void>) () -> {
Runtime.getRuntime().addShutdownHook(shutdownThread);
return null;
});
} else {
Runtime.getRuntime().addShutdownHook(shutdownThread);
}
return executorService;
}
Code review comment: use name is not good idea, if we have same name output in producer

Code before review:
public Rule build() {
return logicalCTEConsumer().thenApply(ctx -> {
LogicalCTEConsumer cteConsumer = ctx.root;
int refCount = ctx.cascadesContext.cteReferencedCount(cteConsumer.getCteId());
if (ConnectContext.get().getSessionVariable().enablePipelineEngine
&& refCount > ConnectContext.get().getSessionVariable().inlineCTEReferencedThreshold) {
return cteConsumer;
}
LogicalPlan inlinedPlan = ctx.cascadesContext.findCTEPlanForInline(cteConsumer.getCteId());
List<Slot> inlinedPlanOutput = inlinedPlan.getOutput();
List<Slot> cteConsumerOutput = cteConsumer.getOutput();
List<NamedExpression> projects = new ArrayList<>();
for (Slot inlineSlot : inlinedPlanOutput) {
String name = inlineSlot.getName();
for (Slot consumerSlot : cteConsumerOutput) {
if (consumerSlot.getName().equals(name)) {
Alias alias = new Alias(consumerSlot.getExprId(), inlineSlot, name);
projects.add(alias);
break;
}
}
}
return new LogicalProject<LogicalPlan>(projects,
inlinedPlan);
}).toRule(RuleType.INLINE_CTE);
}

Line under review: }

Code after addressing the review:
public Rule build() {
return logicalCTEConsumer().thenApply(ctx -> {
LogicalCTEConsumer cteConsumer = ctx.root;
int refCount = ctx.cascadesContext.cteReferencedCount(cteConsumer.getCteId());
/*
*  Current we only implement CTE Materialize on pipeline engine and only materialize those CTE whose
*  refCount > NereidsRewriter.INLINE_CTE_REFERENCED_THRESHOLD.
*/
if (ConnectContext.get().getSessionVariable().enablePipelineEngine
&& ConnectContext.get().getSessionVariable().enableCTEMaterialize
&& refCount > NereidsRewriter.INLINE_CTE_REFERENCED_THRESHOLD) {
return cteConsumer;
}
LogicalPlan inlinedPlan = ctx.cascadesContext.findCTEPlanForInline(cteConsumer.getCteId());
List<Slot> inlinedPlanOutput = inlinedPlan.getOutput();
List<Slot> cteConsumerOutput = cteConsumer.getOutput();
List<NamedExpression> projects = new ArrayList<>();
for (Slot inlineSlot : inlinedPlanOutput) {
String name = inlineSlot.getName();
for (Slot consumerSlot : cteConsumerOutput) {
if (consumerSlot.getName().equals(name)) {
Alias alias = new Alias(consumerSlot.getExprId(), inlineSlot, name);
projects.add(alias);
break;
}
}
}
return new LogicalProject<LogicalPlan>(projects,
inlinedPlan);
}).toRule(RuleType.INLINE_CTE);
}
Code review comment: should be contains BoundStar? what about `select *, c1 from t group by 1`

Code before review:
private Plan bindAggregate(MatchingContext<LogicalAggregate<Plan>> ctx) {
LogicalAggregate<Plan> agg = ctx.root;
CascadesContext cascadesContext = ctx.cascadesContext;
SimpleExprAnalyzer aggOutputAnalyzer = buildSimpleExprAnalyzer(
agg, cascadesContext, agg.children(), true, true);
List<NamedExpression> boundAggOutput = aggOutputAnalyzer.analyzeToList(agg.getOutputExpressions());
if (boundAggOutput.size() == 1 && boundAggOutput.get(0) instanceof BoundStar) {
BoundStar boundStar = (BoundStar) boundAggOutput.get(0);
List<NamedExpression> boundProjections = new ArrayList<>();
boundProjections.addAll(boundStar.getSlots());
boundAggOutput = boundProjections;
}
Supplier<Scope> aggOutputScopeWithoutAggFun = buildAggOutputScopeWithoutAggFun(boundAggOutput, cascadesContext);
List<Expression> boundGroupBy = bindGroupBy(
agg, agg.getGroupByExpressions(), boundAggOutput, aggOutputScopeWithoutAggFun, cascadesContext);
return agg.withGroupByAndOutput(boundGroupBy, boundAggOutput);
}

Line under review: if (boundAggOutput.size() == 1 && boundAggOutput.get(0) instanceof BoundStar) {

Code after addressing the review:
private Plan bindAggregate(MatchingContext<LogicalAggregate<Plan>> ctx) {
LogicalAggregate<Plan> agg = ctx.root;
CascadesContext cascadesContext = ctx.cascadesContext;
SimpleExprAnalyzer aggOutputAnalyzer = buildSimpleExprAnalyzer(
agg, cascadesContext, agg.children(), true, true);
List<NamedExpression> boundAggOutput = aggOutputAnalyzer.analyzeToList(agg.getOutputExpressions());
List<NamedExpression> boundProjections = new ArrayList<>(boundAggOutput.size());
for (NamedExpression output : boundAggOutput) {
if (output instanceof BoundStar) {
boundProjections.addAll(((BoundStar) output).getSlots());
} else {
boundProjections.add(output);
}
}
Supplier<Scope> aggOutputScopeWithoutAggFun =
buildAggOutputScopeWithoutAggFun(boundProjections, cascadesContext);
List<Expression> boundGroupBy = bindGroupBy(
agg, agg.getGroupByExpressions(), boundProjections, aggOutputScopeWithoutAggFun, cascadesContext);
return agg.withGroupByAndOutput(boundGroupBy, boundProjections);
}
Code review comment: According to the JavaDoc of AssertJ, as() should be before isFalse(): ```suggestion             assertThat(reader.isClosed)                     .as("The reader should have not been closed.")                     .isFalse(); ```

Code before review:
public void testIdleShutdownSplitFetcherWaitsUntilRecordProcessed() throws Exception {
final String splitId = "testSplit";
final AwaitingReader<Integer, TestingSourceSplit> reader =
new AwaitingReader<>(
new IOException("Should not happen"),
new RecordsBySplits<>(
Collections.emptyMap(), Collections.singleton(splitId)));
final SplitFetcherManager<Integer, TestingSourceSplit> fetcherManager =
createFetcher(splitId, reader, new Configuration());
try {
FutureCompletingBlockingQueue<RecordsWithSplitIds<Integer>> queue =
fetcherManager.getQueue();
queue.getAvailabilityFuture().get();
waitUntil(
() -> {
fetcherManager.maybeShutdownFinishedFetchers();
return fetcherManager.getNumAliveFetchers() == 0;
},
Duration.ofSeconds(1),
"The fetcher should have already been removed from the alive fetchers.");
waitUntil(
() -> queue.size() == 2,
Duration.ofSeconds(1),
"The element queue should have 2 batches when the fetcher is closed.");
queue.poll().recycle();
assertThat(reader.isClosed)
.isFalse()
.as("The reader should have not been closed.");
queue.poll().recycle();
waitUntil(
() -> reader.isClosed,
Duration.ofSeconds(1),
"The reader should hava been closed.");
} finally {
fetcherManager.close(30_000);
}
}

Line under review: .as("The reader should have not been closed.");

Code after addressing the review:
public void testIdleShutdownSplitFetcherWaitsUntilRecordProcessed() throws Exception {
final String splitId = "testSplit";
final AwaitingReader<Integer, TestingSourceSplit> reader =
new AwaitingReader<>(
new IOException("Should not happen"),
new RecordsBySplits<>(
Collections.emptyMap(), Collections.singleton(splitId)));
final SplitFetcherManager<Integer, TestingSourceSplit> fetcherManager =
createFetcher(splitId, reader, new Configuration());
try {
FutureCompletingBlockingQueue<RecordsWithSplitIds<Integer>> queue =
fetcherManager.getQueue();
queue.getAvailabilityFuture().get();
waitUntil(
() -> {
fetcherManager.maybeShutdownFinishedFetchers();
return fetcherManager.getNumAliveFetchers() == 0;
},
Duration.ofSeconds(1),
"The fetcher should have already been removed from the alive fetchers.");
waitUntil(
() -> queue.size() == 2,
Duration.ofSeconds(1),
"The element queue should have 2 batches when the fetcher is closed.");
queue.poll().recycle();
assertThat(reader.isClosed).as("The reader should have not been closed.").isFalse();
queue.poll().recycle();
waitUntil(
() -> reader.isClosed,
Duration.ofSeconds(1),
"The reader should hava been closed.");
} finally {
fetcherManager.close(30_000);
}
}
Code review comment: 👍good catch, `Thread.sleep(50);` is deleted, so the `InterruptedException` wouldn't throw.

Code before review:
private void seizeCapacity() {
if (currentContext.isKeyOccupied()) {
return;
}
RecordContext<R, K> storedContext = currentContext;
try {
while (inFlightRecordNum.get() > maxInFlightRecordNum) {
if (!mailboxExecutor.tryYield()) {
triggerIfNeeded(true);
Thread.sleep(50);
}
}
setCurrentContext(storedContext);
inFlightRecordNum.incrementAndGet();
} catch (InterruptedException e) {
throw new FlinkRuntimeException(e);
}
}

Line under review: } catch (InterruptedException e) {

Code after addressing the review:
private void seizeCapacity() {
if (currentContext.isKeyOccupied()) {
return;
}
RecordContext<R, K> storedContext = currentContext;
try {
while (inFlightRecordNum.get() > maxInFlightRecordNum) {
if (!mailboxExecutor.tryYield()) {
triggerIfNeeded(true);
Thread.sleep(1);
}
}
} catch (InterruptedException ignored) {
}
setCurrentContext(storedContext);
inFlightRecordNum.incrementAndGet();
}
Code review comment: You can use Objects.requireNonNull to ensure that the parameter cannot be null

Code before review:
public InPredicate(Expression compareExpr, List<Expression> optionsList) {
super(new Builder<Expression>().add(compareExpr).addAll(optionsList).build().toArray(new Expression[0]));
this.compareExpr = compareExpr;
this.optionsList = ImmutableList.copyOf(Objects.requireNonNull(optionsList, "In list cannot be null"));
}

Line under review: this.compareExpr = compareExpr;

Code after addressing the review:
public InPredicate(Expression compareExpr, List<Expression> optionsList) {
super(new Builder<Expression>().add(compareExpr).addAll(optionsList).build().toArray(new Expression[0]));
this.compareExpr = Objects.requireNonNull(compareExpr, "Compare Expr cannot be null");
this.options = ImmutableList.copyOf(Objects.requireNonNull(optionsList, "In list cannot be null"));
}
Code review comment: Logic aggregate above could have project operator.

Code before review:
private Void tryGatherForBroadcastJoin(PhysicalHashJoinOperator node, ExpressionContext context) {
List<Pair<PhysicalPropertySet, List<PhysicalPropertySet>>> result = Lists.newArrayList();
if ((context.getChildOperator(0) instanceof LogicalAggregationOperator)) {
LogicalAggregationOperator childOperator = (LogicalAggregationOperator) context.getChildOperator(0);
if (childOperator.getType().equals(AggType.GLOBAL) && childOperator.getGroupingKeys().isEmpty()) {
for (Pair<PhysicalPropertySet, List<PhysicalPropertySet>> outputInputProp : outputInputProps) {
PhysicalPropertySet left = outputInputProp.second.get(0);
PhysicalPropertySet right = outputInputProp.second.get(1);
if (left.getDistributionProperty().isAny() && right.getDistributionProperty().isBroadcast()) {
result.add(
new Pair<>(distributeRequirements(),
Lists.newArrayList(distributeRequirements(), right)));
}
}
outputInputProps = result;
return visitOperator(node, context);
}
}
return visitOperator(node, context);
}

Line under review: if ((context.getChildOperator(0) instanceof LogicalAggregationOperator)) {

Code after addressing the review:
private Void tryGatherForBroadcastJoin(PhysicalHashJoinOperator node, ExpressionContext context) {
List<Pair<PhysicalPropertySet, List<PhysicalPropertySet>>> result = Lists.newArrayList();
if (context.getChildLogicalProperty(0).isGatherToOneInstance()) {
for (Pair<PhysicalPropertySet, List<PhysicalPropertySet>> outputInputProp : outputInputProps) {
PhysicalPropertySet left = outputInputProp.second.get(0);
PhysicalPropertySet right = outputInputProp.second.get(1);
if (left.getDistributionProperty().isAny() && right.getDistributionProperty().isBroadcast()) {
result.add(new Pair<>(distributeRequirements(),
Lists.newArrayList(distributeRequirements(), right)));
} else {
result.add(outputInputProp);
}
}
outputInputProps = result;
return visitOperator(node, context);
}
return visitOperator(node, context);
}
Code review comment: Failed to drop catalog xxxxx

Code before review:
public ShowResultSet visitDropCatalogStatement(DropCatalogStmt stmt, ConnectContext context) {
ErrorReport.wrapWithRuntimeException(() -> {
String catalogName = stmt.getName();
if (!context.getGlobalStateMgr().getCatalogMgr().catalogExists(catalogName)) {
if (stmt.isIfExists()) {
LOG.info("drop catalog[{}] which does not exist", catalogName);
return;
} else {
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_CATALOG, catalogName);
}
}
context.getGlobalStateMgr().getCatalogMgr().dropCatalog(stmt);
});
return null;
}

Line under review: LOG.info("drop catalog[{}] which does not exist", catalogName);

Code after addressing the review:
public ShowResultSet visitDropCatalogStatement(DropCatalogStmt stmt, ConnectContext context) {
ErrorReport.wrapWithRuntimeException(() -> {
String catalogName = stmt.getName();
if (!context.getGlobalStateMgr().getCatalogMgr().catalogExists(catalogName)) {
if (stmt.isIfExists()) {
LOG.info("drop catalog[{}] which does not exist", catalogName);
return;
} else {
ErrorReport.reportDdlException(ErrorCode.ERR_BAD_CATALOG_ERROR, catalogName);
}
}
context.getGlobalStateMgr().getCatalogMgr().dropCatalog(stmt);
});
return null;
}
Code review comment: Please perform the doc validation soon after annotation validation

Code before review:
public void visit(BLangFunction funcNode) {
SymbolEnv funcEnv = SymbolEnv.createFunctionEnv(funcNode, funcNode.symbol.scope, env);
funcNode.annAttachments.forEach(annotationAttachment -> {
annotationAttachment.attachmentPoint =
new BLangAnnotationAttachmentPoint(BLangAnnotationAttachmentPoint.AttachmentPoint.FUNCTION, null);
this.analyzeDef(annotationAttachment, funcEnv);
});
if (Symbols.isNative(funcNode.symbol)) {
return;
}
analyzeStmt(funcNode.body, funcEnv);
this.processWorkers(funcNode, funcEnv);
funcNode.docAttachments.forEach(doc -> analyzeDef(doc, funcEnv));
}

Line under review: funcNode.docAttachments.forEach(doc -> analyzeDef(doc, funcEnv));

Code after addressing the review:
public void visit(BLangFunction funcNode) {
SymbolEnv funcEnv = SymbolEnv.createFunctionEnv(funcNode, funcNode.symbol.scope, env);
funcNode.annAttachments.forEach(annotationAttachment -> {
annotationAttachment.attachmentPoint =
new BLangAnnotationAttachmentPoint(BLangAnnotationAttachmentPoint.AttachmentPoint.FUNCTION, null);
this.analyzeDef(annotationAttachment, funcEnv);
});
funcNode.docAttachments.forEach(doc -> analyzeDef(doc, funcEnv));
if (Symbols.isNative(funcNode.symbol)) {
return;
}
analyzeStmt(funcNode.body, funcEnv);
this.processWorkers(funcNode, funcEnv);
}
Code review comment: But it only does it if the input `isFinished()`, so that should be a non issue.

Code before review:
public boolean processInput() throws Exception {
initializeNumRecordsIn();
StreamElement recordOrMark = input.pollNextNullable();
if (recordOrMark != null) {
int channel = input.getLastChannel();
checkState(channel != StreamTaskInput.UNSPECIFIED);
processElement(recordOrMark, channel);
}
checkFinished();
return recordOrMark != null;
}

Line under review: checkFinished();

Code after addressing the review:
public boolean processInput() throws Exception {
initializeNumRecordsIn();
StreamElement recordOrMark = input.pollNextNullable();
if (recordOrMark != null) {
int channel = input.getLastChannel();
checkState(channel != StreamTaskInput.UNSPECIFIED);
processElement(recordOrMark, channel);
}
checkFinished();
return recordOrMark != null;
}
Code review comment: ```suggestion                         if (!extracted.isPresent()) { ```

Code before review:
public Rule build() {
return logicalFilter().when(filter -> !filter.isSingleTableExpressionExtracted()).then(filter -> {
List<Expression> conjuncts = ExpressionUtils.extractConjunction(filter.getPredicates())
.stream().collect(Collectors.toList());
List<Expression> redundants = Lists.newArrayList();
for (Expression conjunct : conjuncts) {
List<Expression> disjuncts = ExpressionUtils.extractDisjunction(conjunct);
if (disjuncts.size() == 1) {
continue;
}
Expression first = disjuncts.get(0);
Set<SlotReference> slots = first.getInputSlots()
.stream()
.map(SlotReference.class::cast)
.collect(Collectors.toSet());
Set<String> qualifiers = slots.stream()
.map(slot -> getSlotQualifierAsString(slot))
.collect(Collectors.toSet());
for (String qualifier : qualifiers) {
List<Expression> extract4all = Lists.newArrayList();
boolean success = true;
for (Expression expr : ExpressionUtils.extractDisjunction(conjunct)) {
Optional<Expression> extracted = extractSingleTableExpression(expr, qualifier);
if (! extracted.isPresent()) {
success = false;
break;
} else {
extract4all.add(extracted.get());
}
}
if (success) {
redundants.add(ExpressionUtils.or(extract4all));
}
}
}
if (redundants.isEmpty()) {
return new LogicalFilter<>(filter.getPredicates(), true, filter.child());
} else {
Expression newPredicate = ExpressionUtils.and(filter.getPredicates(), ExpressionUtils.and(redundants));
return new LogicalFilter<>(newPredicate,
true, filter.child());
}
}).toRule(RuleType.EXTRACT_SINGLE_TABLE_EXPRESSION_FROM_DISJUNCTION);
}

Line under review: if (! extracted.isPresent()) {

Code after addressing the review:
public Rule build() {
return logicalFilter().whenNot(LogicalFilter::isSingleTableExpressionExtracted).then(filter -> {
List<Expression> conjuncts = ExpressionUtils.extractConjunction(filter.getPredicates())
.stream().collect(Collectors.toList());
List<Expression> redundants = Lists.newArrayList();
for (Expression conjunct : conjuncts) {
List<Expression> disjuncts = ExpressionUtils.extractDisjunction(conjunct);
if (disjuncts.size() == 1) {
continue;
}
Expression first = disjuncts.get(0);
Set<String> qualifiers = first.getInputSlots()
.stream()
.map(SlotReference.class::cast)
.map(this::getSlotQualifierAsString)
.collect(Collectors.toSet());
for (String qualifier : qualifiers) {
List<Expression> extractForAll = Lists.newArrayList();
boolean success = true;
for (Expression expr : ExpressionUtils.extractDisjunction(conjunct)) {
Optional<Expression> extracted = extractSingleTableExpression(expr, qualifier);
if (!extracted.isPresent()) {
success = false;
break;
} else {
extractForAll.add(extracted.get());
}
}
if (success) {
redundants.add(ExpressionUtils.or(extractForAll));
}
}
}
if (redundants.isEmpty()) {
return new LogicalFilter<>(filter.getPredicates(), true, filter.child());
} else {
Expression newPredicate = ExpressionUtils.and(filter.getPredicates(), ExpressionUtils.and(redundants));
return new LogicalFilter<>(newPredicate,
true, filter.child());
}
}).toRule(RuleType.EXTRACT_SINGLE_TABLE_EXPRESSION_FROM_DISJUNCTION);
}
Code review comment: Personal preference: I would prefer that to be  ```suggestion         reflection.produce(new ReflectiveClassBuildItem(true, true, "com.sun.jndi.ldap.LdapCtxFactory")); ```

Code before review:
void registerForReflection(BuildProducer<ReflectiveClassBuildItem> reflection) {
reflection.produce(new ReflectiveClassBuildItem(true, true, QuarkusDirContextFactory.INITIAL_CONTEXT_FACTORY));
reflection.produce(new ReflectiveClassBuildItem(false, false, "com.sun.jndi.dns.DnsContextFactory"));
reflection.produce(new ReflectiveClassBuildItem(false, false, "com.sun.jndi.rmi.registry.RegistryContextFactory"));
}

Line under review: reflection.produce(new ReflectiveClassBuildItem(true, true, QuarkusDirContextFactory.INITIAL_CONTEXT_FACTORY));

Code after addressing the review:
void registerForReflection(BuildProducer<ReflectiveClassBuildItem> reflection) {
reflection.produce(new ReflectiveClassBuildItem(true, true, QuarkusDirContextFactory.INITIAL_CONTEXT_FACTORY));
reflection.produce(new ReflectiveClassBuildItem(false, false, "com.sun.jndi.dns.DnsContextFactory"));
reflection.produce(new ReflectiveClassBuildItem(false, false, "com.sun.jndi.rmi.registry.RegistryContextFactory"));
}
Code review comment: ```suggestion                                     "or by adding '%s' or '%s' to your Quarkus configuration", ```

Code before review:
private void configureBaseUrl(RestClientBuilder builder) {
Optional<String> propertyOptional = getOptionalProperty(REST_URI_FORMAT, String.class);
if (!propertyOptional.isPresent()) {
propertyOptional = getOptionalProperty(REST_URL_FORMAT, String.class);
}
if (((baseUriFromAnnotation == null) || baseUriFromAnnotation.isEmpty())
&& !propertyOptional.isPresent()) {
throw new IllegalArgumentException(
String.format(
"Unable to determine the proper baseUrl/baseUri. " +
"Consider registering using @RegisterRestClient(baseUri=\"someuri\"), @RegisterRestClient(configKey=\"orkey\"), "
+
"or by adding '%s' or '%s'to your Quarkus configuration",
String.format(REST_URL_FORMAT, propertyPrefix), String.format(REST_URI_FORMAT, propertyPrefix)));
}
String baseUrl = propertyOptional.orElse(baseUriFromAnnotation);
try {
builder.baseUrl(new URL(baseUrl));
} catch (MalformedURLException e) {
throw new IllegalArgumentException("The value of URL was invalid " + baseUrl, e);
} catch (Exception e) {
if ("com.oracle.svm.core.jdk.UnsupportedFeatureError".equals(e.getClass().getCanonicalName())) {
throw new IllegalArgumentException(baseUrl
+ " requires SSL support but it is disabled. You probably have set quarkus.ssl.native to false.");
}
throw e;
}
}

Line under review: "or by adding '%s' or '%s'to your Quarkus configuration",

Code after addressing the review:
private void configureBaseUrl(RestClientBuilder builder) {
Optional<String> propertyOptional = getOptionalProperty(REST_URI_FORMAT, String.class);
if (!propertyOptional.isPresent()) {
propertyOptional = getOptionalProperty(REST_URL_FORMAT, String.class);
}
if (((baseUriFromAnnotation == null) || baseUriFromAnnotation.isEmpty())
&& !propertyOptional.isPresent()) {
throw new IllegalArgumentException(
String.format(
"Unable to determine the proper baseUrl/baseUri. " +
"Consider registering using @RegisterRestClient(baseUri=\"someuri\"), @RegisterRestClient(configKey=\"orkey\"), "
+
"or by adding '%s' or '%s' to your Quarkus configuration",
String.format(REST_URL_FORMAT, propertyPrefix), String.format(REST_URI_FORMAT, propertyPrefix)));
}
String baseUrl = propertyOptional.orElse(baseUriFromAnnotation);
try {
builder.baseUrl(new URL(baseUrl));
} catch (MalformedURLException e) {
throw new IllegalArgumentException("The value of URL was invalid " + baseUrl, e);
} catch (Exception e) {
if ("com.oracle.svm.core.jdk.UnsupportedFeatureError".equals(e.getClass().getCanonicalName())) {
throw new IllegalArgumentException(baseUrl
+ " requires SSL support but it is disabled. You probably have set quarkus.ssl.native to false.");
}
throw e;
}
}
Code review comment: What should I do instead?

Code before review:
private Table toCalciteTable(String tableName, Entry entry) {
if (entry.getSchema().getColumnsCount() == 0) {
throw new UnsupportedOperationException(
"Entry doesn't have a schema. Please attach a schema to '"
+ tableName
+ "' in Data Catalog: "
+ entry.toString());
}
Schema schema = SchemaUtils.fromDataCatalog(entry.getSchema());
Optional<Table.Builder> tableBuilder = tableFactory.tableBuilder(entry);
if (tableBuilder.isPresent()) {
return tableBuilder.get().schema(schema).name(tableName).build();
} else {
throw new UnsupportedOperationException(
String.format(
"Unsupported Data Catalog entry: %s",
MoreObjects.toStringHelper(entry)
.add("linkedResource", entry.getLinkedResource())
.add("hasGcsFilesetSpec", entry.hasGcsFilesetSpec())
.toString()));
}
}

Line under review: return tableBuilder.get().schema(schema).name(tableName).build();

Code after addressing the review:
private Table toCalciteTable(String tableName, Entry entry) {
if (entry.getSchema().getColumnsCount() == 0) {
throw new UnsupportedOperationException(
"Entry doesn't have a schema. Please attach a schema to '"
+ tableName
+ "' in Data Catalog: "
+ entry.toString());
}
Schema schema = SchemaUtils.fromDataCatalog(entry.getSchema());
Optional<Table.Builder> tableBuilder = tableFactory.tableBuilder(entry);
if (!tableBuilder.isPresent()) {
throw new UnsupportedOperationException(
String.format(
"Unsupported Data Catalog entry: %s",
MoreObjects.toStringHelper(entry)
.add("linkedResource", entry.getLinkedResource())
.add("hasGcsFilesetSpec", entry.hasGcsFilesetSpec())
.toString()));
}
return tableBuilder.get().schema(schema).name(tableName).build();
}
Code review comment: I just added `CallCountOutputStream` to test the proper number of call count.

Code before review:
public void testWrite() throws IOException {
ByteArrayOutputStream expected = new ByteArrayOutputStream();
ByteArrayOutputStream actual = new ByteArrayOutputStream();
UnownedOutputStream osActual = new UnownedOutputStream(actual);
byte[] data0 = "Hello World!".getBytes(StandardCharsets.UTF_8);
byte[] data1 = "Welcome!".getBytes(StandardCharsets.UTF_8);
expected.write(data0, 0, data0.length);
osActual.write(data0, 0, data0.length);
expected.write(data1, 0, data1.length);
osActual.write(data1, 0, data1.length);
assertArrayEquals(expected.toByteArray(), actual.toByteArray());
}

Line under review: assertArrayEquals(expected.toByteArray(), actual.toByteArray());

Code after addressing the review:
public void testWrite() throws IOException {
CallCountOutputStream fsCount = new CallCountOutputStream();
FilterOutputStream fs = new FilterOutputStream(fsCount);
CallCountOutputStream osCount = new CallCountOutputStream();
UnownedOutputStream os = new UnownedOutputStream(osCount);
byte[] data = "Hello World!".getBytes(StandardCharsets.UTF_8);
fs.write(data, 0, data.length);
os.write(data, 0, data.length);
fs.write('\n');
os.write('\n');
assertEquals(13, fsCount.callCnt);
assertEquals(2, osCount.callCnt);
assertArrayEquals(fsCount.toByteArray(), osCount.toByteArray());
}
Code review comment: I'm not sure it would be good to emit info logs for split requests. These are per subtask and there could be hundreds at a time depending on parallelism.

Code before review:
public void handleSplitRequest(int subtaskId, String requesterHostname) {
LOG.debug(
"handleSplitRequest subtask={} sourceIndex={} pendingSplits={}",
subtaskId,
currentSourceIndex,
pendingSplits);
assignPendingSplits(subtaskId);
currentEnumerator.handleSplitRequest(subtaskId, requesterHostname);
}

Line under review: pendingSplits);

Code after addressing the review:
public void handleSplitRequest(int subtaskId, String requesterHostname) {
LOG.debug(
"handleSplitRequest subtask={} sourceIndex={} pendingSplits={}",
subtaskId,
currentSourceIndex,
pendingSplits);
Preconditions.checkState(pendingSplits.isEmpty() || !pendingSplits.containsKey(subtaskId));
currentEnumerator.handleSplitRequest(subtaskId, requesterHostname);
}
Code review comment: I'm not sure that would simplify anything in this case. Am I missing something though?

Code before review:
protected static void assertEventRoutesEqual(EventRoute expected, String expectedId, EventRoute actual) {
assertEquals(expectedId, actual.getId());
assertEquals(expected.getEndpointName(), actual.getEndpointName());
assertEquals(expected.getFilter(), actual.getFilter());
}

Line under review: assertEquals(expectedId, actual.getId());

Code after addressing the review:
protected static void assertEventRoutesEqual(EventRoute expected, String expectedId, EventRoute actual) {
assertEquals(expectedId, actual.getId());
assertEquals(expected.getEndpointName(), actual.getEndpointName());
assertEquals(expected.getFilter(), actual.getFilter());
}
Code review comment: `values::add` instead of `Consumer<Elements>`?  Your choice if you still want to provide the StreamObserverClientFactory type instead of a lambda as visible in the old code.

Code before review:
public void testOutboundObserver() {
final Collection<BeamFnApi.Elements> values = new ArrayList<>();
BeamFnDataGrpcMultiplexer multiplexer =
new BeamFnDataGrpcMultiplexer(
DESCRIPTOR,
new StreamObserverClientFactory<Elements, Elements>() {
@Override
public StreamObserver<Elements> outboundObserverFor(
StreamObserver<Elements> inboundObserver) {
return TestStreams.withOnNext(
new Consumer<Elements>() {
@Override
public void accept(Elements item) {
values.add(item);
}
})
.build();
}
});
multiplexer.getOutboundObserver().onNext(ELEMENTS);
assertThat(values, contains(ELEMENTS));
}

Line under review: return TestStreams.withOnNext(

Code after addressing the review:
public void testOutboundObserver() {
final Collection<BeamFnApi.Elements> values = new ArrayList<>();
BeamFnDataGrpcMultiplexer multiplexer =
new BeamFnDataGrpcMultiplexer(
DESCRIPTOR, inboundObserver -> TestStreams.withOnNext(values::add).build());
multiplexer.getOutboundObserver().onNext(ELEMENTS);
assertThat(values, contains(ELEMENTS));
}
Code review comment: Not true, `orElseGet` can only use in the direct value. In this situation,  we need get configuration in the optional value, it is unnecessary to mock the configuration when rule absent. 

Code before review:
public void init(final ShardingSphereDatabase database, final SQLStatement sqlStatement) {
Optional<ShardingRule> rule = database.getRuleMetaData().findSingleRule(ShardingRule.class);
data = rule.map(shardingRule -> ((ShardingRuleConfiguration) shardingRule.getConfiguration()).getScaling().entrySet().iterator()).orElse(Collections.emptyIterator());
}

Line under review: data = rule.map(shardingRule -> ((ShardingRuleConfiguration) shardingRule.getConfiguration()).getScaling().entrySet().iterator()).orElse(Collections.emptyIterator());

Code after addressing the review:
public void init(final ShardingSphereDatabase database, final SQLStatement sqlStatement) {
Optional<ShardingRule> rule = database.getRuleMetaData().findSingleRule(ShardingRule.class);
data = rule.map(optional -> ((ShardingRuleConfiguration) optional.getConfiguration()).getScaling().entrySet().iterator()).orElse(Collections.emptyIterator());
}
Code review comment: Okay @wgy8283335, I'll put `DeleteStatement` as a member in the `MergeStatement`. So that we can visit `deleteWhereClause` and put it inside `DeleteStatement`'s `WhereSegment`.

Code before review:
public ASTNode visitMerge(final MergeContext ctx) {
OracleMergeStatement result = new OracleMergeStatement();
result.setTarget((SimpleTableSegment) visit(ctx.intoClause()));
result.setSource((TableSegment) visit(ctx.usingClause()));
result.setExpr((ExpressionSegment) (visit(ctx.usingClause().expr())));
if (null != ctx.mergeUpdateClause()) {
result.getUpdate().setSetAssignment((SetAssignmentSegment) visit(ctx.mergeUpdateClause().mergeSetAssignmentsClause()));
if (null != ctx.mergeUpdateClause().whereClause()) {
result.getUpdate().setWhere((WhereSegment) visit(ctx.mergeUpdateClause().whereClause()));
}
if (null != ctx.mergeUpdateClause().deleteWhereClause()) {
result.getUpdate().setWhere((WhereSegment) visit(ctx.mergeUpdateClause().deleteWhereClause()));
}
}
return result;
}

Line under review: result.getUpdate().setWhere((WhereSegment) visit(ctx.mergeUpdateClause().deleteWhereClause()));

Code after addressing the review:
public ASTNode visitMerge(final MergeContext ctx) {
OracleMergeStatement result = new OracleMergeStatement();
result.setTarget((SimpleTableSegment) visit(ctx.intoClause()));
result.setSource((TableSegment) visit(ctx.usingClause()));
result.setExpr((ExpressionSegment) (visit(ctx.usingClause().expr())));
if (null != ctx.mergeUpdateClause()) {
result.getUpdate().setSetAssignment((SetAssignmentSegment) visit(ctx.mergeUpdateClause().mergeSetAssignmentsClause()));
if (null != ctx.mergeUpdateClause().whereClause()) {
result.getUpdate().setWhere((WhereSegment) visit(ctx.mergeUpdateClause().whereClause()));
}
if (null != ctx.mergeUpdateClause().deleteWhereClause()) {
result.getDelete().setWhere((WhereSegment) visit(ctx.mergeUpdateClause().deleteWhereClause()));
}
}
return result;
}
Code review comment: Refactored to remove `requestStartTime` from the dataclass

Code before review:
private void flush() throws InterruptedException {
RequestInfo requestInfo = createRequestInfo();
while (rateLimitingStrategy.shouldBlock(requestInfo)) {
mailboxExecutor.yield();
requestInfo = createRequestInfo();
}
List<RequestEntryT> batch = createNextAvailableBatch(requestInfo);
int batchSize = batch.size();
if (batchSize == 0) {
return;
}
requestInfo.setBatchSize(batchSize);
long timestampOfRequest = System.currentTimeMillis();
requestInfo.setRequestStartTime(timestampOfRequest);
Consumer<List<RequestEntryT>> requestResultCallback =
failedRequestEntries ->
mailboxExecutor.execute(
() ->
completeRequest(
failedRequestEntries,
batchSize,
timestampOfRequest),
"Mark in-flight request as completed and requeue %d request entries",
failedRequestEntries.size());
rateLimitingStrategy.registerInFlightRequest(requestInfo);
inFlightRequestsCount++;
submitRequestEntries(batch, requestResultCallback);
}

Line under review: requestInfo.setRequestStartTime(timestampOfRequest);

Code after addressing the review:
private void flush() throws InterruptedException {
RequestInfo requestInfo = createRequestInfo();
while (rateLimitingStrategy.shouldBlock(requestInfo)) {
mailboxExecutor.yield();
requestInfo = createRequestInfo();
}
List<RequestEntryT> batch = createNextAvailableBatch(requestInfo);
if (batch.size() == 0) {
return;
}
int batchSize = requestInfo.getBatchSize();
long requestTimestamp = System.currentTimeMillis();
Consumer<List<RequestEntryT>> requestToRetry =
failedRequestEntries ->
mailboxExecutor.execute(
() ->
completeRequest(
failedRequestEntries, batchSize, requestTimestamp),
"Mark in-flight request as completed and requeue %d request entries",
failedRequestEntries.size());
rateLimitingStrategy.registerInFlightRequest(requestInfo);
inFlightRequestsCount++;
submitRequestEntries(batch, requestToRetry);
}
Code review comment: Exactly, so if the prefetch is enabled and drain couldn't emit downstream, we break from the while-loop in line 216; that way, we don't consider the message as consumed, hence increment won't happen.

Code before review:
private void drainQueue() {
if (isTerminated()) {
return;
}
long numberRequested = REQUESTED.get(this);
boolean isEmpty = bufferMessages.isEmpty();
SynchronousReceiveWork currentDownstream = null;
while (numberRequested != 0L && !isEmpty) {
if (isTerminated()) {
break;
}
long numberConsumed = 0L;
while (numberRequested != numberConsumed) {
if (isEmpty || isTerminated()) {
break;
}
final ServiceBusReceivedMessage message = bufferMessages.poll();
boolean isEmitted = false;
while (!isEmitted) {
currentDownstream = getOrUpdateCurrentWork();
if (currentDownstream == null) {
break;
}
isEmitted = currentDownstream.emitNext(message);
}
if (!isEmitted) {
if (isPrefetchDisabled) {
asyncClient.release(message).subscribe(__ -> { },
error -> logger.warning("lockToken[{}] Couldn't release the message.",
message.getLockToken(), error),
() -> logger.verbose("lockToken[{}] Message successfully released.",
message.getLockToken()));
} else {
bufferMessages.addFirst(message);
break;
}
}
numberConsumed++;
isEmpty = bufferMessages.isEmpty();
}
final long requestedMessages = REQUESTED.get(this);
if (requestedMessages != Long.MAX_VALUE) {
numberRequested = REQUESTED.addAndGet(this, -numberConsumed);
}
}
}

Line under review: numberConsumed++;

Code after addressing the review:
private void drainQueue() {
if (isTerminated()) {
return;
}
long numberRequested = REQUESTED.get(this);
boolean isEmpty = bufferMessages.isEmpty();
SynchronousReceiveWork currentDownstream = null;
while (numberRequested != 0L && !isEmpty) {
if (isTerminated()) {
break;
}
long numberConsumed = 0L;
while (numberRequested != numberConsumed) {
if (isEmpty || isTerminated()) {
break;
}
final ServiceBusReceivedMessage message = bufferMessages.poll();
boolean isEmitted = false;
while (!isEmitted) {
currentDownstream = getOrUpdateCurrentWork();
if (currentDownstream == null) {
break;
}
isEmitted = currentDownstream.emitNext(message);
}
if (!isEmitted) {
if (isPrefetchDisabled) {
asyncClient.release(message).subscribe(__ -> { },
error -> logger.warning("lockToken[{}] Couldn't release the message.",
message.getLockToken(), error),
() -> logger.verbose("lockToken[{}] Message successfully released.",
message.getLockToken()));
} else {
bufferMessages.addFirst(message);
break;
}
}
numberConsumed++;
isEmpty = bufferMessages.isEmpty();
}
final long requestedMessages = REQUESTED.get(this);
if (requestedMessages != Long.MAX_VALUE) {
numberRequested = REQUESTED.addAndGet(this, -numberConsumed);
}
}
}
Code review comment: I am not sure I get how we obtain this executor but can we be sure that it never rejects (`RejectedExecutionException`) the task? Or are we just accepting that intentionally and propagate it?

Code before review:
public CompletionStage<Void> invoke(ScheduledExecution execution) throws Exception {
long delay = ThreadLocalRandom.current().nextLong(maxDelay);
DelayedExecution delayedExecution = new DelayedExecution(execution, delay);
try {
event.fire(delayedExecution);
event.fireAsync(delayedExecution);
} catch (Exception e) {
LOG.errorf("Error while firing DelayedExecution event", e);
}
CompletableFuture<Void> ret = new CompletableFuture<>();
executor.schedule(new Runnable() {
@Override
public void run() {
try {
delegate.invoke(execution);
ret.complete(null);
} catch (Exception e) {
ret.completeExceptionally(e);
}
}
}, delay, TimeUnit.MILLISECONDS);
return ret;
}

Line under review: executor.schedule(new Runnable() {

Code after addressing the review:
public CompletionStage<Void> invoke(ScheduledExecution execution) throws Exception {
long delay = ThreadLocalRandom.current().nextLong(maxDelay);
DelayedExecution delayedExecution = new DelayedExecution(execution, delay);
try {
event.fire(delayedExecution);
event.fireAsync(delayedExecution);
} catch (Exception e) {
LOG.errorf("Error while firing DelayedExecution event", e);
}
CompletableFuture<Void> ret = new CompletableFuture<>();
executor.schedule(new Runnable() {
@Override
public void run() {
try {
delegate.invoke(execution);
ret.complete(null);
} catch (Exception e) {
ret.completeExceptionally(e);
}
}
}, delay, TimeUnit.MILLISECONDS);
return ret;
}
Code review comment: I mean the `KeyGenerator` instance, but if it's done once, then that's okay

Code before review:
public static SecretKey generateSecretKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
return keyGenerator.generateKey();
}

Line under review: keyGenerator.init(256);

Code after addressing the review:
public static SecretKey generateSecretKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
return keyGenerator.generateKey();
}
Code review comment: Is it intended that we neglect the non-record type member types in the union types? If so shall we clearly mention that in the documentations?

Code before review:
public static String getModifiedSignature(DocumentServiceContext context, String signature) {
Matcher matcher = TYPE_NAME_DECOMPOSE_PATTERN.matcher(signature);
while (matcher.find()) {
String orgName = matcher.group(1);
String moduleName = matcher.group(2);
String matchedString = matcher.group();
String modulePrefix = getModulePrefix(context, orgName, moduleName);
String replaceText = modulePrefix.isEmpty() ? matchedString + Names.VERSION_SEPARATOR : matchedString;
signature = signature.replace(replaceText, modulePrefix);
}
return signature;
}

Line under review: }

Code after addressing the review:
public static String getModifiedSignature(DocumentServiceContext context, String signature) {
Matcher matcher = TYPE_NAME_DECOMPOSE_PATTERN.matcher(signature);
while (matcher.find()) {
String orgName = matcher.group(1);
String moduleName = matcher.group(2);
String matchedString = matcher.group();
String modulePrefix = getModulePrefix(context, orgName, moduleName);
String replaceText = modulePrefix.isEmpty() ? matchedString + Names.VERSION_SEPARATOR : matchedString;
signature = signature.replace(replaceText, modulePrefix);
}
return signature;
}
Code review comment: @yvgopal Do you have any idea?

Code before review:
public void setDefaultMessageTimeToLive(Duration defaultMessageTimeToLive) {
if (defaultMessageTimeToLive != null
&& (defaultMessageTimeToLive.compareTo(ManagementClientConstants.MIN_ALLOWED_TTL) < 0
|| defaultMessageTimeToLive.compareTo(ManagementClientConstants.MAX_ALLOWED_TTL) > 0)) {
throw new IllegalArgumentException(
String.format("The value must be between %s and %s.",
ManagementClientConstants.MAX_ALLOWED_TTL,
ManagementClientConstants.MIN_ALLOWED_TTL));
}
this.defaultMessageTimeToLive = defaultMessageTimeToLive;
if (this.defaultMessageTimeToLive != null
&& this.defaultMessageTimeToLive.compareTo(ManagementClientConstants.MAX_DURATION) > 0) {
this.defaultMessageTimeToLive = ManagementClientConstants.MAX_DURATION;
}
}

Line under review: if (this.defaultMessageTimeToLive != null

Code after addressing the review:
public void setDefaultMessageTimeToLive(Duration defaultMessageTimeToLive) {
if (defaultMessageTimeToLive == null
|| (defaultMessageTimeToLive.compareTo(ManagementClientConstants.MIN_ALLOWED_TTL) < 0
|| defaultMessageTimeToLive.compareTo(ManagementClientConstants.MAX_ALLOWED_TTL) > 0)) {
throw new IllegalArgumentException(
String.format("The value must be between %s and %s.",
ManagementClientConstants.MAX_ALLOWED_TTL,
ManagementClientConstants.MIN_ALLOWED_TTL));
}
this.defaultMessageTimeToLive = defaultMessageTimeToLive;
if (this.defaultMessageTimeToLive.compareTo(ManagementClientConstants.MAX_DURATION) > 0) {
this.defaultMessageTimeToLive = ManagementClientConstants.MAX_DURATION;
}
}
Code review comment: Created issue to track this. : https://github.com/ballerina-platform/ballerina-lang/issues/18342

Code before review:
private void checkForExportableType(BTypeSymbol symbol, DiagnosticPos pos) {
if (symbol == null || symbol.type == null || Symbols.isFlagOn(symbol.flags, Flags.TYPE_PARAM)) {
return;
}
switch (symbol.type.tag) {
case TypeTags.ARRAY:
checkForExportableType(((BArrayType) symbol.type).eType.tsymbol, pos);
return;
case TypeTags.TUPLE:
BTupleType tupleType = (BTupleType) symbol.type;
tupleType.tupleTypes.forEach(t -> checkForExportableType(t.tsymbol, pos));
if (tupleType.restType != null) {
checkForExportableType(tupleType.restType.tsymbol, pos);
}
return;
case TypeTags.MAP:
checkForExportableType(((BMapType) symbol.type).constraint.tsymbol, pos);
return;
case TypeTags.RECORD:
if (Symbols.isFlagOn(symbol.flags, Flags.ANONYMOUS)) {
BRecordType recordType = (BRecordType) symbol.type;
recordType.fields.forEach(f -> checkForExportableType(f.type.tsymbol, pos));
if (recordType.restFieldType != null) {
checkForExportableType(recordType.restFieldType.tsymbol, pos);
}
return;
}
break;
case TypeTags.TABLE:
BTableType tableType = (BTableType) symbol.type;
if (tableType.constraint != null) {
checkForExportableType(tableType.constraint.tsymbol, pos);
}
return;
case TypeTags.STREAM:
BStreamType streamType = (BStreamType) symbol.type;
if (streamType.constraint != null) {
checkForExportableType(streamType.constraint.tsymbol, pos);
}
return;
}
if (!Symbols.isPublic(symbol)) {
dlog.error(pos, DiagnosticCode.ATTEMPT_EXPOSE_NON_PUBLIC_SYMBOL, symbol.name);
}
}


Code after addressing the review:
private void checkForExportableType(BTypeSymbol symbol, DiagnosticPos pos) {
if (symbol == null || symbol.type == null || Symbols.isFlagOn(symbol.flags, Flags.TYPE_PARAM)) {
return;
}
switch (symbol.type.tag) {
case TypeTags.ARRAY:
checkForExportableType(((BArrayType) symbol.type).eType.tsymbol, pos);
return;
case TypeTags.TUPLE:
BTupleType tupleType = (BTupleType) symbol.type;
tupleType.tupleTypes.forEach(t -> checkForExportableType(t.tsymbol, pos));
if (tupleType.restType != null) {
checkForExportableType(tupleType.restType.tsymbol, pos);
}
return;
case TypeTags.MAP:
checkForExportableType(((BMapType) symbol.type).constraint.tsymbol, pos);
return;
case TypeTags.RECORD:
if (Symbols.isFlagOn(symbol.flags, Flags.ANONYMOUS)) {
BRecordType recordType = (BRecordType) symbol.type;
recordType.fields.forEach(f -> checkForExportableType(f.type.tsymbol, pos));
if (recordType.restFieldType != null) {
checkForExportableType(recordType.restFieldType.tsymbol, pos);
}
return;
}
break;
case TypeTags.TABLE:
BTableType tableType = (BTableType) symbol.type;
if (tableType.constraint != null) {
checkForExportableType(tableType.constraint.tsymbol, pos);
}
return;
case TypeTags.STREAM:
BStreamType streamType = (BStreamType) symbol.type;
if (streamType.constraint != null) {
checkForExportableType(streamType.constraint.tsymbol, pos);
}
return;
}
if (!Symbols.isPublic(symbol)) {
dlog.error(pos, DiagnosticCode.ATTEMPT_EXPOSE_NON_PUBLIC_SYMBOL, symbol.name);
}
}
Code review comment: (although it's not like the test was actually verifying this before...)

Code before review:
public void testPutSuspendedJobOnClusterShutdown() throws Exception {
final Duration timeout = Duration.ofSeconds(5);
try (final MiniCluster miniCluster =
new PersistingMiniCluster(new MiniClusterConfiguration.Builder().build())) {
miniCluster.start();
final JobGraph jobGraph = JobGraphTestUtils.singleNoOpJobGraph();
final JobID jobId = jobGraph.getJobID();
miniCluster.submitJob(jobGraph);
CommonTestUtils.waitUntilCondition(
() -> {
try {
return miniCluster.getJobStatus(jobId).get() == JobStatus.FINISHED;
} catch (Exception e) {
if (ExceptionUtils.findThrowable(e, FlinkJobNotFoundException.class)
.isPresent()) {
return false;
}
throw e;
}
},
Deadline.fromNow(timeout));
}
}

Line under review: return miniCluster.getJobStatus(jobId).get() == JobStatus.FINISHED;

Code after addressing the review:
public void testPutSuspendedJobOnClusterShutdown() throws Exception {
try (final MiniCluster miniCluster =
new PersistingMiniCluster(new MiniClusterConfiguration.Builder().build())) {
miniCluster.start();
final JobVertex vertex = new JobVertex("blockingVertex");
vertex.setInvokableClass(SignallingBlockingNoOpInvokable.class);
final JobGraph jobGraph = JobGraphTestUtils.streamingJobGraph(vertex);
miniCluster.submitJob(jobGraph);
SignallingBlockingNoOpInvokable.LATCH.await();
}
}