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 f2a996cd6f6 HDDS-15376. Implement new ScmVersionManager. (#10367)
f2a996cd6f6 is described below
commit f2a996cd6f616678f284f83342bd7057368268fc
Author: Ethan Rose <[email protected]>
AuthorDate: Mon Jun 8 11:54:18 2026 -0400
HDDS-15376. Implement new ScmVersionManager. (#10367)
Co-authored-by: Cursor <[email protected]>
---
.../container/upgrade/DatanodeVersionManager.java | 10 +-
...DSVersionManager.java => HDDSVersionUtils.java} | 53 +++--
.../ozone/upgrade/RatisBasedVersionManager.java | 69 +++++++
.../ScmOnFinalizeActionForDatanodeSchemaV2.java | 9 +-
.../hdds/scm/server/upgrade/ScmVersionManager.java | 80 ++++++++
.../hadoop/hdds/upgrade/ScmUpgradeAction.java | 4 +-
.../scm/server/upgrade/TestScmVersionManager.java | 224 +++++++++++++++++++++
.../org/apache/hadoop/ozone/om/OzoneManager.java | 4 +-
.../hadoop/ozone/om/upgrade/OMVersionManager.java | 43 +---
9 files changed, 426 insertions(+), 70 deletions(-)
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/upgrade/DatanodeVersionManager.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/upgrade/DatanodeVersionManager.java
index 17f92c19bcb..ec763575c22 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/upgrade/DatanodeVersionManager.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/upgrade/DatanodeVersionManager.java
@@ -21,18 +21,20 @@
import java.io.IOException;
import java.util.Map;
import org.apache.hadoop.hdds.ComponentVersion;
+import org.apache.hadoop.hdds.HDDSVersion;
import org.apache.hadoop.hdds.upgrade.DatanodeUpgradeAction;
import org.apache.hadoop.hdds.upgrade.DatanodeUpgradeActionProvider;
-import org.apache.hadoop.hdds.upgrade.HDDSVersionManager;
+import org.apache.hadoop.hdds.upgrade.HDDSVersionUtils;
import org.apache.hadoop.ozone.container.common.DatanodeStorage;
import
org.apache.hadoop.ozone.container.common.statemachine.DatanodeStateMachine;
import org.apache.hadoop.ozone.upgrade.ComponentUpgradeActionProvider;
+import org.apache.hadoop.ozone.upgrade.ComponentVersionManager;
import org.apache.hadoop.ozone.upgrade.UpgradeException;
/**
* Datanode-specific version manager that wires upgrade actions internally.
*/
-public class DatanodeVersionManager extends HDDSVersionManager {
+public class DatanodeVersionManager extends ComponentVersionManager {
private final Map<ComponentVersion, DatanodeUpgradeAction> upgradeActions;
private final DatanodeStateMachine upgradeActionArg;
@@ -44,7 +46,9 @@ public DatanodeVersionManager(DatanodeStorage storage,
DatanodeStateMachine upgr
@VisibleForTesting
public DatanodeVersionManager(DatanodeStorage storage, DatanodeStateMachine
upgradeActionArg,
ComponentUpgradeActionProvider<DatanodeUpgradeAction>
upgradeActionProvider) throws IOException {
- super(storage);
+ super(storage,
+
HDDSVersionUtils.deserializedPersistedApparentVersion(storage.getApparentVersion()),
+ HDDSVersion.SOFTWARE_VERSION);
this.upgradeActionArg = upgradeActionArg;
upgradeActions = upgradeActionProvider.load();
}
diff --git
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/upgrade/HDDSVersionManager.java
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/upgrade/HDDSVersionUtils.java
similarity index 54%
rename from
hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/upgrade/HDDSVersionManager.java
rename to
hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/upgrade/HDDSVersionUtils.java
index d9dcb36e670..fa39b19ecb8 100644
---
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/upgrade/HDDSVersionManager.java
+++
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/upgrade/HDDSVersionUtils.java
@@ -20,43 +20,52 @@
import java.io.IOException;
import org.apache.hadoop.hdds.ComponentVersion;
import org.apache.hadoop.hdds.HDDSVersion;
-import org.apache.hadoop.ozone.common.Storage;
-import org.apache.hadoop.ozone.upgrade.ComponentVersionManager;
-import org.apache.hadoop.ozone.upgrade.UpgradeException;
/**
* Component version manager for HDDS (Datanodes and SCM).
*/
-public abstract class HDDSVersionManager extends ComponentVersionManager {
- protected HDDSVersionManager(Storage storage) throws IOException {
- super(storage, computeApparentVersion(storage.getApparentVersion()),
HDDSVersion.SOFTWARE_VERSION);
+public final class HDDSVersionUtils {
+ private HDDSVersionUtils() {
}
/**
* If the apparent version stored on the disk is >= {@link
HDDSVersion#ZDU} serialized, the apparent version is
- * resolved via {@link HDDSVersion#deserialize(int)}. Values with no
matching {@link HDDSVersion} fail startup with
- * the persisted integer in the exception message.
+ * resolved via {@link HDDSVersion#deserialize(int)}.
* If the value is below that threshold, the apparent version is resolved as
a {@link HDDSLayoutFeature}. Integers in
- * the gap between the largest {@link HDDSLayoutFeature} and ZDU are not
valid legacy layout values; startup fails
- * with the persisted integer in the exception message.
+ * the gap between the largest {@link HDDSLayoutFeature} and ZDU are not
valid legacy layout values.
+ *
+ * If the serialized version does not match any of these known versions,
{@link HDDSVersion#UNKNOWN_VERSION} is
+ * returned.
*/
- private static ComponentVersion computeApparentVersion(int
serializedApparentVersion) throws IOException {
- if (serializedApparentVersion >= HDDSVersion.ZDU.serialize()) {
- HDDSVersion fromHdds =
HDDSVersion.deserialize(serializedApparentVersion);
- if (fromHdds != HDDSVersion.UNKNOWN_VERSION) {
- return fromHdds;
- }
+ public static ComponentVersion deserializeHDDSVersionOrLayoutVersion(int
serializedVersion) {
+ if (serializedVersion >= HDDSVersion.ZDU.serialize()) {
+ return HDDSVersion.deserialize(serializedVersion);
} else {
- ComponentVersion fromLayout =
HDDSLayoutFeature.deserialize(serializedApparentVersion);
+ ComponentVersion fromLayout =
HDDSLayoutFeature.deserialize(serializedVersion);
if (fromLayout != null) {
return fromLayout;
+ } else {
+ return HDDSVersion.UNKNOWN_VERSION;
}
}
- throw new IOException("Initialization failed. Disk contains unknown
apparent version " + serializedApparentVersion +
- " for software version " + HDDSVersion.SOFTWARE_VERSION + ". Make sure
this component was not downgraded" +
- " after finalization");
}
- @Override
- protected abstract void runUpgradeAction(ComponentVersion version) throws
UpgradeException;
+ /**
+ * If the apparent version stored on the disk is >= {@link
HDDSVersion#ZDU} serialized, the apparent version is
+ * resolved via {@link HDDSVersion#deserialize(int)}. Values with no
matching {@link HDDSVersion} fail startup with
+ * the persisted integer in the exception message.
+ * If the value is below that threshold, the apparent version is resolved as
a {@link HDDSLayoutFeature}. Integers in
+ * the gap between the largest {@link HDDSLayoutFeature} and ZDU are not
valid legacy layout values; startup fails
+ * with the persisted integer in the exception message.
+ */
+ public static ComponentVersion deserializedPersistedApparentVersion(int
serializedApparentVersion)
+ throws IOException {
+ ComponentVersion persistedVersion =
deserializeHDDSVersionOrLayoutVersion(serializedApparentVersion);
+ if (persistedVersion == HDDSVersion.UNKNOWN_VERSION) {
+ throw new IOException("Initialization failed. Disk contains unknown
apparent version "
+ + serializedApparentVersion + " for software version " +
HDDSVersion.SOFTWARE_VERSION
+ + ". Make sure this component was not downgraded after
finalization");
+ }
+ return persistedVersion;
+ }
}
diff --git
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/ozone/upgrade/RatisBasedVersionManager.java
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/ozone/upgrade/RatisBasedVersionManager.java
new file mode 100644
index 00000000000..74ba51a09da
--- /dev/null
+++
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/ozone/upgrade/RatisBasedVersionManager.java
@@ -0,0 +1,69 @@
+/*
+ * 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.upgrade;
+
+import static org.apache.hadoop.ozone.OzoneConsts.APPARENT_VERSION_KEY;
+
+import java.io.IOException;
+import org.apache.hadoop.hdds.ComponentVersion;
+import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.ozone.common.Storage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base version manager implementation for ratis-backed component versions.
+ */
+public abstract class RatisBasedVersionManager extends ComponentVersionManager
{
+
+ private static final Logger LOG =
LoggerFactory.getLogger(RatisBasedVersionManager.class);
+
+ protected RatisBasedVersionManager(Storage storage, ComponentVersion
apparentVersion,
+ ComponentVersion softwareVersion) {
+ super(storage, apparentVersion, softwareVersion);
+ }
+
+ public void validateDBVersion(Table<String, String> finalizationStore)
throws IOException {
+ ComponentVersion dbVersion = getApparentVersionInDB(finalizationStore);
+ ComponentVersion apparentVersion = getApparentVersion();
+
+ if (!apparentVersion.equals(dbVersion)) {
+ LOG.info("Version file has different apparent version ({}) than DB ({}).
That is expected if this "
+ + "component has never been finalized to a newer version.",
apparentVersion, dbVersion);
+ }
+ }
+
+ public void finalizeFromSnapshotIfRequired(Table<String, String>
finalizationStore) throws IOException {
+ ComponentVersion apparentVersionInNewDB =
getApparentVersionInDB(finalizationStore);
+ if (apparentVersionInNewDB != null && !isAllowed(apparentVersionInNewDB)) {
+ LOG.info("New snapshot received with higher apparent version {}.
Attempting to finalize to that version.",
+ apparentVersionInNewDB);
+ finalizeUpgrade();
+ // Update the apparent version in the DB to match the VERSION file.
+ // When finalization is not done with a snapshot, this DB value is
updated by OMFinalizeUpgradeRequest.
+ finalizationStore.put(APPARENT_VERSION_KEY,
String.valueOf(getApparentVersion().serialize()));
+ }
+ }
+
+ protected abstract ComponentVersion computeApparentVersion(int
serializedVersion) throws IOException;
+
+ private ComponentVersion getApparentVersionInDB(Table<String, String>
finalizationStore) throws IOException {
+ String apparentVersion = finalizationStore.get(APPARENT_VERSION_KEY);
+ return (apparentVersion == null) ? null :
computeApparentVersion(Integer.parseInt(apparentVersion));
+ }
+}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/upgrade/ScmOnFinalizeActionForDatanodeSchemaV2.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/upgrade/ScmOnFinalizeActionForDatanodeSchemaV2.java
index bd62e87def7..d6b3cef1ce3 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/upgrade/ScmOnFinalizeActionForDatanodeSchemaV2.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/upgrade/ScmOnFinalizeActionForDatanodeSchemaV2.java
@@ -19,6 +19,7 @@
import static
org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature.DATANODE_SCHEMA_V2;
+import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
import org.apache.hadoop.hdds.upgrade.ScmUpgradeAction;
import org.apache.hadoop.ozone.upgrade.UpgradeActionScm;
import org.slf4j.Logger;
@@ -28,13 +29,11 @@
* SCM Upgrade Action for the very first Upgrade Version.
*/
@UpgradeActionScm(feature = DATANODE_SCHEMA_V2)
-public class ScmOnFinalizeActionForDatanodeSchemaV2 implements
- ScmUpgradeAction {
- private static final Logger LOG =
- LoggerFactory.getLogger(ScmOnFinalizeActionForDatanodeSchemaV2.class);
+public class ScmOnFinalizeActionForDatanodeSchemaV2 implements
ScmUpgradeAction {
+ private static final Logger LOG =
LoggerFactory.getLogger(ScmOnFinalizeActionForDatanodeSchemaV2.class);
@Override
- public void execute(SCMUpgradeFinalizationContext context) throws Exception {
+ public void execute(OzoneStorageContainerManager context) throws Exception {
LOG.info("Executing SCM On Finalize action for layout feature {}",
DATANODE_SCHEMA_V2);
}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/upgrade/ScmVersionManager.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/upgrade/ScmVersionManager.java
new file mode 100644
index 00000000000..7d28a332850
--- /dev/null
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/upgrade/ScmVersionManager.java
@@ -0,0 +1,80 @@
+/*
+ * 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.hdds.scm.server.upgrade;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.io.IOException;
+import java.util.Map;
+import org.apache.hadoop.hdds.ComponentVersion;
+import org.apache.hadoop.hdds.HDDSVersion;
+import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
+import org.apache.hadoop.hdds.scm.server.SCMStorageConfig;
+import org.apache.hadoop.hdds.upgrade.HDDSVersionUtils;
+import org.apache.hadoop.hdds.upgrade.ScmUpgradeAction;
+import org.apache.hadoop.hdds.upgrade.ScmUpgradeActionProvider;
+import org.apache.hadoop.ozone.upgrade.ComponentUpgradeActionProvider;
+import org.apache.hadoop.ozone.upgrade.RatisBasedVersionManager;
+import org.apache.hadoop.ozone.upgrade.UpgradeException;
+
+/**
+ * SCM-specific version manager that wires upgrade actions internally.
+ */
+public class ScmVersionManager extends RatisBasedVersionManager {
+
+ private final Map<ComponentVersion, ScmUpgradeAction> upgradeActions;
+ private final OzoneStorageContainerManager upgradeActionArg;
+
+ public ScmVersionManager(SCMStorageConfig storage,
OzoneStorageContainerManager upgradeActionArg) throws IOException {
+ this(storage, upgradeActionArg, new ScmUpgradeActionProvider());
+ }
+
+ @VisibleForTesting
+ public ScmVersionManager(SCMStorageConfig storage,
+ OzoneStorageContainerManager upgradeActionArg,
+ ComponentUpgradeActionProvider<ScmUpgradeAction> upgradeActionProvider)
+ throws IOException {
+ super(storage,
HDDSVersionUtils.deserializedPersistedApparentVersion(storage.getApparentVersion()),
+ HDDSVersion.SOFTWARE_VERSION);
+ this.upgradeActionArg = upgradeActionArg;
+ upgradeActions = upgradeActionProvider.load();
+ }
+
+ @VisibleForTesting
+ public Map<ComponentVersion, ScmUpgradeAction> getUpgradeActionsForTesting()
{
+ return upgradeActions;
+ }
+
+ @Override
+ protected void runUpgradeAction(ComponentVersion version) throws
UpgradeException {
+ ScmUpgradeAction action = upgradeActions.get(version);
+ if (action == null) {
+ return;
+ }
+ try {
+ action.execute(upgradeActionArg);
+ } catch (Exception e) {
+ logAndThrow(e, "SCM upgrade action for version " + version + " failed.",
+ UpgradeException.ResultCodes.FINALIZE_UPGRADE_ACTION_FAILED);
+ }
+ }
+
+ @Override
+ protected ComponentVersion computeApparentVersion(int serializedVersion)
throws IOException {
+ return
HDDSVersionUtils.deserializedPersistedApparentVersion(serializedVersion);
+ }
+}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/upgrade/ScmUpgradeAction.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/upgrade/ScmUpgradeAction.java
index 25fa5d3e9db..47cc02ed7ba 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/upgrade/ScmUpgradeAction.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/upgrade/ScmUpgradeAction.java
@@ -17,12 +17,12 @@
package org.apache.hadoop.hdds.upgrade;
-import org.apache.hadoop.hdds.scm.server.upgrade.SCMUpgradeFinalizationContext;
+import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
import org.apache.hadoop.ozone.upgrade.UpgradeAction;
/**
* Storage Container Manager Upgrade Action interface. An upgrade action is an
operation that
* needs to be executed during finalization.
*/
-public interface ScmUpgradeAction extends
UpgradeAction<SCMUpgradeFinalizationContext> {
+public interface ScmUpgradeAction extends
UpgradeAction<OzoneStorageContainerManager> {
}
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/upgrade/TestScmVersionManager.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/upgrade/TestScmVersionManager.java
new file mode 100644
index 00000000000..c112217f80e
--- /dev/null
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/upgrade/TestScmVersionManager.java
@@ -0,0 +1,224 @@
+/*
+ * 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.hdds.scm.server.upgrade;
+
+import static
org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature.DATANODE_SCHEMA_V2;
+import static
org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT;
+import static org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature.INITIAL_VERSION;
+import static
org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature.STORAGE_SPACE_DISTRIBUTION;
+import static
org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature.WITNESSED_CONTAINER_DB_PROTO_VALUE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+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 java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import org.apache.hadoop.hdds.ComponentVersion;
+import org.apache.hadoop.hdds.HDDSVersion;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.scm.ScmConfigKeys;
+import org.apache.hadoop.hdds.scm.server.SCMStorageConfig;
+import org.apache.hadoop.hdds.scm.server.StorageContainerManager;
+import org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature;
+import org.apache.hadoop.hdds.upgrade.ScmUpgradeAction;
+import org.apache.hadoop.hdds.upgrade.ScmUpgradeActionProvider;
+import org.apache.hadoop.ozone.upgrade.AbstractComponentVersionManagerTest;
+import org.apache.hadoop.ozone.upgrade.ComponentUpgradeActionProvider;
+import org.apache.hadoop.ozone.upgrade.ComponentVersionManager;
+import org.apache.hadoop.ozone.upgrade.UpgradeException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.provider.Arguments;
+
+/**
+ * Tests for {@link ScmVersionManager} using on-disk {@link SCMStorageConfig}
+ * under a JUnit temp directory.
+ */
+class TestScmVersionManager extends AbstractComponentVersionManagerTest {
+
+ private OzoneConfiguration conf;
+
+ @TempDir
+ private Path tempDir;
+
+ private static final List<ComponentVersion> ALL_VERSIONS;
+
+ static {
+ ALL_VERSIONS = new ArrayList<>(Arrays.asList(HDDSLayoutFeature.values()));
+ for (HDDSVersion version : HDDSVersion.values()) {
+ // Add all defined versions after and including ZDU to get the complete
version list.
+ if (HDDSVersion.ZDU.isSupportedBy(version) && version !=
HDDSVersion.UNKNOWN_VERSION) {
+ ALL_VERSIONS.add(version);
+ }
+ }
+ }
+
+ @BeforeEach
+ public void init() {
+ conf = new OzoneConfiguration();
+ }
+
+ public static Stream<Arguments> preFinalizedVersionArgs() {
+ return ALL_VERSIONS.stream()
+ .limit(ALL_VERSIONS.size() - 1)
+ .map(org.junit.jupiter.params.provider.Arguments::of);
+ }
+
+ @Override
+ protected ComponentVersionManager createManager(int
serializedApparentVersion) throws IOException {
+ return createManager(serializedApparentVersion, HashMap::new);
+ }
+
+ private ScmVersionManager createManager(int serializedApparentVersion,
+ ComponentUpgradeActionProvider<ScmUpgradeAction> actions) throws
IOException {
+ SCMStorageConfig storage = newScmStorage(serializedApparentVersion);
+ StorageContainerManager context = mock(StorageContainerManager.class);
+ return new ScmVersionManager(storage, context, actions);
+ }
+
+ private SCMStorageConfig newScmStorage(int apparentVersion) throws
IOException {
+ Path storageRoot = Files.createTempDirectory(tempDir,
"scm-version-manager-");
+ conf.set(ScmConfigKeys.OZONE_SCM_DB_DIRS, storageRoot.toString());
+ SCMStorageConfig storage = new SCMStorageConfig(conf);
+ storage.setScmId("test-scm");
+ storage.setApparentVersion(apparentVersion);
+ storage.initialize();
+ return storage;
+ }
+
+ @Override
+ protected List<ComponentVersion> allVersionsInOrder() {
+ return ALL_VERSIONS;
+ }
+
+ @Override
+ protected ComponentVersion expectedSoftwareVersion() {
+ return HDDSVersion.SOFTWARE_VERSION;
+ }
+
+ @Override
+ @Test
+ public void testClasspathScanDiscoversUpgradeActions() throws Exception {
+ try (ScmVersionManager versionManager =
createManager(INITIAL_VERSION.serialize(),
+ new ScmUpgradeActionProvider())) {
+ assertTrue(versionManager.needsFinalization());
+ ScmUpgradeAction upgradeAction =
versionManager.getUpgradeActionsForTesting().get(DATANODE_SCHEMA_V2);
+ assertInstanceOf(ScmOnFinalizeActionForDatanodeSchemaV2.class,
upgradeAction);
+ }
+
+ try (ScmVersionManager versionManager =
createManager(HDDSVersion.SOFTWARE_VERSION.serialize(),
+ new ScmUpgradeActionProvider())) {
+ assertFalse(versionManager.needsFinalization());
+ ScmUpgradeAction upgradeAction =
versionManager.getUpgradeActionsForTesting().get(DATANODE_SCHEMA_V2);
+ assertInstanceOf(ScmOnFinalizeActionForDatanodeSchemaV2.class,
upgradeAction);
+ }
+ }
+
+ @Override
+ @Test
+ public void testFinalizeRunsSuppliedUpgradeAction() throws Exception {
+ ScmUpgradeAction mockECAction = mock(ScmUpgradeAction.class);
+ ScmUpgradeAction mockZDUAction = mock(ScmUpgradeAction.class);
+
+ ComponentUpgradeActionProvider<ScmUpgradeAction> provider = () -> {
+ Map<ComponentVersion, ScmUpgradeAction> m = new HashMap<>();
+ m.put(ERASURE_CODED_STORAGE_SUPPORT, mockECAction);
+ m.put(HDDSVersion.ZDU, mockZDUAction);
+ return m;
+ };
+
+ try (ScmVersionManager versionManager =
createManager(ERASURE_CODED_STORAGE_SUPPORT.serialize(), provider)) {
+ versionManager.finalizeUpgrade();
+ assertEquals(HDDSVersion.SOFTWARE_VERSION,
versionManager.getApparentVersion());
+
+ // Apparent version is already EC; finalization runs actions for later
versions only, not for EC itself.
+ verify(mockECAction, never()).execute(any());
+ verify(mockZDUAction, atLeastOnce()).execute(any());
+ assertScmApparentVersionOnDisk(conf,
HDDSVersion.SOFTWARE_VERSION.serialize());
+ }
+ }
+
+ @Override
+ @Test
+ public void testUpgradeActionFailureAbortsFinalize() throws Exception {
+ ComponentUpgradeActionProvider<ScmUpgradeAction> provider = () -> {
+ Map<ComponentVersion, ScmUpgradeAction> m = new HashMap<>();
+ m.put(STORAGE_SPACE_DISTRIBUTION, o -> {
+ throw new IOException("expected test failure");
+ });
+ return m;
+ };
+
+ try (ScmVersionManager versionManager =
+ createManager(WITNESSED_CONTAINER_DB_PROTO_VALUE.serialize(),
provider)) {
+ UpgradeException thrown = assertThrows(UpgradeException.class,
versionManager::finalizeUpgrade);
+
assertEquals(UpgradeException.ResultCodes.FINALIZE_UPGRADE_ACTION_FAILED,
thrown.getResult());
+ // WITNESSED_CONTAINER_DB_PROTO_VALUE is the version before
STORAGE_SPACE_DISTRIBUTION, which has failed.
+ assertEquals(WITNESSED_CONTAINER_DB_PROTO_VALUE,
versionManager.getApparentVersion());
+ assertScmApparentVersionOnDisk(conf,
WITNESSED_CONTAINER_DB_PROTO_VALUE.serialize());
+ }
+ }
+
+ @Override
+ @Test
+ public void testPersistFailureRollsBack() throws Exception {
+ SCMStorageConfig storage = mock(SCMStorageConfig.class);
+ AtomicInteger persistedApparentVersion = new
AtomicInteger(INITIAL_VERSION.serialize());
+ when(storage.getApparentVersion()).thenAnswer(invocation ->
persistedApparentVersion.get());
+ doAnswer(invocation -> {
+ persistedApparentVersion.set(invocation.getArgument(0));
+ return null;
+ }).when(storage).setApparentVersion(anyInt());
+ doThrow(new IOException("persist
failed")).when(storage).persistCurrentState();
+
+ StorageContainerManager context = mock(StorageContainerManager.class);
+ try (ScmVersionManager versionManager = new ScmVersionManager(storage,
context, HashMap::new)) {
+ assertEquals(INITIAL_VERSION, versionManager.getApparentVersion());
+ UpgradeException thrown = assertThrows(UpgradeException.class,
versionManager::finalizeUpgrade);
+
assertEquals(UpgradeException.ResultCodes.APPARENT_VERSION_UPDATE_FAILED,
thrown.getResult());
+ assertEquals(INITIAL_VERSION, versionManager.getApparentVersion());
+ assertEquals(INITIAL_VERSION.serialize(), storage.getApparentVersion());
+ }
+ }
+
+ private static void assertScmApparentVersionOnDisk(OzoneConfiguration conf,
int expected)
+ throws IOException {
+ SCMStorageConfig reloaded = new SCMStorageConfig(conf);
+ assertEquals(expected, reloaded.getApparentVersion());
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index b17eed0bbe3..04336f659db 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -954,7 +954,7 @@ private void instantiateServices(boolean withNewSnapshot)
throws IOException {
OmMetadataManagerImpl metadataManagerImpl =
new OmMetadataManagerImpl(configuration, this);
this.metadataManager = metadataManagerImpl;
- versionManager.validateDBVersion(metadataManager);
+ versionManager.validateDBVersion(metadataManager.getMetaTable());
LOG.info("S3 Multi-Tenancy is {}",
isS3MultiTenancyEnabled ? "enabled" : "disabled");
if (isS3MultiTenancyEnabled) {
@@ -1041,7 +1041,7 @@ public void close() {
updateActiveSnapshotMetrics();
if (withNewSnapshot) {
- versionManager.finalizeFromSnapshotIfRequired(metadataManager);
+
versionManager.finalizeFromSnapshotIfRequired(metadataManager.getMetaTable());
instantiatePrepareStateAfterSnapshot();
} else {
// Prepare state depends on the transaction ID of metadataManager after a
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMVersionManager.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMVersionManager.java
index fffc76f5322..4d6547792c0 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMVersionManager.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/OMVersionManager.java
@@ -17,28 +17,21 @@
package org.apache.hadoop.ozone.om.upgrade;
-import static org.apache.hadoop.ozone.OzoneConsts.APPARENT_VERSION_KEY;
-
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.util.Map;
import org.apache.hadoop.hdds.ComponentVersion;
import org.apache.hadoop.ozone.OzoneManagerVersion;
-import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.OMStorage;
import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.upgrade.ComponentUpgradeActionProvider;
-import org.apache.hadoop.ozone.upgrade.ComponentVersionManager;
+import org.apache.hadoop.ozone.upgrade.RatisBasedVersionManager;
import org.apache.hadoop.ozone.upgrade.UpgradeException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Component version manager for Ozone Manager.
*/
-public class OMVersionManager extends ComponentVersionManager {
-
- private static final Logger LOG =
LoggerFactory.getLogger(OMVersionManager.class);
+public class OMVersionManager extends RatisBasedVersionManager {
private final Map<ComponentVersion, OmUpgradeAction> upgradeActions;
@@ -53,33 +46,11 @@ public OMVersionManager(OMStorage storage, OzoneManager
upgradeActionArg) throws
@VisibleForTesting
public OMVersionManager(OMStorage storage, OzoneManager upgradeActionArg,
ComponentUpgradeActionProvider<OmUpgradeAction> upgradeActionProvider)
throws IOException {
- super(storage, computeApparentVersion(storage.getApparentVersion()),
OzoneManagerVersion.SOFTWARE_VERSION);
+ super(storage,
computeApparentVersionInternal(storage.getApparentVersion()),
OzoneManagerVersion.SOFTWARE_VERSION);
this.upgradeActionArg = upgradeActionArg;
upgradeActions = upgradeActionProvider.load();
}
- public void validateDBVersion(OMMetadataManager metadataManager) throws
IOException {
- ComponentVersion dbVersion = getApparentVersionInDB(metadataManager);
- ComponentVersion apparentVersion = getApparentVersion();
-
- if (!apparentVersion.equals(dbVersion)) {
- LOG.info("Version file has different apparent version ({}) than OM DB
({}). That is expected if this "
- + "OM has never been finalized to a newer version.",
apparentVersion, dbVersion);
- }
- }
-
- public void finalizeFromSnapshotIfRequired(OMMetadataManager
metadataManager) throws IOException {
- ComponentVersion apparentVersionInDB =
getApparentVersionInDB(metadataManager);
- if (apparentVersionInDB != null && !isAllowed(apparentVersionInDB)) {
- LOG.info("New OM snapshot received with higher apparent version {}. "
- + "Attempting to finalize current OM to that version.",
apparentVersionInDB);
- finalizeUpgrade();
- // Update the apparent version in the DB to match the VERSION file.
- // When finalization is not done with a snapshot, this DB value is
updated by OMFinalizeUpgradeRequest.
- metadataManager.getMetaTable().put(APPARENT_VERSION_KEY,
String.valueOf(getApparentVersion().serialize()));
- }
- }
-
@VisibleForTesting
public Map<ComponentVersion, OmUpgradeAction> getUpgradeActionsForTesting() {
return upgradeActions;
@@ -99,9 +70,9 @@ protected void runUpgradeAction(ComponentVersion
componentVersion) throws Upgrad
}
}
- private static ComponentVersion getApparentVersionInDB(OMMetadataManager
metadataManager) throws IOException {
- String apparentVersion =
metadataManager.getMetaTable().get(APPARENT_VERSION_KEY);
- return (apparentVersion == null) ? null :
computeApparentVersion(Integer.parseInt(apparentVersion));
+ @Override
+ protected ComponentVersion computeApparentVersion(int
serializedApparentVersion) throws IOException {
+ return computeApparentVersionInternal(serializedApparentVersion);
}
/**
@@ -113,7 +84,7 @@ private static ComponentVersion
getApparentVersionInDB(OMMetadataManager metadat
* the gap between the largest {@link OMLayoutFeature} and ZDU are not valid
legacy layout values; startup fails with
* the persisted integer in the exception message.
*/
- private static ComponentVersion computeApparentVersion(int
serializedApparentVersion) throws IOException {
+ private static ComponentVersion computeApparentVersionInternal(int
serializedApparentVersion) throws IOException {
if (serializedApparentVersion >= OzoneManagerVersion.ZDU.serialize()) {
OzoneManagerVersion fromOm =
OzoneManagerVersion.deserialize(serializedApparentVersion);
if (fromOm != OzoneManagerVersion.UNKNOWN_VERSION) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]