@Override
  public void upgradeAndUpdateMultiDeviceFlushedTime(
      long timePartitionId, Map<IDeviceID, Long> flushedTimeMap) {
    ILastFlushTime flushTimeMapForPartition =
        partitionLatestFlushedTime.computeIfAbsent(
            timePartitionId, id -> new DeviceLastFlushTime());
    // upgrade DeviceLastFlushTime to PartitionLastFlushTime
    if (flushTimeMapForPartition instanceof PartitionLastFlushTime) {
      long maxFlushTime = flushTimeMapForPartition.getLastFlushTime(null);
      ILastFlushTime newDeviceLastFlushTime = new DeviceLastFlushTime();
      long memIncr = 0;
      for (Map.Entry<IDeviceID, Long> entry : flushedTimeMap.entrySet()) {
        memIncr += HASHMAP_NODE_BASIC_SIZE + entry.getKey().ramBytesUsed();
        newDeviceLastFlushTime.updateLastFlushTime(entry.getKey(), entry.getValue());
        maxFlushTime = Math.max(maxFlushTime, entry.getValue());
      }
      long finalMemIncr = memIncr;
      memCostForEachPartition.compute(
          timePartitionId, (k1, v1) -> v1 == null ? finalMemIncr : v1 + finalMemIncr);
    } else {
      // go here when DeviceLastFlushTime was recovered by wal recovery
      long memIncr = 0;
      for (Map.Entry<IDeviceID, Long> entry : flushedTimeMap.entrySet()) {
        if (flushTimeMapForPartition.getLastFlushTime(entry.getKey()) == Long.MIN_VALUE) {
          memIncr += HASHMAP_NODE_BASIC_SIZE + entry.getKey().ramBytesUsed();
        }
        flushTimeMapForPartition.updateLastFlushTime(entry.getKey(), entry.getValue());
      }
      long finalMemIncr = memIncr;
      memCostForEachPartition.compute(
          timePartitionId, (k1, v1) -> v1 == null ? finalMemIncr : v1 + finalMemIncr);
    }
  }
record memory cost of map for each partitionId
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/HashLastFlushTimeMap.java