Copilot commented on code in PR #18275:
URL: https://github.com/apache/iotdb/pull/18275#discussion_r3629128887


##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeRegionManager.java:
##########
@@ -164,23 +226,122 @@ public TSStatus createDataRegion(TRegionReplicaSet 
regionReplicaSet, String stor
         peers.add(new Peer(dataRegionId, dataNodeLocation.getDataNodeId(), 
endpoint));
       }
       DataRegionConsensusImpl.getInstance().createLocalPeer(dataRegionId, 
peers);
+      dataRegionLockMap.putIfAbsent(dataRegionId, new 
ReentrantReadWriteLock(false));
       tsStatus = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
     } catch (DataRegionException e) {
       LOGGER.error(DataNodeMiscMessages.CREATE_DATA_REGION_FAILED, 
storageGroup, e.getMessage());
       tsStatus = new 
TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
       tsStatus.setMessage(
           String.format(DataNodeMiscMessages.CREATE_DATA_REGION_FAILED_FMT, 
e.getMessage()));
     } catch (ConsensusGroupAlreadyExistException e) {
+      dataRegionLockMap.putIfAbsent(dataRegionId, new 
ReentrantReadWriteLock(false));
       tsStatus = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
       tsStatus.setMessage(
           String.format(DataNodeMiscMessages.DATA_REGION_ALREADY_EXISTS_FMT, 
dataRegionId.getId()));
     } catch (ConsensusException e) {
+      rollbackDataRegionCreation(
+          dataRegionId, localRegionCreated, consensusGroupExisted, 
storageGroup);
       tsStatus = new 
TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
       tsStatus.setMessage(e.getMessage());
+    } catch (RuntimeException | OutOfMemoryError e) {
+      rollbackDataRegionCreation(
+          dataRegionId,
+          localRegionCreated
+              || (!localRegionExisted && 
storageEngine.getDataRegion(dataRegionId) != null),
+          consensusGroupExisted,
+          storageGroup);
+      LOGGER.error(DataNodeMiscMessages.CREATE_DATA_REGION_FAILED, 
storageGroup, e.getMessage());
+      tsStatus = new 
TSStatus(TSStatusCode.CREATE_REGION_ERROR.getStatusCode());
+      tsStatus.setMessage(
+          String.format(DataNodeMiscMessages.CREATE_DATA_REGION_FAILED_FMT, 
e.getMessage()));
+    } finally {
+      creationLock.unlock();
     }
     return tsStatus;
   }
 
+  private ReentrantLock getRegionCreationLock(ConsensusGroupId regionId) {
+    return regionCreationLocks[
+        (regionId.hashCode() & Integer.MAX_VALUE) % 
REGION_CREATION_LOCK_COUNT];
+  }
+
+  /**
+   * Fences delayed create RPCs after a whole RegionGroup starts deletion.
+   *
+   * <p>RegionGroup ids are never reused. The caller acquires the same striped 
lock as creation, so
+   * an already-running creation finishes before deletion starts, while every 
later creation is
+   * rejected even if it came from an old ConfigNode leader.
+   */
+  public void markRegionGroupDeleted(ConsensusGroupId regionId) {
+    final ReentrantLock creationLock = getRegionCreationLock(regionId);
+    creationLock.lock();
+    try {
+      synchronized (deletedRegionGroupFenceLock) {
+        getDeletedRegionGroupSet(regionId).set(regionId.getId());
+      }
+    } finally {
+      creationLock.unlock();
+    }
+  }
+
+  private boolean isRegionGroupDeleted(ConsensusGroupId regionId) {
+    synchronized (deletedRegionGroupFenceLock) {
+      return getDeletedRegionGroupSet(regionId).get(regionId.getId());
+    }
+  }
+
+  private BitSet getDeletedRegionGroupSet(ConsensusGroupId regionId) {
+    return regionId instanceof DataRegionId ? deletedDataRegionGroups : 
deletedSchemaRegionGroups;
+  }
+
+  private void rollbackDataRegionCreation(
+      DataRegionId regionId,
+      boolean localRegionCreated,
+      boolean consensusGroupExisted,
+      String storageGroup) {
+    rollbackConsensusPeer(
+        DataRegionConsensusImpl.getInstance(), regionId, 
consensusGroupExisted, storageGroup);
+    if (localRegionCreated && !consensusGroupExisted) {
+      storageEngine.deleteDataRegion(regionId);
+      dataRegionLockMap.remove(regionId);
+    }
+  }
+
+  private void rollbackSchemaRegionCreation(
+      SchemaRegionId regionId,
+      boolean localRegionCreated,
+      boolean consensusGroupExisted,
+      String storageGroup) {
+    rollbackConsensusPeer(
+        SchemaRegionConsensusImpl.getInstance(), regionId, 
consensusGroupExisted, storageGroup);
+    if (localRegionCreated && !consensusGroupExisted) {
+      try {
+        schemaEngine.deleteSchemaRegion(regionId);
+        schemaRegionLockMap.remove(regionId);
+      } catch (MetadataException e) {
+        LOGGER.error(
+            DataNodeMiscMessages.CREATE_SCHEMA_REGION_FAILED, storageGroup, 
e.getMessage());
+      }
+    }
+  }
+
+  private void rollbackConsensusPeer(
+      org.apache.iotdb.consensus.IConsensus consensus,
+      ConsensusGroupId regionId,
+      boolean consensusGroupExisted,
+      String storageGroup) {
+    if (consensusGroupExisted) {
+      return;
+    }
+    try {
+      if (consensus.getAllConsensusGroupIds().contains(regionId)) {
+        consensus.deleteLocalPeer(regionId);
+      }
+    } catch (ConsensusException | RuntimeException | OutOfMemoryError e) {
+      LOGGER.error(DataNodeMiscMessages.CREATE_DATA_REGION_FAILED, 
storageGroup, e.getMessage());
+    }

Review Comment:
   rollbackConsensusPeer logs DataNodeMiscMessages.CREATE_DATA_REGION_FAILED 
even when rolling back a SchemaRegion consensus peer, which can mislead 
operators during SchemaRegion creation failures. Use the schema-specific 
message when regionId is a SchemaRegionId (or choose based on regionId type).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to