Skip to content

Instantly share code, notes, and snippets.

@Mons
Last active April 20, 2023 17:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Mons/14e6995f2df67b8855243a31ab7d17a6 to your computer and use it in GitHub Desktop.
Save Mons/14e6995f2df67b8855243a31ab7d17a6 to your computer and use it in GitHub Desktop.
Script for changing stored UUID of Tarantool backup files (.snap, .xlog, .vy*)
#!/usr/bin/env perl
use 5.010;
use strict;
use File::Find;
use Getopt::Long;
sub usage {
return <<EOF
===============================================================
= Usage =
$0 [ -f <from-uuid> ] -t <to-uuid> [ -r ] [ -i <include> ] [ -e <exclude> ] path-to-folders
-f set from which uuid to change to avoid errors
-t which uuid to write into files
-r do real job (by default works in dry run)
-i include files by regexp mask. match full path from entry point. ex: -i '\.bak$'
-e exclude files by regexp mask. match full path from entry point. ex: -e '\.tmp/'
-v be verbose
EOF
}
sub examples {
return <<EOF
===============================================================
= Examples =
$0 -t 00000000-0000-1111-1111-111111111111 -i '\.bak$'
About to replace 94873272-47e4-4915-922f-c911c7079bdc to 00000000-0000-1111-1111-111111111111 in 5 files:
SNAP: 2, XLOG: 3
Run with -r to change files
---------------------------------------------------------------
$0 -t 00000000-0000-1111-1111-111111111111 -i '\.bak$' -v
About to replace 94873272-47e4-4915-922f-c911c7079bdc to 00000000-0000-1111-1111-111111111111 in 5 files:
./00000000000000000000.xlog
./00000000000000000000.snap
./xxx/00000000000000000000.xlog
./xxx/00000000000000000000.snap
./xxx/00000000000000000002.xlog
Run with -r to change files
---------------------------------------------------------------
$0 -t 00000000-0000-1111-1111-111111111111 -i '\.bak$' -r
Replaced 94873272-47e4-4915-922f-c911c7079bdc to 00000000-0000-1111-1111-111111111111 in 5 files:
SNAP: 2, XLOG: 3
---------------------------------------------------------------
$0 -t 00000000-0000-1111-1111-111111111111 -i '\.bak$' -r
No files to change
EOF
}
unless (@ARGV) { print usage(),examples(); exit; };
my $from;
my $to;
my $real;
my @include;
my @exclude;
my $verbose;
GetOptions(
'f|from=s' => \$from,
't|to=s' => \$to,
'r|run' => \$real,
'i|include=s' => \@include,
'e|exclude=s' => \@exclude,
'v|verbose' => \$verbose,
) or die usage();
unshift @include, qr/\.(?:snap|xlog|vylog)$/;
$to or die "Replacement UUID required\n\n".usage();
$to = lc $to;
for ($from?($from):(),$to) {
$_ = lc $_;
m{\A
[0-9a-f]{8}-
(?:[0-9a-f]{4}-){3}
[0-9a-f]{12}
\z}x or die "Malformed uuid `$_'\n\n".usage();
}
@ARGV or @ARGV = (".");
# use DDP;
my %changes;
my %files;
my $changed = 0;
File::Find::finddepth sub {
return unless -f;
if (@exclude) {
for (@exclude) {
return if $File::Find::name =~ /$_/;
}
}
CHECK: {
for (@include) {
last CHECK if $File::Find::name =~ /$_/;
}
return;
}
open my $fd, "+<", $_ or die "Cant open $File::Find::name: $!";
my $rd = sysread $fd, my $buf, 100;
if ($rd > 0) {
if($buf =~ m{
^
(?<prefix>
(?<type>\N+) \n
(?<version>\N+) \n
(\N+\n)*?
Instance: \s )(?<uuid>\S+) \n
}gcsx) {
if ($to eq $+{uuid}) {
say "Skip $File::Find::name: no change required" if $verbose;
return;
}
if ($from) {
if ($from eq $+{uuid}) {
$changes{$from}{ $+{type} }++;
}
else {
say "Skip $File::Find::name: other uuid ($+{uuid})";
return;
}
} else {
$changes{$+{uuid}}{ $+{type} }++;
}
push @{ $files{$+{uuid}}//=[] }, $File::Find::name;
if ($real) {
sysseek $fd, length($+{prefix}), 0 or die "$File::Find::name: Failed to seek: $!\n";
syswrite($fd, $to) == length $to or die "$File::Find::name: Failed to write UUID: $!\n";
close $fd;
if ($verbose) {
say "$File::Find::name: $+{uuid} -> $to";
}
}
} else {
say "Skip $File::Find::name: file format mismatch";
};
} else {
say "Skip $File::Find::name: failed to read file: $!";
}
}, @ARGV;
print "\n";
my $uuids = keys %changes;
my $total = 0;
for my $uuid (keys %changes) {
for my $type (keys %{ $changes{ $uuid } }) {
$total += $changes{ $uuid }{$type};
}
}
if ($total == 0) {
say "No files to change";
exit;
}
if ($uuids == 1) {
my ($uuid,$count) = %changes;
print + ($real ? "Replaced" : "About to replace")." $uuid to $to in $total files:\n";
if ($verbose and not $real) {
for (@{ $files{ $uuid }} ) {
say "\t$_";
}
} else {
print "\t".join (", ", map { "$_: $changes{$uuid}{$_}" } sort keys %{ $changes{ $uuid } })."\n";
}
say "\nRun with -r to change files" unless $real;
}
else {
say + ($real ? "Replaced" : "Found")." $uuids different uuids in $total files";
for my $uuid (keys %changes) {
print "$uuid:";
if ($verbose and not $real) {
print "\n";
for (@{ $files{ $uuid }} ) {
say "\t$_";
}
} else {
print "\t".join (", ", map { "$_: $changes{$uuid}{$_}" } sort keys %{ $changes{ $uuid } })."\n";
}
}
say "\nPlease, specify uuid for replacement with -f" unless $real;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment