private synchronized long write(ByteBuffer byteBuffer, long position) throws IOException {
    // Correct the initial offset of the write
    if (position < 0) {
      // append the record to file tail
      position = fileChannel.size();
    }
    // Read the original data to get the original space offset
    List<Long> blockOffset = parseOffsetList(position);
    // write read data
    int blockNumReal = byteBuffer.capacity() / MAX_LENGTH;
    if (blockNumReal < 1) {
      throw new RuntimeException(
          "ByteBuffer capacity is smaller than tagAttributeTotalSize, which is not allowed.");
    }
    if (blockNumReal == 1 && blockOffset.size() == 1) {
      // If the original data occupies only one block and the new data occupies only one block, the
      // original space is used
      fileChannel.write(byteBuffer, blockOffset.get(0));
    } else {
      // if the original space is larger than the new space, the original space is used
      if (blockOffset.size() >= blockNumReal) {
        ByteBuffer byteBufferFinal = ByteBuffer.allocate(blockOffset.size() * MAX_LENGTH);
        byteBufferFinal.putInt(-blockOffset.size());
        for (int i = 1; i < blockOffset.size(); i++) {
          byteBufferFinal.putLong(blockOffset.get(i));
        }
        if (blockNumReal > 1) { // real data occupies multiple blocks
          byteBuffer.position((blockNumReal - 1) * Long.BYTES + 4);
        } else { // real data occupies only one block
          byteBuffer.position(0);
        }
        byteBufferFinal.put(byteBuffer);
        for (int i = 0; i < blockOffset.size(); i++) {
          byteBufferFinal.position(i * MAX_LENGTH);
          byteBufferFinal.limit((i + 1) * MAX_LENGTH);
          fileChannel.write(byteBufferFinal, blockOffset.get(i));
        }
      } else {
        // if the original space is smaller than the new space, the new space is used
        // prepare the bytebuffer to store the offset of each block
        int blockOffsetStoreLen = (blockNumReal - 1) * Long.BYTES + 4;
        ByteBuffer byteBufferOffset = ByteBuffer.allocate(blockOffsetStoreLen);
        byteBufferOffset.putInt(-blockNumReal);

        // write the data to the file
        for (int i = 0; i < blockNumReal; i++) {
          byteBuffer.position(i * MAX_LENGTH);
          byteBuffer.limit((i + 1) * MAX_LENGTH);

          // what we want to write is the original space
          if (i < blockOffset.size()) {
            if (i > 0) { // first block has been written
              byteBufferOffset.putLong(blockOffset.get(i));
            }
            fileChannel.write(byteBuffer, blockOffset.get(i));
          } else {
            // what we want to write is the new space
            // TODO
            byteBufferOffset.putLong(fileChannel.size());
            blockOffset.add(fileChannel.size());
            fileChannel.write(byteBuffer, fileChannel.size());
          }
        }

        // write the offset of each block to the file
        byteBufferOffset.flip();
        for (int i = 0; i < blockOffset.size(); i++) {
          byteBufferOffset.position(i * MAX_LENGTH);
          if ((i + 1) * MAX_LENGTH > byteBufferOffset.capacity()) {
            byteBufferOffset.limit(byteBufferOffset.capacity());
            fileChannel.write(byteBufferOffset, blockOffset.get(i));
            break;
          } else {
            byteBufferOffset.limit((i + 1) * MAX_LENGTH);
            fileChannel.write(byteBufferOffset, blockOffset.get(i));
          }
        }
      }
    }

    unFlushedRecordNum++;
    if (unFlushedRecordNum >= RECORD_FLUSH_INTERVAL) {
      fileChannel.force(true);
      unFlushedRecordNum = 0;
    }
    return position;
  }
@param byteBuffer the data of record to be persisted
@param position the target position to store the record in tagFile
@return beginning position of the record in tagFile
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/tag/TagLogFile.java