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 37874d15574 HDDS-15549. Recon's INITIAL_VERSION should not have an
upgrade action (#10935)
37874d15574 is described below
commit 37874d15574005d8a1ac0f81322e6214687f0f86
Author: Ethan Rose <[email protected]>
AuthorDate: Mon Aug 17 16:09:08 2026 -0400
HDDS-15549. Recon's INITIAL_VERSION should not have an upgrade action
(#10935)
---
.../upgrade/InitialConstraintUpgradeAction.java | 39 ----
.../upgrade/ReconTaskStatusTableUpgradeAction.java | 6 +-
.../TestInitialConstraintUpgradeAction.java | 199 ---------------------
.../TestReconTaskStatusTableUpgradeAction.java | 29 +++
...estUnhealthyContainerReplicaMismatchAction.java | 29 +++
5 files changed, 63 insertions(+), 239 deletions(-)
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
deleted file mode 100644
index ffcf89768f2..00000000000
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/InitialConstraintUpgradeAction.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.hadoop.ozone.recon.upgrade.ReconVersion.INITIAL_VERSION;
-
-import java.sql.SQLException;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Upgrade action for the INITIAL schema version, which manages constraints
- * for the UNHEALTHY_CONTAINERS table.
- */
-@ReconUpgradeActionForVersion(version = INITIAL_VERSION)
-public class InitialConstraintUpgradeAction implements ReconUpgradeAction {
- private static final Logger LOG =
LoggerFactory.getLogger(InitialConstraintUpgradeAction.class);
-
- @Override
- public void execute(DataSource source) throws SQLException {
- ReconUpgradeAction.updateUnhealthyContainerStatesConstraint(source, 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 f8a5a98a695..9deabc163ea 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
@@ -34,9 +34,11 @@
import org.slf4j.LoggerFactory;
/**
- * Upgrade action for TASK_STATUS_STATISTICS feature layout change, which adds
+ * Upgrade action for TASK_STATUS_STATISTICS version, which adds
* <code>last_task_run_status</code> and <code>current_task_run_status</code>
columns to
* {@link ReconTaskSchemaDefinition} in case it is missing .
+ * <p>
+ * It also applies the UNHEALTHY_CONTAINERS check constraint which must be run
with Recon's first version increase.
*/
@ReconUpgradeActionForVersion(version = ReconVersion.TASK_STATUS_STATISTICS)
public class ReconTaskStatusTableUpgradeAction implements ReconUpgradeAction {
@@ -73,6 +75,8 @@ private void setColumnAsNonNullableIfNeeded(Connection conn,
DSLContext dslConte
@Override
public void execute(DataSource dataSource) throws DataAccessException,
SQLException {
+ ReconUpgradeAction.updateUnhealthyContainerStatesConstraint(dataSource,
LOG);
+
try (Connection conn = dataSource.getConnection()) {
if (!TABLE_EXISTS_CHECK.test(conn, RECON_TASK_STATUS_TABLE_NAME)) {
return;
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
deleted file mode 100644
index 5b90e50a4ce..00000000000
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestInitialConstraintUpgradeAction.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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.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;
-
-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;
-import org.apache.hadoop.ozone.recon.scm.ReconStorageContainerManagerFacade;
-import org.apache.ozone.recon.schema.ContainerSchemaDefinition;
-import org.jooq.DSLContext;
-import org.jooq.impl.DSL;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test class for InitialConstraintUpgradeAction.
- */
-public class TestInitialConstraintUpgradeAction extends AbstractReconSqlDBTest
{
-
- private InitialConstraintUpgradeAction upgradeAction;
- private DSLContext dslContext;
- private ReconStorageContainerManagerFacade mockScmFacade;
-
- @BeforeEach
- public void setUp() throws SQLException {
- // Initialize the DSLContext
- dslContext = getDslContext();
-
- // Initialize the upgrade action
- upgradeAction = new InitialConstraintUpgradeAction();
-
- // Mock the SCM facade to provide the DataSource
- mockScmFacade = mock(ReconStorageContainerManagerFacade.class);
- DataSource dataSource = getInjector().getInstance(DataSource.class);
- when(mockScmFacade.getDataSource()).thenReturn(dataSource);
-
- // Check if the table already exists
- try (Connection conn = dataSource.getConnection()) {
- DatabaseMetaData dbMetaData = conn.getMetaData();
- ResultSet tables = dbMetaData.getTables(null, null,
UNHEALTHY_CONTAINERS_TABLE_NAME, null);
- if (!tables.next()) {
- // Create the initial table if it does not exist
- dslContext.createTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
- .column("container_id", org.jooq.impl.SQLDataType.BIGINT
- .nullable(false))
- .column("container_state", org.jooq.impl.SQLDataType.VARCHAR(16)
- .nullable(false))
- .constraint(DSL.constraint("pk_container_id")
- .primaryKey("container_id", "container_state"))
- .execute();
- }
- }
- }
-
- @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
- upgradeAction.execute(mockScmFacade.getDataSource());
-
- // Iterate over all valid states and insert records
- for (ContainerSchemaDefinition.UnHealthyContainerStates state :
- ContainerSchemaDefinition.UnHealthyContainerStates.values()) {
- dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
- .columns(
- field(name("container_id")),
- field(name("container_state")),
- field(name("in_state_since")),
- field(name("expected_replica_count")),
- field(name("actual_replica_count")),
- field(name("replica_delta")),
- field(name("reason"))
- )
- .values(
- System.currentTimeMillis(), // Unique container_id for each
record
- state.name(), System.currentTimeMillis(), 3, 2, 1, "Replica
count mismatch"
- )
- .execute();
- }
-
- // Verify that the number of inserted records matches the number of enum
values
- int count =
dslContext.fetchCount(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME));
-
assertEquals(ContainerSchemaDefinition.UnHealthyContainerStates.values().length,
- count, "Expected one record for each valid state");
-
- // Try inserting an invalid state (should fail due to constraint)
- assertThrows(org.jooq.exception.DataAccessException.class, () ->
- dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
- .columns(
- field(name("container_id")),
- field(name("container_state")),
- field(name("in_state_since")),
- field(name("expected_replica_count")),
- field(name("actual_replica_count")),
- field(name("replica_delta")),
- field(name("reason"))
- )
- .values(999L, "INVALID_STATE", System.currentTimeMillis(), 3, 2, 1,
- "Invalid state test").execute(),
- "Inserting an invalid container_state should fail due to the
constraint");
- }
-
- @Test
- public void testInsertionWithNullContainerState() {
- assertThrows(org.jooq.exception.DataAccessException.class, () -> {
- dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
- .columns(
- field(name("container_id")),
- field(name("container_state")),
- field(name("in_state_since")),
- field(name("expected_replica_count")),
- field(name("actual_replica_count")),
- field(name("replica_delta")),
- field(name("reason"))
- )
- .values(
- 100L, // container_id
- null, // container_state is NULL
- System.currentTimeMillis(), 3, 2, 1, "Testing NULL state"
- )
- .execute();
- }, "Inserting a NULL container_state should fail due to the NOT NULL
constraint");
- }
-
- @Test
- public void testDuplicatePrimaryKeyInsertion() throws SQLException {
- // Insert the first record
- dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
- .columns(
- field(name("container_id")),
- field(name("container_state")),
- field(name("in_state_since")),
- field(name("expected_replica_count")),
- field(name("actual_replica_count")),
- field(name("replica_delta")),
- field(name("reason"))
- )
- .values(200L, "MISSING", System.currentTimeMillis(), 3, 2, 1, "First
insertion"
- )
- .execute();
-
- // Try inserting a duplicate record with the same primary key
- assertThrows(org.jooq.exception.DataAccessException.class, () -> {
- dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
- .columns(
- field(name("container_id")),
- field(name("container_state")),
- field(name("in_state_since")),
- field(name("expected_replica_count")),
- field(name("actual_replica_count")),
- field(name("replica_delta")),
- field(name("reason"))
- )
- .values(200L, "MISSING", System.currentTimeMillis(), 3, 2, 1,
"Duplicate insertion"
- )
- .execute();
- }, "Inserting a duplicate primary key should fail due to the primary key
constraint");
- }
-
-}
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
index 2d98bba6ab1..a7b43a1aeba 100644
---
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
@@ -17,10 +17,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.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.constraintExists;
import static org.apache.ozone.recon.schema.SqlDbUtils.isColumnNullable;
+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;
@@ -42,6 +45,7 @@ public class TestReconTaskStatusTableUpgradeAction extends
AbstractReconSqlDBTes
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 static final String UNHEALTHY_CONTAINERS_CONSTRAINT =
UNHEALTHY_CONTAINERS_TABLE_NAME + "ck1";
private DSLContext dslContext;
private DataSource dataSource;
@@ -98,6 +102,17 @@ public void testNoOpWhenTableMissing() throws SQLException {
assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
}
+ @Test
+ public void testExecuteAppliesUnhealthyContainersConstraint() throws
Exception {
+ createUnhealthyContainersTableWithoutCheckConstraint();
+
+ upgradeAction.execute(dataSource);
+
+ try (Connection conn = dataSource.getConnection()) {
+ assertTrue(constraintExists(conn, UNHEALTHY_CONTAINERS_TABLE_NAME,
UNHEALTHY_CONTAINERS_CONSTRAINT));
+ }
+ }
+
private void createLegacyTaskStatusTable() throws SQLException {
dropTaskStatusTableIfPresent();
try (Connection conn = dataSource.getConnection()) {
@@ -124,4 +139,18 @@ private void dropTaskStatusTableIfPresent() throws
SQLException {
}
}
}
+
+ private void createUnhealthyContainersTableWithoutCheckConstraint() throws
SQLException {
+ try (Connection conn = dataSource.getConnection()) {
+ if (TABLE_EXISTS_CHECK.test(conn, UNHEALTHY_CONTAINERS_TABLE_NAME)) {
+ dslContext.dropTable(UNHEALTHY_CONTAINERS_TABLE_NAME).execute();
+ }
+ }
+ dslContext.createTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
+ .column("container_id", SQLDataType.BIGINT.nullable(false))
+ .column("container_state", SQLDataType.VARCHAR(16).nullable(false))
+ .constraint(DSL.constraint("pk_container_id")
+ .primaryKey(name("container_id"), name("container_state")))
+ .execute();
+ }
}
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
index 3b58d884609..5f9b1812785 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
@@ -20,15 +20,20 @@
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.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 java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.hadoop.ozone.recon.persistence.AbstractReconSqlDBTest;
+import
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UnHealthyContainerStates;
import org.jooq.DSLContext;
+import org.jooq.exception.DataAccessException;
import org.jooq.impl.DSL;
import org.jooq.impl.SQLDataType;
import org.junit.jupiter.api.BeforeEach;
@@ -68,6 +73,30 @@ public void testNoOpWhenTableMissing() throws SQLException {
assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
}
+ @Test
+ public void testConstraintAdmitsAllStatesAndRejectsInvalid() throws
Exception {
+ upgradeAction.execute(dataSource);
+
+ UnHealthyContainerStates[] states = UnHealthyContainerStates.values();
+ for (int i = 0; i < states.length; i++) {
+ insertContainerState(i, states[i].name());
+ }
+ assertEquals(states.length,
+ dslContext.fetchCount(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME)),
+ "Expected one record for each valid state");
+
+ assertThrows(DataAccessException.class,
+ () -> insertContainerState(states.length, "INVALID_STATE"),
+ "Inserting an invalid container_state should fail due to the check
constraint");
+ }
+
+ private void insertContainerState(long containerId, String containerState) {
+ dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
+ .columns(field(name("container_id")), field(name("container_state")))
+ .values(containerId, containerState)
+ .execute();
+ }
+
private void createTableWithoutCheckConstraint() throws SQLException {
dropTableIfPresent();
dslContext.createTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]