152 lines
3.7 KiB
Bash
152 lines
3.7 KiB
Bash
|
#!/bin/bash
|
|||
|
#
|
|||
|
# This plugin defragments rpm files after update.
|
|||
|
#
|
|||
|
# If the filesystem is btrfs, run defrag command in /var/lib/rpm, set the
|
|||
|
# desired extent size to 32MiB, but this may change in the result depending
|
|||
|
# on the fragmentation of the free space
|
|||
|
#
|
|||
|
## Why 32MiB:
|
|||
|
# - the worst fragmentation has been observed on /var/lib/rpm/Packages
|
|||
|
# - this can grow up to several hundred of megabytes
|
|||
|
# - the file gets updated at random places
|
|||
|
# - although the file will be composed of many extents, it's faster to
|
|||
|
# merge only the extents that affect some portions of the file, instead
|
|||
|
# of the whole file; the difference is negligible
|
|||
|
# - due to the free space fragmentation over time, it's hard to find
|
|||
|
# contiguous space, the bigger the extent is, the worse and the extent
|
|||
|
# size hint is not reached anyway
|
|||
|
|
|||
|
DEBUG="false"
|
|||
|
EXTENT_SIZE="32M"
|
|||
|
|
|||
|
RPMDIR=$(rpm --eval "%_dbpath")
|
|||
|
SCRIPTNAME="$(basename "$0")"
|
|||
|
|
|||
|
cleanup() {
|
|||
|
test -n "$tmpdir" -a -d "$tmpdir" && execute rm -rf "$tmpdir"
|
|||
|
}
|
|||
|
|
|||
|
trap cleanup EXIT
|
|||
|
|
|||
|
tmpdir=$(mktemp -d /tmp/btrfs-defrag-plugin.XXXXXX)
|
|||
|
|
|||
|
log() {
|
|||
|
logger -p info -t $SCRIPTNAME --id=$$ "$@"
|
|||
|
}
|
|||
|
|
|||
|
debug() {
|
|||
|
$DEBUG && log "$@"
|
|||
|
}
|
|||
|
|
|||
|
respond() {
|
|||
|
debug "<< [$1]"
|
|||
|
echo -ne "$1\n\n\x00"
|
|||
|
}
|
|||
|
|
|||
|
execute() {
|
|||
|
debug -- "Executing: $@"
|
|||
|
|
|||
|
$@ 2> $tmpdir/cmd-output
|
|||
|
ret=$?
|
|||
|
|
|||
|
if $DEBUG; then
|
|||
|
if test $ret -ne 0; then
|
|||
|
log -- "Command failed, output follows:"
|
|||
|
log -f $tmpdir/cmd-output
|
|||
|
log -- "End output"
|
|||
|
else
|
|||
|
log -- "Command succeeded"
|
|||
|
fi
|
|||
|
fi
|
|||
|
return $ret
|
|||
|
}
|
|||
|
|
|||
|
btrfs_defrag() {
|
|||
|
# defrag options:
|
|||
|
# - verbose
|
|||
|
# - recursive
|
|||
|
# - flush each file before going to the next one
|
|||
|
# - set the extent target hint
|
|||
|
execute btrfs filesystem defragment -v -f -r -t "$EXTENT_SIZE" "$RPMDIR"
|
|||
|
}
|
|||
|
|
|||
|
debug_fragmentation() {
|
|||
|
if $DEBUG; then
|
|||
|
log -- "Fragmentation $1"
|
|||
|
execute filefrag $RPMDIR/* > $tmpdir/filefrag-output
|
|||
|
if test $? -eq 0; then
|
|||
|
log -f $tmpdir/filefrag-output
|
|||
|
log -- "End output"
|
|||
|
else
|
|||
|
log "Non-fatal error ignored."
|
|||
|
fi
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
ret=0
|
|||
|
|
|||
|
# The frames are terminated with NUL. Use that as the delimeter and get
|
|||
|
# the whole frame in one go.
|
|||
|
while read -d ' |