zfsonlinux / zfs-auto-snapshot

ZFS Automatic Snapshot Service for Linux
GNU General Public License v2.0
857 stars 245 forks source link

Free predefined amount of space by removing snapshots #72

Open Harvie opened 7 years ago

Harvie commented 7 years ago

I'd rather have way to tell zfs-auto-snapshot to use as much space for snapshots as possible while leaving predefined amount of free space. Let's say that i will tell zfs-auto-snapshot to free 10GB or 10% of space, so it will delete oldest snapshots until enough space is freed and then stop. This is somewhat oportunistic approach to snapshots that will not delete more snapshots than needed just because they are old. It's kinda similar to how NILFS2 garbage collection works. Also it's vital to combine with TTL, so snapshots are protected for some time period even when disk gets full.

ljluestc commented 1 year ago
#!/bin/bash

filesystem="pool/dataset"  # Replace with your ZFS filesystem
desired_free_space=10  # Replace with the desired amount of free space in GB or percentage

# Calculate the current snapshot usage
snapshot_usage=$(zfs list -H -o referenced -t snapshot "$filesystem")

# Calculate the available space
available_space=$(zfs get -H -o value available "$filesystem")

# Calculate the target free space
if [[ $desired_free_space =~ % ]]; then
  desired_free_space_pct=$(echo "$desired_free_space" | tr -d '%')
  target_free_space=$(echo "scale=0; $available_space * $desired_free_space_pct / 100" | bc)
else
  target_free_space=$((desired_free_space * 1024 * 1024 * 1024))  # Convert GB to bytes
fi

# List and sort snapshots
snapshots=$(zfs list -H -o name -t snapshot -S creation "$filesystem")

# Iterate over the snapshots
total_snapshot_usage=0
deleted_snapshots=0

for snapshot in $snapshots; do
  # Calculate the space used by the current snapshot
  snapshot_usage=$(zfs list -H -o referenced "$snapshot")

  # Check if deleting the current snapshot reduces usage below the target
  if ((total_snapshot_usage + snapshot_usage > snapshot_usage)); then
    # Delete the current snapshot
    zfs destroy "$snapshot"
    ((deleted_snapshots++))

    # Update the total snapshot usage
    total_snapshot_usage=$((total_snapshot_usage + snapshot_usage))

    # Check if the target free space has been reached
    if ((total_snapshot_usage >= target_free_space)); then
      break
    fi
  fi
done

echo "Deleted $deleted_snapshots snapshots."