muttakin2301/ccr_train_1000 huggingface dataset:
Code review comment: ```suggestion         assertThat(k2).hasSameHashCodeAs(k1); ```

Code before review:
private void testSerialization(BlobKey.BlobType blobType) throws Exception {
final BlobKey k1 = BlobKey.createKey(blobType, KEY_ARRAY_1, RANDOM_ARRAY_1);
final BlobKey k2 = CommonTestUtils.createCopySerializable(k1);
assertThat(k2).isEqualTo(k1);
assertThat(k2.hashCode()).isEqualTo(k1.hashCode());
assertThat(k1.compareTo(k2)).isZero();
}

Line under review: assertThat(k2.hashCode()).isEqualTo(k1.hashCode());

Code after addressing the review:
private void testSerialization(BlobKey.BlobType blobType) throws Exception {
final BlobKey k1 = BlobKey.createKey(blobType, KEY_ARRAY_1, RANDOM_ARRAY_1);
final BlobKey k2 = CommonTestUtils.createCopySerializable(k1);
assertThat(k2).isEqualTo(k1);
assertThat(k2).hasSameHashCodeAs(k1);
assertThat(k1).isEqualByComparingTo(k2);
}
Code review comment: shall this protected by lock? otherwise during the removal, someone set the to-be-removed-volume as default or bind it to db/table?

Code before review:
public void removeStorageVolume(String name) throws AnalysisException, DdlException {
StorageVolume sv = getStorageVolumeByName(name);
Preconditions.checkState(sv != null,
"Storage volume '%s' does not exist", name);
Preconditions.checkState(defaultStorageVolumeId != sv.getId(),
"default storage volume can not be removed");
Preconditions.checkState(!storageVolumeToDbs.containsKey(sv.getId())
&& !storageVolumeToTables.containsKey(sv.getId()),
"Storage volume '%s' is referenced by db or table", name);
GlobalStateMgr.getCurrentState().getStarOSAgent().removeFileStoreByName(name);
}

Line under review: Preconditions.checkState(sv != null,

Code after addressing the review:
public void removeStorageVolume(String name) throws AnalysisException, DdlException {
try (LockCloseable lock = new LockCloseable(rwLock.writeLock())) {
StorageVolume sv = getStorageVolumeByName(name);
Preconditions.checkState(sv != null,
"Storage volume '%s' does not exist", name);
Preconditions.checkState(defaultStorageVolumeId != sv.getId(),
"default storage volume can not be removed");
Set<Long> dbs = storageVolumeToDbs.get(sv.getId());
Set<Long> tables = storageVolumeToTables.get(sv.getId());
Preconditions.checkState(dbs == null && tables == null,
"Storage volume '%s' is referenced by dbs or tables, dbs: %s, tables: %s",
name, dbs != null ? dbs.toString() : "[]", tables != null ? tables.toString() : "[]");
GlobalStateMgr.getCurrentState().getStarOSAgent().removeFileStoreByName(name);
}
}
Code review comment: So you prefer `config.set(CoreOptions.DEFAULT_PARALLELISM, 1);` to `env.setParallelism(1)`? 😅

Code before review:
private StreamExecutionEnvironment getExecutionEnvironment() {
Configuration config = new Configuration();
config.set(ExecutionOptions.RUNTIME_MODE, RuntimeExecutionMode.BATCH);
config.set(CoreOptions.DEFAULT_PARALLELISM, 1);
config.set(ExecutionCheckpointingOptions.CHECKPOINTING_INTERVAL, Duration.ofMillis(42));
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(
config);
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(10, Time.milliseconds(1)));
return env;
}

Line under review: config.set(CoreOptions.DEFAULT_PARALLELISM, 1);

Code after addressing the review:
private StreamExecutionEnvironment getExecutionEnvironment() {
Configuration config = new Configuration();
config.set(ExecutionOptions.RUNTIME_MODE, RuntimeExecutionMode.BATCH);
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(
config);
env.setParallelism(1);
env.enableCheckpointing(42);
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(10, Time.milliseconds(1)));
return env;
}
Code review comment: Please fix assertion by original `getIndexes`

Code before review:
private void assertTableMetaDataMap(final Map<String, TableMetaData> actual) {
assertThat(actual.size(), is(1));
assertThat(actual.get("tbl").getColumns().size(), is(2));
assertThat(actual.get("tbl").getColumnMetaData(0), is(new ColumnMetaData("id", 4, true, true, true)));
assertThat(actual.get("tbl").getColumnMetaData(1), is(new ColumnMetaData("name", 12, false, false, false)));
assertThat(actual.get("tbl").getIndexes().size(), is(1));
assertThat(actual.get("tbl").getIndexMetaData(0), is(new IndexMetaData("id")));
}

Line under review: assertThat(actual.get("tbl").getIndexMetaData(0), is(new IndexMetaData("id")));

Code after addressing the review:
private void assertTableMetaDataMap(final Map<String, TableMetaData> actual) {
assertThat(actual.size(), is(1));
assertThat(actual.get("tbl").getColumns().size(), is(2));
assertThat(actual.get("tbl").getColumnMetaData(0), is(new ColumnMetaData("id", 4, true, true, true)));
assertThat(actual.get("tbl").getColumnMetaData(1), is(new ColumnMetaData("name", 12, false, false, false)));
assertThat(actual.get("tbl").getIndexes().size(), is(1));
assertThat(actual.get("tbl").getIndexes().get("id"), is(new IndexMetaData("id")));
}
Code review comment: Please pass the cause to log.error.

Code before review:
public void start(final String socketPath) {
if (!Epoll.isAvailable()) {
log.error("Epoll is unavailable, DomainSocket can't start.");
return;
}
try {
ChannelFuture future = startDomainSocket(socketPath);
future.addListener((ChannelFutureListener) futureParams -> {
if (futureParams.isSuccess()) {
log.info("The listening address for DomainSocket is {}", socketPath);
} else {
log.error("DomainSocket failed to start.");
futureParams.cause().printStackTrace();
}
});
} catch (final InterruptedException ignored) {
close();
}
}

Line under review: log.error("DomainSocket failed to start.");

Code after addressing the review:
public void start(final String socketPath) {
if (!Epoll.isAvailable()) {
log.error("Epoll is unavailable, DomainSocket can't start.");
return;
}
ChannelFuture future = startDomainSocket(socketPath);
future.addListener((ChannelFutureListener) futureParams -> {
if (futureParams.isSuccess()) {
log.info("The listening address for DomainSocket is {}", socketPath);
} else {
log.error("DomainSocket failed to start:{}", futureParams.cause().getMessage());
futureParams.cause().printStackTrace();
}
});
}
Code review comment: I will block creating db using storage volume in shared_nothing mode in next PR.

Code before review:
private void handleShowCreateDb() throws AnalysisException {
ShowCreateDbStmt showStmt = (ShowCreateDbStmt) stmt;
String catalogName = showStmt.getCatalogName();
String dbName = showStmt.getDb();
List<List<String>> rows = Lists.newArrayList();
Database db;
if (Strings.isNullOrEmpty(catalogName) || CatalogMgr.isInternalCatalog(catalogName)) {
db = connectContext.getGlobalStateMgr().getDb(dbName);
} else {
db = GlobalStateMgr.getCurrentState().getMetadataMgr().getDb(catalogName, dbName);
}
MetaUtils.checkDbNullAndReport(db, showStmt.getDb());
StringBuilder createSqlBuilder = new StringBuilder();
createSqlBuilder.append("CREATE DATABASE `").append(showStmt.getDb()).append("`");
if (!Strings.isNullOrEmpty(db.getLocation())) {
createSqlBuilder.append("\nPROPERTIES (\"location\" = \"").append(db.getLocation()).append("\")");
}
if (RunMode.getCurrentRunMode() == RunMode.SHARED_DATA && !Strings.isNullOrEmpty(db.getStorageVolumeId())) {
StorageVolume sv = GlobalStateMgr.getCurrentState().getStorageVolumeMgr().getStorageVolume(db.getStorageVolumeId());
createSqlBuilder.append("\nPROPERTIES (\"storage_volume\" = \"").append(sv.getName()).append("\")");
}
rows.add(Lists.newArrayList(showStmt.getDb(), createSqlBuilder.toString()));
resultSet = new ShowResultSet(showStmt.getMetaData(), rows);
}

Line under review: if (RunMode.getCurrentRunMode() == RunMode.SHARED_DATA && !Strings.isNullOrEmpty(db.getStorageVolumeId())) {

Code after addressing the review:
private void handleShowCreateDb() throws AnalysisException {
ShowCreateDbStmt showStmt = (ShowCreateDbStmt) stmt;
String catalogName = showStmt.getCatalogName();
String dbName = showStmt.getDb();
List<List<String>> rows = Lists.newArrayList();
Database db;
if (Strings.isNullOrEmpty(catalogName) || CatalogMgr.isInternalCatalog(catalogName)) {
db = connectContext.getGlobalStateMgr().getDb(dbName);
} else {
db = GlobalStateMgr.getCurrentState().getMetadataMgr().getDb(catalogName, dbName);
}
MetaUtils.checkDbNullAndReport(db, showStmt.getDb());
StringBuilder createSqlBuilder = new StringBuilder();
createSqlBuilder.append("CREATE DATABASE `").append(showStmt.getDb()).append("`");
if (!Strings.isNullOrEmpty(db.getLocation())) {
createSqlBuilder.append("\nPROPERTIES (\"location\" = \"").append(db.getLocation()).append("\")");
}
if (!Strings.isNullOrEmpty(db.getStorageVolumeId())) {
StorageVolume sv = GlobalStateMgr.getCurrentState().getStorageVolumeMgr().getStorageVolume(db.getStorageVolumeId());
createSqlBuilder.append("\nPROPERTIES (\"storage_volume\" = \"").append(sv.getName()).append("\")");
}
rows.add(Lists.newArrayList(showStmt.getDb(), createSqlBuilder.toString()));
resultSet = new ShowResultSet(showStmt.getMetaData(), rows);
}
Code review comment: We don't need `bType != symTable.nilType` separately with this? Let's make this the first check instead.

Code before review:
public void visit(BLangExpressionStmt exprStmtNode, AnalyzerData data) {
SymbolEnv currentEnv = data.env;
SymbolEnv stmtEnv = new SymbolEnv(exprStmtNode, currentEnv.scope);
currentEnv.copyTo(stmtEnv);
BLangExpression expr = exprStmtNode.expr;
BType bType = typeChecker.checkExpr(expr, stmtEnv, data.prevEnvs, data.commonAnalyzerData);
if (bType != symTable.nilType && bType != symTable.semanticError &&
expr.getKind() != NodeKind.FAIL &&
!types.isNeverTypeOrStructureTypeWithARequiredNeverMember(bType)
&& !types.isAssignable(bType, symTable.nilType)) {
dlog.error(exprStmtNode.pos, DiagnosticErrorCode.ASSIGNMENT_REQUIRED, bType);
} else if (expr.getKind() == NodeKind.INVOCATION &&
types.isNeverTypeOrStructureTypeWithARequiredNeverMember(expr.getBType())) {
data.notCompletedNormally = true;
}
validateWorkerAnnAttachments(exprStmtNode.expr, data);
}

Line under review: && !types.isAssignable(bType, symTable.nilType)) {

Code after addressing the review:
public void visit(BLangExpressionStmt exprStmtNode, AnalyzerData data) {
SymbolEnv currentEnv = data.env;
SymbolEnv stmtEnv = new SymbolEnv(exprStmtNode, currentEnv.scope);
currentEnv.copyTo(stmtEnv);
BLangExpression expr = exprStmtNode.expr;
BType bType = typeChecker.checkExpr(expr, stmtEnv, data.prevEnvs, data.commonAnalyzerData);
if (!types.isAssignable(bType, symTable.nilType) && bType != symTable.semanticError &&
expr.getKind() != NodeKind.FAIL && !types.isNeverTypeOrStructureTypeWithARequiredNeverMember(bType)) {
dlog.error(exprStmtNode.pos, DiagnosticErrorCode.ASSIGNMENT_REQUIRED, bType);
} else if (expr.getKind() == NodeKind.INVOCATION &&
types.isNeverTypeOrStructureTypeWithARequiredNeverMember(expr.getBType())) {
data.notCompletedNormally = true;
}
validateWorkerAnnAttachments(exprStmtNode.expr, data);
}
Code review comment: +1.. That'd actually simplify things a bit

Code before review:
private boolean isAssignableRecordType(BRecordType recordType, BType type) {
BType targetType;
switch (type.tag) {
case TypeTags.MAP:
targetType = ((BMapType) type).constraint;
break;
case TypeTags.JSON:
targetType = type;
break;
default:
throw new IllegalArgumentException("Incompatible target type: " + type.toString());
}
if (recordType.sealed) {
return recordFieldsAssignableToType(recordType, targetType);
} else {
return recordFieldsAssignableToType(recordType, targetType) &&
isAssignable(recordType.restFieldType, targetType);
}
}

Line under review: isAssignable(recordType.restFieldType, targetType);

Code after addressing the review:
private boolean isAssignableRecordType(BRecordType recordType, BType type) {
BType targetType;
switch (type.tag) {
case TypeTags.MAP:
targetType = ((BMapType) type).constraint;
break;
case TypeTags.JSON:
targetType = type;
break;
default:
throw new IllegalArgumentException("Incompatible target type: " + type.toString());
}
return recordFieldsAssignableToType(recordType, targetType);
}
Code review comment: 此处发心跳并不能发到session里，而是发到了接口调试的session里了 少爷

Code before review:
public void heartbeatCheck() {
WebSocketUtils.sendMessageAll(
new SocketMsgDTO(MsgType.HEARTBEAT.name(), MsgType.HEARTBEAT.name(), MsgType.HEARTBEAT.name(), "heartbeat check")
);
}

Line under review: WebSocketUtils.sendMessageAll(

Code after addressing the review:
public void heartbeatCheck() {
ExportWebSocketHandler.sendMessageSingle(
new SocketMsgDTO(MsgType.HEARTBEAT.name(), MsgType.HEARTBEAT.name(), MsgType.HEARTBEAT.name(), "heartbeat check")
);
}
Code review comment: I think the condition check is probably redundant

Code before review:
public PCollection<Event> expand(PCollection<Event> events) {
final Coder<Event> coder = events.getCoder();
return events
.apply("Pair with random key", ParDo.of(new AssignShardFn<>(configuration.numKeyBuckets)))
.apply(GroupByKey.create())
.apply(
"ExpandIterable",
ParDo.of(
new DoFn<KV<Integer, Iterable<Event>>, Event>() {
@ProcessElement
public void processElement(
@Element KV<Integer, Iterable<Event>> element, OutputReceiver<Event> r) {
for (Event value : element.getValue()) {
r.output(value);
}
}
}))
.apply(
name + ".Serialize",
ParDo.of(
new DoFn<Event, Event>() {
private final Counter bytesMetric = Metrics.counter(name, "serde-bytes");
private final Random random = new Random();
private double pardoCPUFactor =
(configuration.pardoCPUFactor >= 0.0 && configuration.pardoCPUFactor <= 1.0)
? configuration.pardoCPUFactor
: 1.0;
@ProcessElement
public void processElement(ProcessContext c) throws CoderException, IOException {
Event event;
if (random.nextDouble() <= pardoCPUFactor) {
event = encodeDecode(coder, c.element(), bytesMetric);
} else {
event = c.element();
}
c.output(event);
}
}));
}

Line under review: (configuration.pardoCPUFactor >= 0.0 && configuration.pardoCPUFactor <= 1.0)

Code after addressing the review:
public PCollection<Event> expand(PCollection<Event> events) {
final Coder<Event> coder = events.getCoder();
return events
.apply("Pair with random key", ParDo.of(new AssignShardFn<>(configuration.numKeyBuckets)))
.apply(GroupByKey.create())
.apply(
"ExpandIterable",
ParDo.of(
new DoFn<KV<Integer, Iterable<Event>>, Event>() {
@ProcessElement
public void processElement(
@Element KV<Integer, Iterable<Event>> element, OutputReceiver<Event> r) {
for (Event value : element.getValue()) {
r.output(value);
}
}
}))
.apply(
name + ".Serialize",
ParDo.of(
new DoFn<Event, Event>() {
private final Counter bytesMetric = Metrics.counter(name, "serde-bytes");
private final Random random = new Random();
private double pardoCPUFactor =
(configuration.pardoCPUFactor >= 0.0 && configuration.pardoCPUFactor <= 1.0)
? configuration.pardoCPUFactor
: 1.0;
@ProcessElement
public void processElement(ProcessContext c) throws CoderException, IOException {
Event event;
if (random.nextDouble() <= pardoCPUFactor) {
event = encodeDecode(coder, c.element(), bytesMetric);
} else {
event = c.element();
}
c.output(event);
}
}));
}
Code review comment: For async APIs, you should use the Flux or Mono context instead of `Context.None`

Code before review:
private Consumer<Poller<CertificateOperation>> cancelOperation(String name) {
return poller -> {
service.updateCertificateOperation(endpoint, name, API_VERSION, ACCEPT_LANGUAGE,
new CertificateOperationUpdateParameter().cancellationRequested(true), CONTENT_TYPE_HEADER_VALUE, Context.NONE);
};
}

Line under review: new CertificateOperationUpdateParameter().cancellationRequested(true), CONTENT_TYPE_HEADER_VALUE, Context.NONE);

Code after addressing the review:
new CertificateOperationUpdateParameter().cancellationRequested(true);
return service.updateCertificateOperation(endpoint, certificateName, API_VERSION, ACCEPT_LANGUAGE, parameter, CONTENT_TYPE_HEADER_VALUE, context)
.doOnRequest(ignored -> logger.info("Cancelling certificate operation - {}
Code review comment: Changed the name as upsert imples that we always merge but we really just want to do this for EOI now.

Code before review:
void addSummary(CommittableSummary<CommT> summary) {
long checkpointId = summary.getCheckpointIdOrEOI();
SubtaskCommittableManager<CommT> manager =
new SubtaskCommittableManager<>(
summary.getNumberOfCommittables(), subtaskId, checkpointId, metricGroup);
if (checkpointId == CommittableMessage.EOI) {
SubtaskCommittableManager<CommT> merged =
subtasksCommittableManagers.merge(
summary.getSubtaskId(), manager, SubtaskCommittableManager::merge);
} else {
SubtaskCommittableManager<CommT> existing =
subtasksCommittableManagers.putIfAbsent(summary.getSubtaskId(), manager);
if (existing != null) {
throw new UnsupportedOperationException(
String.format(
"Received duplicate committable summary for checkpoint %s + subtask %s (new=%s, old=%s). Please check the status of FLINK-25920",
checkpointId, summary.getSubtaskId(), manager, existing));
}
}
}

Line under review: SubtaskCommittableManager<CommT> merged =

Code after addressing the review:
void addSummary(CommittableSummary<CommT> summary) {
long checkpointId = summary.getCheckpointIdOrEOI();
SubtaskCommittableManager<CommT> manager =
new SubtaskCommittableManager<>(
summary.getNumberOfCommittables(), subtaskId, checkpointId, metricGroup);
if (checkpointId == CommittableMessage.EOI) {
SubtaskCommittableManager<CommT> merged =
subtasksCommittableManagers.merge(
summary.getSubtaskId(), manager, SubtaskCommittableManager::merge);
LOG.debug("Adding EOI summary (new={}}, merged={}}
Code review comment: will adjust message to make it work

Code before review:
static private void checkTls(boolean expect, int ... values) {
byte[] data = new byte[values.length];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) values[i];
}
boolean actual = MaybeTlsCryptoSocket.looksLikeTlsToMe(data);
if(actual != expect) {
throw new AssertionError(message(data, actual));
}
}

Line under review: if(actual != expect) {

Code after addressing the review:
static private void checkTls(boolean expect, int ... values) {
byte[] data = new byte[values.length];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) values[i];
}
boolean actual = MaybeTlsCryptoSocket.looksLikeTlsToMe(data);
if(actual != expect) {
throw new AssertionError(message(data, actual));
}
}
Code review comment: I agree this is a good default, but maybe what we do should be configurable by the user?

Code before review:
public void handle(AsyncResult<Boolean> ar) {
if (ar.failed()) {
log.error("Unable to reload the TLS certificate, keeping the current one.", ar.cause());
} else {
if (ar.result()) {
log.debug("TLS certificates updated");
}
}
}

Line under review: log.error("Unable to reload the TLS certificate, keeping the current one.", ar.cause());

Code after addressing the review:
public void handle(AsyncResult<Boolean> ar) {
if (ar.failed()) {
log.error("Unable to reload the TLS certificate, keeping the current one.", ar.cause());
} else {
if (ar.result()) {
log.debug("TLS certificates updated");
}
}
}
Code review comment: that's a good point :+1: 

Code before review:
void testExceptionForwarding() throws Throwable {
final CreateBuilder mockCreateBuilder =
mock(CreateBuilder.class, Mockito.RETURNS_DEEP_STUBS);
final Exception testException = new Exception("Test exception");
try (final CuratorFrameworkWithUnhandledErrorListener curatorFrameworkWrapper =
ZooKeeperUtils.startCuratorFramework(
configuration, NoOpFatalErrorHandler.INSTANCE)) {
CuratorFramework client = spy(curatorFrameworkWrapper.asCuratorFramework());
doAnswer(invocation -> mockCreateBuilder).when(client).create();
when(mockCreateBuilder
.creatingParentsIfNeeded()
.withMode(ArgumentMatchers.any(CreateMode.class))
.forPath(anyString(), any(byte[].class)))
.thenThrow(testException);
final TestingLeaderElectionListener electionEventHandler =
new TestingLeaderElectionListener();
try (ZooKeeperLeaderElectionDriver leaderElectionDriver =
createAndInitLeaderElectionDriver(client, electionEventHandler)) {
electionEventHandler.await(LeaderElectionEvent.IsLeaderEvent.class);
leaderElectionDriver.publishLeaderInformation(
CONTENDER_ID, LeaderInformation.known(UUID.randomUUID(), "some-address"));
final LeaderElectionEvent.ErrorEvent errorEvent =
electionEventHandler.await(LeaderElectionEvent.ErrorEvent.class);
assertThat(errorEvent.getError()).isEqualTo(testException);
} finally {
electionEventHandler.throwIfErrorEventHappened();
}
}
}

Line under review: electionEventHandler.throwIfErrorEventHappened();

Code after addressing the review:
void testExceptionForwarding() throws Exception {
final CreateBuilder mockCreateBuilder =
mock(CreateBuilder.class, Mockito.RETURNS_DEEP_STUBS);
final Exception testException = new Exception("Test exception");
try (final CuratorFrameworkWithUnhandledErrorListener curatorFrameworkWrapper =
ZooKeeperUtils.startCuratorFramework(
configuration, NoOpFatalErrorHandler.INSTANCE)) {
CuratorFramework client = spy(curatorFrameworkWrapper.asCuratorFramework());
doAnswer(invocation -> mockCreateBuilder).when(client).create();
when(mockCreateBuilder
.creatingParentsIfNeeded()
.withMode(ArgumentMatchers.any(CreateMode.class))
.forPath(anyString(), any(byte[].class)))
.thenThrow(testException);
final TestingLeaderElectionListener electionEventHandler =
new TestingLeaderElectionListener();
try (ZooKeeperLeaderElectionDriver leaderElectionDriver =
createAndInitLeaderElectionDriver(client, electionEventHandler)) {
electionEventHandler.await(LeaderElectionEvent.IsLeaderEvent.class);
leaderElectionDriver.publishLeaderInformation(
CONTENDER_ID, LeaderInformation.known(UUID.randomUUID(), "some-address"));
final LeaderElectionEvent.ErrorEvent errorEvent =
electionEventHandler.await(LeaderElectionEvent.ErrorEvent.class);
assertThat(errorEvent.getError()).isEqualTo(testException);
} finally {
electionEventHandler.failIfErrorEventHappened();
}
}
}
Code review comment: I think the exception should be `new CheckpointException(CheckpointFailureReason#CHECKPOINT_DECLINED_SUBSUMED)`?

Code before review:
public void start(long checkpointId, CheckpointOptions checkpointOptions) {
LOG.debug("{} starting checkpoint {} ({})", taskName, checkpointId, checkpointOptions);
synchronized (lock) {
Preconditions.checkState(checkpointId > ongoingCheckpointId);
if (isCheckpointSubsumedOrAborted(checkpointId)) {
LOG.debug(
"The checkpoint {} of task {} has been aborted, so don't start.",
checkpointId,
taskName);
return;
}
if (result != null) {
result.fail(new CancellationException("Cancel old checkpoint."));
}
this.result = new ChannelStateWriteResult();
ongoingCheckpointId = checkpointId;
enqueue(
new CheckpointStartRequest(
checkpointId, result, checkpointOptions.getTargetLocation()),
false);
}
}

Line under review: result.fail(new CancellationException("Cancel old checkpoint."));

Code after addressing the review:
public void start(long checkpointId, CheckpointOptions checkpointOptions) {
LOG.debug("{} starting checkpoint {} ({})", taskName, checkpointId, checkpointOptions);
ChannelStateWriteResult result = new ChannelStateWriteResult();
ChannelStateWriteResult put =
results.computeIfAbsent(
checkpointId,
id -> {
Preconditions.checkState(
results.size() < maxCheckpoints,
String.format(
"%s can't start %d, results.size() > maxCheckpoints: %d > %d",
taskName,
checkpointId,
results.size(),
maxCheckpoints));
enqueue(
new CheckpointStartRequest(
checkpointId,
result,
checkpointOptions.getTargetLocation()),
false);
return result;
});
Preconditions.checkArgument(
put == result,
taskName + " result future already present for checkpoint " + checkpointId);
}
Code review comment: @geoand that should answer your question, this is what is used to get the list of Java versions, the minimum is set in the Platform/Stream.  So no 11 won't be in the list if the minimum Java version of the stream is 17.

Code before review:
void shouldProperlyUseMinJavaVersion() {
assertThat(getCompatibleLTSVersions(new JavaVersion("11"))).isEqualTo(JAVA_VERSIONS_LTS);
assertThat(getCompatibleLTSVersions(new JavaVersion("17"))).containsExactly(17, 21);
assertThat(getCompatibleLTSVersions(new JavaVersion("21"))).containsExactly(21);
assertThat(getCompatibleLTSVersions(new JavaVersion("100"))).isEmpty();
assertThat(getCompatibleLTSVersions(JavaVersion.NA)).isEqualTo(JAVA_VERSIONS_LTS);
}

Line under review: assertThat(getCompatibleLTSVersions(new JavaVersion("17"))).containsExactly(17, 21);

Code after addressing the review:
void shouldProperlyUseMinJavaVersion() {
assertThat(getCompatibleLTSVersions(new JavaVersion("11"))).isEqualTo(JAVA_VERSIONS_LTS);
assertThat(getCompatibleLTSVersions(new JavaVersion("17"))).containsExactly(17, 21);
assertThat(getCompatibleLTSVersions(new JavaVersion("21"))).containsExactly(21);
assertThat(getCompatibleLTSVersions(new JavaVersion("100"))).isEmpty();
assertThat(getCompatibleLTSVersions(JavaVersion.NA)).isEqualTo(JAVA_VERSIONS_LTS);
}
Code review comment: Thank you for the info!

Code before review:
private Path getDescriptorSetOutputFile(CodeGenContext context) throws IOException {
var dscOutputDir = context.config().getOptionalValue(DESCRIPTOR_SET_OUTPUT_DIR, String.class)
.map(context.projectDir()::resolve)
.orElseGet(context::outDir);
if (Files.notExists(dscOutputDir)) {
Files.createDirectories(dscOutputDir);
}
var dscFilename = context.config().getOptionalValue(DESCRIPTOR_SET_FILENAME, String.class)
.orElse("descriptor_set.dsc");
return dscOutputDir.resolve(dscFilename).normalize();
}

Line under review: .map(context.projectDir()::resolve)

Code after addressing the review:
private Path getDescriptorSetOutputFile(CodeGenContext context) throws IOException {
var dscOutputDir = context.config().getOptionalValue(DESCRIPTOR_SET_OUTPUT_DIR, String.class)
.map(context.workDir()::resolve)
.orElseGet(context::outDir);
if (Files.notExists(dscOutputDir)) {
Files.createDirectories(dscOutputDir);
}
var dscFilename = context.config().getOptionalValue(DESCRIPTOR_SET_FILENAME, String.class)
.orElse("descriptor_set.dsc");
return dscOutputDir.resolve(dscFilename).normalize();
}
Code review comment: ```suggestion             new FatalExitExceptionHandler.INSTANCE.uncaughtException(t, e); ```

Code before review:
public void uncaughtException(Thread t, Throwable e) {
if (handleMode == ClusterOptions.UncaughtExceptionHandleMode.LOG) {
LOG.error("WARNING: Thread '{}' produced an uncaught exception.", t.getName(), e);
} else {
new FatalExitExceptionHandler().uncaughtException(t, e);
}
}

Line under review: new FatalExitExceptionHandler().uncaughtException(t, e);

Code after addressing the review:
public void uncaughtException(Thread t, Throwable e) {
if (handleMode == ClusterOptions.UncaughtExceptionHandleMode.LOG) {
LOG.error(
"WARNING: Thread '{}' produced an uncaught exception. If you want to fail on uncaught exceptions, then configure {} accordingly",
t.getName(),
ClusterOptions.UNCAUGHT_EXCEPTION_HANDLING.key());
} else {
FatalExitExceptionHandler.INSTANCE.uncaughtException(t, e);
}
}
Code review comment: Is it correct that this error is getting logged? Only `Context` is an unknown type here, right? Even though there are errors when attempting to resolve `FunctionEntry`'s members, it is not unknown?

Code before review:
public void testFunctionPointerAsVariable() {
CompileResult result =
BCompileUtil.compile("test-src/expressions/lambda/negative/fp-type-mismatch1-negative.bal");
Assert.assertEquals(result.getErrorCount(), 3);
BAssertUtil.validateError(result, 0, "incompatible types: expected 'function (string,int) returns " +
"(boolean)', found 'function (string,float) returns (boolean)'", 2, 53);
BAssertUtil.validateError(result, 1, "unknown type 'Context'", 10, 29);
BAssertUtil.validateError(result, 2, "unknown type 'FunctionEntry'", 12, 5);
}

Line under review: BAssertUtil.validateError(result, 2, "unknown type 'FunctionEntry'", 12, 5);

Code after addressing the review:
public void testFunctionPointerAsVariable() {
CompileResult result =
BCompileUtil.compile("test-src/expressions/lambda/negative/fp-type-mismatch1-negative.bal");
Assert.assertEquals(result.getErrorCount(), 3);
BAssertUtil.validateError(result, 0, "incompatible types: expected 'function (string,int) returns " +
"(boolean)', found 'function (string,float) returns (boolean)'", 2, 53);
BAssertUtil.validateError(result, 1, "unknown type 'Context'", 10, 29);
BAssertUtil.validateError(result, 2, "unknown type 'FunctionEntry'", 12, 5);
}
Code review comment: nice!

Code before review:
public void execute() throws AnalysisException {
GroupExpression logicalExpression = group.getLogicalExpression();
if (!childrenOptimized) {
pushJob(new RewriteBottomUpJob(group, rules, context, true));
List<Group> children = logicalExpression.children();
for (int i = children.size() - 1; i >= 0; i--) {
pushJob(new RewriteBottomUpJob(children.get(i), rules, context, false));
}
return;
}
trace(logicalExpression);
List<Rule> validRules = getValidRules(logicalExpression, rules);
for (Rule rule : validRules) {
GroupExpressionMatching groupExpressionMatching
= new GroupExpressionMatching(rule.getPattern(), logicalExpression);
for (Plan before : groupExpressionMatching) {
Optional<CopyInResult> copyInResult = invokeRewriteRuleWithTrace(rule, before, group,
REWRITE_BOTTOM_UP_JOB_TRACER);
if (!copyInResult.isPresent()) {
continue;
}
Group correspondingGroup = copyInResult.get().correspondingExpression.getOwnerGroup();
if (copyInResult.get().generateNewExpression
|| correspondingGroup != group
|| logicalExpression.getOwnerGroup() == null) {
pushJob(new RewriteBottomUpJob(correspondingGroup, rules, context, false));
return;
}
}
}
}

Line under review: REWRITE_BOTTOM_UP_JOB_TRACER);

Code after addressing the review:
public void execute() throws AnalysisException {
GroupExpression logicalExpression = group.getLogicalExpression();
if (!childrenOptimized) {
pushJob(new RewriteBottomUpJob(group, rules, context, true));
List<Group> children = logicalExpression.children();
for (int i = children.size() - 1; i >= 0; i--) {
pushJob(new RewriteBottomUpJob(children.get(i), rules, context, false));
}
return;
}
countJobExecutionTimesOfGroupExpressions(logicalExpression);
List<Rule> validRules = getValidRules(logicalExpression, rules);
for (Rule rule : validRules) {
GroupExpressionMatching groupExpressionMatching
= new GroupExpressionMatching(rule.getPattern(), logicalExpression);
for (Plan before : groupExpressionMatching) {
Optional<CopyInResult> copyInResult = invokeRewriteRuleWithTrace(rule, before, group);
if (!copyInResult.isPresent()) {
continue;
}
Group correspondingGroup = copyInResult.get().correspondingExpression.getOwnerGroup();
if (copyInResult.get().generateNewExpression
|| correspondingGroup != group
|| logicalExpression.getOwnerGroup() == null) {
pushJob(new RewriteBottomUpJob(correspondingGroup, rules, context, false));
return;
}
}
}
}
Code review comment: Reproducible in the following code. ```ballerina anydata arr = []; (map<int> & readonly)[2] arr4 = checkpanic arr.cloneWithType(); ``` Fixed in the latest commit.

Code before review:
public boolean hasFillerValue(BType type) {
switch (type.tag) {
case TypeTags.INT:
case TypeTags.BYTE:
case TypeTags.FLOAT:
case TypeTags.DECIMAL:
case TypeTags.STRING:
case TypeTags.BOOLEAN:
case TypeTags.JSON:
case TypeTags.XML:
case TypeTags.XML_TEXT:
case TypeTags.NIL:
case TypeTags.TABLE:
case TypeTags.ANYDATA:
case TypeTags.MAP:
case TypeTags.ANY:
return true;
case TypeTags.ARRAY:
return checkFillerValue((BArrayType) type);
case TypeTags.FINITE:
return checkFillerValue((BFiniteType) type);
case TypeTags.UNION:
return checkFillerValue((BUnionType) type);
case TypeTags.OBJECT:
return checkFillerValue((BObjectType) type);
case TypeTags.RECORD:
return checkFillerValue((BRecordType) type);
case TypeTags.TUPLE:
BTupleType tupleType = (BTupleType) type;
if (tupleType.isCyclic) {
return false;
}
return tupleType.getTupleTypes().stream().allMatch(eleType -> hasFillerValue(eleType));
case TypeTags.TYPEREFDESC:
return hasFillerValue(getReferredType(type));
case TypeTags.INTERSECTION:
return hasFillerValue(((BIntersectionType) type).effectiveType);
default:
return TypeTags.isIntegerTypeTag(type.tag);
}
}

Line under review: return hasFillerValue(((BIntersectionType) type).effectiveType);

Code after addressing the review:
public boolean hasFillerValue(BType type) {
switch (type.tag) {
case TypeTags.INT:
case TypeTags.BYTE:
case TypeTags.FLOAT:
case TypeTags.DECIMAL:
case TypeTags.STRING:
case TypeTags.BOOLEAN:
case TypeTags.JSON:
case TypeTags.XML:
case TypeTags.XML_TEXT:
case TypeTags.NIL:
case TypeTags.TABLE:
case TypeTags.ANYDATA:
case TypeTags.MAP:
case TypeTags.ANY:
return true;
case TypeTags.ARRAY:
return checkFillerValue((BArrayType) type);
case TypeTags.FINITE:
return checkFillerValue((BFiniteType) type);
case TypeTags.UNION:
return checkFillerValue((BUnionType) type);
case TypeTags.OBJECT:
return checkFillerValue((BObjectType) type);
case TypeTags.RECORD:
return checkFillerValue((BRecordType) type);
case TypeTags.TUPLE:
BTupleType tupleType = (BTupleType) type;
if (tupleType.isCyclic) {
return false;
}
return tupleType.getTupleTypes().stream().allMatch(eleType -> hasFillerValue(eleType));
case TypeTags.TYPEREFDESC:
return hasFillerValue(getReferredType(type));
case TypeTags.INTERSECTION:
return hasFillerValue(((BIntersectionType) type).effectiveType);
default:
return TypeTags.isIntegerTypeTag(type.tag);
}
}
Code review comment: But can easily copy the code in our own utils if necessary... I will update the PR tomorrow.

Code before review:
static String adaptMethodName(String name) {
name = Introspector.decapitalize(name);
if (name.contains("_")) {
StringBuilder res = new StringBuilder();
for (String str : name.split("_")) {
if (res.length() == 0) {
res.append(str);
} else {
res.append(Character.toUpperCase(str.charAt(0)));
if (str.length() > 1) {
res.append(str.substring(1));
}
}
}
name = res.toString();
} else if (SourceVersion.isKeyword(name)) {
name += "_";
}
return name;
}

Line under review: name = Introspector.decapitalize(name);

Code after addressing the review:
static String adaptMethodName(String name) {
if (name == null || name.isEmpty()) {
return name;
}
StringBuilder ret = new StringBuilder();
ret.append(Character.toLowerCase(name.charAt(0)));
if (name.length() > 1) {
if (name.contains("_")) {
for (String str : name.substring(1).split("_")) {
if (ret.length() == 1) {
ret.append(str);
} else {
ret.append(Character.toUpperCase(str.charAt(0)));
if (str.length() > 1) {
ret.append(str.substring(1));
}
}
}
} else {
ret.append(name.substring(1));
}
if (isJavaKeyword(ret.toString())) {
ret.append("_");
}
}
return ret.toString();
}
Code review comment: why not capture it in `default` branch?

Code before review:
public static Type convertColumnType(String hiveType) throws DdlException {
String typeUpperCase = Utils.getTypeKeyword(hiveType).toUpperCase();
PrimitiveType primitiveType;
switch (typeUpperCase) {
case "TINYINT":
primitiveType = PrimitiveType.TINYINT;
break;
case "SMALLINT":
primitiveType = PrimitiveType.SMALLINT;
break;
case "INT":
case "INTEGER":
primitiveType = PrimitiveType.INT;
break;
case "BIGINT":
primitiveType = PrimitiveType.BIGINT;
break;
case "FLOAT":
primitiveType = PrimitiveType.FLOAT;
break;
case "DOUBLE":
case "DOUBLE PRECISION":
primitiveType = PrimitiveType.DOUBLE;
break;
case "DECIMAL":
case "NUMERIC":
primitiveType = PrimitiveType.DECIMAL32;
break;
case "TIMESTAMP":
primitiveType = PrimitiveType.DATETIME;
break;
case "DATE":
primitiveType = PrimitiveType.DATE;
break;
case "STRING":
return ScalarType.createDefaultString();
case "VARCHAR":
return ScalarType.createVarcharType(Utils.getVarcharLength(hiveType));
case "CHAR":
return ScalarType.createCharType(Utils.getCharLength(hiveType));
case "BOOLEAN":
primitiveType = PrimitiveType.BOOLEAN;
break;
case "BINARY":
primitiveType = PrimitiveType.CONVERT_FAILED;
break;
case "ARRAY":
Type type = Utils.convertToArrayType(hiveType);
if (type.isArrayType()) {
return type;
}
default:
throw new DdlException("hive table column type [" + typeUpperCase + "] transform failed.");
}
if (primitiveType != PrimitiveType.DECIMAL32) {
return ScalarType.createType(primitiveType);
} else {
int[] parts = Utils.getPrecisionAndScale(hiveType);
return ScalarType.createUnifiedDecimalType(parts[0], parts[1]);
}
}

Line under review: case "BINARY":

Code after addressing the review:
public static Type convertColumnType(String hiveType) throws DdlException {
String typeUpperCase = Utils.getTypeKeyword(hiveType).toUpperCase();
PrimitiveType primitiveType;
switch (typeUpperCase) {
case "TINYINT":
primitiveType = PrimitiveType.TINYINT;
break;
case "SMALLINT":
primitiveType = PrimitiveType.SMALLINT;
break;
case "INT":
case "INTEGER":
primitiveType = PrimitiveType.INT;
break;
case "BIGINT":
primitiveType = PrimitiveType.BIGINT;
break;
case "FLOAT":
primitiveType = PrimitiveType.FLOAT;
break;
case "DOUBLE":
case "DOUBLE PRECISION":
primitiveType = PrimitiveType.DOUBLE;
break;
case "DECIMAL":
case "NUMERIC":
primitiveType = PrimitiveType.DECIMAL32;
break;
case "TIMESTAMP":
primitiveType = PrimitiveType.DATETIME;
break;
case "DATE":
primitiveType = PrimitiveType.DATE;
break;
case "STRING":
return ScalarType.createDefaultString();
case "VARCHAR":
return ScalarType.createVarcharType(Utils.getVarcharLength(hiveType));
case "CHAR":
return ScalarType.createCharType(Utils.getCharLength(hiveType));
case "BOOLEAN":
primitiveType = PrimitiveType.BOOLEAN;
break;
case "ARRAY":
Type type = Utils.convertToArrayType(hiveType);
if (type.isArrayType()) {
return type;
}
default:
primitiveType = PrimitiveType.UNKNOWN_TYPE;
break;
}
if (primitiveType != PrimitiveType.DECIMAL32) {
return ScalarType.createType(primitiveType);
} else {
int[] parts = Utils.getPrecisionAndScale(hiveType);
return ScalarType.createUnifiedDecimalType(parts[0], parts[1]);
}
}
Code review comment: Shouldn't we ideally pass the errors related to WebSocket connection in the onError resource? IMO all other internal errors should be logged in the internal log but should not appear in onError resource since they are not related to WebSocket connection. WDYT?

Code before review:
public static void dispatchError(WebSocketOpenConnectionInfo connectionInfo, Throwable throwable) {
WebSocketService webSocketService = connectionInfo.getService();
Resource onErrorResource = webSocketService.getResourceByName(WebSocketConstants.RESOURCE_NAME_ON_ERROR);
if (isUnexpectedError(throwable)) {
log.error("Unexpected error", throwable);
return;
}
if (onErrorResource == null) {
ErrorHandlerUtils.printError(throwable);
return;
}
BValue[] bValues = new BValue[onErrorResource.getParamDetails().size()];
bValues[0] = connectionInfo.getWebSocketEndpoint();
bValues[1] = getError(webSocketService, throwable);
CallableUnitCallback onErrorCallback = new CallableUnitCallback() {
@Override
public void notifySuccess() {
}
@Override
public void notifyFailure(BStruct error) {
ErrorHandlerUtils.printError("error: " + BLangVMErrors.getPrintableStackTrace(error));
}
};
Executor.submit(onErrorResource, onErrorCallback, null, null, bValues);
}

Line under review: if (isUnexpectedError(throwable)) {

Code after addressing the review:
public static void dispatchError(WebSocketOpenConnectionInfo connectionInfo, Throwable throwable) {
WebSocketService webSocketService = connectionInfo.getService();
Resource onErrorResource = webSocketService.getResourceByName(WebSocketConstants.RESOURCE_NAME_ON_ERROR);
if (isUnexpectedError(throwable)) {
log.error("Unexpected error", throwable);
}
if (onErrorResource == null) {
ErrorHandlerUtils.printError(throwable);
return;
}
BValue[] bValues = new BValue[onErrorResource.getParamDetails().size()];
bValues[0] = connectionInfo.getWebSocketEndpoint();
bValues[1] = getError(webSocketService, throwable);
CallableUnitCallback onErrorCallback = new CallableUnitCallback() {
@Override
public void notifySuccess() {
}
@Override
public void notifyFailure(BStruct error) {
ErrorHandlerUtils.printError("error: " + BLangVMErrors.getPrintableStackTrace(error));
}
};
Executor.submit(onErrorResource, onErrorCallback, null, null, bValues);
}
Code review comment: check this before setting outputTimestamp above (and only if outputTimestamp != null)

Code before review:
private void setAndVerifyOutputTimestamp() {
if (outputTimestamp == null && TimeDomain.EVENT_TIME.equals(spec.getTimeDomain())) {
outputTimestamp = target;
}
if (outputTimestamp == null) {
outputTimestamp = elementInputTimestamp;
}
checkArgument(
!outputTimestamp.isBefore(elementInputTimestamp),
"output timestamp %s should be after input message timestamp or output timestamp of firing timers %s",
outputTimestamp,
elementInputTimestamp);
checkArgument(
!outputTimestamp.isAfter(target),
"output timestamp %s should be before %s delivery timestamp %s",
outputTimestamp,
target);
Instant windowExpiry = window.maxTimestamp().plus(allowedLateness);
checkArgument(
!target.isAfter(windowExpiry),
"Attempted to set event time timer that outputs for %s but that is"
+ " after the expiration of window %s",
target,
windowExpiry);
}

Line under review: elementInputTimestamp);

Code after addressing the review:
private void setAndVerifyOutputTimestamp() {
if (outputTimestamp != null) {
checkArgument(
!outputTimestamp.isBefore(elementInputTimestamp),
"output timestamp %s should be after input message timestamp or output timestamp of firing timers %s",
outputTimestamp,
elementInputTimestamp);
}
if (outputTimestamp == null && TimeDomain.EVENT_TIME.equals(spec.getTimeDomain())) {
outputTimestamp = target;
}
if (outputTimestamp == null) {
outputTimestamp = elementInputTimestamp;
}
Instant windowExpiry = window.maxTimestamp().plus(allowedLateness);
checkArgument(
!target.isAfter(windowExpiry),
"Attempted to set event time timer that outputs for %s but that is"
+ " after the expiration of window %s",
target,
windowExpiry);
}
Code review comment: This should either be removed or logged using the `log`.

Code before review:
private void sendData(Map.Entry<String, byte[]> entry, String session) throws IOException {
HttpURLConnection connection;
System.out.println("Sending " + entry.getKey());
connection = (HttpURLConnection) new URL(url + "/" + entry.getKey()).openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.addRequestProperty(HttpHeaders.CONTENT_TYPE.toString(), RemoteSyncHandler.APPLICATION_QUARKUS);
connection.addRequestProperty(RemoteSyncHandler.QUARKUS_PASSWORD, password);
connection.addRequestProperty(RemoteSyncHandler.QUARKUS_SESSION, session);
connection.getOutputStream().write(entry.getValue());
connection.getOutputStream().close();
IoUtil.readBytes(connection.getInputStream());
}

Line under review: System.out.println("Sending " + entry.getKey());

Code after addressing the review:
private void sendData(Map.Entry<String, byte[]> entry, String session) throws IOException {
HttpURLConnection connection;
log.info("Sending " + entry.getKey());
connection = (HttpURLConnection) new URL(url + "/" + entry.getKey()).openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.addRequestProperty(HttpHeaders.CONTENT_TYPE.toString(), RemoteSyncHandler.APPLICATION_QUARKUS);
connection.addRequestProperty(RemoteSyncHandler.QUARKUS_PASSWORD, password);
connection.addRequestProperty(RemoteSyncHandler.QUARKUS_SESSION, session);
connection.getOutputStream().write(entry.getValue());
connection.getOutputStream().close();
IoUtil.readBytes(connection.getInputStream());
}
Code review comment: I tried to put test removals into their own commits to be able to give the reasoning in the commit message. For this specific test it is: ``` [test] Removes testStopWhileHavingLeadership: This test case is covered by  - testDelayedGrantCallAfterContenderRegistration which checks delayed grant event processing (the first part of the test granting leadership) - testOnRevokeLeadershipIsTriggeredAfterLeaderElectionBeingStop which checks that the leadership is revoked in the contender after the close is called (the second part of the test revoking the leadership in the contender) ```

Code before review:
void testDriverShutdownFailsWithContenderStillBeingRegistered() throws Exception {
new Context() {
{
runTestWithSynchronousEventHandling(
() ->
assertThatThrownBy(leaderElectionService::close)
.as(
"The LeaderContender needs to be deregistered before closing the driver.")
.isInstanceOf(IllegalStateException.class));
}
};
}

Line under review: };

Code after addressing the review:
void testDriverShutdownFailsWithContenderStillBeingRegistered() throws Exception {
new Context() {
{
runTestWithSynchronousEventHandling(
() ->
assertThatThrownBy(leaderElectionService::close)
.as(
"The LeaderContender needs to be deregistered before closing the driver.")
.isInstanceOf(IllegalStateException.class));
}
};
}
Code review comment: Yes, that looks way better. I have dropped the `clear` action on empty collections.

Code before review:
public List<PulsarPartitionSplit> snapshotState(long checkpointId) {
LOG.debug("Trigger the new transaction for downstream readers.");
List<PulsarPartitionSplit> splits =
((PulsarUnorderedFetcherManager<OUT>) splitFetcherManager)
.snapshotState(checkpointId);
if (splits.isEmpty() && transactionsOfFinishedSplits.isEmpty()) {
transactionsToCommit.put(checkpointId, Collections.emptyList());
} else {
List<TxnID> txnIDs =
transactionsToCommit.computeIfAbsent(checkpointId, id -> new ArrayList<>());
for (PulsarPartitionSplit split : splits) {
TxnID uncommittedTransactionId = split.getUncommittedTransactionId();
if (uncommittedTransactionId != null) {
txnIDs.add(uncommittedTransactionId);
}
}
}
return splits;
}

Line under review: .snapshotState(checkpointId);

Code after addressing the review:
public List<PulsarPartitionSplit> snapshotState(long checkpointId) {
LOG.debug("Trigger the new transaction for downstream readers.");
List<PulsarPartitionSplit> splits =
((PulsarUnorderedFetcherManager<OUT>) splitFetcherManager)
.snapshotState(checkpointId);
if (coordinatorClient != null) {
List<TxnID> txnIDs =
transactionsToCommit.computeIfAbsent(checkpointId, id -> new ArrayList<>());
for (PulsarPartitionSplit split : splits) {
TxnID uncommittedTransactionId = split.getUncommittedTransactionId();
if (uncommittedTransactionId != null) {
txnIDs.add(uncommittedTransactionId);
}
}
}
return splits;
}
Code review comment: we should set the request what the DISTINCT_LOCAL agg want to. in later stage if the missing enforce helper found that the GLOBAL agg's distribute satisfy the DISTINCT_LOCAL agg, no exchange node will be added

Code before review:
public Void visitPhysicalAggregate(PhysicalAggregate<? extends Plan> agg, PlanContext context) {
if (agg.getAggPhase().isLocal()) {
addToRequestPropertyToChildren(PhysicalProperties.ANY);
return null;
}
if (agg.getAggPhase() == AggPhase.DISTINCT_LOCAL) {
addToRequestPropertyToChildren(PhysicalProperties.ANY);
return null;
}
List<Expression> partitionExpressions = agg.getPartitionExpressions();
if (partitionExpressions.isEmpty()) {
addToRequestPropertyToChildren(PhysicalProperties.GATHER);
return null;
}
if (partitionExpressions.stream().allMatch(SlotReference.class::isInstance)) {
List<ExprId> partitionedSlots = partitionExpressions.stream()
.map(SlotReference.class::cast)
.map(SlotReference::getExprId)
.collect(Collectors.toList());
addToRequestPropertyToChildren(
PhysicalProperties.createHash(new DistributionSpecHash(partitionedSlots, ShuffleType.AGGREGATE)));
return null;
}
throw new RuntimeException("Need to add a rule to split aggregate to aggregate(project),"
+ " see more in AggregateDisassemble");
}

Line under review: addToRequestPropertyToChildren(PhysicalProperties.ANY);

Code after addressing the review:
public Void visitPhysicalAggregate(PhysicalAggregate<? extends Plan> agg, PlanContext context) {
if (agg.getAggPhase().isLocal()) {
addToRequestPropertyToChildren(PhysicalProperties.ANY);
return null;
}
if (agg.getAggPhase() == AggPhase.GLOBAL && !agg.isFinalPhase()) {
addToRequestPropertyToChildren(requestPropertyFromParent);
return null;
}
List<Expression> partitionExpressions = agg.getPartitionExpressions();
if (partitionExpressions.isEmpty()) {
addToRequestPropertyToChildren(PhysicalProperties.GATHER);
return null;
}
if (partitionExpressions.stream().allMatch(SlotReference.class::isInstance)) {
List<ExprId> partitionedSlots = partitionExpressions.stream()
.map(SlotReference.class::cast)
.map(SlotReference::getExprId)
.collect(Collectors.toList());
addToRequestPropertyToChildren(
PhysicalProperties.createHash(new DistributionSpecHash(partitionedSlots, ShuffleType.AGGREGATE)));
return null;
}
throw new RuntimeException("Need to add a rule to split aggregate to aggregate(project),"
+ " see more in AggregateDisassemble");
}