App-SimpleBackuper
view release on metacpan or search on metacpan
lib/App/SimpleBackuper/Backup.pm view on Meta::CPAN
push @cur_path, $path_node;
my $file = $files->find_by_parent_id_name($file_id, $path_node);
$file //= {
parent_id => $file_id,
id => ++$state->{last_file_id},
name => $path_node,
versions => [ {
backup_id_min => $state->{last_backup_id},
backup_id_max => 0,
uid => 0,
gid => 0,
size => 0,
mode => 0,
mtime => 0,
block_id => 0,
symlink_to => undef,
parts => [],
} ],
};
$dirs2upd{join('/', @cur_path) || '/'} = {
parent_id => $file_id,
filename => $path_node,
};
$files->upsert({ id => $file->{id}, parent_id => $file->{parent_id} }, $file);
$file_id = $file->{id};
}
}
push @{ $files_queues_by_priority{$priority} }, [ $path, $priority, $file_id ];
}
}
delete $files_queues_by_priority{ $_ } foreach grep {! @{ $files_queues_by_priority{ $_ } }} keys %files_queues_by_priority;
my $last_db_save = time;
my $last_print_progress = time;
while(%files_queues_by_priority) {
my($priority) = sort {$b <=> $a} keys %files_queues_by_priority;
my $task = shift @{ $files_queues_by_priority{$priority} };
delete $files_queues_by_priority{$priority} if ! @{ $files_queues_by_priority{$priority} };
my @next = _file_proc( $task, $options, $state );
unshift @{ $files_queues_by_priority{ $_->[1] } }, $_ foreach reverse @next;
if($options->{verbose} and time - $last_print_progress > $PRINT_PROGRESS_PERIOD) {
_print_progress($state);
$last_print_progress = time;
}
if(time - $last_db_save > $SAVE_DB_PERIOD) {
App::SimpleBackuper::BackupDB($options, $state);
$last_db_save = time;
}
}
while(my($full_path, $dir2upd) = each %dirs2upd) {
print "Updating dir $full_path..." if $options->{verbose};
my $file = $files->find_by_parent_id_name($dir2upd->{parent_id}, $dir2upd->{filename});
my @stat = lstat($full_path);
if(@stat and $file->{versions}->[-1]->{backup_id_max} != $state->{last_backup_id}) {
my($uid, $gid) =_proc_uid_gid($stat[4], $stat[5], $state->{db}->{uids_gids});
if($file->{versions}->[-1]->{backup_id_max} == $state->{last_backup_id} - 1) {
$file->{versions}->[-1] = {
%{ $file->{versions}->[-1] },
backup_id_max => $state->{last_backup_id},
uid => $uid,
gid => $gid,
size => $stat[7],
mode => $stat[2],
mtime => $stat[9],
block_id => 0,
symlink_to => undef,
parts => [],
};
} else {
push @{ $file->{versions} }, {
backup_id_min => $state->{last_backup_id},
backup_id_max => $state->{last_backup_id},
uid => $uid,
gid => $gid,
size => $stat[7],
mode => $stat[2],
mtime => $stat[9],
block_id => 0,
symlink_to => undef,
parts => [],
}
}
$files->upsert({ id => $file->{id}, parent_id => $file->{parent_id} }, $file);
my $backup = $backups->find_row({ id => $state->{last_backup_id} });
$backup->{files_cnt}++;
$backup->{max_files_cnt}++;
$backups->upsert({ id => $backup->{id} }, $backup );
}
print "OK\n" if $options->{verbose};
}
my $backup = $backups->find_row({ id => $state->{last_backup_id} });
$backup->{is_done} = 1;
$backups->upsert({ id => $backup->{id} }, $backup );
App::SimpleBackuper::BackupDB($options, $state);
_print_progress($state) if ! $options->{quiet};
}
sub _print_progress {
print "Progress: ";
if($_[0]->{bytes_in_last_backup}) {
printf "processed %s of %s in last backup, ", fmt_weight($_[0]->{bytes_processed}), fmt_weight($_[0]->{bytes_in_last_backup});
}
printf "total backups weight %s.\n", fmt_weight($_[0]->{total_weight});
}
use Text::Glob qw(match_glob);
use Fcntl ':mode'; # For S_ISDIR & same
use App::SimpleBackuper::RegularFile;
sub _file_proc {
my($task, $options, $state) = @_;
confess "No task" if ! $task;
confess "No filepath" if ! $task->[0];
my @next;
my $file_time_spent = 0;
my $file_weight_spent = 0;
print "$task->[0]\n" if $options->{verbose};
print "\tparent #$task->[2], priority $task->[1]" if $options->{verbose};
my $priority = $task->[1];
while(my($mask, $p) = each %{ $options->{files} }) {
if(match_glob( $mask, $task->[0] )) {
$priority = $p;
print ", priority $priority by rule '\"$mask\": $p'" if $options->{verbose};
}
}
if(! $priority) { # Excluded by user
print " -> skip\n" if $options->{verbose};
return;
}
$state->{profile}->{fs} -= time;
$state->{profile}->{fs_lstat} -= time;
$file_time_spent -= time;
my @stat = lstat($task->[0]);
$file_time_spent += time;
$state->{profile}->{fs} += time;
$state->{profile}->{fs_lstat} += time;
if(! @stat) {
print ". Not exists\n" if $options->{verbose};
return;
}
else {
printf ", stat: %s:%s %o %s modified at %s", scalar getpwuid($stat[4]), scalar getgrgid($stat[5]), $stat[2], fmt_weight($stat[7]), fmt_datetime($stat[9]) if $options->{verbose};
}
my($backups, $blocks, $files, $parts, $uids_gids) = @{ $state->{db} }{qw(backups blocks files parts uids_gids)};
my($uid, $gid) = _proc_uid_gid($stat[4], $stat[5], $uids_gids);
my($file); {
my($filename) = $task->[0] =~ /([^\/]+)\/?$/;
$file = $files->find_by_parent_id_name($task->[2], $filename);
if($file) {
print ", is old file #$file->{id}" if $options->{verbose};
if($file->{versions}->[-1]->{backup_id_max} == $state->{last_backup_id}) {
print ", is already backuped.\n" if $options->{verbose};
return;
}
} else {
$file = {
parent_id => $task->[2],
id => ++$state->{last_file_id},
name => $filename,
versions => [],
};
print ", is new file #$file->{id}" if $options->{verbose};
}
}
$state->{bytes_processed} += $file->{versions}->[-1]->{size} if @{ $file->{versions} };
my %version = (
backup_id_min => $state->{last_backup_id},
backup_id_max => $state->{last_backup_id},
uid => $uid,
gid => $gid,
size => $stat[7],
mode => $stat[2],
mtime => $stat[9],
block_id => undef,
symlink_to => undef,
parts => [],
);
if(S_ISDIR $stat[2]) {
print ", is directory.\n" if $options->{verbose};
my $dh;
$state->{profile}->{fs} -= time;
$state->{profile}->{fs_read_dir} -= time;
$file_time_spent -= time;
( run in 2.078 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )