public TsBlock remove() {
    if (closed) {
      // try throw underlying exception instead of "Source handle is aborted."
      if (abortedCause != null) {
        throw new IllegalStateException(abortedCause);
      }
      try {
        blocked.get();
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new IllegalStateException(e);
      } catch (ExecutionException e) {
        throw new IllegalStateException(e.getCause() == null ? e : e.getCause());
      }
      throw new IllegalStateException("queue has been destroyed");
    }
    TsBlock tsBlock = queue.remove();
    localMemoryManager
        .getQueryPool()
        .free(
            localFragmentInstanceId.getQueryId(),
            fullFragmentInstanceId,
            localPlanNodeId,
            tsBlock.getSizeInBytes());
    bufferRetainedSizeInBytes -= tsBlock.getSizeInBytes();
    // Every time LocalSourceHandle consumes a TsBlock, it needs to send the event to
    // corresponding LocalSinkChannel.
    if (sinkChannel != null) {
      sinkChannel.checkAndInvokeOnFinished();
    }
    if (blocked.isDone() && queue.isEmpty() && !noMoreTsBlocks) {
      blocked = SettableFuture.create();
    }
    return tsBlock;
  }
Remove a TsBlock from the head of the queue and return. Should be invoked only when the future
returned by {@link #isBlocked()} completes.

@throws IllegalStateException Cannot remove TsBlock from closed queue.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/exchange/SharedTsBlockQueue.java