muttakin2301/ccr_train_1000 huggingface dataset:
Code review comment: I think you should use the TCCL directly here.

Code before review:
private static InputStream getTikaConfigStream(TikaConfiguration config, String tikaXmlConfiguration) {
InputStream is;
if (config.tikaConfigPath.isPresent()) {
is = TikaRecorder.class.getResourceAsStream(config.tikaConfigPath.get());
if (is == null) {
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(config.tikaConfigPath.get());
}
if (is == null) {
final String errorMessage = "tika-config.xml can not be found at " + config.tikaConfigPath.get();
throw new TikaParseException(errorMessage);
}
} else {
is = new ByteArrayInputStream(tikaXmlConfiguration.getBytes(StandardCharsets.UTF_8));
}
return is;
}

Line under review: is = Thread.currentThread().getContextClassLoader().getResourceAsStream(config.tikaConfigPath.get());

Code after addressing the review:
private static InputStream getTikaConfigStream(TikaConfiguration config, String tikaXmlConfiguration) {
InputStream is;
if (config.tikaConfigPath.isPresent()) {
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(config.tikaConfigPath.get());
if (is == null) {
final String errorMessage = "tika-config.xml can not be found at " + config.tikaConfigPath.get();
throw new TikaParseException(errorMessage);
}
} else {
is = new ByteArrayInputStream(tikaXmlConfiguration.getBytes(StandardCharsets.UTF_8));
}
return is;
}
Code review comment: ``` type LE EmptyListener|Listener; listener LE lsn = new Listener(); ```  In this scenario, this method would return `EmptyListener`, right? Was wondering if that could cause issues, because for example, when we consider the attach method, we'll be retrieving `attach` of `EmptyListener` instead of `Listener` even though the actual value is `Listener`.   Basic scenarios seem to work as expected though.

Code before review:
private BType getListenerType(BType type) {
if (type.tag == TypeTags.UNION) {
for (BType memberType : ((BUnionType) type).getMemberTypes()) {
if (types.checkListenerCompatibility(memberType)) {
return memberType;
}
}
}
return type;
}

Line under review: return memberType;

Code after addressing the review:
private BType getListenerType(BType type) {
if (type.tag == TypeTags.UNION) {
for (BType memberType : ((BUnionType) type).getMemberTypes()) {
if (types.checkListenerCompatibility(memberType)) {
return memberType;
}
}
}
return type;
}
Code review comment: I modified this logic to work regardless of the position of the delimiter. 

Code before review:
public void handle(Buffer buffer) {
try {
byte[] bytes = buffer.getBytes();
MediaType mediaType = response.getMediaType();
if (isNewlineDelimited) {
String charset = mediaType.getParameters().get(MediaType.CHARSET_PARAMETER);
charset = charset == null ? "UTF-8" : charset;
byte[] separator = "\n".getBytes(charset);
int start = 0;
while (start < bytes.length) {
int end = bytes.length;
for (int i = start; i < end; i++) {
if (bytes[i] == separator[0]) {
int j;
boolean matches = true;
for (j = 1; j < separator.length; j++) {
if (bytes[i + j] != separator[j]) {
matches = false;
break;
}
}
if (matches) {
end = i;
break;
}
}
}
if (start < end) {
ByteArrayInputStream in = new ByteArrayInputStream(bytes, start, end);
R item = restClientRequestContext.readEntity(in, responseType, mediaType,
response.getMetadata());
multiRequest.emitter.emit(item);
}
start = end + separator.length;
}
} else {
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
R item = restClientRequestContext.readEntity(in, responseType, mediaType,
response.getMetadata());
multiRequest.emitter.emit(item);
}
} catch (Throwable t) {
multiRequest.emitter.fail(t);
}
}

Line under review: String charset = mediaType.getParameters().get(MediaType.CHARSET_PARAMETER);

Code after addressing the review:
public void handle(Buffer buffer) {
try {
byte[] bytes = buffer.getBytes();
MediaType mediaType = response.getMediaType();
if (isNewlineDelimited) {
String charset = mediaType.getParameters().get(MediaType.CHARSET_PARAMETER);
charset = charset == null ? "UTF-8" : charset;
byte[] separator = "\n".getBytes(charset);
int start = 0;
while (start < bytes.length) {
int end = bytes.length;
for (int i = start; i < end; i++) {
if (bytes[i] == separator[0]) {
int j;
boolean matches = true;
for (j = 1; j < separator.length; j++) {
if (bytes[i + j] != separator[j]) {
matches = false;
break;
}
}
if (matches) {
end = i;
break;
}
}
}
if (start < end) {
ByteArrayInputStream in = new ByteArrayInputStream(bytes, start, end);
R item = restClientRequestContext.readEntity(in, responseType, mediaType,
response.getMetadata());
multiRequest.emitter.emit(item);
}
start = end + separator.length;
}
} else {
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
R item = restClientRequestContext.readEntity(in, responseType, mediaType,
response.getMetadata());
multiRequest.emitter.emit(item);
}
} catch (Throwable t) {
multiRequest.emitter.fail(t);
}
}
Code review comment: We can use methods on `EnvironmentSettings` to check the runtime mode and planner. 

Code before review:
private TableEnvironment createTableEnvironment() {
EnvironmentSettings settings = EnvironmentSettings.fromConfiguration(flinkConfig);
TableConfig config = new TableConfig();
config.addConfiguration(flinkConfig);
if (flinkConfig.get(ExecutionOptions.RUNTIME_MODE).equals(RuntimeExecutionMode.BATCH)
&& flinkConfig.get(TableConfigOptions.TABLE_PLANNER).equals(PlannerType.OLD)) {
ExecutionEnvironment execEnv = createExecutionEnvironment();
return new BatchTableEnvironmentImpl(
execEnv, config, sessionState.catalogManager, sessionState.moduleManager);
} else {
StreamExecutionEnvironment streamExecEnv = createStreamExecutionEnvironment();
final Map<String, String> executorProperties = settings.toExecutorProperties();
Executor executor = lookupExecutor(executorProperties, streamExecEnv);
return createStreamTableEnvironment(
streamExecEnv,
settings,
config,
executor,
sessionState.catalogManager,
sessionState.moduleManager,
sessionState.functionCatalog,
classLoader);
}
}

Line under review: && flinkConfig.get(TableConfigOptions.TABLE_PLANNER).equals(PlannerType.OLD)) {

Code after addressing the review:
private TableEnvironment createTableEnvironment() {
EnvironmentSettings settings = EnvironmentSettings.fromConfiguration(flinkConfig);
TableConfig config = new TableConfig();
config.addConfiguration(flinkConfig);
if (!settings.isStreamingMode() && !settings.isBlinkPlanner()) {
ExecutionEnvironment execEnv = createExecutionEnvironment();
return new BatchTableEnvironmentImpl(
execEnv, config, sessionState.catalogManager, sessionState.moduleManager);
} else {
StreamExecutionEnvironment streamExecEnv = createStreamExecutionEnvironment();
final Map<String, String> executorProperties = settings.toExecutorProperties();
Executor executor = lookupExecutor(executorProperties, streamExecEnv);
return createStreamTableEnvironment(
streamExecEnv,
settings,
config,
executor,
sessionState.catalogManager,
sessionState.moduleManager,
sessionState.functionCatalog,
classLoader);
}
}
Code review comment: `ELSE NULL` makes more sense. But since it's time consuming to change Calcite code, this workaround LGTM

Code before review:
public void testCastToDateWithCase() {
PCollection<Row> input =
pipeline.apply(
Create.of(Row.withSchema(INPUT_ROW_SCHEMA).addValues(1).addValue("20181018").build())
.withSchema(
INPUT_ROW_SCHEMA,
SerializableFunctions.identity(),
SerializableFunctions.identity()));
Schema resultType = Schema.builder().addInt32Field("f_int").addDateTimeField("f_date").build();
PCollection<Row> result =
input.apply(
"sqlQuery",
SqlTransform.query(
"SELECT f_int, \n"
+ "CASE WHEN CHAR_LENGTH(TRIM(f_string)) = 8 \n"
+ "    THEN CAST (\n"
+ "       SUBSTRING(TRIM(f_string) FROM 1 FOR 4) \n"
+ "        ||'-' \n"
+ "        ||SUBSTRING(TRIM(f_string) FROM 5 FOR 2) \n"
+ "        ||'-' \n"
+ "        ||SUBSTRING(TRIM(f_string) FROM 7 FOR 2) AS DATE)\n"
+ "    ELSE DATE '2001-01-01'\n"
+ "END \n"
+ "FROM PCOLLECTION"));
PAssert.that(result)
.containsInAnyOrder(
Row.withSchema(resultType).addValues(1, new DateTime(2018, 10, 18, 0, 0)).build());
pipeline.run();
}

Line under review: + "    ELSE DATE '2001-01-01'\n"

Code after addressing the review:
public void testCastToDateWithCase() {
PCollection<Row> input =
pipeline.apply(
Create.of(Row.withSchema(INPUT_ROW_SCHEMA).addValues(1).addValue("20181018").build())
.withSchema(
INPUT_ROW_SCHEMA,
SerializableFunctions.identity(),
SerializableFunctions.identity()));
Schema resultType = Schema.builder().addInt32Field("f_int").addDateTimeField("f_date").build();
PCollection<Row> result =
input.apply(
"sqlQuery",
SqlTransform.query(
"SELECT f_int, \n"
+ "CASE WHEN CHAR_LENGTH(TRIM(f_string)) = 8 \n"
+ "    THEN CAST (\n"
+ "       SUBSTRING(TRIM(f_string) FROM 1 FOR 4) \n"
+ "        ||'-' \n"
+ "        ||SUBSTRING(TRIM(f_string) FROM 5 FOR 2) \n"
+ "        ||'-' \n"
+ "        ||SUBSTRING(TRIM(f_string) FROM 7 FOR 2) AS DATE)\n"
+ "    ELSE DATE '2001-01-01'\n"
+ "END \n"
+ "FROM PCOLLECTION"));
PAssert.that(result)
.containsInAnyOrder(
Row.withSchema(resultType).addValues(1, new DateTime(2018, 10, 18, 0, 0)).build());
pipeline.run();
}
Code review comment: It is enough to verify the format of the savepoint. We verify savepoints are working if we restore from the savepoint without exceptions (after relocating it).

Code before review:
private static Stream<Arguments> parameters() {
return Stream.of(
Arguments.of(
SavepointFormatType.CANONICAL,
HEAP,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(SavepointKeyedStateHandle.class))),
Arguments.of(
SavepointFormatType.NATIVE,
HEAP,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(KeyGroupsStateHandle.class))),
Arguments.of(
SavepointFormatType.CANONICAL,
ROCKSDB_FULL_SNAPSHOTS,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(SavepointKeyedStateHandle.class))),
Arguments.of(
SavepointFormatType.NATIVE,
ROCKSDB_FULL_SNAPSHOTS,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(KeyGroupsStateHandle.class))),
Arguments.of(
SavepointFormatType.CANONICAL,
ROCKSDB_INCREMENTAL_SNAPSHOTS,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(SavepointKeyedStateHandle.class))),
Arguments.of(
SavepointFormatType.NATIVE,
ROCKSDB_INCREMENTAL_SNAPSHOTS,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(
IncrementalRemoteKeyedStateHandle.class))));
}

Line under review: IncrementalRemoteKeyedStateHandle.class))));

Code after addressing the review:
private static Stream<Arguments> parameters() {
return Stream.of(
Arguments.of(
SavepointFormatType.CANONICAL,
HEAP,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(SavepointKeyedStateHandle.class))),
Arguments.of(
SavepointFormatType.NATIVE,
HEAP,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(KeyGroupsStateHandle.class))),
Arguments.of(
SavepointFormatType.CANONICAL,
ROCKSDB_FULL_SNAPSHOTS,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(SavepointKeyedStateHandle.class))),
Arguments.of(
SavepointFormatType.NATIVE,
ROCKSDB_FULL_SNAPSHOTS,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(KeyGroupsStateHandle.class))),
Arguments.of(
SavepointFormatType.CANONICAL,
ROCKSDB_INCREMENTAL_SNAPSHOTS,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(SavepointKeyedStateHandle.class))),
Arguments.of(
SavepointFormatType.NATIVE,
ROCKSDB_INCREMENTAL_SNAPSHOTS,
(Consumer<KeyedStateHandle>)
keyedState ->
assertThat(
keyedState,
instanceOf(
IncrementalRemoteKeyedStateHandle.class))));
}
Code review comment: We're missing tests for using the delivery state on success and not.

Code before review:
public void testSendWithTransaction() {
Message message = Proton.message();
message.setMessageId("id");
message.setBody(new AmqpValue("hello"));
AmqpTransaction transaction = new AmqpTransaction(ByteBuffer.wrap("1".getBytes()));
ReactorSender reactorSender = new ReactorSender(entityPath, sender, handler, reactorProvider, tokenManager,
messageSerializer, Duration.ofSeconds(1), new ExponentialAmqpRetryPolicy(new AmqpRetryOptions()));
ReactorSender spyReactorSender = spy(reactorSender);
doReturn(Mono.empty()).when(spyReactorSender).send(any(byte[].class), anyInt(), anyInt(), any(AmqpTransaction.class));
StepVerifier.create(spyReactorSender.send(message, transaction))
.verifyComplete();
StepVerifier.create(spyReactorSender.send(message, transaction))
.verifyComplete();
verify(sender, times(1)).getRemoteMaxMessageSize();
verify(spyReactorSender, times(2)).send(any(byte[].class), anyInt(), anyInt(), ArgumentMatchers.same(transaction));
}

Line under review: ReactorSender reactorSender = new ReactorSender(entityPath, sender, handler, reactorProvider, tokenManager,

Code after addressing the review:
public void testSendWithTransaction() {
Message message = Proton.message();
message.setMessageId("id");
message.setBody(new AmqpValue("hello"));
ReactorSender reactorSender = new ReactorSender(entityPath, sender, handler, reactorProvider, tokenManager,
messageSerializer, Duration.ofSeconds(1), new ExponentialAmqpRetryPolicy(new AmqpRetryOptions()));
ReactorSender spyReactorSender = spy(reactorSender);
doReturn(Mono.empty()).when(spyReactorSender).send(any(byte[].class), anyInt(), anyInt(), eq(transactionalState));
StepVerifier.create(spyReactorSender.send(message, transactionalState))
.verifyComplete();
StepVerifier.create(spyReactorSender.send(message, transactionalState))
.verifyComplete();
verify(sender, times(1)).getRemoteMaxMessageSize();
verify(spyReactorSender, times(2)).send(any(byte[].class), anyInt(),
eq(DeliveryImpl.DEFAULT_MESSAGE_FORMAT), eq(transactionalState));
}
Code review comment: ```suggestion         out.append("Build a Ballerina module(s)/file and produce an executable JAR file(s). \n"); ```

Code before review:
public void printLongDesc(StringBuilder out) {
out.append("Build Ballerina module(s)/file and produce an executable JAR file(s). \n");
out.append("\n");
out.append("Build a Ballerina project or a specific module in a project. The \n");
out.append("executable \".jar\" files will be created in the <PROJECT-ROOT>/target/bin directory. \n");
out.append("\n");
out.append("Build a single Ballerina file. This creates an executable .jar file in the \n");
out.append("current directory. The name of the executable file will be \n");
out.append("<ballerina-file-name>.jar. \n");
out.append("\n");
out.append("If the output file is specified with the -o flag, the output \n");
out.append("will be written to the given output file name. The -o flag will only \n");
out.append("work for single files. \n");
}

Line under review: out.append("Build Ballerina module(s)/file and produce an executable JAR file(s). \n");

Code after addressing the review:
public void printLongDesc(StringBuilder out) {
out.append("Build a Ballerina module(s)/file and produce an executable JAR file(s). \n");
out.append("\n");
out.append("Build a Ballerina project or a specific module in a project. The \n");
out.append("executable \".jar\" files will be created in the <PROJECT-ROOT>/target/bin directory. \n");
out.append("\n");
out.append("Build a single Ballerina file. This creates an executable .jar file in the \n");
out.append("current directory. The name of the executable file will be \n");
out.append("<ballerina-file-name>.jar. \n");
out.append("\n");
out.append("If the output file is specified with the -o flag, the output \n");
out.append("will be written to the given output file name. The -o flag will only \n");
out.append("work for single files. \n");
}
Code review comment: I like `Closer`. We don't have to change it for this PR but consider it for a potential improvement in the future.

Code before review:
private void terminateMiniClusterServices() throws Exception {
Exception exception = null;
synchronized (lock) {
if (blobCacheService != null) {
try {
blobCacheService.close();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
blobCacheService = null;
}
if (blobServer != null) {
try {
blobServer.close();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
blobServer = null;
}
if (haServices != null) {
try {
haServices.closeAndCleanupAllData();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
haServices = null;
}
try {
rpcSystem.close();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
if (exception != null) {
throw exception;
}
}
}

Line under review: try {

Code after addressing the review:
private void terminateMiniClusterServices() throws Exception {
Exception exception = null;
synchronized (lock) {
if (blobCacheService != null) {
try {
blobCacheService.close();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
blobCacheService = null;
}
if (blobServer != null) {
try {
blobServer.close();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
blobServer = null;
}
if (haServices != null) {
try {
haServices.closeAndCleanupAllData();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
haServices = null;
}
try {
rpcSystem.close();
} catch (Exception e) {
exception = ExceptionUtils.firstOrSuppressed(e, exception);
}
if (exception != null) {
throw exception;
}
}
}
Code review comment: Let me confirm that this line of code should reverts to the state before modification, so that the test will be skipped instead of failed in the CI environment without k8s, right?

Code before review:
public static void checkEnv() {
final String kubeConfigEnv = System.getenv("ITCASE_KUBECONFIG");
assertThat(StringUtils.isNullOrWhitespaceOnly(kubeConfigEnv))
.withFailMessage("ITCASE_KUBECONFIG environment is not set.")
.isFalse();
kubeConfigFile = kubeConfigEnv;
}

Line under review: assertThat(StringUtils.isNullOrWhitespaceOnly(kubeConfigEnv))

Code after addressing the review:
public static void checkEnv() {
final String kubeConfigEnv = System.getenv("ITCASE_KUBECONFIG");
assumeThat(kubeConfigEnv)
.withFailMessage("ITCASE_KUBECONFIG environment is not set.")
.isNotBlank();
kubeConfigFile = kubeConfigEnv;
}
Code review comment: ```suggestion ```  nit: We can remove this check here since `recordActiveMessageInProcessingTimesMap` also has a null check inside

Code before review:
public Closeable enterState(ExecutionState newState) {
Closeable baseCloseable = super.enterState(newState);
final boolean isDataflowProcessElementState =
newState.isProcessElementState && newState instanceof DataflowExecutionState;
if (isDataflowProcessElementState) {
DataflowExecutionState newDFState = (DataflowExecutionState) newState;
if (newDFState.getStepName() != null && newDFState.getStepName().userName() != null) {
synchronized (this) {
if (this.activeMessageMetadata != null) {
recordActiveMessageInProcessingTimesMap();
}
this.activeMessageMetadata =
ActiveMessageMetadata.create(
newDFState.getStepName().userName(), clock.getMillis());
}
}
elementExecutionTracker.enter(newDFState.getStepName());
}
return () -> {
if (isDataflowProcessElementState) {
synchronized (this) {
if (this.activeMessageMetadata != null) {
recordActiveMessageInProcessingTimesMap();
}
}
elementExecutionTracker.exit();
}
baseCloseable.close();
};
}

Line under review: if (this.activeMessageMetadata != null) {

Code after addressing the review:
public Closeable enterState(ExecutionState newState) {
Closeable baseCloseable = super.enterState(newState);
final boolean isDataflowProcessElementState =
newState.isProcessElementState && newState instanceof DataflowExecutionState;
if (isDataflowProcessElementState) {
DataflowExecutionState newDFState = (DataflowExecutionState) newState;
if (newDFState.getStepName() != null && newDFState.getStepName().userName() != null) {
recordActiveMessageInProcessingTimesMap();
synchronized (this) {
this.activeMessageMetadata =
ActiveMessageMetadata.create(
newDFState.getStepName().userName(), clock.getMillis());
}
}
elementExecutionTracker.enter(newDFState.getStepName());
}
return () -> {
if (isDataflowProcessElementState) {
recordActiveMessageInProcessingTimesMap();
elementExecutionTracker.exit();
}
baseCloseable.close();
};
}
Code review comment: Isn't this a no-op unless you put maps separated by `forward()` into different slot sharing groups?

Code before review:
private long calculateExpectedResultBeforeSavepoint() {
long expectedBeforeSavepointResult = 0;
for (int i = 0; i < TOTAL_RECORDS; i++) {
expectedBeforeSavepointResult += i;
}
return PARALLELISM * expectedBeforeSavepointResult;
}


Code after addressing the review:
private long calculateExpectedResultBeforeSavepoint() {
long expectedBeforeSavepointResult = 0;
for (int i = 0; i < TOTAL_RECORDS; i++) {
expectedBeforeSavepointResult += i;
}
return PARALLELISM * expectedBeforeSavepointResult;
}
Code review comment: Is there a reason why we need to propogate individual parameters here and not just pass on the full system properties map ? 

Code before review:
private void propagateUserProperties() {
final String mavenCmdLine = BootstrapMavenOptions.getMavenCmdLine();
if (mavenCmdLine == null || mavenCmdLine.isEmpty()) {
return;
}
int i = mavenCmdLine.indexOf("-D");
if (i < 0) {
return;
}
final StringBuilder buf = new StringBuilder();
buf.append("-D");
i += 2;
while (i < mavenCmdLine.length()) {
final char ch = mavenCmdLine.charAt(i++);
if (!Character.isWhitespace(ch)) {
buf.append(ch);
} else if (buf.length() > 2) {
args.add(buf.toString());
buf.setLength(2);
i = mavenCmdLine.indexOf("-D", i);
if (i < 0) {
break;
}
i += 2;
}
}
if (buf.length() > 2) {
args.add(buf.toString());
}
}

Line under review: i = mavenCmdLine.indexOf("-D", i);

Code after addressing the review:
private void propagateUserProperties() {
final String mavenCmdLine = BootstrapMavenOptions.getMavenCmdLine();
if (mavenCmdLine == null || mavenCmdLine.isEmpty()) {
return;
}
int i = mavenCmdLine.indexOf("-D");
if (i < 0) {
return;
}
final StringBuilder buf = new StringBuilder();
buf.append("-D");
i += 2;
while (i < mavenCmdLine.length()) {
final char ch = mavenCmdLine.charAt(i++);
if (!Character.isWhitespace(ch)) {
buf.append(ch);
} else if (buf.length() > 2) {
args.add(buf.toString());
buf.setLength(2);
i = mavenCmdLine.indexOf("-D", i);
if (i < 0) {
break;
}
i += 2;
}
}
if (buf.length() > 2) {
args.add(buf.toString());
}
}
Code review comment: ```suggestion           if (terminated) {             return false;           }           if (terminate.get()) { ```  `trySplit` may have already set `terminated` to true which means that future `tryClaim` calls should fail.

Code before review:
public boolean tryClaim(Integer newPosition) {
checkArgument(newPosition >= position);
if (terminate.get()) {
terminated = true;
return false;
}
position = newPosition;
return true;
}

Line under review: if (terminate.get()) {

Code after addressing the review:
public boolean tryClaim(Integer newPosition) {
checkArgument(newPosition >= position);
if (terminated) {
return false;
}
if (terminate.get()) {
terminated = true;
return false;
}
position = newPosition;
return true;
}
Code review comment: Consider including the iteration in the message, to make it clearer for the reader of the message it is actually running more often

Code before review:
protected boolean maintain() {
if (iteration % 10 == 0)
log.log(LogLevel.INFO, () -> "Running " + SessionsMaintainer.class.getSimpleName());
applicationRepository.deleteExpiredLocalSessions();
if (hostedVespa) {
Duration expiryTime = Duration.ofMinutes(90);
int deleted = applicationRepository.deleteExpiredRemoteSessions(expiryTime);
log.log(LogLevel.FINE, () -> "Deleted " + deleted + " expired remote sessions older than " + expiryTime);
}
iteration++;
return true;
}

Line under review: log.log(LogLevel.INFO, () -> "Running " + SessionsMaintainer.class.getSimpleName());

Code after addressing the review:
protected boolean maintain() {
if (iteration % 10 == 0)
log.log(LogLevel.INFO, () -> "Running " + SessionsMaintainer.class.getSimpleName() + ", iteration "  + iteration);
applicationRepository.deleteExpiredLocalSessions();
if (hostedVespa) {
Duration expiryTime = Duration.ofMinutes(90);
int deleted = applicationRepository.deleteExpiredRemoteSessions(expiryTime);
log.log(LogLevel.FINE, () -> "Deleted " + deleted + " expired remote sessions older than " + expiryTime);
}
iteration++;
return true;
}
Code review comment: Why this line has to repeat all the time? Can't we resolve URL at the init and then re-use it?

Code before review:
public void onError(Throwable throwable) {
logger.error("Kafka Ballerina server connector retrieved exception: " + throwable.getMessage(), throwable);
String url = ((Properties) listener.getNativeData(NATIVE_CONSUMER_CONFIG)).getProperty(BOOTSTRAP_SERVERS);
KafkaMetricsUtil.reportConsumerError(url, KafkaObservabilityConstants.ERROR_TYPE_MSG_RECEIVED);
}

Line under review: String url = ((Properties) listener.getNativeData(NATIVE_CONSUMER_CONFIG)).getProperty(BOOTSTRAP_SERVERS);

Code after addressing the review:
public void onError(Throwable throwable) {
logger.error("Kafka Ballerina server connector retrieved exception: " + throwable.getMessage(), throwable);
KafkaMetricsUtil.reportConsumerError(listener, KafkaObservabilityConstants.ERROR_TYPE_MSG_RECEIVED);
}
Code review comment: Not a problem at all, it's me who did it without consulting! ;) Done.

Code before review:
private static void setupLocalstack() throws Exception {
System.setProperty(SDKGlobalConfiguration.DISABLE_CERT_CHECKING_SYSTEM_PROPERTY, "true");
System.setProperty(SDKGlobalConfiguration.AWS_CBOR_DISABLE_SYSTEM_PROPERTY, "true");
now = Instant.ofEpochMilli(Long.divideUnsigned(Instant.now().getMillis(), 1000));
localstackContainer =
new LocalStackContainer("0.11.3")
.withServices(LocalStackContainer.Service.KINESIS)
.withEnv("USE_SSL", "true")
.withStartupAttempts(3);
localstackContainer.start();
options.setAwsServiceEndpoint(
localstackContainer
.getEndpointConfiguration(LocalStackContainer.Service.KINESIS)
.getServiceEndpoint()
.replace("http", "https"));
options.setAwsKinesisRegion(
localstackContainer
.getEndpointConfiguration(LocalStackContainer.Service.KINESIS)
.getSigningRegion());
options.setAwsAccessKey(
localstackContainer.getDefaultCredentialsProvider().getCredentials().getAWSAccessKeyId());
options.setAwsSecretKey(
localstackContainer.getDefaultCredentialsProvider().getCredentials().getAWSSecretKey());
options.setNumberOfRecords(1000);
options.setNumberOfShards(1);
options.setAwsKinesisStream("beam_kinesis_test");
options.setAwsVerifyCertificate(false);
createStream(options.getAwsKinesisStream());
}

Line under review: new LocalStackContainer("0.11.3")

Code after addressing the review:
private static void setupLocalstack() {
now = Instant.ofEpochMilli(Long.divideUnsigned(now.getMillis(), 1000L));
System.setProperty(SDKGlobalConfiguration.DISABLE_CERT_CHECKING_SYSTEM_PROPERTY, "true");
System.setProperty(SDKGlobalConfiguration.AWS_CBOR_DISABLE_SYSTEM_PROPERTY, "true");
localstackContainer =
new LocalStackContainer(LOCALSTACK_VERSION)
.withServices(LocalStackContainer.Service.KINESIS)
.withEnv("USE_SSL", "true")
.withStartupAttempts(3);
localstackContainer.start();
options.setAwsServiceEndpoint(
localstackContainer
.getEndpointConfiguration(LocalStackContainer.Service.KINESIS)
.getServiceEndpoint()
.replace("http", "https"));
options.setAwsKinesisRegion(
localstackContainer
.getEndpointConfiguration(LocalStackContainer.Service.KINESIS)
.getSigningRegion());
options.setAwsAccessKey(
localstackContainer.getDefaultCredentialsProvider().getCredentials().getAWSAccessKeyId());
options.setAwsSecretKey(
localstackContainer.getDefaultCredentialsProvider().getCredentials().getAWSSecretKey());
options.setNumberOfRecords(1000);
options.setNumberOfShards(1);
options.setAwsKinesisStream("beam_kinesis_test");
options.setAwsVerifyCertificate(false);
}
Code review comment: we need to do infer predicate later to process `a join b on a.id = b.id join c on b.id = c.id` it could be transform to `a join c on a.id = c.id join b on b.id = c.id`

Code before review:
public boolean initJoinOnCondition() {
List<Expression> topJoinOnClauseConjuncts = ExpressionUtils.extractConjunction(topJoinOnClause);
for (Expression topJoinOnClauseConjunct : topJoinOnClauseConjuncts) {
if (ExpressionUtils.isIntersecting(
topJoinOnClauseConjunct.collect(SlotReference.class::isInstance), aOutputSlots)
&& ExpressionUtils.isIntersecting(
topJoinOnClauseConjunct.collect(SlotReference.class::isInstance), bOutputSlots)
&& ExpressionUtils.isIntersecting(
topJoinOnClauseConjunct.collect(SlotReference.class::isInstance), cOutputSlots)
) {
return false;
}
}
List<Expression> bottomJoinOnClauseConjuncts = ExpressionUtils.extractConjunction(
bottomJoinOnClause);
List<Expression> allOnCondition = Lists.newArrayList();
allOnCondition.addAll(topJoinOnClauseConjuncts);
allOnCondition.addAll(bottomJoinOnClauseConjuncts);
List<SlotReference> newBottomJoinSlots = Lists.newArrayList();
newBottomJoinSlots.addAll(aOutputSlots);
newBottomJoinSlots.addAll(cOutputSlots);
for (Expression onCondition : allOnCondition) {
List<SlotReference> slots = onCondition.collect(SlotReference.class::isInstance);
if (new HashSet<>(newBottomJoinSlots).containsAll(slots)) {
newBottomJoinOnCondition.add(onCondition);
} else {
newTopJoinOnCondition.add(onCondition);
}
}
if (newBottomJoinOnCondition.isEmpty() || newTopJoinOnCondition.isEmpty()) {
return false;
}
return true;
}

Line under review: if (newBottomJoinOnCondition.isEmpty() || newTopJoinOnCondition.isEmpty()) {

Code after addressing the review:
public boolean initJoinOnCondition() {
List<Expression> topJoinOnClauseConjuncts = ExpressionUtils.extractConjunction(topJoinOnClause);
for (Expression topJoinOnClauseConjunct : topJoinOnClauseConjuncts) {
List<SlotReference> topJoinUsedSlot = topJoinOnClauseConjunct.collect(SlotReference.class::isInstance);
if (ExpressionUtils.isIntersecting(topJoinUsedSlot, aOutputSlots)
&& ExpressionUtils.isIntersecting(topJoinUsedSlot, bOutputSlots)
&& ExpressionUtils.isIntersecting(topJoinUsedSlot, cOutputSlots)
) {
return false;
}
}
List<Expression> allOnCondition = Lists.newArrayList();
allOnCondition.addAll(topJoinOnClauseConjuncts);
allOnCondition.addAll(ExpressionUtils.extractConjunction(bottomJoinOnClause));
HashSet<SlotReference> newBottomJoinSlots = new HashSet<>(aOutputSlots);
newBottomJoinSlots.addAll(cOutputSlots);
for (Expression onCondition : allOnCondition) {
List<SlotReference> slots = onCondition.collect(SlotReference.class::isInstance);
if (newBottomJoinSlots.containsAll(slots)) {
newBottomJoinOnCondition.add(onCondition);
} else {
newTopJoinOnCondition.add(onCondition);
}
}
if (newBottomJoinOnCondition.isEmpty() || newTopJoinOnCondition.isEmpty()) {
return false;
}
return true;
}
Code review comment: Okay, thanks for the hint. Changed 

Code before review:
void assertFind() {
ShardingRuleConfiguration ruleConfig = new ShardingRuleConfiguration();
ShardingTableRuleConfiguration shardingTableRuleConfiguration = getShardingTableRuleConfiguration();
Map<String, AlgorithmConfiguration> allAlgorithms = getAlgorithms();
ruleConfig.getTables().add(shardingTableRuleConfiguration);
ruleConfig.getShardingAlgorithms().putAll(allAlgorithms);
ruleConfig.setDefaultDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("order_id", USED_DATABASE_SHARDING_DEFAULT_ALGORITHM));
ruleConfig.setDefaultTableShardingStrategy(new StandardShardingStrategyConfiguration("order_id", USED_TABLE_SHARDING_DEFAULT_ALGORITHM));
Collection<String> unusedAlgorithmsCollection = UnusedAlgorithmFinder.find(ruleConfig);
assertNotNull(unusedAlgorithmsCollection);
assertThat(unusedAlgorithmsCollection.size(), is(1));
assertTrue(unusedAlgorithmsCollection.contains(UNUSED_ALGORITHM));
}

Line under review: Map<String, AlgorithmConfiguration> allAlgorithms = getAlgorithms();

Code after addressing the review:
void assertFind() {
ShardingRuleConfiguration ruleConfig = new ShardingRuleConfiguration();
ShardingTableRuleConfiguration shardingTableRuleConfig = getShardingTableRuleConfiguration();
ruleConfig.getTables().add(shardingTableRuleConfig);
ruleConfig.getShardingAlgorithms().putAll(getAlgorithms());
ruleConfig.setDefaultDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("order_id", USED_DATABASE_SHARDING_DEFAULT_ALGORITHM));
ruleConfig.setDefaultTableShardingStrategy(new StandardShardingStrategyConfiguration("order_id", USED_TABLE_SHARDING_DEFAULT_ALGORITHM));
Collection<String> actual = UnusedAlgorithmFinder.find(ruleConfig);
assertNotNull(actual);
assertThat(actual.size(), is(1));
assertTrue(actual.contains(UNUSED_ALGORITHM));
}
Code review comment: Is this should be `StorageInfoV2`?

Code before review:
private void getNewImage(HostInfo helperNode) throws IOException {
long localImageVersion = 0;
Storage storage = new Storage(this.imageDir);
localImageVersion = storage.getLatestImageSeq();
try {
String hostPort = NetUtils.getHostPortInAccessibleFormat(helperNode.getHost(), Config.http_port);
String infoUrl = "http:
ResponseBody<StorageInfo> responseBody = MetaHelper
.doGet(infoUrl, HTTP_TIMEOUT_SECOND * 1000, StorageInfo.class);
if (responseBody.getCode() != RestApiStatusCode.OK.code) {
LOG.warn("get image failed,responseBody:{}", responseBody);
throw new IOException(responseBody.toString());
}
StorageInfo info = responseBody.getData();
long version = info.getImageSeq();
if (version > localImageVersion) {
String url = "http:
String filename = Storage.IMAGE + "." + version;
File dir = new File(this.imageDir);
MetaHelper.getRemoteFile(url, HTTP_TIMEOUT_SECOND * 1000, MetaHelper.getFile(filename, dir));
MetaHelper.complete(filename, dir);
} else {
LOG.warn("get an image with a lower version, localImageVersion: {}, got version: {}",
localImageVersion, version);
}
} catch (Exception e) {
throw new IOException(e);
}
}

Line under review: .doGet(infoUrl, HTTP_TIMEOUT_SECOND * 1000, StorageInfo.class);

Code after addressing the review:
private void getNewImage(HostInfo helperNode) throws IOException {
long localImageVersion = 0;
Storage storage = new Storage(this.imageDir);
localImageVersion = storage.getLatestImageSeq();
try {
String hostPort = NetUtils.getHostPortInAccessibleFormat(helperNode.getHost(), Config.http_port);
String infoUrl = "http:
ResponseBody<StorageInfo> responseBody = MetaHelper
.doGet(infoUrl, HTTP_TIMEOUT_SECOND * 1000, StorageInfo.class);
if (responseBody.getCode() != RestApiStatusCode.OK.code) {
LOG.warn("get image failed,responseBody:{}", responseBody);
throw new IOException(responseBody.toString());
}
StorageInfo info = responseBody.getData();
long version = info.getImageSeq();
if (version > localImageVersion) {
String url = "http:
String filename = Storage.IMAGE + "." + version;
File dir = new File(this.imageDir);
MetaHelper.getRemoteFile(url, HTTP_TIMEOUT_SECOND * 1000, MetaHelper.getFile(filename, dir));
MetaHelper.complete(filename, dir);
} else {
LOG.warn("get an image with a lower version, localImageVersion: {}, got version: {}",
localImageVersion, version);
}
} catch (Exception e) {
throw new IOException(e);
}
}
Code review comment: the issue was preexisting but let's fix the typo: s/is does/is done/

Code before review:
public void createRegistries(BeanContainer container) {
log.info("Creating registries");
MetricRegistries.get(MetricRegistry.Type.APPLICATION);
MetricRegistries.get(MetricRegistry.Type.BASE);
MetricRegistries.get(MetricRegistry.Type.VENDOR);
container.instance(MetricRegistries.class).getApplicationRegistry();
}


Code after addressing the review:
public void createRegistries(BeanContainer container) {
MetricRegistries.get(MetricRegistry.Type.APPLICATION);
MetricRegistries.get(MetricRegistry.Type.BASE);
MetricRegistries.get(MetricRegistry.Type.VENDOR);
container.instance(MetricRegistries.class).getApplicationRegistry();
}
Code review comment: This is a known issue tracked via https://github.com/AzureAD/azure-activedirectory-library-for-java/blob/dev/src/main/java/com/microsoft/aad/adal4j/AuthenticationContext.java.

Code before review:
protected RestClient buildRestClient(AzureTokenCredentials credentials, AzureEnvironment.Endpoint endpoint) {
RestClient client =  restClientBuilder
.withBaseUrl(credentials.environment(), endpoint)
.withCredentials(credentials)
.withInterceptor(new ProviderRegistrationInterceptor(credentials))
.build();
if (client.httpClient().proxy() != null) {
credentials.withProxy(client.httpClient().proxy());
}
return client;
}

Line under review: credentials.withProxy(client.httpClient().proxy());

Code after addressing the review:
protected RestClient buildRestClient(AzureTokenCredentials credentials, AzureEnvironment.Endpoint endpoint) {
RestClient client =  restClientBuilder
.withBaseUrl(credentials.environment(), endpoint)
.withCredentials(credentials)
.withInterceptor(new ProviderRegistrationInterceptor(credentials))
.build();
if (client.httpClient().proxy() != null) {
credentials.withProxy(client.httpClient().proxy());
}
return client;
}
Code review comment: Besides, can you add unit test for this logic?

Code before review:
public static Optional<SqlNode> convert(final LiteralExpressionSegment segment) {
if (null == segment.getLiterals()) {
return Optional.of(SqlLiteral.createNull(SqlParserPos.ZERO));
}
String literalValue = String.valueOf(segment.getLiterals());
if (TRIM_FUNCTION_FLAGS.contains(literalValue)) {
return Optional.of(SqlLiteral.createSymbol(Flag.valueOf(literalValue), SqlParserPos.ZERO));
}
if (TIME_UNIT_NAMES.contains(literalValue)) {
return Optional.of(new SqlIntervalQualifier(TimeUnit.valueOf(literalValue), null, SqlParserPos.ZERO));
}
if (segment.getLiterals() instanceof Integer || segment.getLiterals() instanceof BigDecimal || segment.getLiterals() instanceof Long) {
return Optional.of(SqlLiteral.createExactNumeric(literalValue, SqlParserPos.ZERO));
}
if (segment.getLiterals() instanceof String) {
return Optional.of(SqlLiteral.createCharString(literalValue, SqlParserPos.ZERO));
}
return Optional.empty();
}

Line under review: if (segment.getLiterals() instanceof Integer || segment.getLiterals() instanceof BigDecimal || segment.getLiterals() instanceof Long) {

Code after addressing the review:
public static Optional<SqlNode> convert(final LiteralExpressionSegment segment) {
if (null == segment.getLiterals()) {
return Optional.of(SqlLiteral.createNull(SqlParserPos.ZERO));
}
String literalValue = String.valueOf(segment.getLiterals());
if (TRIM_FUNCTION_FLAGS.contains(literalValue)) {
return Optional.of(SqlLiteral.createSymbol(Flag.valueOf(literalValue), SqlParserPos.ZERO));
}
if (TIME_UNIT_NAMES.contains(literalValue)) {
return Optional.of(new SqlIntervalQualifier(TimeUnit.valueOf(literalValue), null, SqlParserPos.ZERO));
}
if (segment.getLiterals() instanceof Integer || segment.getLiterals() instanceof BigDecimal || segment.getLiterals() instanceof Number) {
return Optional.of(SqlLiteral.createExactNumeric(literalValue, SqlParserPos.ZERO));
}
if (segment.getLiterals() instanceof String) {
return Optional.of(SqlLiteral.createCharString(literalValue, SqlParserPos.ZERO));
}
return Optional.empty();
}
Code review comment: It seems that only boolean vector dose not need dictionary. byte vector need dictionary for storage, dictionaryIds use runLengthCoding, it will be very small. In reading, we need decode it.

Code before review:
public byte getByte(int i) {
if (dictionary == null) {
return vector[i];
} else {
return (byte) dictionary.decodeToInt(dictionaryIds.vector[i]);
}
}

Line under review: return (byte) dictionary.decodeToInt(dictionaryIds.vector[i]);

Code after addressing the review:
public byte getByte(int i) {
if (dictionary == null) {
return vector[i];
} else {
return (byte) dictionary.decodeToInt(dictionaryIds.vector[i]);
}
}
Code review comment: Ah. So we probably end up with custom parser code for this anyway, so we don't need those. See following PR. 

Code before review:
static String toEndpointsConfig(TestConfig config) throws IOException {
Cursor root = new Slime().setObject();
Cursor endpointsArray = root.setArray("endpoints");
config.deployments().get(config.zone()).forEach((cluster, url) -> {
Cursor endpointObject = endpointsArray.addObject();
endpointObject.setString("cluster", cluster);
endpointObject.setString("url", url.toString());
});
return new String(SlimeUtils.toJsonBytes(root), UTF_8);
}

Line under review: config.deployments().get(config.zone()).forEach((cluster, url) -> {

Code after addressing the review:
static String toEndpointsConfig(TestConfig config) throws IOException {
Cursor root = new Slime().setObject();
Cursor endpointsArray = root.setArray("endpoints");
config.deployments().get(config.zone()).forEach((cluster, url) -> {
Cursor endpointObject = endpointsArray.addObject();
endpointObject.setString("cluster", cluster);
endpointObject.setString("url", url.toString());
});
return new String(SlimeUtils.toJsonBytes(root), UTF_8);
}
Code review comment: consider checking if the validity of the nixes are the same (we should also update this in C++)

Code before review:
public boolean equalTo(Inspector that) {
boolean equal = type() == that.type();
if (equal) {
switch (type()) {
case NIX:
break;
case BOOL:
equal = asBool() == that.asBool();
break;
case LONG:
equal = asLong() == that.asLong();
break;
case DOUBLE:
equal = Double.compare(asDouble(), that.asDouble()) == 0;
break;
case STRING:
equal = asString().equals(that.asString());
break;
case DATA:
equal = Arrays.equals(asData(), that.asData());
break;
case ARRAY:
{
var traverser = new EqualArray(that);
traverse(traverser);
equal = traverser.isEqual() && (entries() == that.entries());
}
break;
case OBJECT:
{
var traverser = new EqualObject(that);
traverse(traverser);
equal = traverser.isEqual() && (fields() == that.fields());
}
break;
default:
assert(false);
break;
}
}
return equal;
}

Line under review: break;

Code after addressing the review:
public boolean equalTo(Inspector that) {
boolean equal = type() == that.type();
if (equal) {
switch (type()) {
case NIX:
equal = valid() == that.valid();
break;
case BOOL:
equal = asBool() == that.asBool();
break;
case LONG:
equal = asLong() == that.asLong();
break;
case DOUBLE:
equal = Double.compare(asDouble(), that.asDouble()) == 0;
break;
case STRING:
equal = asString().equals(that.asString());
break;
case DATA:
equal = Arrays.equals(asData(), that.asData());
break;
case ARRAY:
{
var traverser = new EqualArray(that);
traverse(traverser);
equal = traverser.isEqual() && (entries() == that.entries());
}
break;
case OBJECT:
{
var traverser = new EqualObject(that);
traverse(traverser);
equal = traverser.isEqual() && (fields() == that.fields());
}
break;
default:
assert(false);
break;
}
}
return equal;
}
Code review comment: It looks like it would be OK to create a similar failed graph deconstruction task, providing the current graph as both current and failed graph arguments?

Code before review:
public ComponentGraphResult waitForNextGraphGeneration(ComponentGraph oldGraph, Injector fallbackInjector, boolean isInitializing) {
try {
ComponentGraph newGraph;
Collection<Bundle> obsoleteBundles = new HashSet<>();
try {
newGraph = waitForNewConfigGenAndCreateGraph(oldGraph, fallbackInjector, isInitializing, obsoleteBundles);
newGraph.reuseNodes(oldGraph);
} catch (Throwable t) {
log.warning("Failed to set up component graph - uninstalling latest bundles. Bootstrap generation: " + getBootstrapGeneration());
osgi.completeBundleGeneration(Osgi.GenerationStatus.FAILURE);
throw t;
}
try {
constructComponents(newGraph);
} catch (Throwable e) {
log.warning("Failed to construct components for generation '" + newGraph.generation() + "' - scheduling partial graph for deconstruction");
Collection<Bundle> newBundlesFromFailedGen = osgi.completeBundleGeneration(Osgi.GenerationStatus.FAILURE);
deconstructFailedGraph(oldGraph, newGraph, newBundlesFromFailedGen);
throw e;
}
osgi.completeBundleGeneration(Osgi.GenerationStatus.SUCCESS);
Runnable cleanupTask = createPreviousGraphDeconstructionTask(oldGraph, newGraph, obsoleteBundles);
return new ComponentGraphResult(newGraph, cleanupTask);
} catch (Throwable t) {
invalidateGeneration(oldGraph.generation(), t);
throw t;
}
}

Line under review: }

Code after addressing the review:
public ComponentGraphResult waitForNextGraphGeneration(ComponentGraph oldGraph, Injector fallbackInjector, boolean isInitializing) {
try {
ComponentGraph newGraph;
Collection<Bundle> obsoleteBundles = new HashSet<>();
try {
newGraph = waitForNewConfigGenAndCreateGraph(oldGraph, fallbackInjector, isInitializing, obsoleteBundles);
newGraph.reuseNodes(oldGraph);
} catch (Throwable t) {
log.warning("Failed to set up component graph - uninstalling latest bundles. Bootstrap generation: " + getBootstrapGeneration());
Collection<Bundle> newBundlesFromFailedGen = osgi.completeBundleGeneration(Osgi.GenerationStatus.FAILURE);
deconstructComponentsAndBundles(getBootstrapGeneration(), newBundlesFromFailedGen, List.of());
throw t;
}
try {
constructComponents(newGraph);
} catch (Throwable e) {
log.warning("Failed to construct components for generation '" + newGraph.generation() + "' - scheduling partial graph for deconstruction");
Collection<Bundle> newBundlesFromFailedGen = osgi.completeBundleGeneration(Osgi.GenerationStatus.FAILURE);
deconstructFailedGraph(oldGraph, newGraph, newBundlesFromFailedGen);
throw e;
}
osgi.completeBundleGeneration(Osgi.GenerationStatus.SUCCESS);
Runnable cleanupTask = createPreviousGraphDeconstructionTask(oldGraph, newGraph, obsoleteBundles);
return new ComponentGraphResult(newGraph, cleanupTask);
} catch (Throwable t) {
invalidateGeneration(oldGraph.generation(), t);
throw t;
}
}