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

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


The following commit(s) were added to refs/heads/master by this push:
     new 1e37accd4e8 Pipe: Move parsing event logic into PipeProcessorSubtask 
to separate CPU intensive and IO intensive tasks (#11965)
1e37accd4e8 is described below

commit 1e37accd4e80df866dd860c334bcfc01ad889cf1
Author: Zikun Ma <[email protected]>
AuthorDate: Wed Feb 7 13:02:58 2024 +0800

    Pipe: Move parsing event logic into PipeProcessorSubtask to separate CPU 
intensive and IO intensive tasks (#11965)
    
    Co-authored-by: Caideyipi <[email protected]>
    Co-authored-by: Steve Yurong Su <[email protected]>
---
 .../protocol/airgap/IoTDBAirGapConnector.java      | 31 --------
 .../async/IoTDBThriftAsyncClientManager.java       |  2 +-
 .../thrift/async/IoTDBThriftAsyncConnector.java    | 37 ----------
 .../thrift/sync/IoTDBThriftSyncConnector.java      | 34 ---------
 .../protocol/writeback/WriteBackConnector.java     | 20 -----
 .../tablet/PipeInsertNodeTabletInsertionEvent.java |  2 +-
 .../common/tablet/PipeRawTabletInsertionEvent.java |  4 +-
 .../db/pipe/resource/memory/PipeMemoryManager.java | 77 +++++++++++++++++---
 .../resource/memory/PipeTabletMemoryBlock.java     | 64 ++++++++++++++++
 .../pipe/task/connection/PipeEventCollector.java   | 85 ++++++++++++++++++++++
 .../subtask/processor/PipeProcessorSubtask.java    |  5 +-
 .../apache/iotdb/commons/conf/CommonConfig.java    | 11 +++
 .../iotdb/commons/conf/CommonDescriptor.java       |  6 ++
 .../iotdb/commons/pipe/config/PipeConfig.java      |  7 ++
 14 files changed, 245 insertions(+), 140 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBAirGapConnector.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBAirGapConnector.java
index 854f527222c..b018ff0bb80 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBAirGapConnector.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBAirGapConnector.java
@@ -37,7 +37,6 @@ import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransfer
 import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletBinaryReq;
 import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletInsertNodeReq;
 import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletRawReq;
-import org.apache.iotdb.db.pipe.event.EnrichedEvent;
 import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent;
 import 
org.apache.iotdb.db.pipe.event.common.tablet.PipeInsertNodeTabletInsertionEvent;
 import 
org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent;
@@ -256,25 +255,6 @@ public class IoTDBAirGapConnector extends IoTDBConnector {
       return;
     }
 
-    if (((EnrichedEvent) tabletInsertionEvent).shouldParsePatternOrTime()) {
-      if (tabletInsertionEvent instanceof PipeInsertNodeTabletInsertionEvent) {
-        transfer(
-            ((PipeInsertNodeTabletInsertionEvent) tabletInsertionEvent)
-                .parseEventWithPatternOrTime());
-      } else { // tabletInsertionEvent instanceof PipeRawTabletInsertionEvent
-        transfer(
-            ((PipeRawTabletInsertionEvent) 
tabletInsertionEvent).parseEventWithPatternOrTime());
-      }
-      return;
-    } else {
-      // ignore raw tablet event with zero rows
-      if (tabletInsertionEvent instanceof PipeRawTabletInsertionEvent) {
-        if (((PipeRawTabletInsertionEvent) 
tabletInsertionEvent).hasNoNeedParsingAndIsEmpty()) {
-          return;
-        }
-      }
-    }
-
     final int socketIndex = nextSocketIndex();
     final Socket socket = sockets.get(socketIndex);
 
@@ -312,17 +292,6 @@ public class IoTDBAirGapConnector extends IoTDBConnector {
       return;
     }
 
-    if (((EnrichedEvent) tsFileInsertionEvent).shouldParsePatternOrTime()) {
-      try {
-        for (final TabletInsertionEvent event : 
tsFileInsertionEvent.toTabletInsertionEvents()) {
-          transfer(event);
-        }
-      } finally {
-        tsFileInsertionEvent.close();
-      }
-      return;
-    }
-
     final int socketIndex = nextSocketIndex();
     final Socket socket = sockets.get(socketIndex);
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/IoTDBThriftAsyncClientManager.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/IoTDBThriftAsyncClientManager.java
index b70794667dd..59cedeb9d3c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/IoTDBThriftAsyncClientManager.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/IoTDBThriftAsyncClientManager.java
@@ -186,7 +186,7 @@ public class IoTDBThriftAsyncClientManager extends 
IoTDBThriftClientManager {
 
     // Retry to handshake by PipeTransferHandshakeV1Req.
     if (resp.get() != null
-        && resp.get().getStatus().getCode() == 
TSStatusCode.PIPE_VERSION_ERROR.getStatusCode()) {
+        && resp.get().getStatus().getCode() == 
TSStatusCode.PIPE_TYPE_ERROR.getStatusCode()) {
       LOGGER.info(
           "Handshake error by PipeTransferHandshakeV2Req with receiver {}:{} "
               + "retry to handshake by PipeTransferHandshakeV1Req.",
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/IoTDBThriftAsyncConnector.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/IoTDBThriftAsyncConnector.java
index 185699cf3d9..b182e35adcd 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/IoTDBThriftAsyncConnector.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/IoTDBThriftAsyncConnector.java
@@ -152,25 +152,6 @@ public class IoTDBThriftAsyncConnector extends 
IoTDBConnector {
       return;
     }
 
-    if (((EnrichedEvent) tabletInsertionEvent).shouldParsePatternOrTime()) {
-      if (tabletInsertionEvent instanceof PipeInsertNodeTabletInsertionEvent) {
-        transfer(
-            ((PipeInsertNodeTabletInsertionEvent) tabletInsertionEvent)
-                .parseEventWithPatternOrTime());
-      } else { // tabletInsertionEvent instanceof PipeRawTabletInsertionEvent
-        transfer(
-            ((PipeRawTabletInsertionEvent) 
tabletInsertionEvent).parseEventWithPatternOrTime());
-      }
-      return;
-    } else {
-      // ignore raw tablet event with zero rows
-      if (tabletInsertionEvent instanceof PipeRawTabletInsertionEvent) {
-        if (((PipeRawTabletInsertionEvent) 
tabletInsertionEvent).hasNoNeedParsingAndIsEmpty()) {
-          return;
-        }
-      }
-    }
-
     if (isTabletBatchModeEnabled) {
       if (tabletBatchBuilder.onEvent(tabletInsertionEvent)) {
         final PipeTransferTabletBatchEventHandler 
pipeTransferTabletBatchEventHandler =
@@ -259,24 +240,6 @@ public class IoTDBThriftAsyncConnector extends 
IoTDBConnector {
 
     final PipeTsFileInsertionEvent pipeTsFileInsertionEvent =
         (PipeTsFileInsertionEvent) tsFileInsertionEvent;
-    if (!pipeTsFileInsertionEvent.waitForTsFileClose()) {
-      LOGGER.warn(
-          "Pipe skipping temporary TsFile which shouldn't be transferred: {}",
-          pipeTsFileInsertionEvent.getTsFile());
-      return;
-    }
-
-    if ((pipeTsFileInsertionEvent).shouldParsePatternOrTime()) {
-      try {
-        for (final TabletInsertionEvent event :
-            pipeTsFileInsertionEvent.toTabletInsertionEvents()) {
-          transfer(event);
-        }
-      } finally {
-        pipeTsFileInsertionEvent.close();
-      }
-      return;
-    }
 
     // Just in case. To avoid the case that exception occurred when 
constructing the handler.
     if (!pipeTsFileInsertionEvent.getTsFile().exists()) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/sync/IoTDBThriftSyncConnector.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/sync/IoTDBThriftSyncConnector.java
index 91eba79f4c4..0cdb4c6882f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/sync/IoTDBThriftSyncConnector.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/sync/IoTDBThriftSyncConnector.java
@@ -34,7 +34,6 @@ import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransfer
 import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletBinaryReq;
 import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletInsertNodeReq;
 import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletRawReq;
-import org.apache.iotdb.db.pipe.event.EnrichedEvent;
 import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent;
 import 
org.apache.iotdb.db.pipe.event.common.tablet.PipeInsertNodeTabletInsertionEvent;
 import 
org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent;
@@ -196,25 +195,6 @@ public class IoTDBThriftSyncConnector extends 
IoTDBConnector {
       return;
     }
 
-    if (((EnrichedEvent) tabletInsertionEvent).shouldParsePatternOrTime()) {
-      if (tabletInsertionEvent instanceof PipeInsertNodeTabletInsertionEvent) {
-        transfer(
-            ((PipeInsertNodeTabletInsertionEvent) tabletInsertionEvent)
-                .parseEventWithPatternOrTime());
-      } else { // tabletInsertionEvent instanceof PipeRawTabletInsertionEvent
-        transfer(
-            ((PipeRawTabletInsertionEvent) 
tabletInsertionEvent).parseEventWithPatternOrTime());
-      }
-      return;
-    } else {
-      // ignore raw tablet event with zero rows
-      if (tabletInsertionEvent instanceof PipeRawTabletInsertionEvent) {
-        if (((PipeRawTabletInsertionEvent) 
tabletInsertionEvent).hasNoNeedParsingAndIsEmpty()) {
-          return;
-        }
-      }
-    }
-
     try {
       if (isTabletBatchModeEnabled) {
         if (tabletBatchBuilder.onEvent(tabletInsertionEvent)) {
@@ -246,20 +226,6 @@ public class IoTDBThriftSyncConnector extends 
IoTDBConnector {
       return;
     }
 
-    if (!((PipeTsFileInsertionEvent) 
tsFileInsertionEvent).waitForTsFileClose()) {
-      LOGGER.warn(
-          "Pipe skipping temporary TsFile which shouldn't be transferred: {}",
-          ((PipeTsFileInsertionEvent) tsFileInsertionEvent).getTsFile());
-      return;
-    }
-
-    if (((EnrichedEvent) tsFileInsertionEvent).shouldParsePatternOrTime()) {
-      for (final TabletInsertionEvent event : 
tsFileInsertionEvent.toTabletInsertionEvents()) {
-        transfer(event);
-      }
-      return;
-    }
-
     try {
       // in order to commit in order
       if (isTabletBatchModeEnabled && !tabletBatchBuilder.isEmpty()) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/writeback/WriteBackConnector.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/writeback/WriteBackConnector.java
index 40ff1fb6ea3..dface1e770e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/writeback/WriteBackConnector.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/writeback/WriteBackConnector.java
@@ -26,7 +26,6 @@ import org.apache.iotdb.db.pipe.agent.PipeAgent;
 import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletBinaryReq;
 import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletInsertNodeReq;
 import 
org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletRawReq;
-import org.apache.iotdb.db.pipe.event.EnrichedEvent;
 import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent;
 import 
org.apache.iotdb.db.pipe.event.common.tablet.PipeInsertNodeTabletInsertionEvent;
 import 
org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent;
@@ -93,25 +92,6 @@ public class WriteBackConnector implements PipeConnector {
       return;
     }
 
-    if (((EnrichedEvent) tabletInsertionEvent).shouldParsePatternOrTime()) {
-      if (tabletInsertionEvent instanceof PipeInsertNodeTabletInsertionEvent) {
-        transfer(
-            ((PipeInsertNodeTabletInsertionEvent) tabletInsertionEvent)
-                .parseEventWithPatternOrTime());
-      } else { // tabletInsertionEvent instanceof PipeRawTabletInsertionEvent
-        transfer(
-            ((PipeRawTabletInsertionEvent) 
tabletInsertionEvent).parseEventWithPatternOrTime());
-      }
-      return;
-    } else {
-      // ignore raw tablet event with zero rows
-      if (tabletInsertionEvent instanceof PipeRawTabletInsertionEvent) {
-        if (((PipeRawTabletInsertionEvent) 
tabletInsertionEvent).hasNoNeedParsingAndIsEmpty()) {
-          return;
-        }
-      }
-    }
-
     if (tabletInsertionEvent instanceof PipeInsertNodeTabletInsertionEvent) {
       doTransfer((PipeInsertNodeTabletInsertionEvent) tabletInsertionEvent);
     } else {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeInsertNodeTabletInsertionEvent.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeInsertNodeTabletInsertionEvent.java
index 98ab1c7b2ac..4ae1b9ee64d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeInsertNodeTabletInsertionEvent.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeInsertNodeTabletInsertionEvent.java
@@ -240,7 +240,7 @@ public class PipeInsertNodeTabletInsertionEvent extends 
EnrichedEvent
 
   /////////////////////////// parsePatternOrTime ///////////////////////////
 
-  public TabletInsertionEvent parseEventWithPatternOrTime() {
+  public PipeRawTabletInsertionEvent parseEventWithPatternOrTime() {
     return new PipeRawTabletInsertionEvent(
         convertToTablet(), isAligned, pipeName, pipeTaskMeta, this, true);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeRawTabletInsertionEvent.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeRawTabletInsertionEvent.java
index 03df841181c..93fe966409c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeRawTabletInsertionEvent.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeRawTabletInsertionEvent.java
@@ -99,7 +99,7 @@ public class PipeRawTabletInsertionEvent extends 
EnrichedEvent implements Tablet
 
   @Override
   public boolean internallyIncreaseResourceReferenceCount(String 
holderMessage) {
-    allocatedMemoryBlock = PipeResourceManager.memory().forceAllocate(tablet);
+    allocatedMemoryBlock = 
PipeResourceManager.memory().forceAllocateWithRetry(tablet);
     return true;
   }
 
@@ -200,7 +200,7 @@ public class PipeRawTabletInsertionEvent extends 
EnrichedEvent implements Tablet
 
   /////////////////////////// parsePatternOrTime ///////////////////////////
 
-  public TabletInsertionEvent parseEventWithPatternOrTime() {
+  public PipeRawTabletInsertionEvent parseEventWithPatternOrTime() {
     return new PipeRawTabletInsertionEvent(
         convertToTablet(), isAligned, pipeName, pipeTaskMeta, this, 
needToReport);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeMemoryManager.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeMemoryManager.java
index ad4e1951a1e..3f7a3eb2849 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeMemoryManager.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeMemoryManager.java
@@ -57,6 +57,12 @@ public class PipeMemoryManager {
 
   private long usedMemorySizeInBytes;
 
+  // To avoid too much parsed events causing OOM. If total tablet memory size 
exceeds this
+  // threshold, allocations of memory block for tablets will be rejected.
+  private static final double TABLET_MEMORY_REJECT_THRESHOLD =
+      
PipeConfig.getInstance().getPipeDataStructureTabletMemoryBlockAllocationRejectThreshold();
+  private long usedMemorySizeInBytesOfTablets;
+
   private final Set<PipeMemoryBlock> allocatedBlocks = new HashSet<>();
 
   public PipeMemoryManager() {
@@ -69,13 +75,51 @@ public class PipeMemoryManager {
 
   public synchronized PipeMemoryBlock forceAllocate(long sizeInBytes)
       throws PipeRuntimeOutOfMemoryCriticalException {
+    return forceAllocate(sizeInBytes, false);
+  }
+
+  public PipeMemoryBlock forceAllocateWithRetry(Tablet tablet)
+      throws PipeRuntimeOutOfMemoryCriticalException {
+    for (int i = 1; i <= MEMORY_ALLOCATE_MAX_RETRIES; i++) {
+      if ((double) usedMemorySizeInBytesOfTablets / TOTAL_MEMORY_SIZE_IN_BYTES
+          < TABLET_MEMORY_REJECT_THRESHOLD) {
+        break;
+      }
+
+      try {
+        Thread.sleep(MEMORY_ALLOCATE_RETRY_INTERVAL_IN_MS);
+      } catch (InterruptedException ex) {
+        Thread.currentThread().interrupt();
+        LOGGER.warn("forceAllocateWithRetry: interrupted while waiting for 
available memory", ex);
+      }
+    }
+
+    if ((double) usedMemorySizeInBytesOfTablets / TOTAL_MEMORY_SIZE_IN_BYTES
+        >= TABLET_MEMORY_REJECT_THRESHOLD) {
+      throw new PipeRuntimeOutOfMemoryCriticalException(
+          String.format(
+              "forceAllocateForTablet: failed to allocate because there's too 
much memory for tablets, "
+                  + "total memory size %d bytes, used memory for tablet size 
%d bytes,",
+              TOTAL_MEMORY_SIZE_IN_BYTES, usedMemorySizeInBytesOfTablets));
+    }
+
+    synchronized (this) {
+      final PipeMemoryBlock block = 
forceAllocate(calculateTabletSizeInBytes(tablet), true);
+      usedMemorySizeInBytesOfTablets += block.getMemoryUsageInBytes();
+      return block;
+    }
+  }
+
+  private PipeMemoryBlock forceAllocate(long sizeInBytes, boolean isForTablet)
+      throws PipeRuntimeOutOfMemoryCriticalException {
     if (!PIPE_MEMORY_MANAGEMENT_ENABLED) {
+      // No need to consider isForTablet, for memory control is disabled
       return new PipeMemoryBlock(sizeInBytes);
     }
 
     for (int i = 1; i <= MEMORY_ALLOCATE_MAX_RETRIES; i++) {
       if (TOTAL_MEMORY_SIZE_IN_BYTES - usedMemorySizeInBytes >= sizeInBytes) {
-        return registeredMemoryBlock(sizeInBytes);
+        return registerMemoryBlock(sizeInBytes, isForTablet);
       }
 
       try {
@@ -98,11 +142,6 @@ public class PipeMemoryManager {
             sizeInBytes));
   }
 
-  public synchronized PipeMemoryBlock forceAllocate(Tablet tablet)
-      throws PipeRuntimeOutOfMemoryCriticalException {
-    return forceAllocate(calculateTabletSizeInBytes(tablet));
-  }
-
   /**
    * Allocate a memory block for pipe only if memory already used is less than 
specified threshold.
    *
@@ -199,7 +238,7 @@ public class PipeMemoryManager {
     }
 
     if (TOTAL_MEMORY_SIZE_IN_BYTES - usedMemorySizeInBytes >= sizeInBytes) {
-      return registeredMemoryBlock(sizeInBytes);
+      return registerMemoryBlock(sizeInBytes);
     }
 
     long sizeToAllocateInBytes = sizeInBytes;
@@ -214,7 +253,7 @@ public class PipeMemoryManager {
             usedMemorySizeInBytes,
             sizeInBytes,
             sizeToAllocateInBytes);
-        return registeredMemoryBlock(sizeToAllocateInBytes);
+        return registerMemoryBlock(sizeToAllocateInBytes);
       }
 
       sizeToAllocateInBytes =
@@ -233,7 +272,7 @@ public class PipeMemoryManager {
           usedMemorySizeInBytes,
           sizeInBytes,
           sizeToAllocateInBytes);
-      return registeredMemoryBlock(sizeToAllocateInBytes);
+      return registerMemoryBlock(sizeToAllocateInBytes);
     } else {
       LOGGER.warn(
           "tryAllocate: failed to allocate memory, "
@@ -242,7 +281,7 @@ public class PipeMemoryManager {
           TOTAL_MEMORY_SIZE_IN_BYTES,
           usedMemorySizeInBytes,
           sizeInBytes);
-      return registeredMemoryBlock(0);
+      return registerMemoryBlock(0);
     }
   }
 
@@ -254,6 +293,9 @@ public class PipeMemoryManager {
 
     if (TOTAL_MEMORY_SIZE_IN_BYTES - usedMemorySizeInBytes >= 
memoryInBytesNeededToBeAllocated) {
       usedMemorySizeInBytes += memoryInBytesNeededToBeAllocated;
+      if (block instanceof PipeTabletMemoryBlock) {
+        usedMemorySizeInBytesOfTablets += memoryInBytesNeededToBeAllocated;
+      }
       block.setMemoryUsageInBytes(block.getMemoryUsageInBytes() + 
memoryInBytesNeededToBeAllocated);
       return true;
     }
@@ -261,10 +303,15 @@ public class PipeMemoryManager {
     return false;
   }
 
-  private PipeMemoryBlock registeredMemoryBlock(long sizeInBytes) {
+  private PipeMemoryBlock registerMemoryBlock(long sizeInBytes) {
+    return registerMemoryBlock(sizeInBytes, false);
+  }
+
+  private PipeMemoryBlock registerMemoryBlock(long sizeInBytes, boolean 
isForTablet) {
     usedMemorySizeInBytes += sizeInBytes;
 
-    final PipeMemoryBlock returnedMemoryBlock = new 
PipeMemoryBlock(sizeInBytes);
+    final PipeMemoryBlock returnedMemoryBlock =
+        isForTablet ? new PipeTabletMemoryBlock(sizeInBytes) : new 
PipeMemoryBlock(sizeInBytes);
     allocatedBlocks.add(returnedMemoryBlock);
     return returnedMemoryBlock;
   }
@@ -300,6 +347,9 @@ public class PipeMemoryManager {
 
     allocatedBlocks.remove(block);
     usedMemorySizeInBytes -= block.getMemoryUsageInBytes();
+    if (block instanceof PipeTabletMemoryBlock) {
+      usedMemorySizeInBytesOfTablets -= block.getMemoryUsageInBytes();
+    }
     block.markAsReleased();
 
     this.notifyAll();
@@ -311,6 +361,9 @@ public class PipeMemoryManager {
     }
 
     usedMemorySizeInBytes -= sizeInBytes;
+    if (block instanceof PipeTabletMemoryBlock) {
+      usedMemorySizeInBytesOfTablets -= sizeInBytes;
+    }
     block.setMemoryUsageInBytes(block.getMemoryUsageInBytes() - sizeInBytes);
 
     this.notifyAll();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeTabletMemoryBlock.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeTabletMemoryBlock.java
new file mode 100644
index 00000000000..ed23215874a
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeTabletMemoryBlock.java
@@ -0,0 +1,64 @@
+/*
+ * 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.iotdb.db.pipe.resource.memory;
+
+import java.util.function.BiConsumer;
+import java.util.function.LongUnaryOperator;
+
+public class PipeTabletMemoryBlock extends PipeMemoryBlock {
+
+  public PipeTabletMemoryBlock(long memoryUsageInBytes) {
+    super(memoryUsageInBytes);
+  }
+
+  @Override
+  boolean shrink() {
+    return false;
+  }
+
+  @Override
+  boolean expand() {
+    return false;
+  }
+
+  @Override
+  public PipeMemoryBlock setShrinkMethod(LongUnaryOperator shrinkMethod) {
+    throw new UnsupportedOperationException(
+        "Shrink method is not supported in PipeTabletMemoryBlock");
+  }
+
+  @Override
+  public PipeMemoryBlock setShrinkCallback(BiConsumer<Long, Long> 
shrinkCallback) {
+    throw new UnsupportedOperationException(
+        "Shrink callback is not supported in PipeTabletMemoryBlock");
+  }
+
+  @Override
+  public PipeMemoryBlock setExpandMethod(LongUnaryOperator extendMethod) {
+    throw new UnsupportedOperationException(
+        "Expand method is not supported in PipeTabletMemoryBlock");
+  }
+
+  @Override
+  public PipeMemoryBlock setExpandCallback(BiConsumer<Long, Long> 
expandCallback) {
+    throw new UnsupportedOperationException(
+        "Expand callback is not supported in PipeTabletMemoryBlock");
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/connection/PipeEventCollector.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/connection/PipeEventCollector.java
index 727b976b098..50a91c82648 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/connection/PipeEventCollector.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/connection/PipeEventCollector.java
@@ -22,15 +22,26 @@ package org.apache.iotdb.db.pipe.task.connection;
 import 
org.apache.iotdb.commons.pipe.task.connection.BoundedBlockingPendingQueue;
 import org.apache.iotdb.db.pipe.event.EnrichedEvent;
 import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent;
+import 
org.apache.iotdb.db.pipe.event.common.tablet.PipeInsertNodeTabletInsertionEvent;
+import 
org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent;
+import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent;
 import org.apache.iotdb.db.pipe.progress.committer.PipeEventCommitManager;
 import org.apache.iotdb.pipe.api.collector.EventCollector;
 import org.apache.iotdb.pipe.api.event.Event;
+import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent;
+import org.apache.iotdb.pipe.api.exception.PipeException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.LinkedList;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class PipeEventCollector implements EventCollector, AutoCloseable {
 
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(PipeEventCollector.class);
+
   private final BoundedBlockingPendingQueue<Event> pendingQueue;
 
   private final EnrichedDeque<Event> bufferQueue;
@@ -39,6 +50,8 @@ public class PipeEventCollector implements EventCollector, 
AutoCloseable {
 
   private final AtomicBoolean isClosed = new AtomicBoolean(false);
 
+  private final AtomicInteger collectInvocationCount = new AtomicInteger(0);
+
   public PipeEventCollector(BoundedBlockingPendingQueue<Event> pendingQueue, 
int dataRegionId) {
     this.pendingQueue = pendingQueue;
     this.dataRegionId = dataRegionId;
@@ -47,6 +60,68 @@ public class PipeEventCollector implements EventCollector, 
AutoCloseable {
 
   @Override
   public synchronized void collect(Event event) {
+    try {
+      if (event instanceof PipeInsertNodeTabletInsertionEvent) {
+        parseAndCollectEvent((PipeInsertNodeTabletInsertionEvent) event);
+      } else if (event instanceof PipeRawTabletInsertionEvent) {
+        parseAndCollectEvent((PipeRawTabletInsertionEvent) event);
+      } else if (event instanceof PipeTsFileInsertionEvent) {
+        parseAndCollectEvent((PipeTsFileInsertionEvent) event);
+      } else {
+        collectEvent(event);
+      }
+    } catch (Exception e) {
+      throw new PipeException("Error occurred when collecting events from 
processor.", e);
+    }
+  }
+
+  private void parseAndCollectEvent(PipeInsertNodeTabletInsertionEvent 
sourceEvent) {
+    if (sourceEvent.shouldParsePatternOrTime()) {
+      final PipeRawTabletInsertionEvent parsedEvent = 
sourceEvent.parseEventWithPatternOrTime();
+      if (!parsedEvent.hasNoNeedParsingAndIsEmpty()) {
+        collectEvent(parsedEvent);
+      }
+    } else {
+      collectEvent(sourceEvent);
+    }
+  }
+
+  private void parseAndCollectEvent(PipeRawTabletInsertionEvent sourceEvent) {
+    if (sourceEvent.shouldParsePatternOrTime()) {
+      final PipeRawTabletInsertionEvent parsedEvent = 
sourceEvent.parseEventWithPatternOrTime();
+      if (!parsedEvent.hasNoNeedParsingAndIsEmpty()) {
+        collectEvent(parsedEvent);
+      }
+    } else {
+      collectEvent(sourceEvent);
+    }
+  }
+
+  private void parseAndCollectEvent(PipeTsFileInsertionEvent sourceEvent) 
throws Exception {
+    if (!sourceEvent.waitForTsFileClose()) {
+      LOGGER.warn(
+          "Pipe skipping temporary TsFile which shouldn't be transferred: {}",
+          sourceEvent.getTsFile());
+      return;
+    }
+
+    if (!sourceEvent.shouldParsePatternOrTime()) {
+      collectEvent(sourceEvent);
+      return;
+    }
+
+    try {
+      for (final TabletInsertionEvent parsedEvent : 
sourceEvent.toTabletInsertionEvents()) {
+        collectEvent(parsedEvent);
+      }
+    } finally {
+      sourceEvent.close();
+    }
+  }
+
+  private void collectEvent(Event event) {
+    collectInvocationCount.incrementAndGet();
+
     if (event instanceof EnrichedEvent) {
       ((EnrichedEvent) 
event).increaseReferenceCount(PipeEventCollector.class.getName());
 
@@ -82,6 +157,14 @@ public class PipeEventCollector implements EventCollector, 
AutoCloseable {
     }
   }
 
+  public void resetCollectInvocationCount() {
+    collectInvocationCount.set(0);
+  }
+
+  public boolean hasNoCollectInvocationAfterReset() {
+    return collectInvocationCount.get() == 0;
+  }
+
   public boolean isBufferQueueEmpty() {
     return bufferQueue.isEmpty();
   }
@@ -118,6 +201,8 @@ public class PipeEventCollector implements EventCollector, 
AutoCloseable {
     bufferQueue.clear();
   }
 
+  //////////////////////////// APIs provided for metric framework 
////////////////////////////
+
   public int getTabletInsertionEventCount() {
     return bufferQueue.getTabletInsertionEventCount();
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtask.java
index 6ab50749760..2d3006b4166 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtask.java
@@ -104,6 +104,7 @@ public class PipeProcessorSubtask extends 
PipeDataNodeSubtask {
             : UserDefinedEnrichedEvent.maybeOf(inputEventSupplier.supply());
     // Record the last event for retry when exception occurs
     setLastEvent(event);
+
     if (
     // Though there is no event to process, there may still be some buffered 
events
     // in the outputEventCollector. Return true if there are still buffered 
events,
@@ -115,6 +116,7 @@ public class PipeProcessorSubtask extends 
PipeDataNodeSubtask {
       return outputEventCollector.tryCollectBufferedEvents();
     }
 
+    outputEventCollector.resetCollectInvocationCount();
     try {
       // event can be supplied after the subtask is closed, so we need to 
check isClosed here
       if (!isClosed.get()) {
@@ -136,8 +138,7 @@ public class PipeProcessorSubtask extends 
PipeDataNodeSubtask {
               outputEventCollector);
         }
       }
-
-      releaseLastEvent(true);
+      releaseLastEvent(!isClosed.get() && 
outputEventCollector.hasNoCollectInvocationAfterReset());
     } catch (Exception e) {
       if (!isClosed.get()) {
         throw new PipeException(
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java
index c54a8325685..114f759d759 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java
@@ -151,6 +151,7 @@ public class CommonConfig {
       Math.min(5, Math.max(1, Runtime.getRuntime().availableProcessors() / 2));
 
   private int pipeDataStructureTabletRowSize = 2048;
+  private double pipeDataStructureTabletMemoryBlockAllocationRejectThreshold = 
0.4;
 
   private int pipeSubtaskExecutorBasicCheckPointIntervalByConsumedEventCount = 
10_000;
   private long pipeSubtaskExecutorBasicCheckPointIntervalByTimeDuration = 10 * 
1000L;
@@ -531,6 +532,16 @@ public class CommonConfig {
     this.pipeDataStructureTabletRowSize = pipeDataStructureTabletRowSize;
   }
 
+  public double 
getPipeDataStructureTabletMemoryBlockAllocationRejectThreshold() {
+    return pipeDataStructureTabletMemoryBlockAllocationRejectThreshold;
+  }
+
+  public void setPipeDataStructureTabletMemoryBlockAllocationRejectThreshold(
+      double pipeDataStructureTabletMemoryBlockAllocationRejectThreshold) {
+    this.pipeDataStructureTabletMemoryBlockAllocationRejectThreshold =
+        pipeDataStructureTabletMemoryBlockAllocationRejectThreshold;
+  }
+
   public int getPipeExtractorAssignerDisruptorRingBufferSize() {
     return pipeExtractorAssignerDisruptorRingBufferSize;
   }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
index 43ec8f911b4..f6dfe120db0 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
@@ -258,6 +258,12 @@ public class CommonDescriptor {
             properties.getProperty(
                 "pipe_data_structure_tablet_row_size",
                 String.valueOf(config.getPipeDataStructureTabletRowSize()))));
+    config.setPipeDataStructureTabletMemoryBlockAllocationRejectThreshold(
+        Double.parseDouble(
+            properties.getProperty(
+                
"pipe_data_structure_tablet_memory_block_allocation_reject_threshold",
+                String.valueOf(
+                    
config.getPipeDataStructureTabletMemoryBlockAllocationRejectThreshold()))));
 
     config.setPipeSubtaskExecutorMaxThreadNum(
         Integer.parseInt(
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/PipeConfig.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/PipeConfig.java
index 74a6711a96b..219701f74ee 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/PipeConfig.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/PipeConfig.java
@@ -53,6 +53,10 @@ public class PipeConfig {
     return COMMON_CONFIG.getPipeDataStructureTabletRowSize();
   }
 
+  public double 
getPipeDataStructureTabletMemoryBlockAllocationRejectThreshold() {
+    return 
COMMON_CONFIG.getPipeDataStructureTabletMemoryBlockAllocationRejectThreshold();
+  }
+
   /////////////////////////////// Subtask Executor 
///////////////////////////////
 
   public int getPipeSubtaskExecutorMaxThreadNum() {
@@ -218,6 +222,9 @@ public class PipeConfig {
     LOGGER.info("PipeHardLinkWALEnabled: {}", getPipeHardLinkWALEnabled());
 
     LOGGER.info("PipeDataStructureTabletRowSize: {}", 
getPipeDataStructureTabletRowSize());
+    LOGGER.info(
+        "PipeDataStructureTabletMemoryBlockAllocationRejectThreshold: {}",
+        getPipeDataStructureTabletMemoryBlockAllocationRejectThreshold());
 
     LOGGER.info("PipeSubtaskExecutorMaxThreadNum: {}", 
getPipeSubtaskExecutorMaxThreadNum());
     LOGGER.info(


Reply via email to