/usr/sbin/tarantool_snapshot_rotate is in tarantool-common 1.5.1.218.g1a69fd6-1ubuntu1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | #!/usr/bin/perl
use warnings;
use strict;
use constant CONFIG_DIR => '/var/lib/tarantool/started';
use constant PID_DIR => '/var/run/tarantool';
use constant SNAPSHOT_DIR => '/var/lib/tarantool/snapshot';
use File::Spec::Functions 'catfile';
use File::Basename 'basename', 'dirname';
use IO::Socket::INET;
use Getopt::Long;
use Pod::Usage;
use Data::Dumper;
pod2usage(-exitstatus => 0, -verbose => 2) unless
GetOptions
'help|h' => \my $help,
'verbose|v' => \my $verbose,
'snapshots|s=i' => \my $snapshots,
'snapshot_period|p=i' => \my $period,
;
sub DEBUGF($;@) {
return unless $verbose;
my ($fmt, @arg) = @_;
$fmt =~ s/\s*$/\n/;
printf STDERR $fmt, @arg;
}
sub list_files($) {
my $sndir = shift;
unless (-d $sndir) {
DEBUGF 'Snapshot directory "%s" was not found', $sndir;
return;
}
unless (-w $sndir) {
DEBUGF 'Can not write into directory %s', $sndir;
return;
}
my $dh;
opendir $dh, $sndir;
my @files = sort
grep /\.(snap|xlog)$/,
grep { -r $_ and -f $_ }
map { catfile $sndir, $_ }
readdir $dh;
return @files;
}
sub rotate_snapshot($$$) {
my ($pidfile, $snap_count, $snap_period) = @_;
$snap_count = $snapshots || 10 unless defined $snap_count;
$snap_period = $period || 24 unless defined $snap_period;
$snap_count = $snapshots if defined $snapshots;
$snap_period = $period if defined $period;
$snap_period ||= 0;
my $pid;
DEBUGF "\tBegin rotating process period=%s, count=%s",
$snap_period, $snap_count;
if (open my $ph, '<', $pidfile) {
$pid = <$ph>;
$pid =~ s/\D+//g;
} else {
warn "Can't open file $pidfile: $!\n";
return;
}
unless($pid) {
warn "PID was not received\n";
return;
}
my $sndir = catfile SNAPSHOT_DIR, basename $pidfile, '.pid';
my @files = list_files $sndir;
goto FINISH unless @files;
my ($last_snap) = grep /\.snap$/, reverse @files;
if ($last_snap) {{
my @stat = stat $last_snap;
last unless @stat;
my $ctime = $stat[10];
if (time - $ctime < $snap_period * 3600 - 3600 / 2) {
DEBUGF "\tLast snapshot was created %3.2f hours ago, ".
"do not create new",
(time - $ctime) / 3600;
return;
}
DEBUGF "\tLast snapshot was created %3.2f hours ago, creating new",
(time - $ctime) / 3600;
}} else {
DEBUGF "\tLast snapshot was not found, creating new";
}
while(@files and $files[0] =~ /\.xlog$/) {
DEBUGF "\tRemove orphaned %s", $files[0];
unless (unlink $files[0]) {
DEBUGF "\tCan't unlink file %s: %s", $files[0], $!;
return;
}
shift @files;
}
unless (kill 0 => $pid) {
DEBUGF "\tProcess %s is not started", $pidfile;
return;
}
if (kill USR1 => $pid) {
goto FINISH unless @files;
for (my $i = 0; $i < 5; $i++) {
sleep 1;
my @inpr = sort glob catfile SNAPSHOT_DIR, '*.snap.inprogress';
last unless @inpr;
if ($inpr[-1] and $inpr[-1] gt $files[-1]) {
DEBUGF "\tsnapshot %s is still in progress...", $inpr[-1];
next;
}
}
} else {
warn "Error while sending snapshot signal: $!";
return;
}
if ($snap_count) {
@files = list_files $sndir;
my $snaps = grep /\.snap$/, @files;
if ($snaps > $snap_count) {
my $to_remove = $snaps - $snap_count;
while (@files) {
my $file = shift @files;
$to_remove-- if $file =~ /\.snap$/;
DEBUGF "\tUnlink file: %s...", $file;
unless (unlink $file) {
DEBUGF "\tCan't unlink file %s: %s", $file, $!;
return;
}
last unless $to_remove > 0;
}
while(@files and $files[0] =~ /\.xlog$/) {
DEBUGF "\tRemove orphaned %s", $files[0];
unless (unlink $files[0]) {
DEBUGF "\tCan't unlink file %s: %s", $files[0], $!;
return;
}
shift @files;
}
}
} else {
DEBUGF "\tDon't remove any old snapshots";
}
FINISH:
}
DEBUGF "Looking through %s...", PID_DIR;
for (glob catfile PID_DIR, '*.pid') {
my $cfg = catfile CONFIG_DIR, basename $_, '.pid';
unless(-r $cfg) {
warn "Config file '$cfg' is not found\n";
next;
}
DEBUGF 'Found instance "%s" (%s)', basename($cfg), basename $_;
if (open my $fh, '<:encoding(UTF-8)', $cfg) {
my @lines = <$fh>;
my ($user_snapshots) =
grep /^\s*(?:opt\s+)?save_snapshots\s*=\s*\d+\s*(?:#.*)?$/,
reverse @lines;
my ($snapshot_period) =
grep /^\s*(?:opt\s+)?snapshot_period\s*=\s*\d+\s*(?:#.*)?$/,
reverse @lines;
if ($user_snapshots) {
for ($user_snapshots) {
s/#.*//;
s/\D//g;
}
unless($user_snapshots =~ /^[1-9]\d*$/) {
warn "wrong format of save_snapshots\n";
$user_snapshots = undef;
}
}
if ($snapshot_period) {
for ($snapshot_period) {
s/#.*//;
s/\D//g;
}
unless($snapshot_period =~ /^[1-9]\d*$/) {
warn "wrong format of snapshot_period\n";
$snapshot_period = undef;
}
}
rotate_snapshot $_, $user_snapshots, $snapshot_period;
} else {
warn "Can't open file $cfg: $!\n";
next;
}
}
exit 0 unless -x PID_DIR;
exit 0 unless -x CONFIG_DIR;
=head1 NAME
tarantool_snapshot_rotate - script to creates/rotates snapshots
=head1 SYNOPSIS
tarantool_snapshot_rotate
tarantool_snapshot_rotate --verbose
=head1 DESCRIPTION
The script passes through all started tarantool instances and creates
snapshots for each instance.
The script understands some additional options in tarantool.cfg:
=over
=item save_snapshots = COUNT
Count of snapshots to save (default = 10). COUNT=0 disables removing
old snapshots.
=back
=head1 OPTIONS
=over
=item -h | --help
show the helpscreen
=item -v | --verbose
log process to B<STDOUT>
=item -s | --snapshots COUNT
redefines B<save_snapshots> option of config file
=back
=cut
|