@@ -192,6 +192,7 @@ public class IoTDBDataNodeReceiver extends IoTDBFileReceiver {
192192 private static final PipeConfig PIPE_CONFIG = PipeConfig .getInstance ();
193193
194194 private PipeMemoryBlock allocatedMemoryBlock ;
195+ private final List <PipeMemoryBlock > allocatedSliceMemoryBlocks = new ArrayList <>();
195196 private final Set <String > autoCreatedTreeDatabases = ConcurrentHashMap .newKeySet ();
196197 private final Set <String > conflictedTreeDatabases = ConcurrentHashMap .newKeySet ();
197198
@@ -219,7 +220,7 @@ public synchronized TPipeTransferResp receive(final TPipeTransferReq req) {
219220 if (PipeRequestType .isValidatedRequestType (rawRequestType )) {
220221 final PipeRequestType requestType = PipeRequestType .valueOf (rawRequestType );
221222 if (requestType != PipeRequestType .TRANSFER_SLICE ) {
222- sliceReqHandler . clear ();
223+ clearSliceReqHandler ();
223224 }
224225 switch (requestType ) {
225226 case HANDSHAKE_DATANODE_V1 :
@@ -442,8 +443,18 @@ public synchronized TPipeTransferResp receive(final TPipeTransferReq req) {
442443 }
443444 case TRANSFER_COMPRESSED :
444445 {
446+ long requestedMemorySizeInBytes = 0 ;
445447 try {
446- return receive (PipeTransferCompressedReq .fromTPipeTransferReq (req ));
448+ requestedMemorySizeInBytes =
449+ PipeTransferCompressedReq .getMaxAdditionalDecompressedLengthInBytes (req );
450+ try (final PipeMemoryBlock ignored =
451+ tryAllocateReceiverMemory (requestedMemorySizeInBytes )) {
452+ return receive (PipeTransferCompressedReq .fromTPipeTransferReq (req ));
453+ }
454+ } catch (final PipeRuntimeOutOfMemoryCriticalException e ) {
455+ return new TPipeTransferResp (
456+ getReceiverTemporaryUnavailableStatus (
457+ "decompressing pipe transfer request" , requestedMemorySizeInBytes , e ));
447458 } finally {
448459 PipeDataNodeReceiverMetrics .getInstance ()
449460 .recordTransferCompressedTimer (System .nanoTime () - startTime );
@@ -823,22 +834,96 @@ private String getConfigReceiverId() {
823834 }
824835
825836 private TPipeTransferResp handleTransferSlice (final PipeTransferSliceReq pipeTransferSliceReq ) {
826- final boolean isInorder = sliceReqHandler .receiveSlice (pipeTransferSliceReq );
827- if (!isInorder ) {
837+ final long sliceBodySizeInBytes = getSliceBodySizeInBytes (pipeTransferSliceReq );
838+ long requestedMemorySizeInBytes = sliceBodySizeInBytes ;
839+ String memoryAction = "buffering sliced pipe transfer request" ;
840+ PipeMemoryBlock sliceMemoryBlock = null ;
841+ try {
842+ sliceMemoryBlock = tryAllocateReceiverMemory (sliceBodySizeInBytes );
843+
844+ final boolean isInorder = sliceReqHandler .receiveSlice (pipeTransferSliceReq );
845+ if (!isInorder ) {
846+ closeMemoryBlock (sliceMemoryBlock );
847+ clearSliceReqHandler ();
848+ return new TPipeTransferResp (
849+ RpcUtils .getStatus (
850+ TSStatusCode .PIPE_TRANSFER_SLICE_OUT_OF_ORDER ,
851+ "Slice request is out of order, please check the request sequence." ));
852+ }
853+
854+ allocatedSliceMemoryBlocks .add (sliceMemoryBlock );
855+ sliceMemoryBlock = null ;
856+
857+ if (pipeTransferSliceReq .getSliceIndex () + 1 < pipeTransferSliceReq .getSliceCount ()) {
858+ return new TPipeTransferResp (
859+ RpcUtils .getStatus (
860+ TSStatusCode .SUCCESS_STATUS ,
861+ "Slice received, waiting for more slices to complete the request." ));
862+ }
863+
864+ memoryAction = "assembling sliced pipe transfer request" ;
865+ requestedMemorySizeInBytes = pipeTransferSliceReq .getOriginBodySize ();
866+ try (final PipeMemoryBlock ignored = tryAllocateReceiverMemory (requestedMemorySizeInBytes )) {
867+ final Optional <TPipeTransferReq > req = sliceReqHandler .makeReqIfComplete ();
868+ if (!req .isPresent ()) {
869+ return new TPipeTransferResp (
870+ RpcUtils .getStatus (
871+ TSStatusCode .SUCCESS_STATUS ,
872+ "Slice received, waiting for more slices to complete the request." ));
873+ }
874+ clearSliceReqHandler ();
875+ return receive (req .get ());
876+ }
877+ } catch (final PipeRuntimeOutOfMemoryCriticalException e ) {
878+ closeMemoryBlock (sliceMemoryBlock );
879+ clearSliceReqHandler ();
828880 return new TPipeTransferResp (
829- RpcUtils .getStatus (
830- TSStatusCode .PIPE_TRANSFER_SLICE_OUT_OF_ORDER ,
831- "Slice request is out of order, please check the request sequence." ));
881+ getReceiverTemporaryUnavailableStatus (memoryAction , requestedMemorySizeInBytes , e ));
882+ } catch (final RuntimeException e ) {
883+ closeMemoryBlock (sliceMemoryBlock );
884+ clearSliceReqHandler ();
885+ throw e ;
832886 }
833- final Optional <TPipeTransferReq > req = sliceReqHandler .makeReqIfComplete ();
834- if (!req .isPresent ()) {
835- return new TPipeTransferResp (
836- RpcUtils .getStatus (
837- TSStatusCode .SUCCESS_STATUS ,
838- "Slice received, waiting for more slices to complete the request." ));
887+ }
888+
889+ private long getSliceBodySizeInBytes (final PipeTransferSliceReq pipeTransferSliceReq ) {
890+ return pipeTransferSliceReq .getSliceBody () == null
891+ ? 0
892+ : pipeTransferSliceReq .getSliceBody ().length ;
893+ }
894+
895+ private void clearSliceReqHandler () {
896+ sliceReqHandler .clear ();
897+ allocatedSliceMemoryBlocks .forEach (this ::closeMemoryBlock );
898+ allocatedSliceMemoryBlocks .clear ();
899+ }
900+
901+ private void closeMemoryBlock (final PipeMemoryBlock memoryBlock ) {
902+ if (Objects .nonNull (memoryBlock )) {
903+ memoryBlock .close ();
839904 }
840- // sliceReqHandler will be cleared in the receive(req) method
841- return receive (req .get ());
905+ }
906+
907+ private PipeMemoryBlock tryAllocateReceiverMemory (final long requestedMemorySizeInBytes )
908+ throws PipeRuntimeOutOfMemoryCriticalException {
909+ return PipeDataNodeResourceManager .memory ()
910+ .forceAllocate (Math .max (requestedMemorySizeInBytes , 0 ));
911+ }
912+
913+ @ Override
914+ protected TSStatus getReceiverTemporaryUnavailableStatus (
915+ final String action ,
916+ final long requestedMemorySizeInBytes ,
917+ final PipeRuntimeOutOfMemoryCriticalException e ) {
918+ return new TSStatus (TSStatusCode .PIPE_RECEIVER_TEMPORARY_UNAVAILABLE_EXCEPTION .getStatusCode ())
919+ .setMessage (
920+ String .format (
921+ DataNodePipeMessages .RECEIVER_TEMPORARILY_OUT_OF_MEMORY_FORMAT ,
922+ action ,
923+ requestedMemorySizeInBytes ,
924+ PipeDataNodeResourceManager .memory ().getUsedMemorySizeInBytes (),
925+ PipeDataNodeResourceManager .memory ().getFreeMemorySizeInBytes (),
926+ PipeDataNodeResourceManager .memory ().getTotalNonFloatingMemorySizeInBytes ()));
842927 }
843928
844929 /**
@@ -1395,6 +1480,7 @@ private TSStatus executeStatementForTableModelWithPermissionCheck(
13951480
13961481 @ Override
13971482 public synchronized void handleExit () {
1483+ clearSliceReqHandler ();
13981484 if (Objects .nonNull (configReceiverId .get ())) {
13991485 try {
14001486 ClusterConfigTaskExecutor .getInstance ().handlePipeConfigClientExit (configReceiverId .get ());
0 commit comments