Skip to content

Instantly share code, notes, and snippets.

@thejhh
Created January 24, 2012 20:42
Show Gist options
  • Save thejhh/1672448 to your computer and use it in GitHub Desktop.
Save thejhh/1672448 to your computer and use it in GitHub Desktop.
Testing btrfs snapshots and git on ramdisk (tmpfs)

Why does deleting a snapshot increase the used space on btrfs filesystem?

# time ./transaction-test.sh
DEBUG   452     work_begin: before snapshot creation
DEBUG   452     snapshot_create: before sync
DEBUG   408     snapshot_create: before snapshot creation
DEBUG   412     snapshot_create: after snapshot creation
DEBUG   412     work_begin: before changing pwd
DEBUG   412     work_begin: after changing pwd
DEBUG   412     do_test: before test
DEBUG   412     do_test: after test
DEBUG   412     work_commit: before git commit
DEBUG   412     work_commit: before changing pwd to master ram git
DEBUG   412     work_commit: before git pull
DEBUG   412     work_commit: before changing pwd back
DEBUG   412     work_commit: before changing pwd back
DEBUG   412     snapshot_delete: Before changing pwd
DEBUG   412     snapshot_delete: before deleting snapshot
DEBUG   460     snapshot_delete: before changing pwd back
DEBUG   460     snapshot_delete: after changing pwd back
DEBUG   460     work_commit: after changing pwd back
Commit successful.

real    0m0.431s
user    0m0.272s
sys     0m0.228s

These are my notes while testing.

Installing newer btrfs-tools

Ubuntu LTS 10.04 doesn't support removing btrfs snapshots. It can be fixed by installing newer btrfs.

cd /tmp
wget "http://se.archive.ubuntu.com/ubuntu/pool/main/b/btrfs-tools/btrfs-tools_0.19+20100601-3ubuntu3_i386.deb"
dpkg -i btrfs-tools_0.19+20100601-3ubuntu3_i386.deb

Creating the master git repository (on a flash drive):

mkdir -p /flash/disk0
cd /flash/disk0
git init
echo 'This is a test file.' > test.txt
git add test.txt
git commit -a -m 'Added initial test data.'

Initialising tmpfs

mkdir /ramdisks
mount -t tmpfs tmpfs /ramdisks
mkdir /ramdisks/raw /ramdisks/mnt

Creating images on ramdisk

dd if=/dev/zero of=/ramdisks/raw/disk0 bs=1M count=256

Initializing btrfs image

mkfs.btrfs /ramdisks/raw/disk0

Mounting btrfs image

mount -o loop /ramdisks/raw/disk0 /ramdisks/mnt/disk0

Cloning flash to the ramdisk

git clone /flash/disk0 /ramdisks/mnt/disk0/data

Creating snapshot

btrfsctl -s /ramdisks/mnt/disk0/snapshot/disk0-20120124-2149 /ramdisks/mnt/disk0/data

Removing snapshot

cd /ramdisks/mnt/disk0/snapshot && btrfsctl -D disk0-20120124-2149 . && cd -

For some strange reason this doesn't work:

# btrfsctl -D /ramdisks/mnt/disk0/snapshot/disk0-20120124-2149 /ramdisks/mnt/disk0/snapshot
ioctl:: Invalid argument

...or any of these -- although these are probably wrong anyway:

# btrfsctl -D disk0-20120124-2149 /ramdisks/mnt/disk0/data
ioctl:: No such file or directory
# btrfsctl -D /ramdisks/mnt/disk0/snapshot/disk0-20120124-2149 /ramdisks/mnt/disk0/data
ioctl:: Invalid argument
# btrfsctl -D disk0-20120124-2149 /ramdisks/mnt/disk0/snapshot
ioctl:: No such file or directory

Transaction tests

# time ./transaction-test.sh 
Commit successful.

real    0m0.220s
user    0m0.112s
sys     0m0.072s

Test Platform

I am running these tests on a VIA ARTiGO A2000 Storage Server which has a VIA C7-D processor.

# cat /proc/cpuinfo 
processor       : 0
vendor_id       : CentaurHauls
cpu family      : 6
model           : 13
model name      : VIA C7-D Processor 1500MHz
stepping        : 0
cpu MHz         : 1499.885
cache size      : 128 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 1
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge cmov pat clflush acpi mmx fxsr sse sse2 tm nx up pni xtpr rng rng_en ace ace_en ace2 ace2_en phe phe_en pmm pmm_en
bogomips        : 2999.77
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 32 bits virtual
power management:

This machine has 1 GB 800 MHz DDR-2 RAM.

#!/bin/sh
ramdisk_dir=/ramdisks/mnt/disk0
snapshot_dir="$ramdisk_dir"/snapshot
master_ram_git="$ramdisk_dir"/data
orig_pwd="$(pwd)"
# Output line for debuging
print_debug_line() {
msg="$1"
ram="$(df -P /ramdisks/mnt/disk0|tail -n 1|awk '{print $3}')"
echo "DEBUG\t$ram\t$msg" >&2
}
# Create working copy in a COW snapshot
snapshot_create() {
name="$1"
print_debug_line "snapshot_create: before filesystem sync"
btrfs filesystem sync "$ramdisk_dir" >/dev/null || return 2
print_debug_line "snapshot_create: before snapshot creation"
btrfs subvolume snapshot "$ramdisk_dir" "$snapshot_dir/$name" >/dev/null || return 1
#btrfsctl -s "$snapshot_dir/$name" "$master_ram_git"|grep -qxF 'operation complete' || return 1
print_debug_line "snapshot_create: after snapshot creation"
return 0
}
# Delete snapshot
snapshot_delete() {
name="$1"
status=0
print_debug_line "snapshot_delete: Before changing pwd"
cd "$snapshot_dir" || return 2
print_debug_line "snapshot_delete: before deleting snapshot"
btrfs subvolume delete "$name" > /dev/null || status=1
#btrfsctl -D "$name" .|grep -qxF 'operation complete' || status=1
print_debug_line "snapshot_delete: before changing pwd back"
cd "$orig_pwd"
print_debug_line "snapshot_delete: after changing pwd back"
return "$status"
}
# Start working on snapshot
work_begin() {
name="$1"
print_debug_line "work_begin: before snapshot creation"
snapshot_create "disk0-$time"
print_debug_line "work_begin: before changing pwd"
cd "$snapshot_dir/$name/data"
print_debug_line "work_begin: after changing pwd"
return 0
}
# Commit changes to master ram git
work_commit() {
name="$1"
status=0
print_debug_line "work_commit: before git commit"
git commit -q -a -m 'Changed data' || return 1
print_debug_line "work_commit: before changing pwd to master ram git"
cd "$master_ram_git" || return 3
print_debug_line "work_commit: before git pull"
git pull -q "$snapshot_dir/$name/data" master || status=2
print_debug_line "work_commit: before changing pwd back"
cd "$orig_pwd" || return 4
print_debug_line "work_commit: before changing pwd back"
snapshot_delete "$name" || return 5
print_debug_line "work_commit: after changing pwd back"
return "$status"
}
# Rollback, lcean up snapshot without saving data
work_rollback() {
name="$1"
status=0
print_debug_line "work_rollback: before changing pwd back"
cd "$orig_pwd" || return 4
print_debug_line "work_rollback: before snapshot deletion"
snapshot_delete "$name" || return 5
print_debug_line "work_rollback: after snapshot deletion"
return "$status"
}
set -e
time="$(date +%Y%m%d-%H%M%S-%N)"
# Test modifying data
do_test() {
print_debug_line "do_test: before test"
echo 'New test line written '"$(date -u)" >> test.txt || return 1
print_debug_line "do_test: after test"
return 0
}
# Perform the test
if work_begin "disk0-$time"; then
if do_test; then
if work_commit "disk0-$time"; then
echo 'Commit successful.'
else
echo 'Error: Commit failed!' >&2
work_rollback "disk0-$time"
fi
else
echo 'Error: Test failed!' >&2
work_rollback "disk0-$time"
fi
else
echo 'Error: Failed to begin transaction!' >&2
exit 1
fi
# EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment