This is an automated email from the ASF dual-hosted git repository.
errose28 pushed a commit to branch HDDS-14496-zdu
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-14496-zdu by this push:
new 353b7cc67cd HDDS-15488. Recon upgrade actions should be idempotent
(#10442)
353b7cc67cd is described below
commit 353b7cc67cdbb8de63f778f9ee48adbf92a6fe54
Author: Ethan Rose <[email protected]>
AuthorDate: Tue Jun 16 14:52:50 2026 -0400
HDDS-15488. Recon upgrade actions should be idempotent (#10442)
---
.../org/apache/ozone/recon/schema/SqlDbUtils.java | 98 ++++++++++++++++
.../upgrade/InitialConstraintUpgradeAction.java | 59 +---------
.../upgrade/NSSummaryAggregatedTotalsUpgrade.java | 22 +---
.../upgrade/ReconTaskStatusTableUpgradeAction.java | 57 ++++-----
.../ozone/recon/upgrade/ReconUpgradeAction.java | 86 ++++++++++++++
.../ReplicatedSizeOfFilesUpgradeAction.java | 26 +----
.../UnhealthyContainerReplicaMismatchAction.java | 53 +--------
...ntainersStateContainerIdIndexUpgradeAction.java | 20 +---
.../TestInitialConstraintUpgradeAction.java | 17 ++-
.../TestNSSummaryAggregatedTotalsUpgrade.java | 24 ++++
.../TestReconTaskStatusTableUpgradeAction.java | 127 +++++++++++++++++++++
.../TestReplicatedSizeOfFilesUpgradeAction.java | 36 ++++--
...stUnhealthyContainerReplicaMismatchAction.java} | 55 +++------
...ntainersStateContainerIdIndexUpgradeAction.java | 25 ++--
14 files changed, 432 insertions(+), 273 deletions(-)
diff --git
a/hadoop-ozone/recon-codegen/src/main/java/org/apache/ozone/recon/schema/SqlDbUtils.java
b/hadoop-ozone/recon-codegen/src/main/java/org/apache/ozone/recon/schema/SqlDbUtils.java
index 22c00cb9685..5e75bbe9413 100644
---
a/hadoop-ozone/recon-codegen/src/main/java/org/apache/ozone/recon/schema/SqlDbUtils.java
+++
b/hadoop-ozone/recon-codegen/src/main/java/org/apache/ozone/recon/schema/SqlDbUtils.java
@@ -22,6 +22,7 @@
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Connection;
+import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -115,4 +116,101 @@ public static List<String> listAllTables(Connection
connection) throws SQLExcept
LOG.debug("Found {} user-defined tables in the database: {}",
tableNames.size(), tableNames);
return tableNames;
}
+
+ /**
+ * Checks whether a column exists in a Derby table via {@code
SYS.SYSCOLUMNS}.
+ *
+ * @param conn the database connection
+ * @param tableName the table name (case-insensitive)
+ * @param columnName the column name (case-insensitive)
+ * @return true if the column exists
+ */
+ public static boolean columnExists(Connection conn, String tableName, String
columnName)
+ throws SQLException {
+ DatabaseMetaData metaData = conn.getMetaData();
+ try (ResultSet rs = metaData.getColumns(null, null, tableName,
columnName)) {
+ if (rs.next()) {
+ return true;
+ }
+ }
+ try (ResultSet rs = metaData.getColumns(null, null,
tableName.toUpperCase(), columnName.toUpperCase())) {
+ return rs.next();
+ }
+ }
+
+ /**
+ * Checks whether a Derby column allows NULL values.
+ *
+ * @param conn the database connection
+ * @param tableName the table name (case-insensitive)
+ * @param columnName the column name (case-insensitive)
+ * @return true if the column is nullable, false if NOT NULL or column does
not exist
+ */
+ public static boolean isColumnNullable(Connection conn, String tableName,
String columnName)
+ throws SQLException {
+ DatabaseMetaData metaData = conn.getMetaData();
+ try (ResultSet rs = metaData.getColumns(null, null, tableName,
columnName)) {
+ if (rs.next()) {
+ return rs.getInt("NULLABLE") != DatabaseMetaData.columnNoNulls;
+ }
+ }
+ try (ResultSet rs = metaData.getColumns(null, null,
tableName.toUpperCase(), columnName.toUpperCase())) {
+ if (rs.next()) {
+ return rs.getInt("NULLABLE") != DatabaseMetaData.columnNoNulls;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether a named constraint exists on a Derby table.
+ *
+ * @param conn the database connection
+ * @param tableName the table name (case-insensitive)
+ * @param constraintName the constraint name (case-insensitive)
+ * @return true if the constraint exists on the table
+ */
+ public static boolean constraintExists(Connection conn, String tableName,
String constraintName)
+ throws SQLException {
+ String sql = "SELECT 1 FROM SYS.SYSCONSTRAINTS c "
+ + "INNER JOIN SYS.SYSTABLES t ON c.TABLEID = t.TABLEID "
+ + "WHERE t.TABLENAME = ? AND c.CONSTRAINTNAME = ?";
+ try (java.sql.PreparedStatement ps = conn.prepareStatement(sql)) {
+ ps.setString(1, tableName.toUpperCase());
+ ps.setString(2, constraintName);
+ try (ResultSet rs = ps.executeQuery()) {
+ if (rs.next()) {
+ return true;
+ }
+ }
+ }
+ try (java.sql.PreparedStatement ps = conn.prepareStatement(sql)) {
+ ps.setString(1, tableName.toUpperCase());
+ ps.setString(2, constraintName.toUpperCase());
+ try (ResultSet rs = ps.executeQuery()) {
+ return rs.next();
+ }
+ }
+ }
+
+ /**
+ * Checks whether a named index exists on a table.
+ *
+ * @param conn the database connection
+ * @param tableName the table name
+ * @param indexName the index name (case-insensitive)
+ * @return true if the index exists
+ */
+ public static boolean indexExists(Connection conn, String tableName, String
indexName) throws SQLException {
+ DatabaseMetaData metaData = conn.getMetaData();
+ try (ResultSet rs = metaData.getIndexInfo(null, null, tableName, false,
false)) {
+ while (rs.next()) {
+ String existing = rs.getString("INDEX_NAME");
+ if (existing != null && existing.equalsIgnoreCase(indexName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/InitialConstraintUpgradeAction.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/InitialConstraintUpgradeAction.java
index 6f632de180b..3adadafe222 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/InitialConstraintUpgradeAction.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/InitialConstraintUpgradeAction.java
@@ -18,18 +18,9 @@
package org.apache.hadoop.ozone.recon.upgrade;
import static
org.apache.hadoop.ozone.recon.upgrade.ReconVersion.INITIAL_VERSION;
-import static
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
-import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
-import static org.jooq.impl.DSL.field;
-import com.google.common.annotations.VisibleForTesting;
-import java.sql.Connection;
import java.sql.SQLException;
-import java.util.Arrays;
import javax.sql.DataSource;
-import org.apache.ozone.recon.schema.ContainerSchemaDefinition;
-import org.jooq.DSLContext;
-import org.jooq.impl.DSL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,58 +30,10 @@
*/
@UpgradeActionRecon(feature = INITIAL_VERSION)
public class InitialConstraintUpgradeAction implements ReconUpgradeAction {
-
private static final Logger LOG =
LoggerFactory.getLogger(InitialConstraintUpgradeAction.class);
- private DSLContext dslContext;
@Override
public void execute(DataSource source) throws SQLException {
- try (Connection conn = source.getConnection()) {
- if (!TABLE_EXISTS_CHECK.test(conn, UNHEALTHY_CONTAINERS_TABLE_NAME)) {
- return;
- }
- dslContext = DSL.using(conn);
- // Drop the existing constraint
- dropConstraint();
- // Add the updated constraint with all enum states
- addUpdatedConstraint();
- } catch (SQLException e) {
- throw new SQLException("Failed to execute
InitialConstraintUpgradeAction", e);
- }
- }
-
- /**
- * Drops the existing constraint from the UNHEALTHY_CONTAINERS table.
- */
- private void dropConstraint() {
- String constraintName = UNHEALTHY_CONTAINERS_TABLE_NAME + "ck1";
- dslContext.alterTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
- .dropConstraint(constraintName)
- .execute();
- LOG.debug("Dropped the existing constraint: {}", constraintName);
- }
-
- /**
- * Adds the updated constraint directly within this class.
- */
- private void addUpdatedConstraint() {
- String[] enumStates = Arrays
- .stream(ContainerSchemaDefinition.UnHealthyContainerStates.values())
- .map(Enum::name)
- .toArray(String[]::new);
-
-
dslContext.alterTable(ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME)
-
.add(DSL.constraint(ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME +
"ck1")
- .check(field(DSL.name("container_state"))
- .in(enumStates)))
- .execute();
-
- LOG.info("Added the updated constraint to the UNHEALTHY_CONTAINERS table
for enum state values: {}",
- Arrays.toString(enumStates));
- }
-
- @VisibleForTesting
- public void setDslContext(DSLContext dslContext) {
- this.dslContext = dslContext;
+ ReconUpgradeAction.updateUnhealthyContainerStatesConstraint(source, LOG);
}
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/NSSummaryAggregatedTotalsUpgrade.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/NSSummaryAggregatedTotalsUpgrade.java
index f153c4a35ac..b806e29fd61 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/NSSummaryAggregatedTotalsUpgrade.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/NSSummaryAggregatedTotalsUpgrade.java
@@ -17,11 +17,7 @@
package org.apache.hadoop.ozone.recon.upgrade;
-import com.google.inject.Injector;
import javax.sql.DataSource;
-import org.apache.hadoop.ozone.recon.ReconGuiceServletContextListener;
-import org.apache.hadoop.ozone.recon.tasks.ReconTaskController;
-import org.apache.hadoop.ozone.recon.tasks.ReconTaskReInitializationEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,22 +36,6 @@ public class NSSummaryAggregatedTotalsUpgrade implements
ReconUpgradeAction {
@Override
public void execute(DataSource source) throws Exception {
- // Resolve required services from Guice
- Injector injector = ReconGuiceServletContextListener.getGlobalInjector();
- if (injector == null) {
- throw new IllegalStateException(
- "Guice injector not initialized. NSSummary rebuild cannot proceed
during upgrade.");
- }
-
- ReconTaskController reconTaskController =
injector.getInstance(ReconTaskController.class);
- LOG.info("Triggering asynchronous NSSummary tree rebuild for materialized
totals (upgrade action).");
- ReconTaskController.ReInitializationResult result =
reconTaskController.queueReInitializationEvent(
- ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER);
- if (result != ReconTaskController.ReInitializationResult.SUCCESS) {
- LOG.error(
- "Failed to queue reinitialization event for manual trigger (result:
{}), failing the reinitialization " +
- "during NSSummaryAggregatedTotalsUpgrade action, will be retried
as part of syncDataFromOM " +
- "scheduler task.", result);
- }
+ ReconUpgradeAction.queueNSSummaryRebuildIfNeeded(LOG);
}
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconTaskStatusTableUpgradeAction.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconTaskStatusTableUpgradeAction.java
index 49e86b0d55e..91509598c4f 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconTaskStatusTableUpgradeAction.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconTaskStatusTableUpgradeAction.java
@@ -19,6 +19,8 @@
import static
org.apache.ozone.recon.schema.ReconTaskSchemaDefinition.RECON_TASK_STATUS_TABLE_NAME;
import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
+import static org.apache.ozone.recon.schema.SqlDbUtils.columnExists;
+import static org.apache.ozone.recon.schema.SqlDbUtils.isColumnNullable;
import java.sql.Connection;
import java.sql.SQLException;
@@ -40,31 +42,37 @@
public class ReconTaskStatusTableUpgradeAction implements ReconUpgradeAction {
private static final Logger LOG =
LoggerFactory.getLogger(ReconTaskStatusTableUpgradeAction.class);
+ private static final String LAST_TASK_RUN_STATUS = "last_task_run_status";
+ private static final String IS_CURRENT_TASK_RUNNING =
"is_current_task_running";
- /**
- * Utility function to add provided column to RECON_TASK_STATUS table as
INTEGER type.
- * @param dslContext Stores {@link DSLContext} to perform alter operations
- * @param columnName Name of the column to be inserted to the table
- */
- private void addColumnToTable(DSLContext dslContext, String columnName) {
- //Column is set as nullable to avoid any errors.
+ private void addColumnIfMissing(Connection conn, DSLContext dslContext,
String columnName)
+ throws SQLException {
+ if (columnExists(conn, RECON_TASK_STATUS_TABLE_NAME, columnName)) {
+ LOG.info("Column '{}' already exists on {}, skipping add.", columnName,
RECON_TASK_STATUS_TABLE_NAME);
+ return;
+ }
+ LOG.info("Adding '{}' column to task status table", columnName);
dslContext.alterTable(RECON_TASK_STATUS_TABLE_NAME)
- .addColumn(columnName, SQLDataType.INTEGER.nullable(true)).execute();
+ .addColumn(columnName, SQLDataType.INTEGER.nullable(true))
+ .execute();
}
- /**
- * Utility function to set the provided column as Non-Null to enforce
constraints in RECON_TASK_STATUS table.
- * @param dslContext Stores {@link DSLContext} to perform alter operations
- * @param columnName Name of the column to set as non-null
- */
- private void setColumnAsNonNullable(DSLContext dslContext, String
columnName) {
+ private void setColumnAsNonNullableIfNeeded(Connection conn, DSLContext
dslContext, String columnName)
+ throws SQLException {
+ if (!columnExists(conn, RECON_TASK_STATUS_TABLE_NAME, columnName)) {
+ return;
+ }
+ if (!isColumnNullable(conn, RECON_TASK_STATUS_TABLE_NAME, columnName)) {
+ LOG.info("Column '{}' is already NOT NULL on {}, skipping.", columnName,
RECON_TASK_STATUS_TABLE_NAME);
+ return;
+ }
dslContext.alterTable(RECON_TASK_STATUS_TABLE_NAME)
.alterColumn(DSL.name(columnName)).setNotNull()
.execute();
}
@Override
- public void execute(DataSource dataSource) throws DataAccessException {
+ public void execute(DataSource dataSource) throws DataAccessException,
SQLException {
try (Connection conn = dataSource.getConnection()) {
if (!TABLE_EXISTS_CHECK.test(conn, RECON_TASK_STATUS_TABLE_NAME)) {
return;
@@ -73,23 +81,18 @@ public void execute(DataSource dataSource) throws
DataAccessException {
DSLContext dslContext = DSL.using(conn);
// JOOQ doesn't support Derby DB officially, there is no way to run 'ADD
COLUMN' command in single call
// for multiple columns. Hence, we run it as two separate steps.
- LOG.info("Adding 'last_task_run_status' column to task status table");
- addColumnToTable(dslContext, "last_task_run_status");
- LOG.info("Adding 'is_current_task_running' column to task status table");
- addColumnToTable(dslContext, "is_current_task_running");
+ addColumnIfMissing(conn, dslContext, LAST_TASK_RUN_STATUS);
+ addColumnIfMissing(conn, dslContext, IS_CURRENT_TASK_RUNNING);
- //Handle previous table values with new columns default values
+ // Handle previous table values with new columns default values
int updatedRowCount =
dslContext.update(DSL.table(RECON_TASK_STATUS_TABLE_NAME))
- .set(DSL.field(DSL.name("last_task_run_status"),
SQLDataType.INTEGER), 0)
- .set(DSL.field(DSL.name("is_current_task_running"),
SQLDataType.INTEGER), 0)
+ .set(DSL.field(DSL.name(LAST_TASK_RUN_STATUS), SQLDataType.INTEGER),
0)
+ .set(DSL.field(DSL.name(IS_CURRENT_TASK_RUNNING),
SQLDataType.INTEGER), 0)
.execute();
LOG.info("Updated {} rows with default value for new columns",
updatedRowCount);
- // Now we will set the column as not-null to enforce constraints
- setColumnAsNonNullable(dslContext, "last_task_run_status");
- setColumnAsNonNullable(dslContext, "is_current_task_running");
- } catch (SQLException | DataAccessException ex) {
- LOG.error("Error while upgrading RECON_TASK_STATUS table.", ex);
+ setColumnAsNonNullableIfNeeded(conn, dslContext, LAST_TASK_RUN_STATUS);
+ setColumnAsNonNullableIfNeeded(conn, dslContext,
IS_CURRENT_TASK_RUNNING);
}
}
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconUpgradeAction.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconUpgradeAction.java
index 3994223447f..e0336664b52 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconUpgradeAction.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconUpgradeAction.java
@@ -17,11 +17,97 @@
package org.apache.hadoop.ozone.recon.upgrade;
+import static
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
+import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
+import static org.jooq.impl.DSL.field;
+
+import com.google.inject.Injector;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Arrays;
import javax.sql.DataSource;
+import org.apache.hadoop.ozone.recon.ReconGuiceServletContextListener;
+import org.apache.hadoop.ozone.recon.tasks.NSSummaryTask;
+import org.apache.hadoop.ozone.recon.tasks.ReconTaskController;
+import org.apache.hadoop.ozone.recon.tasks.ReconTaskReInitializationEvent;
import org.apache.hadoop.ozone.upgrade.UpgradeAction;
+import org.apache.ozone.recon.schema.ContainerSchemaDefinition;
+import org.jooq.DSLContext;
+import org.jooq.exception.DataAccessException;
+import org.jooq.impl.DSL;
+import org.slf4j.Logger;
/**
* Recon upgrade action executed during finalization of a {@link ReconVersion}.
*/
public interface ReconUpgradeAction extends UpgradeAction<DataSource> {
+ /**
+ * Execute the upgrade action during finalization.
+ */
+ @Override
+ void execute(DataSource source) throws Exception;
+
+ /**
+ * Helper method used by upgrade actions that need to add new unhealthy
container states to the unhealthy containers
+ * table.
+ */
+ static void updateUnhealthyContainerStatesConstraint(DataSource dataSource,
Logger log) throws SQLException {
+ try (Connection conn = dataSource.getConnection()) {
+ if (!TABLE_EXISTS_CHECK.test(conn, UNHEALTHY_CONTAINERS_TABLE_NAME)) {
+ return;
+ }
+ DSLContext dslContext = DSL.using(conn);
+ final String constraintName = UNHEALTHY_CONTAINERS_TABLE_NAME + "ck1";
+
+ try {
+ dslContext.alterTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
+ .dropConstraint(constraintName)
+ .execute();
+ log.debug("Dropped the existing constraint: {}", constraintName);
+ } catch (DataAccessException e) {
+ log.debug("Constraint {} was not present: {}", constraintName,
e.getMessage());
+ }
+
+ String[] enumStates = Arrays
+ .stream(ContainerSchemaDefinition.UnHealthyContainerStates.values())
+ .map(Enum::name)
+ .toArray(String[]::new);
+
+ dslContext.alterTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
+ .add(DSL.constraint(constraintName)
+ .check(field(DSL.name("container_state")).in(enumStates)))
+ .execute();
+
+ log.info("Added the updated constraint to the UNHEALTHY_CONTAINERS table
for enum state values: {}",
+ Arrays.toString(enumStates));
+ }
+ }
+
+ /**
+ * Idempotently queues an NSSummary rebuild, skipping if a rebuild is
already in progress.
+ * Logs and returns without throwing if the queue attempt does not succeed.
+ */
+ static void queueNSSummaryRebuildIfNeeded(Logger log) {
+ Injector injector = ReconGuiceServletContextListener.getGlobalInjector();
+ if (injector == null) {
+ throw new IllegalStateException(
+ "Guice injector not initialized. NSSummary rebuild cannot proceed
during upgrade.");
+ }
+
+ ReconTaskController reconTaskController =
injector.getInstance(ReconTaskController.class);
+
+
+ log.info("Triggering asynchronous NSSummary tree rebuild.");
+ if (NSSummaryTask.getRebuildState() == NSSummaryTask.RebuildState.RUNNING)
{
+ log.info("NSSummary rebuild already in progress, skipping duplicate
upgrade queue.");
+ return;
+ }
+ ReconTaskController.ReInitializationResult result =
reconTaskController.queueReInitializationEvent(
+ ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER);
+ if (result != ReconTaskController.ReInitializationResult.SUCCESS) {
+ log.error(
+ "Failed to queue reinitialization event for NSSummary rebuild
(result: {}). "
+ + "Will be retried as part of syncDataFromOM scheduler task.",
result);
+ }
+ }
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReplicatedSizeOfFilesUpgradeAction.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReplicatedSizeOfFilesUpgradeAction.java
index b12e2e93eea..d1e5889d599 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReplicatedSizeOfFilesUpgradeAction.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReplicatedSizeOfFilesUpgradeAction.java
@@ -17,11 +17,7 @@
package org.apache.hadoop.ozone.recon.upgrade;
-import com.google.inject.Injector;
import javax.sql.DataSource;
-import org.apache.hadoop.ozone.recon.ReconGuiceServletContextListener;
-import org.apache.hadoop.ozone.recon.tasks.ReconTaskController;
-import org.apache.hadoop.ozone.recon.tasks.ReconTaskReInitializationEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,25 +32,7 @@ public class ReplicatedSizeOfFilesUpgradeAction implements
ReconUpgradeAction {
private static final Logger LOG =
LoggerFactory.getLogger(ReplicatedSizeOfFilesUpgradeAction.class);
@Override
- public void execute(DataSource dataSource) {
- try {
- Injector injector = ReconGuiceServletContextListener.getGlobalInjector();
- if (injector == null) {
- throw new IllegalStateException("Guice injector is not initialized.
Cannot perform NSSummary rebuild.");
- }
- ReconTaskController reconTaskController =
injector.getInstance(ReconTaskController.class);
- LOG.info("Starting full rebuild of NSSummary for
REPLICATED_SIZE_OF_FILES upgrade...");
- ReconTaskController.ReInitializationResult result =
reconTaskController.queueReInitializationEvent(
-
ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER);
- if (result != ReconTaskController.ReInitializationResult.SUCCESS) {
- throw new RuntimeException(
- "Failed to queue reinitialization event (result: " + result + ").
" +
- "NSSummary rebuild required for REPLICATED_SIZE_OF_FILES
upgrade.");
- }
- } catch (Exception e) {
- LOG.error("Error during NSSummary rebuild for REPLICATED_SIZE_OF_FILES
upgrade.", e);
- throw new RuntimeException("Failed to rebuild NSSummary during upgrade",
e);
- }
- LOG.info("Completed full rebuild of NSSummary for REPLICATED_SIZE_OF_FILES
upgrade.");
+ public void execute(DataSource dataSource) throws Exception {
+ ReconUpgradeAction.queueNSSummaryRebuildIfNeeded(LOG);
}
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/UnhealthyContainerReplicaMismatchAction.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/UnhealthyContainerReplicaMismatchAction.java
index a5b313192cc..3753ad244ab 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/UnhealthyContainerReplicaMismatchAction.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/UnhealthyContainerReplicaMismatchAction.java
@@ -18,17 +18,8 @@
package org.apache.hadoop.ozone.recon.upgrade;
import static
org.apache.hadoop.ozone.recon.upgrade.ReconVersion.UNHEALTHY_CONTAINER_REPLICA_MISMATCH;
-import static
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
-import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
-import static org.jooq.impl.DSL.field;
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Arrays;
import javax.sql.DataSource;
-import org.apache.ozone.recon.schema.ContainerSchemaDefinition;
-import org.jooq.DSLContext;
-import org.jooq.impl.DSL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,51 +30,9 @@
@UpgradeActionRecon(feature = UNHEALTHY_CONTAINER_REPLICA_MISMATCH)
public class UnhealthyContainerReplicaMismatchAction implements
ReconUpgradeAction {
private static final Logger LOG =
LoggerFactory.getLogger(UnhealthyContainerReplicaMismatchAction.class);
- private DSLContext dslContext;
@Override
public void execute(DataSource source) throws Exception {
- try (Connection conn = source.getConnection()) {
- if (!TABLE_EXISTS_CHECK.test(conn, UNHEALTHY_CONTAINERS_TABLE_NAME)) {
- return;
- }
- dslContext = DSL.using(conn);
- // Drop the existing constraint
- dropConstraint();
- // Add the updated constraint with all enum states
- addUpdatedConstraint();
- } catch (SQLException e) {
- throw new SQLException("Failed to execute
UnhealthyContainerReplicaMismatchAction", e);
- }
- }
-
- /**
- * Drops the existing constraint from the UNHEALTHY_CONTAINERS table.
- */
- private void dropConstraint() {
- String constraintName = UNHEALTHY_CONTAINERS_TABLE_NAME + "ck1";
- dslContext.alterTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
- .dropConstraint(constraintName)
- .execute();
- LOG.debug("Dropped the existing constraint: {}", constraintName);
- }
-
- /**
- * Adds the updated constraint directly within this class.
- */
- private void addUpdatedConstraint() {
- String[] enumStates = Arrays
- .stream(ContainerSchemaDefinition.UnHealthyContainerStates.values())
- .map(Enum::name)
- .toArray(String[]::new);
-
-
dslContext.alterTable(ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME)
-
.add(DSL.constraint(ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME +
"ck1")
- .check(field(DSL.name("container_state"))
- .in(enumStates)))
- .execute();
-
- LOG.info("Added the updated constraint to the UNHEALTHY_CONTAINERS table
for enum state values: {}",
- Arrays.toString(enumStates));
+ ReconUpgradeAction.updateUnhealthyContainerStatesConstraint(source, LOG);
}
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/UnhealthyContainersStateContainerIdIndexUpgradeAction.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/UnhealthyContainersStateContainerIdIndexUpgradeAction.java
index ebfe459a6fc..c64a6e33ca1 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/UnhealthyContainersStateContainerIdIndexUpgradeAction.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/UnhealthyContainersStateContainerIdIndexUpgradeAction.java
@@ -19,10 +19,9 @@
import static
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
+import static org.apache.ozone.recon.schema.SqlDbUtils.indexExists;
import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.jooq.DSLContext;
@@ -48,7 +47,7 @@ public void execute(DataSource source) throws Exception {
return;
}
- if (indexExists(conn, INDEX_NAME)) {
+ if (indexExists(conn, UNHEALTHY_CONTAINERS_TABLE_NAME, INDEX_NAME)) {
LOG.info("Index {} already exists on {}", INDEX_NAME,
UNHEALTHY_CONTAINERS_TABLE_NAME);
return;
@@ -67,19 +66,4 @@ public void execute(DataSource source) throws Exception {
+ " on " + UNHEALTHY_CONTAINERS_TABLE_NAME, e);
}
}
-
- private boolean indexExists(Connection conn, String indexName)
- throws SQLException {
- DatabaseMetaData metaData = conn.getMetaData();
- try (ResultSet rs = metaData.getIndexInfo(
- null, null, UNHEALTHY_CONTAINERS_TABLE_NAME, false, false)) {
- while (rs.next()) {
- String existing = rs.getString("INDEX_NAME");
- if (existing != null && existing.equalsIgnoreCase(indexName)) {
- return true;
- }
- }
- }
- return false;
- }
}
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestInitialConstraintUpgradeAction.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestInitialConstraintUpgradeAction.java
index 7c4c8e55122..5b90e50a4ce 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestInitialConstraintUpgradeAction.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestInitialConstraintUpgradeAction.java
@@ -18,10 +18,13 @@
package org.apache.hadoop.ozone.recon.upgrade;
import static
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
+import static org.apache.ozone.recon.schema.SqlDbUtils.constraintExists;
import static org.jooq.impl.DSL.field;
import static org.jooq.impl.DSL.name;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -60,9 +63,6 @@ public void setUp() throws SQLException {
DataSource dataSource = getInjector().getInstance(DataSource.class);
when(mockScmFacade.getDataSource()).thenReturn(dataSource);
- // Set the DataSource and DSLContext directly
- upgradeAction.setDslContext(dslContext);
-
// Check if the table already exists
try (Connection conn = dataSource.getConnection()) {
DatabaseMetaData dbMetaData = conn.getMetaData();
@@ -81,6 +81,17 @@ public void setUp() throws SQLException {
}
}
+ @Test
+ public void testExecuteIsIdempotent() throws SQLException {
+ DataSource dataSource = getInjector().getInstance(DataSource.class);
+ upgradeAction.execute(dataSource);
+ try (Connection conn = dataSource.getConnection()) {
+ assertTrue(constraintExists(conn, UNHEALTHY_CONTAINERS_TABLE_NAME,
+ UNHEALTHY_CONTAINERS_TABLE_NAME + "ck1"));
+ }
+ assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
+ }
+
@Test
public void testUpgradeAppliesConstraintModificationForAllStates() throws
SQLException {
// Run the upgrade action
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestNSSummaryAggregatedTotalsUpgrade.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestNSSummaryAggregatedTotalsUpgrade.java
index 80b6d7cc576..99ac2a1a76d 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestNSSummaryAggregatedTotalsUpgrade.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestNSSummaryAggregatedTotalsUpgrade.java
@@ -19,13 +19,16 @@
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.inject.Injector;
import javax.sql.DataSource;
import org.apache.hadoop.ozone.recon.ReconGuiceServletContextListener;
+import org.apache.hadoop.ozone.recon.tasks.NSSummaryTask;
import org.apache.hadoop.ozone.recon.tasks.ReconTaskController;
import org.apache.hadoop.ozone.recon.tasks.ReconTaskReInitializationEvent;
import org.junit.jupiter.api.BeforeEach;
@@ -136,6 +139,27 @@ public void testExecuteWithNullInjector() {
}
}
+ @Test
+ public void testExecuteIsIdempotentWhenRebuildRunning() {
+ try (MockedStatic<ReconGuiceServletContextListener> mockedListener =
+ Mockito.mockStatic(ReconGuiceServletContextListener.class);
+ MockedStatic<NSSummaryTask> mockedNSSummary =
Mockito.mockStatic(NSSummaryTask.class)) {
+
+ mockedListener.when(ReconGuiceServletContextListener::getGlobalInjector)
+ .thenReturn(mockInjector);
+
+ when(mockInjector.getInstance(ReconTaskController.class))
+ .thenReturn(mockReconTaskController);
+
+ mockedNSSummary.when(NSSummaryTask::getRebuildState)
+ .thenReturn(NSSummaryTask.RebuildState.RUNNING);
+
+ assertDoesNotThrow(() -> upgradeAction.execute(mockDataSource));
+
+ verify(mockReconTaskController,
never()).queueReInitializationEvent(any());
+ }
+ }
+
@Test
public void testExecuteWithInjectorException() throws Exception {
try (MockedStatic<ReconGuiceServletContextListener> mockedListener =
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReconTaskStatusTableUpgradeAction.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReconTaskStatusTableUpgradeAction.java
new file mode 100644
index 00000000000..2d98bba6ab1
--- /dev/null
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReconTaskStatusTableUpgradeAction.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.recon.upgrade;
+
+import static
org.apache.ozone.recon.schema.ReconTaskSchemaDefinition.RECON_TASK_STATUS_TABLE_NAME;
+import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
+import static org.apache.ozone.recon.schema.SqlDbUtils.columnExists;
+import static org.apache.ozone.recon.schema.SqlDbUtils.isColumnNullable;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import javax.sql.DataSource;
+import org.apache.hadoop.ozone.recon.persistence.AbstractReconSqlDBTest;
+import org.jooq.DSLContext;
+import org.jooq.impl.DSL;
+import org.jooq.impl.SQLDataType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for ReconTaskStatusTableUpgradeAction.
+ */
+public class TestReconTaskStatusTableUpgradeAction extends
AbstractReconSqlDBTest {
+
+ private static final String LAST_TASK_RUN_STATUS = "last_task_run_status";
+ private static final String IS_CURRENT_TASK_RUNNING =
"is_current_task_running";
+
+ private DSLContext dslContext;
+ private DataSource dataSource;
+ private ReconTaskStatusTableUpgradeAction upgradeAction;
+
+ @BeforeEach
+ public void setUp() {
+ dslContext = getDslContext();
+ dataSource = getInjector().getInstance(DataSource.class);
+ upgradeAction = new ReconTaskStatusTableUpgradeAction();
+ }
+
+ @Test
+ public void testExecuteAddsColumnsToLegacyTable() throws Exception {
+ createLegacyTaskStatusTable();
+ try (Connection conn = dataSource.getConnection()) {
+ assertFalse(columnExists(conn, RECON_TASK_STATUS_TABLE_NAME,
LAST_TASK_RUN_STATUS));
+ assertFalse(columnExists(conn, RECON_TASK_STATUS_TABLE_NAME,
IS_CURRENT_TASK_RUNNING));
+ }
+
+ upgradeAction.execute(dataSource);
+
+ try (Connection conn = dataSource.getConnection()) {
+ assertTrue(columnExists(conn, RECON_TASK_STATUS_TABLE_NAME,
LAST_TASK_RUN_STATUS));
+ assertTrue(columnExists(conn, RECON_TASK_STATUS_TABLE_NAME,
IS_CURRENT_TASK_RUNNING));
+ assertFalse(isColumnNullable(conn, RECON_TASK_STATUS_TABLE_NAME,
LAST_TASK_RUN_STATUS));
+ assertFalse(isColumnNullable(conn, RECON_TASK_STATUS_TABLE_NAME,
IS_CURRENT_TASK_RUNNING));
+ }
+ }
+
+ @Test
+ public void testExecuteIsIdempotentOnLegacyTable() throws Exception {
+ createLegacyTaskStatusTable();
+ upgradeAction.execute(dataSource);
+ assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
+
+ try (Connection conn = dataSource.getConnection()) {
+ assertTrue(columnExists(conn, RECON_TASK_STATUS_TABLE_NAME,
LAST_TASK_RUN_STATUS));
+ assertTrue(columnExists(conn, RECON_TASK_STATUS_TABLE_NAME,
IS_CURRENT_TASK_RUNNING));
+ assertFalse(isColumnNullable(conn, RECON_TASK_STATUS_TABLE_NAME,
LAST_TASK_RUN_STATUS));
+ assertFalse(isColumnNullable(conn, RECON_TASK_STATUS_TABLE_NAME,
IS_CURRENT_TASK_RUNNING));
+ }
+ }
+
+ @Test
+ public void testExecuteIsIdempotentOnCurrentSchema() {
+ assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
+ assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
+ }
+
+ @Test
+ public void testNoOpWhenTableMissing() throws SQLException {
+ dropTaskStatusTableIfPresent();
+ assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
+ }
+
+ private void createLegacyTaskStatusTable() throws SQLException {
+ dropTaskStatusTableIfPresent();
+ try (Connection conn = dataSource.getConnection()) {
+ DSLContext legacyDsl = DSL.using(conn);
+ // Derby rejects explicit "null" in CREATE TABLE for BIGINT columns; add
them via ALTER instead.
+ legacyDsl.createTable(RECON_TASK_STATUS_TABLE_NAME)
+ .column("task_name", SQLDataType.VARCHAR(766).nullable(false))
+ .constraint(DSL.constraint("pk_task_name")
+ .primaryKey("task_name"))
+ .execute();
+ legacyDsl.alterTable(RECON_TASK_STATUS_TABLE_NAME)
+ .addColumn("last_updated_timestamp", SQLDataType.BIGINT)
+ .execute();
+ legacyDsl.alterTable(RECON_TASK_STATUS_TABLE_NAME)
+ .addColumn("last_updated_seq_number", SQLDataType.BIGINT)
+ .execute();
+ }
+ }
+
+ private void dropTaskStatusTableIfPresent() throws SQLException {
+ try (Connection conn = dataSource.getConnection()) {
+ if (TABLE_EXISTS_CHECK.test(conn, RECON_TASK_STATUS_TABLE_NAME)) {
+ dslContext.dropTable(RECON_TASK_STATUS_TABLE_NAME).execute();
+ }
+ }
+ }
+}
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReplicatedSizeOfFilesUpgradeAction.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReplicatedSizeOfFilesUpgradeAction.java
index 2597b8877c6..54227a40dd8 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReplicatedSizeOfFilesUpgradeAction.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReplicatedSizeOfFilesUpgradeAction.java
@@ -17,11 +17,10 @@
package org.apache.hadoop.ozone.recon.upgrade;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -29,6 +28,7 @@
import com.google.inject.Injector;
import javax.sql.DataSource;
import org.apache.hadoop.ozone.recon.ReconGuiceServletContextListener;
+import org.apache.hadoop.ozone.recon.tasks.NSSummaryTask;
import org.apache.hadoop.ozone.recon.tasks.ReconTaskController;
import org.apache.hadoop.ozone.recon.tasks.ReconTaskReInitializationEvent;
import org.junit.jupiter.api.BeforeEach;
@@ -58,7 +58,7 @@ public void setUp() {
}
@Test
- public void testExecuteSuccessfullyRebuildsNSSummary() {
+ public void testExecuteSuccessfullyRebuildsNSSummary() throws Exception {
try (MockedStatic<ReconGuiceServletContextListener> mockStaticContext =
mockStatic(ReconGuiceServletContextListener.class)) {
mockStaticContext.when(ReconGuiceServletContextListener::getGlobalInjector).thenReturn(mockInjector);
@@ -74,18 +74,34 @@ public void testExecuteSuccessfullyRebuildsNSSummary() {
}
@Test
- public void testExecuteThrowsRuntimeExceptionOnRebuildFailure() {
+ public void testExecuteIsIdempotentWhenRebuildRunning() {
+ try (MockedStatic<ReconGuiceServletContextListener> mockStaticContext =
+ mockStatic(ReconGuiceServletContextListener.class);
+ MockedStatic<NSSummaryTask> mockedNSSummary =
mockStatic(NSSummaryTask.class)) {
+
mockStaticContext.when(ReconGuiceServletContextListener::getGlobalInjector).thenReturn(mockInjector);
+
when(mockInjector.getInstance(ReconTaskController.class)).thenReturn(mockReconTaskController);
+ mockedNSSummary.when(NSSummaryTask::getRebuildState)
+ .thenReturn(NSSummaryTask.RebuildState.RUNNING);
+
+ assertDoesNotThrow(() -> upgradeAction.execute(mockDataSource));
+
+ verify(mockReconTaskController,
never()).queueReInitializationEvent(any());
+ }
+ }
+
+ @Test
+ public void testExecuteDoesNotThrowOnRebuildFailure() {
try (MockedStatic<ReconGuiceServletContextListener> mockStaticContext =
mockStatic(ReconGuiceServletContextListener.class)) {
mockStaticContext.when(ReconGuiceServletContextListener::getGlobalInjector).thenReturn(mockInjector);
when(mockInjector.getInstance(ReconTaskController.class)).thenReturn(mockReconTaskController);
+ when(mockReconTaskController.queueReInitializationEvent(
+ any(ReconTaskReInitializationEvent.ReInitializationReason.class)))
+ .thenReturn(ReconTaskController.ReInitializationResult.RETRY_LATER);
- // Simulate a failure during the rebuild process
- doThrow(new RuntimeException("Simulated rebuild
error")).when(mockReconTaskController)
-
.queueReInitializationEvent(any(ReconTaskReInitializationEvent.ReInitializationReason.class));
+ assertDoesNotThrow(() -> upgradeAction.execute(mockDataSource));
- RuntimeException thrown = assertThrows(RuntimeException.class, () ->
upgradeAction.execute(mockDataSource));
- assertEquals("Failed to rebuild NSSummary during upgrade",
thrown.getMessage());
+ verify(mockReconTaskController,
times(1)).queueReInitializationEvent(any());
}
}
}
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainersStateContainerIdIndexUpgradeAction.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
similarity index 64%
copy from
hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainersStateContainerIdIndexUpgradeAction.java
copy to
hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
index b4cde1bb673..3b58d884609 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainersStateContainerIdIndexUpgradeAction.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
@@ -19,14 +19,12 @@
import static
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
+import static org.apache.ozone.recon.schema.SqlDbUtils.constraintExists;
import static org.jooq.impl.DSL.name;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.hadoop.ozone.recon.persistence.AbstractReconSqlDBTest;
@@ -37,42 +35,31 @@
import org.junit.jupiter.api.Test;
/**
- * Tests for UnhealthyContainersStateContainerIdIndexUpgradeAction.
+ * Tests for UnhealthyContainerReplicaMismatchAction.
*/
-public class TestUnhealthyContainersStateContainerIdIndexUpgradeAction
- extends AbstractReconSqlDBTest {
+public class TestUnhealthyContainerReplicaMismatchAction extends
AbstractReconSqlDBTest {
- private static final String INDEX_NAME = "idx_state_container_id";
+ private static final String CONSTRAINT_NAME =
UNHEALTHY_CONTAINERS_TABLE_NAME + "ck1";
private DSLContext dslContext;
private DataSource dataSource;
- private UnhealthyContainersStateContainerIdIndexUpgradeAction upgradeAction;
+ private UnhealthyContainerReplicaMismatchAction upgradeAction;
@BeforeEach
- public void setUp() {
+ public void setUp() throws SQLException {
dslContext = getDslContext();
dataSource = getInjector().getInstance(DataSource.class);
- upgradeAction = new
UnhealthyContainersStateContainerIdIndexUpgradeAction();
+ upgradeAction = new UnhealthyContainerReplicaMismatchAction();
+ createTableWithoutCheckConstraint();
}
@Test
- public void testCreatesIndexWhenMissing() throws Exception {
- createTableWithoutIndex();
- assertFalse(indexExists(INDEX_NAME));
-
+ public void testExecuteIsIdempotent() throws Exception {
upgradeAction.execute(dataSource);
-
- assertTrue(indexExists(INDEX_NAME));
- }
-
- @Test
- public void testExecuteIsIdempotentWhenIndexAlreadyExists() throws Exception
{
- createTableWithoutIndex();
- upgradeAction.execute(dataSource);
- assertTrue(indexExists(INDEX_NAME));
-
+ try (Connection conn = dataSource.getConnection()) {
+ assertTrue(constraintExists(conn, UNHEALTHY_CONTAINERS_TABLE_NAME,
CONSTRAINT_NAME));
+ }
assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
- assertTrue(indexExists(INDEX_NAME));
}
@Test
@@ -81,7 +68,7 @@ public void testNoOpWhenTableMissing() throws SQLException {
assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
}
- private void createTableWithoutIndex() throws SQLException {
+ private void createTableWithoutCheckConstraint() throws SQLException {
dropTableIfPresent();
dslContext.createTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
.column("container_id", SQLDataType.BIGINT.nullable(false))
@@ -98,20 +85,4 @@ private void dropTableIfPresent() throws SQLException {
}
}
}
-
- private boolean indexExists(String indexName) throws SQLException {
- try (Connection conn = dataSource.getConnection()) {
- DatabaseMetaData metaData = conn.getMetaData();
- try (ResultSet rs = metaData.getIndexInfo(
- null, null, UNHEALTHY_CONTAINERS_TABLE_NAME, false, false)) {
- while (rs.next()) {
- String existing = rs.getString("INDEX_NAME");
- if (existing != null && existing.equalsIgnoreCase(indexName)) {
- return true;
- }
- }
- }
- }
- return false;
- }
}
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainersStateContainerIdIndexUpgradeAction.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainersStateContainerIdIndexUpgradeAction.java
index b4cde1bb673..98aab4aea92 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainersStateContainerIdIndexUpgradeAction.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainersStateContainerIdIndexUpgradeAction.java
@@ -19,14 +19,13 @@
import static
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
+import static org.apache.ozone.recon.schema.SqlDbUtils.indexExists;
import static org.jooq.impl.DSL.name;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.hadoop.ozone.recon.persistence.AbstractReconSqlDBTest;
@@ -58,21 +57,21 @@ public void setUp() {
@Test
public void testCreatesIndexWhenMissing() throws Exception {
createTableWithoutIndex();
- assertFalse(indexExists(INDEX_NAME));
+ assertFalse(tableHasIndex(INDEX_NAME));
upgradeAction.execute(dataSource);
- assertTrue(indexExists(INDEX_NAME));
+ assertTrue(tableHasIndex(INDEX_NAME));
}
@Test
public void testExecuteIsIdempotentWhenIndexAlreadyExists() throws Exception
{
createTableWithoutIndex();
upgradeAction.execute(dataSource);
- assertTrue(indexExists(INDEX_NAME));
+ assertTrue(tableHasIndex(INDEX_NAME));
assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
- assertTrue(indexExists(INDEX_NAME));
+ assertTrue(tableHasIndex(INDEX_NAME));
}
@Test
@@ -99,19 +98,9 @@ private void dropTableIfPresent() throws SQLException {
}
}
- private boolean indexExists(String indexName) throws SQLException {
+ private boolean tableHasIndex(String indexName) throws SQLException {
try (Connection conn = dataSource.getConnection()) {
- DatabaseMetaData metaData = conn.getMetaData();
- try (ResultSet rs = metaData.getIndexInfo(
- null, null, UNHEALTHY_CONTAINERS_TABLE_NAME, false, false)) {
- while (rs.next()) {
- String existing = rs.getString("INDEX_NAME");
- if (existing != null && existing.equalsIgnoreCase(indexName)) {
- return true;
- }
- }
- }
+ return indexExists(conn, UNHEALTHY_CONTAINERS_TABLE_NAME, indexName);
}
- return false;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]