use PublicInbox::IdxStack;
use Carp qw(croak);
use POSIX qw(strftime);
+use Time::Local qw(timegm);
use PublicInbox::OverIdx;
use PublicInbox::Spawn qw(spawn nodatacow_dir);
use PublicInbox::Git qw(git_unquote);
if ($version == 1) {
$self->{lock_path} = "$inboxdir/ssoma.lock";
my $dir = $self->xdir;
- $self->{over} = PublicInbox::OverIdx->new("$dir/over.sqlite3");
- $self->{over}->{-no_fsync} = 1 if $ibx->{-no_fsync};
+ $self->{oidx} = PublicInbox::OverIdx->new("$dir/over.sqlite3");
+ $self->{oidx}->{-no_fsync} = 1 if $ibx->{-no_fsync};
} elsif ($version == 2) {
defined $shard or die "shard is required for v2\n";
# shard is a number
}
eval 'require '.$X->{WritableDatabase} or die;
*sortable_serialise = $xap.'::sortable_serialise';
+ *sortable_unserialise = $xap.'::sortable_unserialise';
$DB_CREATE_OR_OPEN = eval($xap.'::DB_CREATE_OR_OPEN()');
$DB_OPEN = eval($xap.'::DB_OPEN()');
my $ver = (eval($xap.'::major_version()') << 16) |
($is_shard && need_xapian($self)))) {
File::Path::mkpath($dir);
nodatacow_dir($dir);
+ $self->{-set_has_threadid_once} = 1;
}
}
return unless defined $flag;
$flag |= $DB_NO_SYNC if $self->{ibx}->{-no_fsync};
my $xdb = eval { ($X->{WritableDatabase})->new($dir, $flag) };
- if ($@) {
- die "Failed opening $dir: ", $@;
- }
+ croak "Failed opening $dir: $@" if $@;
$self->{xdb} = $xdb;
}
$doc->add_boolean_term('Q' . $_) for @$mids;
for my $l ($hdr->header_raw('List-Id')) {
$l =~ /<([^>]+)>/ or next;
- my $lid = $1;
+ my $lid = lc $1;
$doc->add_boolean_term('G' . $lid);
index_text($self, $lid, 1, 'XL'); # probabilistic
}
# of the fields which exist in over.sqlite3. We may stop
# storing doc_data in Xapian sometime after we get multi-inbox
# search working.
- if (my $over = $self->{over}) { # v1 only
- $over->add_overview($mime, $smsg);
+ if (my $oidx = $self->{oidx}) { # v1 only
+ $oidx->add_overview($mime, $smsg);
}
if (need_xapian($self)) {
add_xapian($self, $mime, $smsg, $mids);
$smsg->{num};
}
+sub get_val ($$) {
+ my ($doc, $col) = @_;
+ sortable_unserialise($doc->get_value($col));
+}
+
+sub smsg_from_doc ($) {
+ my ($doc) = @_;
+ my $data = $doc->get_data or return;
+ my $smsg = bless {}, 'PublicInbox::Smsg';
+ $smsg->{ts} = get_val($doc, PublicInbox::Search::TS());
+ my $dt = get_val($doc, PublicInbox::Search::DT());
+ my ($yyyy, $mon, $dd, $hh, $mm, $ss) = unpack('A4A2A2A2A2A2', $dt);
+ $smsg->{ds} = timegm($ss, $mm, $hh, $dd, $mon - 1, $yyyy);
+ $smsg->load_from_data($data);
+ $smsg;
+}
+
sub xdb_remove {
my ($self, $oid, @removed) = @_;
my $xdb = $self->{xdb} or return;
warn "E: #$num $oid missing in Xapian\n";
next;
}
- my $smsg = bless {}, 'PublicInbox::Smsg';
- $smsg->load_expand($doc);
- my $blob = $smsg->{blob} // '(unset)';
- if ($blob eq $oid) {
+ my $smsg = smsg_from_doc($doc);
+ my $blob = $smsg->{blob}; # may be undef if --skip-docdata
+ if (!defined($blob) || $blob eq $oid) {
$xdb->delete_document($num);
} else {
warn "E: #$num $oid != $blob in Xapian\n";
sub remove_by_oid {
my ($self, $oid, $num) = @_;
- die "BUG: remove_by_oid is v2-only\n" if $self->{over};
+ die "BUG: remove_by_oid is v2-only\n" if $self->{oidx};
$self->begin_txn_lazy;
xdb_remove($self, $oid, $num) if need_xapian($self);
}
my $nr = 0;
my %tmp;
for my $mid (@$mids) {
- my @removed = eval { $self->{over}->remove_oid($oid, $mid) };
- if ($@) {
- warn "E: failed to remove <$mid> from overview: $@\n";
- } else {
- $nr += scalar @removed;
- $tmp{$_}++ for @removed;
- }
+ my @removed = $self->{oidx}->remove_oid($oid, $mid);
+ $nr += scalar @removed;
+ $tmp{$_}++ for @removed;
}
if (!$nr) {
$mids = join('> <', @$mids);
my $mids = mids($mime);
my $mm = $self->{mm};
if ($sync->{reindex}) {
- my $over = $self->{over};
+ my $oidx = $self->{oidx};
for my $mid (@$mids) {
- my ($num, undef) = $over->num_mid0_for_oid($oid, $mid);
+ my ($num, undef) = $oidx->num_mid0_for_oid($oid, $mid);
return $num if defined $num;
}
$mm->num_for($mids->[0]) // $mm->mid_insert($mids->[0]);
sub v1_checkpoint ($$;$) {
my ($self, $sync, $stk) = @_;
- $self->{ibx}->git->check_async_wait;
- $self->{ibx}->git->cat_async_wait;
+ $self->{ibx}->git->async_wait_all;
# latest_cmt may be undef
my $newest = $stk ? $stk->{latest_cmt} : undef;
$self->{mm}->{dbh}->commit;
if ($newest && need_xapian($self)) {
- my $cur = $self->{xdb}->get_metadata('last_commit');
+ my $xdb = $self->{xdb};
+ my $cur = $xdb->get_metadata('last_commit');
if (need_update($self, $cur, $newest)) {
- $self->{xdb}->set_metadata('last_commit', $newest);
+ $xdb->set_metadata('last_commit', $newest);
+ }
+
+ # let SearchView know a full --reindex was done so it can
+ # generate ->has_threadid-dependent links
+ if ($sync->{reindex} && !ref($sync->{reindex})) {
+ my $n = $xdb->get_metadata('has_threadid');
+ $xdb->set_metadata('has_threadid', '1') if $n ne '1';
}
}
- $self->{over}->rethread_done($sync->{-opt}) if $newest; # all done
+ $self->{oidx}->rethread_done($sync->{-opt}) if $newest; # all done
commit_txn_lazy($self);
$self->{ibx}->git->cleanup;
my $nr = ${$sync->{nr}};
my $pr = $opt->{-progress};
my $sync = { reindex => $opt->{reindex}, -opt => $opt };
my $xdb = $self->begin_txn_lazy;
- $self->{over}->rethread_prepare($opt);
+ $self->{oidx}->rethread_prepare($opt);
my $mm = _msgmap_init($self);
if ($sync->{reindex}) {
my $last = $mm->last_commit;
sub _begin_txn {
my ($self) = @_;
my $xdb = $self->{xdb} || idx_acquire($self);
- $self->{over}->begin_lazy if $self->{over};
+ $self->{oidx}->begin_lazy if $self->{oidx};
$xdb->begin_transaction if $xdb;
$self->{txn} = 1;
$xdb;
return if $self->{shard}; # only continue if undef or 0, not >0
my $xdb = $self->{xdb};
+ if (delete($self->{-set_has_threadid_once})) {
+ $xdb->set_metadata('has_threadid', '1');
+ }
if (delete($self->{-set_indexlevel_once})) {
my $level = $xdb->get_metadata('indexlevel');
if (!$level || $level ne 'medium') {
set_metadata_once($self);
$xdb->commit_transaction;
}
- $self->{over}->commit_lazy if $self->{over};
+ $self->{oidx}->commit_lazy if $self->{oidx};
}
sub commit_txn_lazy {