- 论坛徽章:
- 0
|
#!/usr/bin/perl
# defragfs.pl -- Measurement and Report and Defrag fs/file fragmentation
# CanHao Xu <xucanhao@gmail.com>, 2007
($DIR, $FORCE) = @ARGV;
if (($DIR eq "") || ($DIR eq "-f")) {
die "Usage: defragfs.pl DIRECTORY [-f], -f means force defragmentation";
}
if (!(-e $DIR) || !(-d $DIR)) {
die "You must specify a correct directory name!";
}
#number of files
my $files = 0;
#number of fragment before defrag
my $fragments_before = 0;
#number of fragmented files before defrag
my $fragfiles_before = 0;
#number of fragment after defrag
my $fragments_after = 0;
#number of fragmented files after defrag
my $fragfiles_after = 0;
my $TMP_filefrag_before_1 = "/tmp/frags-result-before-tmp";
my $TMP_filefrag_before_2 = "/tmp/frags-result-before";
my $TMP_filefrag_after_1 = "/tmp/frags-result-after-tmp";
my $TMP_filefrag_after_2 = "/tmp/frags-result-after";
my $TMP_defrag_filelist_1 = "/tmp/defrag-filelist-tmp";
my $TMP_defrag_filelist_2 = "/tmp/defrag-filelist";
#max "File Fragmentation Rate" used to determine whether worth defrag.
my $max_fragrate = 20;
#max "Avg File Fragments" used to determine whether worth defrag.
my $max_avgfrags = 60;
#default defragmentation ratio in percentage
my $default_defrag_ratio;
#display how much files in report
my $max_display_num = 10;
#which files to be defrag, determined after user input the ratio
my $total_defrag_files = 0;
#sub routine measurefs measure before/after
my $measure_ba = "before";
#search fs for all file
system("rm -f $TMP_filefrag_before_1");
system("rm -f $TMP_filefrag_before_1");
system("rm -f $TMP_filefrag_after_1");
system("rm -f $TMP_filefrag_after_2");
system("rm -f $TMP_defrag_filelist_1");
system("rm -f $TMP_defrag_filelist_2");
sub measurefs {
open (FILES, "find \"" . $DIR . "\" -xdev -type f |");
while (defined (my $file = <FILES>)) {
$file =~ s/!/\\!/g;
$file =~ s/#/\\#/g;
$file =~ s/&/\\&/g;
$file =~ s/>/\\>/g;
$file =~ s/</\\</g;
$file =~ s/\$/\\\$/g;
$file =~ s/\(/\\\(/g;
$file =~ s/\)/\\\)/g;
$file =~ s/\|/\\\|/g;
$file =~ s/'/\\'/g;
$file =~ s/ /\\ /g;
open (FRAG, "filefrag $file |");
my $res = <FRAG>;
if ($res =~ m/.*:\s+(\d+) extents? found/) {
if ($_[0] eq "before") {
system("echo \"$res\" >> $TMP_filefrag_before_1");
my $fragment = $1;
$fragments_before+=$fragment;
if ($fragment > 1) {
$fragfiles_before++;
}
$files++;
}
else {
system("echo \"$res\" >> $TMP_filefrag_after_1");
my $fragment = $1;
$fragments_after+=$fragment;
if ($fragment > 1) {
$fragfiles_after++;
}
$files++;
}
}
close (FRAG);
}
close (FILES);
}
print ("defragfs 0.8, Released under GPL by xucanhao\@gmail.com\n");
print ("Analysis in progress...\n");
print ("NOTE: if the directory you specified contains too much files(e.g. tens of thousands), it could take you several minutes on analysis, you may disturb it by CTRL+C at anytime. And BTW: the program is CURRENTLY not accurate on Reiser4 due to its default tailing policy(you may see a high fragment rate before and even after)\n");
$measure_ba = "before";
&measurefs($measure_ba);
if ($files eq 0) {
print ("The selected directory contains no file!\n");
exit;
}
system("sort $TMP_filefrag_before_1 -g -t : -k 2 -r | sed \"/^\$/d\" > $TMP_filefrag_before_2");
print ("Statistics for $DIR\n");
print ("Total Files:\t\t\t" . $files . "\n");
print ("Fragmented Files:\t\t" . $fragfiles_before . "\n");
print ("File Fragmentation Rate:\t" . $fragfiles_before / $files * 100 . "%\n");
print ("Avg File Fragments(1 is best):\t" . $fragments_before / $files . "\n");
print ("Most Fragmented Files(for details see $TMP_filefrag_before_2):\n");
system("head $TMP_filefrag_before_2 -n $max_display_num");
$default_defrag_ratio = int($fragfiles_before / $files * 100);
if ($default_defrag_ratio > 50) {
$default_defrag_ratio = 50;
}
if ((($fragfiles_before / $files * 100) > $max_fragrate) || (($fragments_before / $files) > $max_avgfrags) || ($FORCE eq "-f")) {
print ("You need a defragmentation!\n");
}
else {
print ("You do not need a defragmentation!\n");
exit;
}
defrag:
print ("Please specify the percentage of files should be defrag(1-100, default $default_defrag_ratio):");
$defrag_ratio = <STDIN>;
chop($defrag_ratio);
if (!($defrag_ratio eq "") && (($defrag_ratio < 1) || ($defrag_ratio > 100))) {
print ("Error percentage numbers, please re-enter!\n");
goto defrag;
}
else {
$default_defrag_ratio = ($defrag_ratio || $default_defrag_ratio);
}
$total_defrag_files = int($default_defrag_ratio * $files / 100);
print ("Preparing defragmentation, please wait...");
print ("\nFiles to be defragmented:" . $total_defrag_files . "\n");
if ($total_defrag_files eq 0) {
exit;
}
system("head $TMP_filefrag_before_2 -n $total_defrag_files > $TMP_defrag_filelist_1");
open TMPFRAGLIST, "$TMP_defrag_filelist_1";
while (<TMPFRAGLIST>) {
m/(.*):\s+(\d+) extents? found/;
my $filename = $1;
system("echo \"$1\" >> $TMP_defrag_filelist_2");
}
open GETSIZE, "$TMP_defrag_filelist_2";
my $max = 0;
while (<GETSIZE>) {
s/(.*)\n/$1/;
$size = -s "$_";
if ($size > $max) {
$max = $size;
}
}
print ("You need AT LEAST " . $max . " Bytes temporarily used for defragmentation(at the directory where you specified), continue(Y/N)?[N] ");
$confirm = <STDIN>;
chop($confirm);
if (($confirm eq "y") || ($confirm eq "Y")) {
print ("OK, please drink a cup of tea and wait...\n");
open DEFRAG, "$TMP_defrag_filelist_2";
while (<DEFRAG>) {
s/(.*)\n/$1/;
$from = $_;
s/(.*)/$1.fragstmp/;
$to = $_;
system("cp -af \"$from\" \"$to\" 2>/dev/null");
system("rm -f \"$from\"");
#NOTE: CTIME will change here!!
system("cp -af \"$to\" \"$from\" 2>/dev/null");
system("rm -f \"$to\"");
print "#";
}
system("sync");
print ("Done!\n");
print ("Now lets see the results...\n");
$files = 0;
$measure_ba = "after";
&measurefs($measure_ba);
system("sort $TMP_filefrag_after_1 -g -t : -k 2 -r | sed \"/^\$/d\" > $TMP_filefrag_after_2");
print ("Statistics for $DIR\n");
print ("Total Files:\t\t\t" . $files . "\n");
print ("Fragmented Files:\t\t" . $fragfiles_after . "\n");
print ("File Fragmentation Rate:\t" . $fragfiles_after / $files * 100 . "%\n");
print ("Avg File Fragments(1 is best):\t" . $fragments_after / $files . "\n");
print ("Most Fragmented Files(for details see $TMP_filefrag_after_2):\n");
system("head $TMP_filefrag_after_2 -n $max_display_num");
}
else {
exit;
}
这就是源码 |
|