• Filipe Manana's avatar
    Btrfs: send, do not issue unnecessary truncate operations · ffa7c429
    Filipe Manana authored
    When send finishes processing an inode representing a regular file, it
    always issues a truncate operation for that file, even if its size did
    not change or the last write sets the file size correctly. In the most
    common cases, the issued write operations set the file to correct size
    (either full or incremental sends) or the file size did not change (for
    incremental sends), so the only case where a truncate operation is needed
    is when a file size becomes smaller in the send snapshot when compared
    to the parent snapshot.
    
    By not issuing unnecessary truncate operations we reduce the stream size
    and save time in the receiver. Currently truncating a file to the same
    size triggers writeback of its last page (if it's dirty) and waits for it
    to complete (only if the file size is not aligned with the filesystem's
    sector size). This is being fixed by another patch and is independent of
    this change (that patch's title is "Btrfs: skip writeback of last page
    when truncating file to same size").
    
    The following script was used to measure time spent by a receiver without
    this change applied, with this change applied, and without this change and
    with the truncate fix applied (the fix to not make it start and wait for
    writeback to complete).
    
      $ cat test_send.sh
      #!/bin/bash
    
      SRC_DEV=/dev/sdc
      DST_DEV=/dev/sdd
      SRC_MNT=/mnt/sdc
      DST_MNT=/mnt/sdd
    
      mkfs.btrfs -f $SRC_DEV >/dev/null
      mkfs.btrfs -f $DST_DEV >/dev/null
      mount $SRC_DEV $SRC_MNT
      mount $DST_DEV $DST_MNT
    
      echo "Creating source filesystem"
      for ((t = 0; t < 10; t++)); do
          (
              for ((i = 1; i <= 20000; i++)); do
                  xfs_io -f -c "pwrite -S 0xab 0 5000" \
                      $SRC_MNT/file_$i > /dev/null
              done
          ) &
         worker_pids[$t]=$!
      done
      wait ${worker_pids[@]}
    
      echo "Creating and sending snapshot"
      btrfs subvolume snapshot -r $SRC_MNT $SRC_MNT/snap1 >/dev/null
      /usr/bin/time -f "send took %e seconds"    \
             btrfs send -f $SRC_MNT/send_file $SRC_MNT/snap1
      /usr/bin/time -f "receive took %e seconds" \
             btrfs receive -f $SRC_MNT/send_file $DST_MNT
    
      umount $SRC_MNT
      umount $DST_MNT
    
    The results, which are averages for 5 runs for each case, were the
    following:
    
    * Without this change
    
    average receive time was 26.49 seconds
    standard deviation of 2.53 seconds
    
    * Without this change and with the truncate fix
    
    average receive time was 12.51 seconds
    standard deviation of 0.32 seconds
    
    * With this change and without the truncate fix
    
    average receive time was 10.02 seconds
    standard deviation of 1.11 seconds
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    ffa7c429
send.c 160 KB