This is an automated email from the ASF dual-hosted git repository.

weichiu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new 58434d2176 HDDS-8310. Recon goes down with RepeatedOmKeyInfo cannot be 
cast to OmKeyInfo (#5043)
58434d2176 is described below

commit 58434d2176ce23759526c1d9201c966cfdad205e
Author: Arafat2198 <[email protected]>
AuthorDate: Thu Jul 13 21:26:49 2023 +0530

    HDDS-8310. Recon goes down with RepeatedOmKeyInfo cannot be cast to 
OmKeyInfo (#5043)
---
 .../ozone/recon/tasks/OMDBUpdatesHandler.java      |  20 +++
 .../ozone/recon/tasks/OmUpdateEventValidator.java  |  92 +++++++++++++
 .../recon/tasks/TestContainerKeyMapperTask.java    |   2 +
 .../recon/tasks/TestOmUpdateEventValidator.java    | 145 +++++++++++++++++++++
 4 files changed, 259 insertions(+)

diff --git 
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OMDBUpdatesHandler.java
 
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OMDBUpdatesHandler.java
index ff17939010..944ae32244 100644
--- 
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OMDBUpdatesHandler.java
+++ 
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OMDBUpdatesHandler.java
@@ -51,11 +51,13 @@ public class OMDBUpdatesHandler extends 
ManagedWriteBatch.Handler {
   private Map<Object, OMDBUpdateEvent> omdbLatestUpdateEvents
       = new HashMap<>();
   private OMDBDefinition omdbDefinition;
+  private OmUpdateEventValidator omUpdateEventValidator;
 
   public OMDBUpdatesHandler(OMMetadataManager metadataManager) {
     omMetadataManager = metadataManager;
     tablesNames = metadataManager.getStore().getTableNames();
     omdbDefinition = new OMDBDefinition();
+    omUpdateEventValidator = new OmUpdateEventValidator(omdbDefinition);
   }
 
   @Override
@@ -127,16 +129,34 @@ public class OMDBUpdatesHandler extends 
ManagedWriteBatch.Handler {
 
       if (action == PUT) {
         final Object value = 
cf.getValueCodec().fromPersistedFormat(valueBytes);
+
+        // If the updated value is not valid for this event, we skip it.
+        if (!omUpdateEventValidator.isValidEvent(tableName, value, key,
+            action)) {
+          return;
+        }
+
         builder.setValue(value);
         // If a PUT operation happens on an existing Key, it is tagged
         // as an "UPDATE" event.
         if (oldValue != null) {
+
+          // If the oldValue is not valid for this event, we skip it.
+          if (!omUpdateEventValidator.isValidEvent(tableName, oldValue, key,
+              action)) {
+            return;
+          }
+
           builder.setOldValue(oldValue);
           if (latestEvent == null || latestEvent.getAction() != DELETE) {
             builder.setAction(UPDATE);
           }
         }
       } else if (action.equals(DELETE)) {
+        if (oldValue != null && !omUpdateEventValidator.isValidEvent(tableName,
+            oldValue, key, action)) {
+          return;
+        }
         // When you delete a Key, we add the old value to the event so that
         // a downstream task can use it.
         builder.setValue(oldValue);
diff --git 
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OmUpdateEventValidator.java
 
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OmUpdateEventValidator.java
new file mode 100644
index 0000000000..3c7ce844e9
--- /dev/null
+++ 
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OmUpdateEventValidator.java
@@ -0,0 +1,92 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.tasks;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.hadoop.ozone.om.codec.OMDBDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+/**
+ * OmUpdateEventValidator is a utility class for validating OMDBUpdateEvents
+ * It can be further extended to different types of validations.
+ */
+public class OmUpdateEventValidator {
+
+  private static Logger log =
+      LoggerFactory.getLogger(OmUpdateEventValidator.class);
+  private OMDBDefinition omdbDefinition;
+
+  public OmUpdateEventValidator(OMDBDefinition omdbDefinition) {
+    this.omdbDefinition = omdbDefinition;
+  }
+
+  /**
+   * Validates the OMDBUpdateEvent based on the expected value type for a
+   * given table.
+   *
+   * @param tableName        the name of the table associated with the event.
+   * @param actualValueType  the actual value type of the event.
+   * @param keyType          the key type of the event.
+   * @param action           the action performed on the event.
+   * @return true if the event is valid, false otherwise.
+   * @throws IOException if an I/O error occurs during the validation.
+   */
+  public boolean isValidEvent(String tableName,
+                              Object actualValueType,
+                              Object keyType,
+                              OMDBUpdateEvent.OMDBUpdateAction action) {
+
+    String expectedValueTypeString =
+        omdbDefinition.getColumnFamily(tableName).getValueType().getName();
+    String actualValueTypeString = actualValueType.getClass().getName();
+
+    // Check if both objects are of the same type
+    if (expectedValueTypeString.equals(actualValueTypeString)) {
+      // Both objects are of the same type
+      return true;
+    }
+    // Objects are not of the same type
+    logWarn(keyType.toString(), tableName, action.toString(),
+        expectedValueTypeString,
+        actualValueTypeString);
+    return false;
+  }
+
+  /**
+   * Logs an warning message indicating a validation failure.
+   */
+  private void logWarn(String keyType, String tableName, String action,
+                        String expectedValueType, String actualValueType) {
+    String warnMessage = String.format(
+        "Validation failed for keyType: %s, tableName: %s, action: %s, " +
+            "Expected value type: %s, Actual value type: %s",
+        keyType, tableName, action, expectedValueType, actualValueType);
+    // Log the warning message as an WARN level log
+    log.warn(warnMessage);
+  }
+
+  @VisibleForTesting
+  public static void setLogger(Logger logger) {
+    OmUpdateEventValidator.log = logger;
+  }
+
+}
diff --git 
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestContainerKeyMapperTask.java
 
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestContainerKeyMapperTask.java
index eea213a544..32ca5cab48 100644
--- 
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestContainerKeyMapperTask.java
+++ 
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestContainerKeyMapperTask.java
@@ -306,6 +306,7 @@ public class TestContainerKeyMapperTask {
         OMUpdateEventBuilder<String, OmKeyInfo>()
         .setKey(omKey)
         .setAction(OMDBUpdateEvent.OMDBUpdateAction.DELETE)
+        .setValue(omKeyInfo)
         .setTable(omMetadataManager.getKeyTable(getBucketLayout()).getName())
         .build();
 
@@ -448,6 +449,7 @@ public class TestContainerKeyMapperTask {
         OMUpdateEventBuilder<String, OmKeyInfo>()
         .setKey(omKey)
         .setAction(OMDBUpdateEvent.OMDBUpdateAction.DELETE)
+        .setValue(omKeyInfo)
         .setTable(
             omMetadataManager.getKeyTable(BucketLayout.FILE_SYSTEM_OPTIMIZED)
                 .getName())
diff --git 
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOmUpdateEventValidator.java
 
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOmUpdateEventValidator.java
new file mode 100644
index 0000000000..de866de152
--- /dev/null
+++ 
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOmUpdateEventValidator.java
@@ -0,0 +1,145 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.tasks;
+
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.codec.OMDBDefinition;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.OmPrefixInfo;
+import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.util.List;
+
+import static 
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.initializeNewOmMetadataManager;
+import static 
org.apache.hadoop.ozone.recon.tasks.OMDBUpdateEvent.OMDBUpdateAction.PUT;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.times;
+
+/**
+ * Test class for OmUpdateEventValidator.
+ */
+public class TestOmUpdateEventValidator {
+
+  private OmUpdateEventValidator eventValidator;
+  private OMDBDefinition omdbDefinition;
+  private OMMetadataManager omMetadataManager;
+  private Logger logger;
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Before
+  public void setUp() throws IOException {
+    omMetadataManager = initializeNewOmMetadataManager(
+        temporaryFolder.newFolder());
+    omdbDefinition = new OMDBDefinition();
+    eventValidator = new OmUpdateEventValidator(omdbDefinition);
+    // Create a mock logger
+    logger = mock(Logger.class);
+    eventValidator.setLogger(logger);
+  }
+
+  @Test
+  public void testValidEvents() throws IOException {
+    // Validate a valid event for KeyTable
+    assertTrue(eventValidator.isValidEvent(
+        omMetadataManager.getKeyTable(BucketLayout.LEGACY).getName(),
+        mock(OmKeyInfo.class), "key1", PUT));
+
+    // Validate a valid event for BucketTable
+    assertTrue(eventValidator.isValidEvent(
+        omMetadataManager.getBucketTable().getName(),
+        mock(OmBucketInfo.class), "key1", PUT));
+
+    // Validate a valid event for DeletedTable
+    assertTrue(eventValidator.isValidEvent(
+        omMetadataManager.getDeletedTable().getName(),
+        mock(RepeatedOmKeyInfo.class), "key1", PUT));
+
+    // Validate a valid event for Prefix table
+    assertTrue(eventValidator.isValidEvent(
+        omMetadataManager.getPrefixTable().getName(),
+        mock(OmPrefixInfo.class), "key1", PUT));
+
+    // Validate a valid event for SnapshotInfo table
+    assertTrue(eventValidator.isValidEvent(
+        omMetadataManager.getSnapshotInfoTable().getName(),
+        mock(SnapshotInfo.class), "key1", PUT));
+
+    // Verify that no log message is printed
+    verify(logger, Mockito.never()).warn(Mockito.anyString());
+  }
+
+  @Test
+  public void testInvalidEvents() throws IOException {
+
+    // Validate an invalid event for VolumeInfo table
+    assertFalse(eventValidator.isValidEvent(
+        omMetadataManager.getVolumeTable().getName(),
+        "Invalid Object", "key1", PUT));
+
+    // Validate an invalid event for BucketTable
+    assertFalse(eventValidator.isValidEvent(
+        omMetadataManager.getBucketTable().getName(),
+        "Invalid Object", "key1", PUT));
+
+    // Validate an invalid event for DeletedTable
+    assertFalse(eventValidator.isValidEvent(
+        omMetadataManager.getDeletedTable().getName(),
+        "Invalid Object", "key1", PUT));
+
+    // Validate an invalid event for Prefix table
+    assertFalse(eventValidator.isValidEvent(
+        omMetadataManager.getPrefixTable().getName(),
+        "Invalid Object", "key1", PUT));
+
+    // Validate an invalid event for SnapshotInfo table
+    assertFalse(eventValidator.isValidEvent(
+        omMetadataManager.getSnapshotInfoTable().getName(),
+        "Invalid Object", "key1", PUT));
+    // Verify that the logger is called 5 times
+    verifyLogMessage(logger);
+  }
+
+  private void verifyLogMessage(Logger localLogger) {
+    // Use ArgumentCaptor to capture the log message
+    ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+    verify(localLogger, times(5)).warn(captor.capture());
+
+    // Assert that the captured log messages are not empty
+    List<String> logMessages = captor.getAllValues();
+    for (String logMessage : logMessages) {
+      assertFalse("Warning message is empty", logMessage.isEmpty());
+    }
+  }
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to