X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FV2Writable.pm;h=553dd839f39a9a56227e8a092d55e791ca54b2e0;hb=94ae705673cb03045a109041eec9a6704b8a735b;hp=a029fe4c4075029115f330d1a692014c60b067b3;hpb=8b1950055d51d4360e596446e5ac0f41008e357d;p=public-inbox.git diff --git a/lib/PublicInbox/V2Writable.pm b/lib/PublicInbox/V2Writable.pm index a029fe4c..553dd839 100644 --- a/lib/PublicInbox/V2Writable.pm +++ b/lib/PublicInbox/V2Writable.pm @@ -8,7 +8,6 @@ use strict; use v5.10.1; use parent qw(PublicInbox::Lock); use PublicInbox::SearchIdxShard; -use PublicInbox::IdxStack; use PublicInbox::Eml; use PublicInbox::Git; use PublicInbox::Import; @@ -20,7 +19,7 @@ use PublicInbox::Msgmap; use PublicInbox::Spawn qw(spawn popen_rd); use PublicInbox::SearchIdx qw(log2stack crlf_adjust is_ancestor check_size); use IO::Handle; # ->autoflush -use File::Temp qw(tempfile); +use File::Temp (); my $OID = qr/[a-f0-9]{40,}/; # an estimate of the post-packed size to the raw uncompressed size @@ -35,14 +34,13 @@ my $PACKING_FACTOR = 0.4; our $NPROC_MAX_DEFAULT = 4; sub detect_nproc () { - for my $nproc (qw(nproc gnproc)) { # GNU coreutils nproc - `$nproc 2>/dev/null` =~ /^(\d+)$/ and return $1; - } - # getconf(1) is POSIX, but *NPROCESSORS* vars are not for (qw(_NPROCESSORS_ONLN NPROCESSORS_ONLN)) { `getconf $_ 2>/dev/null` =~ /^(\d+)$/ and return $1; } + for my $nproc (qw(nproc gnproc)) { # GNU coreutils nproc + `$nproc 2>/dev/null` =~ /^(\d+)$/ and return $1; + } # should we bother with `sysctl hw.ncpu`? Those only give # us total processor count, not online processor count. @@ -160,7 +158,7 @@ sub do_idx ($$$$) { my $idx = idx_shard($self, $smsg->{num} % $self->{shards}); $idx->index_raw($msgref, $mime, $smsg); my $n = $self->{transact_bytes} += $smsg->{raw_bytes}; - $n >= ($PublicInbox::SearchIdx::BATCH_BYTES * $self->{shards}); + $n >= $self->{batch_bytes}; } sub _add { @@ -281,6 +279,9 @@ sub _idx_init { # with_umask callback # xcpdb can change shard count while -watch is idle my $nshards = count_shards($self); $self->{shards} = $nshards if $nshards && $nshards != $self->{shards}; + $self->{batch_bytes} = $opt->{batch_size} // + $PublicInbox::SearchIdx::BATCH_BYTES; + $self->{batch_bytes} *= $self->{shards} if $self->{parallel}; # need to create all shards before initializing msgmap FD # idx_shards must be visible to all forked processes @@ -629,12 +630,12 @@ sub checkpoint ($;$) { my $barrier = $self->barrier_init(scalar @$shards); # each shard needs to issue a barrier command - $_->remote_barrier for @$shards; + $_->shard_barrier for @$shards; # wait for each Xapian shard $self->barrier_wait($barrier); } else { - $_->remote_commit for @$shards; + $_->shard_commit for @$shards; } # last_commit is special, don't commit these until @@ -654,6 +655,9 @@ sub checkpoint ($;$) { # public sub barrier { checkpoint($_[0], 1) }; +# true if locked and active +sub active { !!$_[0]->{im} } + # public sub done { my ($self) = @_; @@ -674,12 +678,12 @@ sub done { my $shards = delete $self->{idx_shards}; if ($shards) { for (@$shards) { - eval { $_->remote_close }; + eval { $_->shard_close }; $err .= "shard close: $@\n" if $@; } } - eval { $self->{over}->disconnect }; - $err .= "over disconnect: $@\n" if $@; + eval { $self->{over}->dbh_close }; + $err .= "over close: $@\n" if $@; delete $self->{bnote}; my $nbytes = $self->{total_bytes}; $self->{total_bytes} = 0; @@ -727,12 +731,14 @@ sub fill_alternates ($$) { } return unless $new; - my ($fh, $tmp) = tempfile('alt-XXXXXXXX', DIR => $info_dir); + my $fh = File::Temp->new(TEMPLATE => 'alt-XXXXXXXX', DIR => $info_dir); + my $tmp = $fh->filename; print $fh join("\n", sort { $alt{$b} <=> $alt{$a} } keys %alt), "\n" or die "print $tmp: $!\n"; chmod($mode, $fh) or die "fchmod $tmp: $!\n"; close $fh or die "close $tmp $!\n"; rename($tmp, $alt) or die "rename $tmp => $alt: $!\n"; + $fh->unlink_on_destroy(0); } sub git_init { @@ -813,18 +819,17 @@ sub import_init { sub diff ($$$) { my ($mid, $cur, $new) = @_; - my ($ah, $an) = tempfile('email-cur-XXXXXXXX', TMPDIR => 1); + my $ah = File::Temp->new(TEMPLATE => 'email-cur-XXXXXXXX', TMPDIR => 1); print $ah $cur->as_string or die "print: $!"; - close $ah or die "close: $!"; - my ($bh, $bn) = tempfile('email-new-XXXXXXXX', TMPDIR => 1); + $ah->flush or die "flush: $!"; PublicInbox::Import::drop_unwanted_headers($new); + my $bh = File::Temp->new(TEMPLATE => 'email-new-XXXXXXXX', TMPDIR => 1); print $bh $new->as_string or die "print: $!"; - close $bh or die "close: $!"; - my $cmd = [ qw(diff -u), $an, $bn ]; + $bh->flush or die "flush: $!"; + my $cmd = [ qw(diff -u), $ah->filename, $bh->filename ]; print STDERR "# MID conflict <$mid>\n"; my $pid = spawn($cmd, undef, { 1 => 2 }); waitpid($pid, 0) == $pid or die "diff did not finish"; - unlink($an, $bn); } sub get_blob ($$) { @@ -884,7 +889,7 @@ sub reindex_checkpoint ($$) { } # allow -watch or -mda to write... - $self->idx_init; # reacquire lock + $self->idx_init($sync->{-opt}); # reacquire lock $mm_tmp->atfork_parent if $mm_tmp; } @@ -993,7 +998,7 @@ sub log_range ($$$$$) { my $opt = $sync->{-opt}; my $pr = $opt->{-progress} if (($opt->{verbose} || 0) > 1); my $cur = $sync->{ranges}->[$i] or do { - $pr->("$i.git indexing all of $tip") if $pr; + $pr->("$i.git indexing all of $tip\n") if $pr; return $tip; # all of it }; @@ -1105,7 +1110,7 @@ sub unindex_oid_remote ($$$) { my @removed = $self->{over}->remove_oid($oid, $mid); for my $num (@removed) { my $idx = idx_shard($self, $num % $self->{shards}); - $idx->remote_remove($oid, $num); + $idx->shard_remove($oid, $num); } } @@ -1192,21 +1197,20 @@ sub index_xap_only { # git->cat_async callback sub index_xap_step ($$$;$) { my ($self, $sync, $beg, $step) = @_; - my $ibx = $self->{ibx}; - my $all = $ibx->git; - my $over = $ibx->over; - my $batch_bytes = $PublicInbox::SearchIdx::BATCH_BYTES; - $step //= $self->{shards}; my $end = $sync->{art_end}; + return if $beg > $end; # nothing to do + + $step //= $self->{shards}; + my $ibx = $self->{ibx}; if (my $pr = $sync->{-opt}->{-progress}) { $pr->("Xapian indexlevel=$ibx->{indexlevel} ". "$beg..$end (% $step)\n"); } for (my $num = $beg; $num <= $end; $num += $step) { - my $smsg = $over->get_art($num) or next; + my $smsg = $ibx->over->get_art($num) or next; $smsg->{v2w} = $self; - $all->cat_async($smsg->{blob}, \&index_xap_only, $smsg); - if ($self->{transact_bytes} >= $batch_bytes) { + $ibx->git->cat_async($smsg->{blob}, \&index_xap_only, $smsg); + if ($self->{transact_bytes} >= $self->{batch_bytes}) { ${$sync->{nr}} = $num; reindex_checkpoint($self, $sync); } @@ -1229,7 +1233,7 @@ sub index_epoch ($$$) { $self->{current_info} = "$i.git $oid"; if ($f eq 'm') { my $arg = { %$sync, autime => $at, cotime => $ct }; - if ($sync->{index_max_size}) { + if ($sync->{max_size}) { $all->check_async($oid, \&check_size, $arg); } else { $all->cat_async($oid, \&index_oid, $arg); @@ -1247,8 +1251,9 @@ sub index_epoch ($$$) { } sub xapian_only { - my ($self, $opt, $sync) = @_; - my $seq = $opt->{sequentialshard}; + my ($self, $opt, $sync, $art_beg) = @_; + my $seq = $opt->{sequential_shard}; + $art_beg //= 0; local $self->{parallel} = 0 if $seq; $self->idx_init($opt); # acquire lock if (my $art_end = $self->{ibx}->mm->max) { @@ -1262,9 +1267,14 @@ sub xapian_only { $sync->{art_end} = $art_end; if ($seq || !$self->{parallel}) { my $shard_end = $self->{shards} - 1; - index_xap_step($self, $sync, $_) for (0..$shard_end); + for my $i (0..$shard_end) { + index_xap_step($self, $sync, $art_beg + $i); + if ($i != $shard_end) { + reindex_checkpoint($self, $sync); + } + } } else { # parallel (maybe) - index_xap_step($self, $sync, 0, 1); + index_xap_step($self, $sync, $art_beg, 1); } } $self->{ibx}->git->cat_async_wait; @@ -1275,14 +1285,15 @@ sub xapian_only { sub index_sync { my ($self, $opt) = @_; $opt //= $_[1] //= {}; - goto \&xapian_only if $opt->{xapianonly}; + goto \&xapian_only if $opt->{xapian_only}; my $pr = $opt->{-progress}; my $epoch_max; my $latest = git_dir_latest($self, \$epoch_max); return unless defined $latest; - my $seq = $opt->{sequentialshard}; + my $seq = $opt->{sequential_shard}; + my $art_beg; # the NNTP article number we start xapian_only at my $idxlevel = $self->{ibx}->{indexlevel}; local $self->{ibx}->{indexlevel} = 'basic' if $seq; @@ -1306,8 +1317,14 @@ sub index_sync { $self->{mm}->{dbh}->begin_work; $sync->{mm_tmp} = $self->{mm}->tmp_clone($self->{ibx}->{inboxdir}); + + # xapian_only works incrementally w/o --reindex + if ($seq && !$opt->{reindex}) { + $art_beg = $sync->{mm_tmp}->max; + $art_beg++ if defined($art_beg); + } } - if ($sync->{index_max_size} = $self->{ibx}->{index_max_size}) { + if ($sync->{max_size} = $opt->{max_size}) { $sync->{index_oid} = \&index_oid; } # work forwards through history @@ -1320,10 +1337,22 @@ sub index_sync { $pr->('all.git '.sprintf($sync->{-regen_fmt}, $$nr)) if $pr; } - if ($seq) { # deal with Xapian shards sequentially + # deal with Xapian shards sequentially + if ($seq && delete($sync->{mm_tmp})) { $self->{ibx}->{indexlevel} = $idxlevel; - delete $sync->{mm_tmp}; - xapian_only($self, $opt, $sync); + xapian_only($self, $opt, $sync, $art_beg); + } + + # --reindex on the command-line + if ($opt->{reindex} && !ref($opt->{reindex}) && $idxlevel ne 'basic') { + $self->lock_acquire; + my $s0 = PublicInbox::SearchIdx->new($self->{ibx}, 0, 0); + if (my $xdb = $s0->idx_acquire) { + my $n = $xdb->get_metadata('has_threadid'); + $xdb->set_metadata('has_threadid', '1') if $n ne '1'; + } + $s0->idx_release; + $self->lock_release; } # reindex does not pick up new changes, so we rerun w/o it: