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 cfaf4bb60a8f..41e6bf962a7e 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 @@ -48,8 +48,7 @@ public class OMDBUpdatesHandler extends ManagedWriteBatch.Handler { private Map tablesNames; private OMMetadataManager omMetadataManager; private List omdbUpdateEvents = new ArrayList<>(); - private Map omdbLatestUpdateEvents - = new HashMap<>(); + private Map> omdbLatestUpdateEvents = new HashMap<>(); private OMDBDefinition omdbDefinition; private OmUpdateEventValidator omUpdateEventValidator; @@ -112,6 +111,10 @@ private void processEvent(int cfIndex, byte[] keyBytes, byte[] final Object key = cf.getKeyCodec().fromPersistedFormat(keyBytes); builder.setKey(key); + // Initialize table-specific event map if it does not exist + omdbLatestUpdateEvents.putIfAbsent(tableName, new HashMap<>()); + Map tableEventsMap = omdbLatestUpdateEvents.get(tableName); + // Handle the event based on its type: // - PUT with a new key: Insert the new value. // - PUT with an existing key: Update the existing value. @@ -120,7 +123,7 @@ private void processEvent(int cfIndex, byte[] keyBytes, byte[] // necessary. Table table = omMetadataManager.getTable(tableName); - OMDBUpdateEvent latestEvent = omdbLatestUpdateEvents.get(key); + OMDBUpdateEvent latestEvent = tableEventsMap.get(key); Object oldValue; if (latestEvent != null) { oldValue = latestEvent.getValue(); @@ -184,7 +187,7 @@ private void processEvent(int cfIndex, byte[] keyBytes, byte[] "action = %s", tableName, action)); } omdbUpdateEvents.add(event); - omdbLatestUpdateEvents.put(key, event); + tableEventsMap.put(key, event); } else { // Log and ignore events if key or value types are undetermined. if (LOG.isWarnEnabled()) { diff --git a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOMDBUpdatesHandler.java b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOMDBUpdatesHandler.java index 9676af015747..3831f03bfd89 100644 --- a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOMDBUpdatesHandler.java +++ b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOMDBUpdatesHandler.java @@ -42,6 +42,8 @@ import org.apache.hadoop.ozone.om.OMMetadataManager; import org.apache.hadoop.ozone.om.OmMetadataManagerImpl; import org.apache.hadoop.ozone.om.codec.OMDBDefinition; +import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; +import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo; import org.apache.hadoop.ozone.om.helpers.BucketLayout; import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; import org.apache.hadoop.ozone.om.helpers.OmKeyInfo; @@ -286,6 +288,71 @@ public void testOperateOnSameEntry() throws Exception { ((OmKeyInfo)keyPut2.getOldValue()).getKeyName()); } + /** + * Test to verify that events with duplicate keys in different tables + * (FileTable and DirectoryTable) are handled correctly without causing + * ClassCastException or event conflicts. + * + * This test simulates creating a file, deleting the file, and then creating + * a directory with the same name under the same parent ID in different tables. + * It ensures that the events are correctly processed and stored in the + * `omdbLatestUpdateEvents` map without causing any type mismatches or + * exceptions. + * + * @throws Exception if any error occurs during the test execution. + */ + @Test + public void testEventsHavingDuplicateRocksDBKey() throws Exception { + // Step 1: Create a file with the name "sameName" in the fileTable + OmKeyInfo fileKeyInfo = getOmKeyInfo("sampleVol", "bucketOne", "sameName"); + omMetadataManager.getFileTable().put("/sampleVol/bucketOne/parentId/sameName", fileKeyInfo); + + // Step 2: Delete the file by adding its information to the deletedTable + RepeatedOmKeyInfo repeatedKeyInfo = new RepeatedOmKeyInfo(fileKeyInfo); + omMetadataManager.getDeletedTable().put("/sampleVol/bucketOne/parentId/sameName", repeatedKeyInfo); + + // Step 3: Create a directory with the same name "sameName" in the directoryTable + OmDirectoryInfo dirInfo = OmDirectoryInfo.newBuilder() + .setName("sameName") + .setParentObjectID(fileKeyInfo.getParentObjectID()) + .setObjectID(fileKeyInfo.getObjectID()) + .setCreationTime(System.currentTimeMillis()) + .setModificationTime(System.currentTimeMillis()) + .build(); + omMetadataManager.getDirectoryTable().put("/sampleVol/bucketOne/parentId/sameName", dirInfo); + + // Capture the events from the OM Metadata Manager + List writeBatches = getBytesFromOmMetaManager(0); + OMDBUpdatesHandler omdbUpdatesHandler = captureEvents(writeBatches); + + // Retrieve the captured events and assert the correct number of events + List events = omdbUpdatesHandler.getEvents(); + // Verify no events were discarded + assertEquals(3, events.size()); + + // Validate the file creation event + OMDBUpdateEvent filePutEvent = events.get(0); + assertEquals(PUT, filePutEvent.getAction()); + assertEquals("/sampleVol/bucketOne/parentId/sameName", filePutEvent.getKey()); + assertEquals("sameName", ((OmKeyInfo) filePutEvent.getValue()).getKeyName()); + assertNull(filePutEvent.getOldValue()); + + // Validate the file deletion event + OMDBUpdateEvent fileDeleteEvent = events.get(1); + assertEquals(PUT, fileDeleteEvent.getAction()); + assertEquals("/sampleVol/bucketOne/parentId/sameName", fileDeleteEvent.getKey()); + assertEquals("sameName", + ((RepeatedOmKeyInfo) fileDeleteEvent.getValue()).getOmKeyInfoList().get(0).getKeyName()); + + // Validate the directory creation event + OMDBUpdateEvent dirPutEvent = events.get(2); + assertEquals(PUT, dirPutEvent.getAction()); + assertEquals("/sampleVol/bucketOne/parentId/sameName", dirPutEvent.getKey()); + assertEquals("sameName", ((OmDirectoryInfo) dirPutEvent.getValue()).getName()); + // There will be no old value as the key was not present in the directoryTable before + assertNull(dirPutEvent.getOldValue()); + } + @Test public void testGetKeyType() throws IOException { final String keyTable = omMetadataManager