Non vogliamo tirarla lunga con un articolo accademico sulla frammentazione e sulle tecniche implementate per minimizzarla sui filesystem della famiglia ext*.
Vogliamo solo farvi giocare concretamente con questo concetto/problema che sfugge all’attenzione degli utenti (e sistemisti Linux) per un assunto ben poco esatto ma comunque in concreto valido: “Linux non soffre di problemi di frammentazione”.
In realtà questo, come abbiamo detto, non è “esattamente” vero (e non vogliamo tediarvi con questioni tecniche), ma è altrettanto vero che il filesystem ext2 (e successori) ha dei buoni anticorpi per risolvere l’influenza della deframmentazione.
Il primo giocattolo per poter cominciare a saggiare con mano l’esistenza di questa realtà è il comando filefrag
. Questo è disponibile nel pacchetto e2fsprogs
(disponibile sia su distribuzioni RedHat like che Debian like).
Questo comando è capace di rilevare la frammentazione di un file indicato, in numero e identità dei blocchi di indirezione (extents).
A partire da questo e considerando che tra gli artifici del filesystem ext2 (e successori) per evitare la framentazione vi è la tecnica di allocare sequenzialmente i blocchi di un file in fase di creazione, possiamo porre le basi per un nuovo giocattolo.
Prendiamo ora il seguente nuovo assunto: “per deframmentare un file basta copiarlo”.
La nuova copia (per via del modo di allocazione blocchi) sarà “probabilmente” deframmentato. Il “probabilmente” è dovuto al fatto che i blocchi contigui devono essere disponibili. Ecco perché nell’implementazione provvediamo a copiare il file su un filesystem di appoggio (di base /tmp), liberiamo spazio sul filesystem sorgente (per aumentare la probabilità di trovare blocchi consecutivi) e ricopiamo nuovamente il file.
Dato che “repetita iuvant”, ripetere questa operazione quando la deframmentazione non è stata pienamente possibile potrà renderla possibile (a patto che il filesystem sia nel frattempo mutato rendendo disponibile nuove sequenze di blocchi contigui).
Ed ecco il nostro defrag per Linux:
#!/bin/bash # # [ "$USER" != "root" ] && echo Must be root && exit 1 TEMPFILE=`mktemp` trap 'rm -f $TEMPFILE' EXIT 1 15 echo -n "Raccolgo elenco file(s) ... " find ${1:-.} -type f 2>/dev/null | grep -v $TEMPFILE >$TEMPFILE echo fatto NFILES=`cat $TEMPFILE | wc -l` echo "Trovati $NFILES file(s)" exec 3<> $TEMPFILE declare -i i declare -i defrag i=0 defrag=0 read <&3 while [ -n "$REPLY" ] do EXTENTS=`filefrag "$REPLY" | cut -d: -f2 | awk '{ print $1 }'` if [ ${EXTENTS:-0} -gt 2 ] 2>/dev/null; then # Usare mktemp -p /altrodisco (se server più spazio) TEMP=`mktemp` cp -dp $REPLY $TEMP rm -f $REPLY cp $TEMP $REPLY rm -f $TEMP defrag=$(( defrag + 1 )) fi i=$((i + 1)) echo -en "\r$i/$NFILES ($(( 100 * i / NFILES ))%)" read <&3 done echo exec 3>&- echo "Processati $i file(s)" echo "Deframmentati $defrag file(s)" trap '' 1 15 exit 0
Ovviamente, in quanto giocattolo, non possiamo chiedervi di provarlo in ambienti di produzione. Pur essendo (crediamo) esente da problemi, non è consigliato soprattutto per il suo tempo di esecuzione, che è legato proporzionalmente alla dimensione e numero dei files da ottimizzare.
Non è il migliore degli approcci, ma è capace di ottenere il suo scopo. Soprattutto è capace di mostrarci il motivo nascosto del perché in Linux abbiamo pochi problemi di frammentazione (la copia dei file che ogni tanto avviene o la creazione degli stessi sono alla base della deframmentazione che avviene fuori dal nostro sguardo)
A noi bastava fornire una fascinazione riguardo il problema.