private void endTsFileResource(
        TsFileIOWriter writer, TsFileResource tsFileResource, ProgressIndex progressIndex)
        throws IOException {
      // Update time index by chunk groups still in memory
      Map<IDeviceID, Map<String, TimeValuePair>> deviceLastValues = null;
      if (IoTDBDescriptor.getInstance().getConfig().isCacheLastValuesForLoad()) {
        deviceLastValues = new HashMap<>();
      }
      AtomicLong lastValuesMemCost = new AtomicLong(0);

      for (final ChunkGroupMetadata chunkGroupMetadata : writer.getChunkGroupMetadataList()) {
        final IDeviceID device = chunkGroupMetadata.getDevice();
        for (final ChunkMetadata chunkMetadata : chunkGroupMetadata.getChunkMetadataList()) {
          tsFileResource.updateStartTime(device, chunkMetadata.getStartTime());
          tsFileResource.updateEndTime(device, chunkMetadata.getEndTime());
          if (deviceLastValues != null) {
            Map<String, TimeValuePair> deviceMap =
                deviceLastValues.computeIfAbsent(
                    device,
                    d -> {
                      Map<String, TimeValuePair> map = new HashMap<>();
                      lastValuesMemCost.addAndGet(RamUsageEstimator.shallowSizeOf(map));
                      lastValuesMemCost.addAndGet(device.ramBytesUsed());
                      return map;
                    });
            int prevSize = deviceMap.size();
            deviceMap.compute(
                chunkMetadata.getMeasurementUid(),
                (m, oldPair) -> {
                  if (oldPair != null && oldPair.getTimestamp() > chunkMetadata.getEndTime()) {
                    return oldPair;
                  }
                  TsPrimitiveType lastValue =
                      chunkMetadata.getStatistics() != null
                              && chunkMetadata.getDataType() != TSDataType.BLOB
                          ? TsPrimitiveType.getByType(
                              chunkMetadata.getDataType() == TSDataType.VECTOR
                                  ? TSDataType.INT64
                                  : chunkMetadata.getDataType(),
                              chunkMetadata.getStatistics().getLastValue())
                          : null;
                  TimeValuePair timeValuePair =
                      lastValue != null
                          ? new TimeValuePair(chunkMetadata.getEndTime(), lastValue)
                          : null;
                  if (oldPair != null) {
                    lastValuesMemCost.addAndGet(-oldPair.getSize());
                  }
                  if (timeValuePair != null) {
                    lastValuesMemCost.addAndGet(timeValuePair.getSize());
                  }
                  return timeValuePair;
                });
            int afterSize = deviceMap.size();
            lastValuesMemCost.addAndGet(
                (afterSize - prevSize) * RamUsageEstimator.HASHTABLE_RAM_BYTES_PER_ENTRY);
            if (lastValuesMemCost.get()
                > IoTDBDescriptor.getInstance()
                    .getConfig()
                    .getCacheLastValuesMemoryBudgetInByte()) {
              deviceLastValues = null;
            }
          }
        }
      }
      if (deviceLastValues != null) {
        Map<IDeviceID, List<Pair<String, TimeValuePair>>> finalDeviceLastValues;
        finalDeviceLastValues = new HashMap<>(deviceLastValues.size());
        for (final Map.Entry<IDeviceID, Map<String, TimeValuePair>> entry :
            deviceLastValues.entrySet()) {
          final IDeviceID device = entry.getKey();
          Map<String, TimeValuePair> lastValues = entry.getValue();
          List<Pair<String, TimeValuePair>> pairList =
              lastValues.entrySet().stream()
                  .map(e -> new Pair<>(e.getKey(), e.getValue()))
                  .collect(Collectors.toList());
          finalDeviceLastValues.put(device, pairList);
        }
        tsFileResource.setLastValues(finalDeviceLastValues);
      }
      tsFileResource.setStatus(TsFileResourceStatus.NORMAL);
      tsFileResource.setProgressIndex(progressIndex);
      tsFileResource.serialize();
    }
It should be noted that all AlignedChunkData of the same partition split from a source file
should be guaranteed to be written to the same new file. Otherwise, for detached
BatchedAlignedChunkData, it may result in no data for the time column in the new file.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/load/LoadTsFileManager.java