From 371f00f2f0698915b49599a834696c7ae3631ce7 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 23 May 2019 09:36:50 +0000 Subject: xapcmd: xcpdb supports compaction To minimize the delay on active inboxes, it's actually ideal to run xapian-compact at the end of the per-partition cpdb process; since the new DB isn't accessible yet and so we don't have to deal with lock contention with -mda or -watch processes. The downside is temporary file overhead (3x instead of 2x) required. --- lib/PublicInbox/Xapcmd.pm | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/PublicInbox/Xapcmd.pm b/lib/PublicInbox/Xapcmd.pm index ca74ea0c..d2de8743 100644 --- a/lib/PublicInbox/Xapcmd.pm +++ b/lib/PublicInbox/Xapcmd.pm @@ -8,6 +8,10 @@ use PublicInbox::Over; use File::Temp qw(tempdir); use File::Path qw(remove_tree); +# support testing with dev versions of Xapian which installs +# commands with a version number suffix (e.g. "xapian-compact-1.5") +our $XAPIAN_COMPACT = $ENV{XAPIAN_COMPACT} || 'xapian-compact'; + sub commit_changes ($$$) { my ($im, $old, $new) = @_; my @st = stat($old) or die "failed to stat($old): $!\n"; @@ -38,17 +42,23 @@ sub xspawn { } } +sub runnable_or_die ($) { + my ($exe) = @_; + which($exe) or die "$exe not found in PATH\n"; +} + sub run { my ($ibx, $cmd, $env, $opt) = @_; $opt ||= {}; my $dir = $ibx->{mainrepo} or die "no mainrepo in inbox\n"; my $exe = $cmd->[0]; my $pfx = $exe; + runnable_or_die($XAPIAN_COMPACT) if $opt->{compact}; if (ref($exe) eq 'CODE') { $pfx = 'CODE'; require Search::Xapian::WritableDatabase; } else { - which($exe) or die "$exe not found in PATH\n"; + runnable_or_die($exe); } $ibx->umask_prepare; my $old = $ibx->search->xdir(1); @@ -107,11 +117,12 @@ sub cpdb { my ($args, $env, $opt) = @_; my ($old, $new) = @$args; my $src = Search::Xapian::Database->new($old); + my $tmp = $opt->{compact} ? "$new.compact" : $new; # like copydatabase(1), be sure we don't overwrite anything in case # of other bugs: my $creat = Search::Xapian::DB_CREATE(); - my $dst = Search::Xapian::WritableDatabase->new($new, $creat); + my $dst = Search::Xapian::WritableDatabase->new($tmp, $creat); my ($it, $end); do { @@ -140,6 +151,25 @@ sub cpdb { # (and public-inbox does not use those features) }; } while (cpdb_retryable($src, $@)); + + return unless $opt->{compact}; + + $src = $dst = undef; # flushes and closes + + # this is probably the best place to do xapian-compact + # since $dst isn't readable by HTTP or NNTP clients, yet: + my $cmd = [ $XAPIAN_COMPACT, '--no-renumber', $tmp, $new ]; + my $rdr = {}; + foreach my $fd (0..2) { + defined(my $dst = $opt->{$fd}) or next; + $rdr->{$fd} = $dst; + } + my $pid = spawn($cmd, $env, $rdr); + my $r = waitpid($pid, 0); + if ($? || $r != $pid) { + die join(' ', @$cmd)." failed: $? (pid=$pid, reaped=$r)\n"; + } + remove_tree($tmp) or die "failed to remove $tmp: $!\n"; } 1; -- cgit v1.2.3-24-ge0c7