equal
deleted
inserted
replaced
13 use IO::Compress::Gzip qw(gzip $GzipError :level :strategy); |
13 use IO::Compress::Gzip qw(gzip $GzipError :level :strategy); |
14 use Hash::Util qw(lock_keys); |
14 use Hash::Util qw(lock_keys); |
15 use Getopt::Long; |
15 use Getopt::Long; |
16 use Pod::Usage; |
16 use Pod::Usage; |
17 |
17 |
|
18 |
18 use constant KiB => 1024; |
19 use constant KiB => 1024; |
19 use constant MiB => 1024 * KiB; |
20 use constant MiB => 1024 * KiB; |
20 use constant GiB => 1024 * MiB; |
21 use constant GiB => 1024 * MiB; |
21 use constant NOW => time(); |
22 use constant NOW => time(); |
22 use constant DATETIME => strftime("%Y-%m-%dT%H:%M:%SZ" => gmtime(NOW)); |
23 use constant DATETIME => strftime("%Y-%m-%dT%H:%M:%SZ" => gmtime(NOW)); |
23 |
24 |
24 sub get_devsize; |
25 sub get_devsize; |
25 sub get_devname; |
26 sub get_devname; |
|
27 sub save; |
26 |
28 |
27 $SIG{INT} = sub { die "Got INT\n" }; |
29 $SIG{INT} = sub { die "Got INT\n" }; |
28 |
30 |
29 my %o = ( |
31 my %o = ( |
30 compress => undef, |
32 compress => undef, |
31 verbose => undef, |
33 verbose => undef, |
32 blocksize => 2 * MiB, |
34 blocksize => 4 * MiB, |
33 ); |
35 ); |
34 lock_keys(%o); |
36 lock_keys(%o); |
35 |
37 |
36 my $NOW = time(); |
38 my $NOW = time(); |
37 |
39 |
38 MAIN: { |
40 MAIN: { |
39 my ($src, $dst); |
|
40 |
|
41 my $idx = "{DIR}/idx/{HOSTNAME}/{DEVICE}/"; |
|
42 my $data = "{DIR}/data"; |
|
43 my $size; |
|
44 |
|
45 GetOptions( |
41 GetOptions( |
46 "h|help" => sub { pod2usage(-verbose => 1, exit => 0) }, |
42 "h|help" => sub { pod2usage(-verbose => 1, exit => 0) }, |
47 "m|man" => sub { |
43 "m|man" => sub { |
48 pod2usage( |
44 pod2usage( |
49 -verbose => 2, |
45 -verbose => 2, |
62 die "Blocksize $_[1] is incorrect!\n" |
58 die "Blocksize $_[1] is incorrect!\n" |
63 }; |
59 }; |
64 } |
60 } |
65 }, |
61 }, |
66 ) |
62 ) |
67 and @ARGV == 2 |
63 and @ARGV >= 2 or pod2usage; |
68 or pod2usage; |
64 |
69 ($src, $dst) = @ARGV; |
65 my $dst = pop @ARGV; |
|
66 foreach my $src (@ARGV) { |
|
67 if (my $pid = fork()) { |
|
68 next; |
|
69 } |
|
70 elsif (not defined $pid) { |
|
71 die "Can't fork: $!\n" |
|
72 } |
|
73 save($src, $dst); |
|
74 exit; |
|
75 } |
|
76 |
|
77 do 1 while wait != -1; |
|
78 |
|
79 } |
|
80 |
|
81 sub save { |
|
82 my ($src, $dst) = @_; |
|
83 my $idx = "{DIR}/idx/{HOSTNAME}/{DEVICE}/"; |
|
84 my $data = "{DIR}/data"; |
|
85 my $size; |
70 |
86 |
71 foreach ($idx, $data) { |
87 foreach ($idx, $data) { |
72 s/{DIR}/$dst/g; |
88 s/{DIR}/$dst/g; |
73 s/{HOSTNAME}/hostname/eg; |
89 s/{HOSTNAME}/hostname/eg; |
74 s/{DEVICE}/get_devname($src)/eg; |
90 s/{DEVICE}/get_devname($src)/eg; |
103 ); |
119 ); |
104 |
120 |
105 local $SIG{ALRM} = sub { |
121 local $SIG{ALRM} = sub { |
106 my $speed = ($stats{written} + $stats{skipped}) / (time - $^T + 1); |
122 my $speed = ($stats{written} + $stats{skipped}) / (time - $^T + 1); |
107 say sprintf |
123 say sprintf |
108 "# done %5.1f%% | %24s (%*d of $stats{todo}, written %*d, skipped %*d)", |
124 "# %*s done %5.1f%% | %24s (%*d of $stats{todo}, written %*d, skipped %*d)", |
|
125 (sort {$a<=>$b} map { length basename $_ } @ARGV)[-1] => basename($src), |
109 100 * (($stats{written} + $stats{skipped}) / $stats{todo}), |
126 100 * (($stats{written} + $stats{skipped}) / $stats{todo}), |
110 ($speed ? (scalar localtime($^T + $stats{todo} / $speed)) : ""), |
127 ($speed ? (scalar localtime($^T + $stats{todo} / $speed)) : ""), |
111 length($stats{todo}) => $stats{written} + $stats{skipped}, |
128 length($stats{todo}) => $stats{written} + $stats{skipped}, |
112 length($stats{todo}) => $stats{written}, |
129 length($stats{todo}) => $stats{written}, |
113 length($stats{todo}) => $stats{skipped}; |
130 length($stats{todo}) => $stats{skipped}; |
155 $SIG{ALRM}->(); |
172 $SIG{ALRM}->(); |
156 alarm 0; |
173 alarm 0; |
157 |
174 |
158 say {$index} "# DONE (runtime " . (time() - $^T) . "s)"; |
175 say {$index} "# DONE (runtime " . (time() - $^T) . "s)"; |
159 |
176 |
160 say "# DONE (runtime " . (time() - $^T) . "s)"; |
177 say "# $src DONE (runtime " . (time() - $^T) . "s)"; |
161 say "# WRITTEN $stats{written}, SKIPPED $stats{skipped} blocks"; |
178 say "# $src WRITTEN $stats{written}, SKIPPED $stats{skipped} blocks"; |
162 say "# SAVINGS " |
179 say "# $src SAVINGS " |
163 . sprintf "%3d%%" => 100 * |
180 . sprintf "%3d%%" => 100 * |
164 ($stats{skipped} / ($stats{written} + $stats{skipped})); |
181 ($stats{skipped} / ($stats{written} + $stats{skipped})); |
165 |
182 |
166 rename $index->filename => "$idx/" . DATETIME; |
183 rename $index->filename => "$idx/" . DATETIME; |
167 close $index; |
184 close $index; |
213 |
230 |
214 Use compression when writing the blocks to disk. (default: off) |
231 Use compression when writing the blocks to disk. (default: off) |
215 |
232 |
216 =item B<-b> I<blocksize>|B<--blocksize>=I<blocksize> |
233 =item B<-b> I<blocksize>|B<--blocksize>=I<blocksize> |
217 |
234 |
218 The blocksize used. (may be suffixed with K, M, G). (default: 2MiB) |
235 The blocksize used. (may be suffixed with K, M, G). (default: 4 MiB) |
219 |
236 |
220 =item B<-h>|B<--help> |
237 =item B<-h>|B<--help> |
221 |
238 |
222 =item B<-m>|B<--man> |
239 =item B<-m>|B<--man> |
223 |
240 |