-# Copyright (C) 2020 all contributors <meta@public-inbox.org>
+# Copyright (C) all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
# like PublicInbox::SearchIdx, but for searching for non-mail messages.
use PublicInbox::InboxWritable;
use PublicInbox::Search; # for SWIG Xapian and Search::Xapian compat
use PublicInbox::SearchIdx qw(index_text term_generator add_val);
-use PublicInbox::Spawn qw(nodatacow_dir);
use Carp qw(croak);
use File::Path ();
use PublicInbox::MiscSearch;
use PublicInbox::Config;
+use PublicInbox::Syscall;
+my $json;
sub new {
my ($class, $eidx) = @_;
PublicInbox::SearchIdx::load_xapian_writable();
my $mi_dir = "$eidx->{xpfx}/misc";
File::Path::mkpath($mi_dir);
- nodatacow_dir($mi_dir);
+ PublicInbox::Syscall::nodatacow_dir($mi_dir);
my $flags = $PublicInbox::SearchIdx::DB_CREATE_OR_OPEN;
$flags |= $PublicInbox::SearchIdx::DB_NO_SYNC if $eidx->{-no_fsync};
+ $flags |= $PublicInbox::SearchIdx::DB_DANGEROUS if $eidx->{-dangerous};
+ $json //= PublicInbox::Config::json();
bless {
mi_dir => $mi_dir,
flags => $flags,
}, $class;
}
-sub begin_txn {
+sub _begin_txn ($) {
my ($self) = @_;
- croak 'BUG: already in txn' if $self->{xdb}; # XXX make lazy?
my $wdb = $PublicInbox::Search::X{WritableDatabase};
my $xdb = eval { $wdb->new($self->{mi_dir}, $self->{flags}) };
croak "Failed opening $self->{mi_dir}: $@" if $@;
- $self->{xdb} = $xdb;
$xdb->begin_transaction;
+ $xdb;
}
sub commit_txn {
my ($self) = @_;
- croak 'BUG: not in txn' unless $self->{xdb}; # XXX make lazy?
- delete($self->{xdb})->commit_transaction;
+ my $xdb = delete $self->{xdb} or return;
+ $xdb->commit_transaction;
}
+sub create_xdb {
+ my ($self) = @_;
+ $self->{xdb} //= _begin_txn($self);
+ commit_txn($self);
+}
+
+sub remove_eidx_key {
+ my ($self, $eidx_key) = @_;
+ my $xdb = $self->{xdb} //= _begin_txn($self);
+ my $head = $xdb->postlist_begin('Q'.$eidx_key);
+ my $tail = $xdb->postlist_end('Q'.$eidx_key);
+ my @docids; # only one, unless we had bugs
+ for (; $head != $tail; $head++) {
+ push @docids, $head->get_docid;
+ }
+ for my $docid (@docids) {
+ $xdb->delete_document($docid);
+ warn "# remove inbox docid #$docid ($eidx_key)\n";
+ }
+}
+
+# adds or updates according to $eidx_key
sub index_ibx {
my ($self, $ibx) = @_;
my $eidx_key = $ibx->eidx_key;
- my $xdb = $self->{xdb};
+ my $xdb = $self->{xdb} //= _begin_txn($self);
# Q = uniQue in Xapian terminology
my $head = $xdb->postlist_begin('Q'.$eidx_key);
my $tail = $xdb->postlist_end('Q'.$eidx_key);
$xdb->delete_document($_) for @drop; # just in case
my $doc = $PublicInbox::Search::X{Document}->new;
+ term_generator($self)->set_document($doc);
- # allow sorting by modified
+ # allow sorting by modified and uidvalidity (created at)
add_val($doc, $PublicInbox::MiscSearch::MODIFIED, $ibx->modified);
+ add_val($doc, $PublicInbox::MiscSearch::UIDVALIDITY, $ibx->uidvalidity);
- $doc->add_boolean_term('Q'.$eidx_key);
- $doc->add_boolean_term('T'.'inbox');
- term_generator($self)->set_document($doc);
+ $doc->add_boolean_term('Q'.$eidx_key); # uniQue id
+ $doc->add_boolean_term('T'.'inbox'); # Type
+
+ # force reread from disk, {description} could be loaded from {misc}
+ delete @$ibx{qw(-art_min -art_max description)};
+ if (defined($ibx->{newsgroup}) && $ibx->nntp_usable) {
+ $doc->add_boolean_term('T'.'newsgroup'); # additional Type
+ my $n = $ibx->art_min;
+ add_val($doc, $PublicInbox::MiscSearch::ART_MIN, $n) if $n;
+ $n = $ibx->art_max;
+ add_val($doc, $PublicInbox::MiscSearch::ART_MAX, $n) if $n;
+ }
+
+ my $desc = $ibx->description;
# description = S/Subject (or title)
# address = A/Author
- index_text($self, $ibx->description, 1, 'S');
+ index_text($self, $desc, 1, 'S');
+ index_text($self, $ibx->{name}, 1, 'XNAME');
my %map = (
address => 'A',
listid => 'XLISTID',
index_text($self, $v, 1, $pfx);
}
}
- index_text($self, $ibx->{name}, 1, 'XNAME');
my $data = {};
if (defined(my $max = $ibx->max_git_epoch)) { # v2
- my $desc = $ibx->description;
my $pfx = "/$ibx->{name}/git/";
for my $epoch (0..$max) {
my $git = $ibx->git_epoch($epoch) or return;
$ent->{git_dir} = $ibx->{inboxdir};
$data->{"/$ibx->{name}"} = $ent;
}
- $doc->set_data(PublicInbox::Config::json()->encode($data));
+ $doc->set_data($json->encode($data));
if (defined $docid) {
$xdb->replace_document($docid, $doc);
} else {