Changeset 161
- Timestamp:
- 08/02/07 20:54:41 (2 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 10 modified
-
Changes (modified) (1 diff)
-
brackup-target (modified) (5 diffs)
-
lib/Brackup.pm (modified) (1 diff)
-
lib/Brackup/Config.pm (modified) (2 diffs)
-
lib/Brackup/Manual/Overview.pod (modified) (1 diff)
-
lib/Brackup/Metafile.pm (added)
-
lib/Brackup/Restore.pm (modified) (3 diffs)
-
lib/Brackup/Target.pm (modified) (5 diffs)
-
lib/Brackup/Target/Amazon.pm (modified) (3 diffs)
-
lib/Brackup/Target/Filesystem.pm (modified) (3 diffs)
-
lib/Brackup/Test.pm (modified) (1 diff)
-
t/04-gc.t (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Changes
r159 r161 1 - 'prune' and 'gc' commands commands for both Amazon 2 and Filesystem targets. from Alessandro Ranellucci <aar@cpan.org>. 3 1 4 1.04 (july 30, 2007) 2 5 -
trunk/brackup-target
r158 r161 11 11 $ brackup-target [opts] <target_name> get_backups 12 12 $ brackup-target [opts] <target_name> delete_backup <backup_file> 13 $ brackup-target [opts] <target_name> gc # run garbage collector 13 $ brackup-target [opts] <target_name> prune # remove old backups 14 $ brackup-target [opts] <target_name> gc # run garbage collector 14 15 15 16 =head2 OPTIONS … … 24 25 25 26 Be verbose with status. 27 28 =item --dry-run 29 30 Do not actually execute write operations. 31 32 =item --keep-backups 33 34 To be used in combination with the I<prune> command. This overrides the 35 I<keep_backups> option specified in the configuration file. 26 36 27 37 =back … … 61 71 my $opt_help; 62 72 my $opt_verbose; 73 my $opt_keep_backups; 74 my $opt_dryrun; 63 75 usage() unless 64 76 GetOptions( … … 66 78 'dest=s' => \$destdir, 67 79 'config=s' => \$config_file, 80 'keep-backups=i' => \$opt_keep_backups, 81 'dry-run' => \$opt_dryrun, 68 82 'help' => \$opt_help, 69 83 ); … … 132 146 } 133 147 148 sub CMD_prune { 149 my $removed_count = $target->prune( keep_backups => $opt_keep_backups, 150 dryrun => $opt_dryrun); 151 debug("$removed_count backups removed from target"); 152 } 153 154 sub CMD_gc { 155 my $removed_chunks = $target->gc(dryrun => $opt_dryrun); 156 debug("$removed_chunks chunks removed from target"); 157 } 158 134 159 sub debug { 135 160 my $msg = shift; -
trunk/lib/Brackup.pm
r159 r161 7 7 use Brackup::ConfigSection; 8 8 use Brackup::File; 9 use Brackup::Metafile; 9 10 use Brackup::PositionedChunk; 10 11 use Brackup::StoredChunk; -
trunk/lib/Brackup/Config.pm
r141 r161 84 84 #type = Filesystem 85 85 #path = /raid/backup/brackup 86 #keep_backups = 10 86 87 87 88 #[TARGET:amazon] … … 89 90 #aws_access_key_id = XXXXXXXXXX 90 91 #aws_secret_access_key = XXXXXXXXXXXX 92 #keep_backups = 10 91 93 92 94 #[SOURCE:proj] -
trunk/lib/Brackup/Manual/Overview.pod
r153 r161 127 127 brackup-restore --help 128 128 129 =head1 Number of backups to keep 130 131 To free space on your target you can remove old backups. There are two steps 132 to do this: 133 134 brackup-target <target> prune 135 brackup-target <target> gc 136 137 The first command will look for backup metafiles in your target and remove the 138 oldest ones according to the I<keep_backups> option you specified in the config 139 file. Thus, if you have, say, 15 backups stored and I<keep_backups> is set to 10 140 then I<prune> will remove the oldest 5 backups. 141 142 The second command will remove from your target the orphaned chunks that are no 143 more referenced by any metafile. This will free some space while preserving chunks 144 that are still referenced by recent backups. 145 129 146 =head1 SEE ALSO 130 147 -
trunk/lib/Brackup/Restore.pm
r153 r161 54 54 my ($self) = @_; 55 55 my $parser = $self->parser; 56 my $meta = $parser-> ();56 my $meta = $parser->readline; 57 57 my $driver_class = $meta->{BackupDriver}; 58 58 die "No driver specified" unless $driver_class; … … 69 69 $self->{_meta} = $meta; 70 70 71 while (my $it = $parser-> ()) {71 while (my $it = $parser->readline) { 72 72 my $full = $self->{to} . "/" . $it->{Path}; 73 73 my $type = $it->{Type} || "f"; … … 263 263 sub parser { 264 264 my $self = shift; 265 open (my $fh, $self->{file}) or die "Failed to open metafile: $!"; 266 my $linenum = 0; 267 return sub { 268 my $ret = {}; 269 my $last; # scalarref to last item 270 my $line; # 271 while (defined ($line = <$fh>)) { 272 $linenum++; 273 if ($line =~ /^([\w\-]+):\s*(.+)/) { 274 $ret->{$1} = $2; 275 $last = \$ret->{$1}; 276 next; 277 } 278 if ($line eq "\n") { 279 return $ret; 280 } 281 if ($line =~ /^\s+(.+)/) { 282 die "Can't continue line without start" unless $last; 283 $$last .= " $1"; 284 next; 285 } 286 287 $line =~ s/[:^print:]/?/g; 288 die "Unexpected line in metafile $self->{file}, line $linenum: $line"; 289 } 290 return undef; 291 } 265 return Brackup::Metafile->open($self->{file}); 292 266 } 293 267 -
trunk/lib/Brackup/Target.pm
r148 r161 5 5 use Brackup::InventoryDatabase; 6 6 use Brackup::TargetBackupStatInfo; 7 use Brackup::Util 'tempfile'; 7 8 use Carp qw(croak); 8 9 … … 12 13 my $name = $confsec->name; 13 14 $name =~ s!^TARGET:!! or die; 14 15 16 $self->{keep_backups} = $confsec->value("keep_backups"); 15 17 $self->{inv_db} = 16 18 Brackup::InventoryDatabase->new($confsec->value("inventory_db") || 17 19 "$ENV{HOME}/.brackup-target-$name.invdb"); 20 18 21 return $self; 19 22 } … … 36 39 my ($self, $chunk) = @_; 37 40 die "ERROR: store_chunk not implemented in sub-class $self"; 41 } 42 43 # returns true on success, or returns false or dies otherwise. 44 sub delete_chunk { 45 my ($self, $chunk) = @_; 46 die "ERROR: delete_chunk not implemented in sub-class $self"; 47 } 48 49 # returns a list of names of all chunks 50 sub chunks { 51 my ($self) = @_; 52 die "ERROR: chunks not implemented in sub-class $self"; 38 53 } 39 54 … … 75 90 } 76 91 92 # deletes the given backup from this target 93 sub delete_backup { 94 my ($self, $name) = @_; 95 die "ERROR: delete_backup method not implemented in sub-class $self"; 96 } 97 98 # removes old metafiles from this target 99 sub prune { 100 my ($self, %opt) = @_; 101 102 my $keep_backups = $self->{keep_backups} || $opt{keep_backups} 103 or die "ERROR: keep_backups option not set\n"; 104 die "ERROR: keep_backups option must be at least 1\n" 105 unless $keep_backups > 0; 106 107 # select backups to delete 108 my (%backups, @backups_to_delete) = (); 109 foreach my $backup_name (map {$_->filename} $self->backups) { 110 $backup_name =~ /^(.+)-\d+$/; 111 $backups{$1} ||= []; 112 push @{ $backups{$1} }, $backup_name; 113 } 114 foreach my $source (keys %backups) { 115 my @b = reverse sort @{ $backups{$source} }; 116 push @backups_to_delete, splice(@b, ($keep_backups > $#b+1) ? $#b+1 : $keep_backups); 117 } 118 119 unless ($opt{dryrun}) { 120 $self->delete_backup($_) for @backups_to_delete; 121 } 122 return scalar @backups_to_delete; 123 } 124 125 # removes orphaned chunks in the target 126 sub gc { 127 my ($self, %opt) = @_; 128 129 # get all chunks and then loop through metafiles to detect 130 #Â referenced ones 131 my %chunks = map {$_ => 1} $self->chunks; 132 my $tempfile = tempfile(); 133 BACKUP: foreach my $backup ($self->backups) { 134 $self->get_backup($backup->filename, $tempfile); 135 my $parser = Brackup::Metafile->open($tempfile); 136 $parser->readline; # skip header 137 ITEM: while (my $it = $parser->readline) { 138 next ITEM unless $it->{Chunks}; 139 my @item_chunks = map { (split /;/)[3] } grep { $_ } split(/\s+/, $it->{Chunks} || ""); 140 delete $chunks{$_} for (@item_chunks); 141 } 142 } 143 my @orphaned_chunks = keys %chunks; 144 145 # remove orphaned chunks 146 unless ($opt{dryrun}) { 147 $self->delete_chunk($_) for @orphaned_chunks; 148 } 149 return scalar @orphaned_chunks; 150 } 151 152 153 77 154 1; 78 155 … … 107 184 B<Filesystem> -- see L<Brackup::Target::Filesystem> for configuration details 108 185 186 =item B<keep_backups> 187 188 The number of recent backups to keep when running I<brackup-target prune>. 189 109 190 =back -
trunk/lib/Brackup/Target/Amazon.pm
r158 r161 130 130 } 131 131 132 sub delete_chunk { 133 my ($self, $dig) = @_; 134 my $bucket = $self->{s3}->bucket($self->{chunk_bucket}); 135 return $bucket->delete_key($dig); 136 } 137 138 # returns a list of names of all chunks 139 sub chunks { 140 my $self = shift; 141 142 my $chunks = $self->{s3}->list_bucket_all({ bucket => $self->{chunk_bucket} }); 143 return map { $_->{key} } @{ $chunks->{keys} }; 144 } 145 132 146 sub store_backup_meta { 133 147 my ($self, $name, $file) = @_; … … 158 172 sub get_backup { 159 173 my $self = shift; 160 my $name = shift;174 my ($name, $output_file) = @_; 161 175 162 176 my $bucket = $self->{s3}->bucket($self->{backup_bucket}); … … 164 178 or return 0; 165 179 166 open(my $out, ">$name.brackup") or die "Failed to open $name.brackup: $!\n"; 180 $output_file ||= "$name.brackup"; 181 open(my $out, ">$output_file") or die "Failed to open $output_file: $!\n"; 167 182 my $outv = syswrite($out, $val->{value}); 168 183 die "download/write error" unless $outv == do { use bytes; length $val->{value} }; -
trunk/lib/Brackup/Target/Filesystem.pm
r158 r161 3 3 use warnings; 4 4 use base 'Brackup::Target'; 5 use File::Basename; 6 use File::Find (); 5 7 use File::Path; 6 8 use File::stat (); … … 96 98 } 97 99 100 sub delete_chunk { 101 my ($self, $dig) = @_; 102 my $path = $self->chunkpath($dig); 103 unlink $path; 104 } 105 106 107 # returns a list of names of all chunks 108 sub chunks { 109 my $self = shift; 110 111 my @chunks = (); 112 my $found_chunk = sub { 113 m/\.chunk$/ or return; 114 my $chunk_name = basename($_); 115 $chunk_name =~ s/\.chunk$//; 116 push @chunks, $chunk_name; 117 }; 118 File::Find::find({ wanted => $found_chunk, no_chdir => 1}, $self->{path}); 119 return @chunks; 120 } 121 98 122 sub _metafile_dir { 99 123 return $_[0]->{path}."/backups/"; … … 134 158 135 159 # downloads the given backup name to the current directory (with 136 # *.brackup extension) 160 # *.brackup extension) or to the specified location 137 161 sub get_backup { 138 my ($self, $name ) = @_;162 my ($self, $name, $output_file) = @_; 139 163 my $dir = $self->_metafile_dir; 140 164 my $file = "$dir/$name.brackup"; 141 165 die "File doesn't exist: $file" unless -e $file; 142 166 open(my $in, $file) or die "Failed to open $file: $!\n"; 143 open(my $out, ">$name.brackup") or die "Failed to open $name.brackup: $!\n"; 167 $output_file ||= "$name.brackup"; 168 open(my $out, ">$output_file") or die "Failed to open $output_file: $!\n"; 144 169 my $buf; 145 170 my $rv; -
trunk/lib/Brackup/Test.pm
r157 r161 78 78 ok(-s $meta_filename, "backup file has size"); 79 79 80 return wantarray ? ($meta_filename, $backup ) : $meta_filename;80 return wantarray ? ($meta_filename, $backup, $target) : $meta_filename; 81 81 } 82 82
