]> Sergey Matveev's repositories - public-inbox.git/log
public-inbox.git
3 years agolei: start working on bash completion
Eric Wong [Fri, 18 Dec 2020 05:05:09 +0000 (05:05 +0000)]
lei: start working on bash completion

Much work still needs to be done, but that goes for this
entire project :P

3 years agolei: drop $SIG{__DIE__}, add oneshot fallbacks
Eric Wong [Thu, 17 Dec 2020 23:54:04 +0000 (23:54 +0000)]
lei: drop $SIG{__DIE__}, add oneshot fallbacks

We'll force stdout+stderr to be a pipe the spawning client
controls, thus there's no need to lose error reporting by
prematurely redirecting stdout+stderr to /dev/null.

We can now rely exclusively on OnDestroy to write to syslog() on
uncaught die failures.

Also support falling back to oneshot mode on socket and cwd
failures, since some commands may still be useful if the current
working directory goes missing :P

3 years agolei: restore default __DIE__ handler for event loop
Eric Wong [Thu, 17 Dec 2020 11:23:57 +0000 (11:23 +0000)]
lei: restore default __DIE__ handler for event loop

The kqueue code paths will trigger exceptions which are caught
by eval{}, so we can't be calling exit() from the __DIE__
handler and expect eval to catch it.

We only need the __DIE__ handler to deal with fork or open
failures at startup (since stderr is pointed to /dev/null).
After that we can rely on OnDestroy writing errors to syslog
when it goes out of scope.

3 years agoon_destroy: generic localized END
Eric Wong [Thu, 17 Dec 2020 10:45:12 +0000 (10:45 +0000)]
on_destroy: generic localized END

This is a localized version of the process-wide END{}, but runs
at the end of variable scope.  A subroutine ref and arguments
may be passed, which allows us to avoid anonymous subs and
problems they cause.

It's similar to `defer' or `ensure' in other languages; Perl can
rely on deterministic destructors due to refcounting.

3 years agolei_store: keyword extraction from mbox and Maildir
Eric Wong [Thu, 17 Dec 2020 09:20:29 +0000 (09:20 +0000)]
lei_store: keyword extraction from mbox and Maildir

Dovecot, mutt, and likely much other software support mbox
Status/X-Status headers.  Ensure we have a way to extract these
headers as JMAP-compatible keywords before removing them for git
storage.

->add_eml now accepts setting keywords at import time,
and will probably be called like this:

$lst->add_eml($eml, $lst->mbox_keywords($eml));
$lst->add_eml($eml, $lst->maildir_keywords($fn));

3 years agolei_store: relax GIT_COMMITTER_IDENT check
Eric Wong [Thu, 17 Dec 2020 08:13:16 +0000 (08:13 +0000)]
lei_store: relax GIT_COMMITTER_IDENT check

It's pretty meaningless, since probably nobody notices committer
info we extract author info from individual emails, anyways.

3 years agolei: micro-optimize startup time
Eric Wong [Thu, 17 Dec 2020 06:54:41 +0000 (06:54 +0000)]
lei: micro-optimize startup time

We'll use lower-level Socket and avoid IO::Socket::UNIX,
use Cwd::fastcwd(*), avoid IO::Handle->autoflush by
using the select operator, and reuse buffer for reading
the socket while avoiding unnecessary $/ localization
in a tiny script.

All these things adds up to ~5-10 ms savings on my loaded
system.

(*) caveats about fastcwd won't apply since lei won't work
    in removed directories.

3 years agolei: rename $client => $self and bless
Eric Wong [Thu, 17 Dec 2020 06:20:17 +0000 (06:20 +0000)]
lei: rename $client => $self and bless

lei will get bigger, so follow existing OO conventions to make
it easy to call methods in PublicInbox::LEI from other packages.

3 years agolei: help: show actual paths being operated on
Eric Wong [Thu, 17 Dec 2020 05:47:57 +0000 (05:47 +0000)]
lei: help: show actual paths being operated on

This allows us to respect XDG_* environment variables
to override HOME.

We'll also make the $lei wrapper easier-to-use by auto-clearing
$out/$err and reducing [] needed for common cases.

3 years agolei: support pass-through for `lei config'
Eric Wong [Thu, 17 Dec 2020 05:16:16 +0000 (05:16 +0000)]
lei: support pass-through for `lei config'

This will be a handy wrapper for "git config" for manipulating
~/.config/lei/config.  Since we'll have many commands, start
breaking up t/lei.t into more distinct sections for
ease-of-testing.

3 years agorename LeiDaemon package to PublicInbox::LEI
Eric Wong [Thu, 17 Dec 2020 03:53:13 +0000 (03:53 +0000)]
rename LeiDaemon package to PublicInbox::LEI

"LEI" is an acronym, and ALL CAPS is consistent with existing
PublicInbox::{IMAP,HTTP,NNTP,WWW} naming for top-level modules,
3 of 4 old ones which deal directly with sockets and requests.

3 years agosearch: simplify initialization, add ->xdb_shards_flat
Eric Wong [Thu, 17 Dec 2020 03:39:49 +0000 (03:39 +0000)]
search: simplify initialization, add ->xdb_shards_flat

This reduces differences between v1 and v2 code, and
introduces ->xdb_shards_flat to provide read-only access
to shards without using Xapian::MultiDatabase.  This
will allow us to combine shards of several inboxes
AND extindexes for lei.

3 years agolei_store: simplify git_epoch_max, slightly
Eric Wong [Thu, 17 Dec 2020 00:16:18 +0000 (00:16 +0000)]
lei_store: simplify git_epoch_max, slightly

This follows how we detect the max epoch for v2 and shard count
in Xapian.

3 years agolei: support `daemon-env' for modifying long-lived env
Eric Wong [Wed, 16 Dec 2020 09:30:28 +0000 (09:30 +0000)]
lei: support `daemon-env' for modifying long-lived env

While lei(1) socket connections can set environment variables
for its running context, it may not completely remove some of
them.  The background daemon just inherits whatever env the
client spawning it had.  This command ensures the persistent env
can be modified as needed.

Similar to env(1), this supports "-u", "-" (--clear), and
"-0"/"-z" switches.  It may be useful to unset or change
or even completely clear the environment independently
of what a socket client feeds us.

"-i" is omitted since "--ignore-environment" seems like a bad
name for a persistent daemon as opposed to a one-shot command.
"-" and --clear (like clearenv(3)) will completely clobber
the environment.

"Lonesome dash" support is added to our option/help parsing
for the "-" shortcut to "--clear".
Getopt::Long doesn't seem to support specs like "clear|" or
"stdin|", but only "", so we do a little pre/post-processing
to merge the cases.

3 years agolei: ensure we run a restrictive umask
Eric Wong [Wed, 16 Dec 2020 05:59:41 +0000 (05:59 +0000)]
lei: ensure we run a restrictive umask

While we configure the LeiStore git repos and DBs to have a
restrictive umask, lei may also write to Maildirs/mboxes/etc.

We will follow mutt behavior when saving files/messages to the FS.
We only want to create files which are only readable by the local
user since this is intended for private mail and could be used
on shared systems.

We may allow passing the umask on a per-command-basis, but it's
probably not worth the effort to support.

3 years agot/lei-oneshot: standalone oneshot (non-socket) test
Eric Wong [Wed, 16 Dec 2020 05:45:52 +0000 (05:45 +0000)]
t/lei-oneshot: standalone oneshot (non-socket) test

We can use the same "local $ENV{FOO}" hack we do with
t/nntpd-v2.t to test the oneshot code path without imposing
an extra script in the users' $PATH.

3 years agolei: refine help/option parsing, implement "init"
Eric Wong [Tue, 15 Dec 2020 09:14:31 +0000 (09:14 +0000)]
lei: refine help/option parsing, implement "init"

There's a bunch of work in here as the foundations are being
fleshed out.  One of the UI/UX is to make it easy to keep
built-in help and shell completions consistent

3 years agolei: use spawn (vfork + execve) for lazy start
Eric Wong [Tue, 15 Dec 2020 09:03:34 +0000 (09:03 +0000)]
lei: use spawn (vfork + execve) for lazy start

This allows us to rely on FD_CLOEXEC being set on pipes
from prove(1), so forgetting `daemon-stop' won't cause
tests to hang.

Unfortunately, daemon tests will be slower with this.

3 years agotests: more common JSON module loading
Eric Wong [Tue, 15 Dec 2020 08:21:24 +0000 (08:21 +0000)]
tests: more common JSON module loading

We'll probably be using JSON more in the future, so make
it easier to require in tests

3 years agolei_store: local storage for Local Email Interface
Eric Wong [Mon, 14 Dec 2020 11:42:40 +0000 (11:42 +0000)]
lei_store: local storage for Local Email Interface

Still unstable, this builds off the equally unstable extindex :P

This will be used for caching/memoization of traditional mail
stores (IMAP, Maildir, etc) while providing indexing via Xapian,
along with compression, and checksumming from git.

Most notably, this adds the ability to add/remove per-message
keywords (draft, seen, flagged, answered) as described in the
JMAP specification (RFC 8621 section 4.1.1).

We'll use `.' (a single period) as an $eidx_key since it's an
invalid {inboxdir} or {newsgroup} name.

3 years agolei: proposed command-listing and options
Eric Wong [Tue, 15 Dec 2020 03:14:16 +0000 (03:14 +0000)]
lei: proposed command-listing and options

In an attempt to ensure a coherent UI/UX, we'll try to document
all proposed commands and options in one place for easy reference

3 years agolei: FD-passing and IPC basics
Eric Wong [Sun, 13 Dec 2020 22:38:48 +0000 (22:38 +0000)]
lei: FD-passing and IPC basics

The start of lei, a Local Email Interface.  It'll support a
daemon via FD passing to avoid startup time penalties if
IO::FDPass is installed, but fall back to a slow one-shot mode
if not.

Compared to traditional socket daemon, FD passing should allow
us to eventually do stuff like run "git show" and still have
proper terminal support for pager and color.

3 years agoextsearchidx: improve missing machine-id fallback
Eric Wong [Thu, 17 Dec 2020 19:40:06 +0000 (19:40 +0000)]
extsearchidx: improve missing machine-id fallback

It's likely most GNU/Linux systems have /etc/machine-id these
days, so anything missing it is likely a *BSD, most of which
support and favor "sysctl -n kern.hostid".  We'll also support
"ghostid" since GNU utils are commonly prefixed with 'g' on
non-GNU platforms.

In any case, we'll suppress stderr from missing commands and
fall back to hard coding an $OSNAME-based identifier as a last
resort and hope the hostname is unique.

3 years agonntpd: skip inboxes w/o {newsgroup}
Eric Wong [Fri, 18 Dec 2020 11:54:37 +0000 (11:54 +0000)]
nntpd: skip inboxes w/o {newsgroup}

So we don't trigger an uninitialized variable warning :x

3 years agoFix manpage section of perl module documentation
Uwe Kleine-König [Fri, 18 Dec 2020 11:56:14 +0000 (12:56 +0100)]
Fix manpage section of perl module documentation

On Debian (at least) perl documentation is supposed to be installed in
section 3pm. With the build system hardcoding this to 3 instead this
results in a warning by the Debian package linter:

W: public-inbox: wrong-manual-section usr/share/man/man3/PublicInbox::Git.3.gz:74 3 != 3pm
W: public-inbox: wrong-manual-section usr/share/man/man3/PublicInbox::Import.3.gz:74 3 != 3pm
W: public-inbox: wrong-manual-section usr/share/man/man3/PublicInbox::SaPlugin::ListMirror.3.gz:74 3 != 3pm
W: public-inbox: wrong-manual-section ... use --no-tag-display-limit to see all (or pipe to a file/program)

So use "$(MAN3EXT)" instead of "3".

3 years agoimport: drop X-Status in addition to Status
Eric Wong [Thu, 17 Dec 2020 09:14:48 +0000 (09:14 +0000)]
import: drop X-Status in addition to Status

It's actually supported by mutt, dovecot[1], and likely some other
software to augment the Status: header.  While dovecot doesn't
expose X-Status to clients, mutt will write 'A' (answered) and
'F' to X-Status (but not T (draft)).

So we'll drop it like we do Status since it's not suitable for
public mail, but stick it in an @UNWANTED_HEADERS array will
allow us to configure an override if needed.

[1]  https://doc.dovecot.org/configuration_manual/mail_location/mbox/

3 years agoextsearchidx: no need to make InboxWritable
Eric Wong [Wed, 16 Dec 2020 23:19:06 +0000 (23:19 +0000)]
extsearchidx: no need to make InboxWritable

extindex treats v1/v2 public inboxes as read-only, so there's
no need to scare people by using the InboxWritable package
now that ->git_dir_n is gone and we can use ->max_git_epoch
instead of ->git_dir_latest.

3 years agoinboxwritable: drop git_dir_n sub
Eric Wong [Wed, 16 Dec 2020 23:19:05 +0000 (23:19 +0000)]
inboxwritable: drop git_dir_n sub

There's only one caller, unlikely to be any more, and
should be harmless to open code.

3 years agoinbox: simplify v2 epoch counting
Eric Wong [Wed, 16 Dec 2020 23:19:04 +0000 (23:19 +0000)]
inbox: simplify v2 epoch counting

Perl readdir detects list context and can return an array
suitable for the grep op.  From there, we can rely on
substr to remove the ".git" suffix and integerize the value
to save a few bytes before letting List::Util::max return
the value.

This is how we detect Xapian shards nowadays, too, and
we'll also use defined-or (//) to simplify the return
value there.

We'll also simplify InboxWritable->git_dir_latest,
remove some callers, and consider removing it entirely.

3 years agoindex: ignore some warnings, set {current_info} for v1
Eric Wong [Wed, 16 Dec 2020 23:19:03 +0000 (23:19 +0000)]
index: ignore some warnings, set {current_info} for v1

-index runs on data that's already frozen in git, so there's
no point in warning users about it.

While we're at it, set the {current_info} prefix for v1 as
we do in v2 inboxes in case new problems show up.

3 years agoinboxwritable: warn_ignore: "Bad UTF7 data escape"
Eric Wong [Wed, 16 Dec 2020 23:19:02 +0000 (23:19 +0000)]
inboxwritable: warn_ignore: "Bad UTF7 data escape"

As with the other messages in this callback, there's
nothing we can do about invalid messages ending up in
our Maildirs for -watch.

3 years agoextsearchidx: lock eidxq on full --reindex
Eric Wong [Wed, 16 Dec 2020 23:04:53 +0000 (23:04 +0000)]
extsearchidx: lock eidxq on full --reindex

Incremental indexing can use the `eidxq' reindexing queue for
handling deletes and resuming interrupted indexing.  Ensure
those incremental -extindex invocations do not steal (and
prematurely perform) work that an "-extindex --reindex"
invocation is handling.

3 years agosearchidxshard: simplify newline elimination
Eric Wong [Tue, 15 Dec 2020 02:02:24 +0000 (02:02 +0000)]
searchidxshard: simplify newline elimination

This overdue change fixes {current_info} to not inject a newline
into every warning message.

Simpler code helps us avoid bugs and the need to make
fixes like commit 44de182766037948d62bc2a8ba924de2264dd5fc
("searchidxshard: chomp $eidx_key from pipe").

3 years agoextsearchidx: reindex releases over.sqlite3 handles properly
Eric Wong [Tue, 15 Dec 2020 02:02:23 +0000 (02:02 +0000)]
extsearchidx: reindex releases over.sqlite3 handles properly

When checkpointing and yielding the lock to other processes,
we need to ensure any open DB statement handles are closed,
since they reference and prevent DB FDs from being closed
and unlocked.

And clean up some progress reporting while we're at it.

3 years agoextsearchidx: simplify reindex code paths
Eric Wong [Tue, 15 Dec 2020 02:02:22 +0000 (02:02 +0000)]
extsearchidx: simplify reindex code paths

Since we're inside a Xapian transaction, calling ->index_raw
followed by ->shard_add_eidx_info calls on the same docid
doesn't seem to hurt indexing performance.  It definitely
reduces FS read traffic and IPC from git at the cost of some
more IPC between the parent and workers.  Nevertheless, the code
and FD reductions seem worth it.

3 years agoextsearchidx: checkpoint releases locks
Eric Wong [Tue, 15 Dec 2020 02:02:21 +0000 (02:02 +0000)]
extsearchidx: checkpoint releases locks

--reindex can take many hours or days, ensure we release
locks according to --batch-size so automated fetch+index
jobs can write new data to indices while we update old data.

3 years agoextsearchidx: reindex works on Xapian, too
Eric Wong [Tue, 15 Dec 2020 02:02:20 +0000 (02:02 +0000)]
extsearchidx: reindex works on Xapian, too

Instead of just working on over.sqlite3, we need to work on
the Xapian DBs as well.  While no changes to our Xapian use
have taken place recently, they could in the future and
--reindex exists to account for that.

3 years agoextindex: support --rethread and content bifurcation
Eric Wong [Tue, 15 Dec 2020 02:02:19 +0000 (02:02 +0000)]
extindex: support --rethread and content bifurcation

--rethread is useful for dealing with bugs and behaves
just like it does with current inboxes.

This is in case our content deduplication logic changes for
whatever reason and causes previously merged messages to be
considered "different".  As with v2, this won't allow us to
merge messages in a way that allows deduplicating messages which
were previously considered different, but v2 inboxes do not
allow that, either.

In other words, this makes the --reindex and --rethread
switches of -extindex match the behavior of v2 -index.

3 years agoover: sort xref3 by xnum if ibx_id repeats
Eric Wong [Tue, 15 Dec 2020 02:02:18 +0000 (02:02 +0000)]
over: sort xref3 by xnum if ibx_id repeats

While unlikely to happen, it may be possible for messages
from the same inbox to get indexed multiple times.  Provide
consistent results in this case for ease-of-testing.

3 years agoextindex: delete stale messages from over.sqlite3
Eric Wong [Tue, 15 Dec 2020 02:02:17 +0000 (02:02 +0000)]
extindex: delete stale messages from over.sqlite3

In addition to removing stale messages from Xapian, we must
also remove them from over.sqlite3.

3 years agoextindex: preliminary --reindex support
Eric Wong [Tue, 15 Dec 2020 02:02:16 +0000 (02:02 +0000)]
extindex: preliminary --reindex support

--reindex allows us to catch missed and stale messages due to
-extindex vs -index races prior to commit 02b2fcc46f364b51
("extsearchidx: enforce -index before -extindex").

We'll also rely on reindex to internally deal with v1/v2 inbox
removals and partial-unindexing of messages which are only
removed from one inbox out of many.

This reindex design is completely different than how normal
v1/v2 inbox reindex operates due to extindex having multiple
histories to work with.  Instead of scanning git history, this
relies exclusively on comparing over.sqlite3 contents between
the v1/v2 inboxes and the extindex.

Changes to Xapian behavior also get picked up, now.  Xapian indexing
is handled by workers with minimal IPC to the parent process.
This results in more read I/O but fewer writes when dealing
with cross-posted messages.

Changes to $smsg->populate and --rethread still need further
work.

3 years agot/psgi_v2: ignore warnings on missing P::M::ReverseProxy
Eric Wong [Wed, 16 Dec 2020 04:39:37 +0000 (04:39 +0000)]
t/psgi_v2: ignore warnings on missing P::M::ReverseProxy

Plack::Test::ExternalServer doesn't depend on
Plack::Middleware::ReverseProxy, so we need to account for
some warnings in stderr if P::M::RP is missing.

3 years agoinbox: ->uidvalidity returns undef w/o ->mm
Eric Wong [Wed, 16 Dec 2020 23:56:29 +0000 (23:56 +0000)]
inbox: ->uidvalidity returns undef w/o ->mm

While totally unindexed inboxes are rare, we still support
them for v1 and may hit code which calls this method.  Just
return `undef' when ->mm access fails.

3 years agoimap: rename parse_query => parse_imap_query
Eric Wong [Wed, 16 Dec 2020 23:55:34 +0000 (23:55 +0000)]
imap: rename parse_query => parse_imap_query

Avoid confusing hackers since this conflicts with a method name
provided by (Search::)Xapian::QueryParser.

3 years agodaemon: simplify fork() failure checks
Eric Wong [Tue, 15 Dec 2020 11:47:17 +0000 (11:47 +0000)]
daemon: simplify fork() failure checks

The defined-or `//' operator in 5.10 allows us to golf down
our code slightly.

3 years agodaemon: support --daemonize without Net::Server::Daemonize
Eric Wong [Tue, 15 Dec 2020 11:47:16 +0000 (11:47 +0000)]
daemon: support --daemonize without Net::Server::Daemonize

We don't actually need Net::Server::Daemonize to support
the --daemonize flag, since the daemonize() sub provided
by N::S::D doesn't exactly do the things we want.

3 years agoPublicInbox::Feed owns `feedmax' default value
Eric Wong [Fri, 11 Dec 2020 20:49:58 +0000 (20:49 +0000)]
PublicInbox::Feed owns `feedmax' default value

There's no need to have extra code in the Inbox package for this
or to waste dozens of bytes for every Inbox object which uses
the default value.

This makes our code more flexible w.r.t Inbox-like ExtSearch
objects and fixes uninitialized value warnings with ->ALL.

3 years agodoc: v2-format: drop repeated word
Kyle Meyer [Sat, 12 Dec 2020 18:24:48 +0000 (18:24 +0000)]
doc: v2-format: drop repeated word

3 years agodoc: add public-inbox-extindex-format(5) manpage
Eric Wong [Sat, 12 Dec 2020 09:31:42 +0000 (09:31 +0000)]
doc: add public-inbox-extindex-format(5) manpage

The CLI tool still needs usability work, and "misc" is still in
flux, but the core message indexing part is stable (since it's
stolen from v2 :P).

3 years agonntp+www: drop List-* and Archived-At headers
Eric Wong [Thu, 10 Dec 2020 22:38:47 +0000 (22:38 +0000)]
nntp+www: drop List-* and Archived-At headers

These headers can conflict with headers in the DKIM signature;
and parsing the DKIM-Signature header to determine whether or
not we can safely add a header would be more code and CPU
cycles.

Since IMAP seems fine without these headers (and JMAP will
likely be, too), there's likely no need to continue appending
these to every message.  Nowadays, developers seem sufficiently
trained to use URLs with Message-IDs in them.  So drop the
headers and save some cycles and bandwidth all around.

3 years agoextmsg: avoid exceptions when /all/$MSGID/ fails
Eric Wong [Thu, 10 Dec 2020 23:04:50 +0000 (23:04 +0000)]
extmsg: avoid exceptions when /all/$MSGID/ fails

If a message can't be found in ->ALL, we shouldn't attempt to
enter code paths which iterate normal inboxes or attempt to
access non-existent fields (e.g. {name}, {newsgroup},
{inboxdir}) in the ExtSearch object.

3 years agomanifest: account for future cache in MiscIdx docdata
Eric Wong [Thu, 10 Dec 2020 08:35:47 +0000 (08:35 +0000)]
manifest: account for future cache in MiscIdx docdata

We'll be storing private data inside the "" (empty string) key
of the JSON doc we use for store for manifest.js.gz generation.
This private data will allow us to reduce FS activity at and
speed up startup times, but some will also be in Xapian boolean
terms and values for searching and filtering.

3 years agoextsearchidx: enforce -index before -extindex
Eric Wong [Wed, 9 Dec 2020 09:25:12 +0000 (09:25 +0000)]
extsearchidx: enforce -index before -extindex

We cannot set xref3 data without the `xnum' column to
tie it to the per-inbox over.sqlite3 DB.  So ensure we don't
read brand-new history that only exists in git, but instead
rely on last_commit and last_xap15-$EPOCH metadata in msgmap
to decide how far we can index.

Before this change, it was possible to miss messages in
the extindex if -index did not run (which will be fixable by
upcoming --reindex support in -extindex).

3 years agot/extsearch: use indexlevel=basic in inboxes
Eric Wong [Wed, 9 Dec 2020 09:25:11 +0000 (09:25 +0000)]
t/extsearch: use indexlevel=basic in inboxes

There's no need for per-inbox Xapian DBs when using extindex, so
reduce wear on the poor systems this test runs on.

3 years agosearchidx: all indexers check for bad blobs
Eric Wong [Wed, 9 Dec 2020 09:25:10 +0000 (09:25 +0000)]
searchidx: all indexers check for bad blobs

This should help us detect bugs in our code or storage
synchronization problems more easily.  This probably won't
detect corrupted git storage, but can detect corrupted SQLite
files.

"Bad blobs, bad blobs, whatcha gonna do when they come for you?"

3 years agowww+nntp: deal with lack of addresses for ->ALL
Eric Wong [Wed, 9 Dec 2020 23:33:00 +0000 (23:33 +0000)]
www+nntp: deal with lack of addresses for ->ALL

Since extindex is an amalgamation of several inboxes, discerning
an appropriate address for List-Post: would be expensive and
most likely unnecessary.  Some legacy/historical inboxes may
have no active address, either, so don't attempt to set the
List-Post header if no addresses are configured.

3 years agoextsearchidx: ck_existing: set $OID for warning context
Eric Wong [Tue, 8 Dec 2020 21:21:30 +0000 (21:21 +0000)]
extsearchidx: ck_existing: set $OID for warning context

The content_hash() hash in the same scope may trigger warnings
for a given blob, so ensure we correctly report the blob where
it happens.

3 years agoadmin: resolve_repo_dir => resolve_inboxdir
Eric Wong [Tue, 8 Dec 2020 21:21:29 +0000 (21:21 +0000)]
admin: resolve_repo_dir => resolve_inboxdir

We've stopped referring to inboxdirs as "repos" a while ago
since v2 inboxes have multiple git repos associated with them.

So update the name to reflect that and avoid an unnecessary
export that's only used by a test case.

3 years agoextindex: do not use current dir like -index does
Eric Wong [Tue, 8 Dec 2020 21:21:28 +0000 (21:21 +0000)]
extindex: do not use current dir like -index does

At least not for resolving inboxes, since there's no good way
for a user to specify what is an inbox or extindex directory
without a command-line switch.

Instead of changing the -extindex command, we change the -index
command internals to rely on the new {-use_cwd} flag to avoid
internal use of negation, since double-negatives and the like
are confusing to me.

3 years agorename {pi_config} fields to {pi_cfg}
Eric Wong [Tue, 8 Dec 2020 21:21:27 +0000 (21:21 +0000)]
rename {pi_config} fields to {pi_cfg}

{pi_config} may be confused with the documented `PI_CONFIG'
environment variable, and we'll favor vowel-removal to be
consistent with our usage of object references.

The `pi_' prefix may stay in some places, for now; since a
separate namespace may come into this codebase for local/private
client-tooling.

For InboxIdle, we'll also remove an invalid comment about
holding a reference to the PublicInbox::Config object, too.

3 years agonntp: replace {ng} with {ibx} for consistency
Eric Wong [Tue, 8 Dec 2020 21:21:26 +0000 (21:21 +0000)]
nntp: replace {ng} with {ibx} for consistency

They're PublicInbox::Inbox objects just like the rest of
the non-NNTP code.  So rename the NNTP code for consistency
with the rest of the codebase.  Furthermore, {ng} and $ng
may be confused with the `--ng' switch for -init, and that's
a non-ref scalar string.

3 years agotreewide: replace {-inbox} with {ibx} for consistency
Eric Wong [Tue, 8 Dec 2020 21:21:25 +0000 (21:21 +0000)]
treewide: replace {-inbox} with {ibx} for consistency

{ibx} is shorter and is the most prevalent abbreviation
in indexing and IMAP code, and the `$ibx' local variable
is already prevalent throughout.

In general, the codebase favors removal of vowels in variable
and field names to denote non-references (because references are
"lighter" than non-references).

So update WWW and Filter users to use the same code since
it reduces confusion and may allow easier code sharing.

3 years agosearch: reinstate "uid:" internal search prefix
Eric Wong [Sat, 5 Dec 2020 22:22:46 +0000 (22:22 +0000)]
search: reinstate "uid:" internal search prefix

User-supplied queries (via PublicInbox::IMAPsearchqp) may
restrict messages to certain UID ranges in addition to the
limits we impose ourselves for mailbox slices.  So we'll
continue to ask Xapian::QueryParser to "uid:" numeric ranges.

Fixes: 4b551c884a648b45 ("imap: support isearch and reduce Xapian queries")
3 years agoshard_add_eidx_info: pass $eidx_key instead of $ibx object
Eric Wong [Mon, 7 Dec 2020 07:40:53 +0000 (07:40 +0000)]
shard_add_eidx_info: pass $eidx_key instead of $ibx object

This improves consistency with sibling methods such as
->shard_remove_eidx_info and ->add_xref3.  Passing the
$eidx_key scalar is preferable to the entire $ibx object
for IPC-friendliness.

3 years agosearchidx: remove $oid parameter from most calls
Eric Wong [Mon, 7 Dec 2020 07:40:52 +0000 (07:40 +0000)]
searchidx: remove $oid parameter from most calls

Xapian docids have been tied to the over {num} column for
nearly 3 years, now; and OIDs are no longer stored in Xapian
document data.  There's no need to increase code and IPC
complexity by passing the OID around.

3 years agoextsearchidx: remove needless SHA-1 check
Eric Wong [Mon, 7 Dec 2020 07:40:51 +0000 (07:40 +0000)]
extsearchidx: remove needless SHA-1 check

There is no need to verify checksums of data already stored in
git.  Doing this ourselves also limits flexibility in moving to
other hashes.

3 years agooveridx: wrap eidx_key => ibx_id mapping
Eric Wong [Mon, 7 Dec 2020 07:40:50 +0000 (07:40 +0000)]
overidx: wrap eidx_key => ibx_id mapping

This makes things a little less noisy and will be
called by ExtSearchIdx.

3 years agoover: gracefully show invalid ibx_id
Eric Wong [Mon, 7 Dec 2020 07:40:49 +0000 (07:40 +0000)]
over: gracefully show invalid ibx_id

While "public-inbox-extindex --gc" invocations try to ensure
proper ordering, it is still possible for users to change
the `inboxes' tables via sqlite3(1) or similar means.  So
show a "missing://ibx_id=$ibx_id" placeholder to avoid undefined
variable warnings.

URLs such as "imaps://..." will eventually be supported as
eidx_keys, so having a URL-like "missing://" as a placeholder
probably makes sense.

3 years agooveridx: {num} column is INTEGER PRIMARY KEY
Eric Wong [Sat, 5 Dec 2020 22:59:31 +0000 (22:59 +0000)]
overidx: {num} column is INTEGER PRIMARY KEY

INTEGER PRIMARY KEY can be an alias for ROWID in SQLite and is
already unique, so there's no need for a separate UNIQUE(num)
index.

With a smallish ~3K, freshly indexed v2 inbox, this results in a
~40K space savings, reducing over.sqlite3 from 1.375M to 1.335M
(post-VACUUM).

This only affects newly-indexed inboxes; existing DBs will
require manual intervention to take advantage of space savings.

Link: https://www.sqlite.org/rowidtable.html
3 years agoimap: support isearch and reduce Xapian queries
Eric Wong [Sat, 5 Dec 2020 11:10:45 +0000 (11:10 +0000)]
imap: support isearch and reduce Xapian queries

Since IMAP search (either with Isearch or traditional per-Inbox
search) only returns UIDs, we can safely set the limit to the
UID slice size(*).  With isearch, we can also trust the Xapian
result to fit any docid range we specify.

Limiting Xapian results to 1000 was making ->ALL docid <=>
per-Inbox UID impossible since results could overlap between
ranges unpredictably.

Finally, we can map the ->ALL docids into per-Inbox UIDs and
show them to the client in the UID order of the Inbox, not the
docid order of the ->ALL extindex.

This also lets us get rid of the "uid:" query parser prefix
and use the Xapian::Query API directly to reduce our search
prefix footprint.

For mbox.gz downloads in WWW, we'll also make a best effort to
preserve the order from the Inbox, not the order of extindex;
though it's possible large result sets can have non-overlapping
windows.

(*) by definition, UID slice size is a "safe" value which
    shouldn't OOM either the server or clients.

3 years agoisearch: emulate per-inbox search with ->ALL
Eric Wong [Sat, 5 Dec 2020 10:11:38 +0000 (10:11 +0000)]
isearch: emulate per-inbox search with ->ALL

Using "eidx_key:" boolean prefix to limit results to a given
inbox, we can use ->ALL to emulate and replace per-Inbox
xap15/[0-9] search indices.

With this change, the presence of "extindex.all.topdir" in the
$PI_CONFIG will cause the WWW code to use that extindex and
ignore per-inbox Xapian DBs in xap15/[0-9].

Unfortunately IMAP search still requires old per-inbox indices,
for now.  Mapping extindex Xapian docids to per-Inbox UIDs and
vice-versa is proving tricky.  Fortunately, IMAP search is
rarely used and optional.  The RFCs don't specify expensive
phrase search, either, so `indexlevel=medium' can be used in
per-inbox Xapian indices to save space.

For primarily WWW (and future JMAP) users; this should result in
significant disk space, FD, and page cache footprint savings for
large instances with many inboxes and many cross-posted
messages.

3 years agoinbox: simplify ->search and callers
Eric Wong [Sat, 5 Dec 2020 10:11:37 +0000 (10:11 +0000)]
inbox: simplify ->search and callers

Stop leaking WWW/PSGI-specific logic into classes like
PublicInbox::Inbox, which is used universally.

We'll also decouple $ibx->over from $ibx->search and just deal
with duplicate the code inside ->over to reduce argument
complexity in ->search.

This is also a step in moving away from using {psgi.errors}
to ease code sharing between IMAP, NNTP, and command-line
interfaces.  Perl's built-in `warn' and `local $SIG{__WARN__}'
provides all the flexibility we need to control warning output
and should be universally understood by Perl hackers who may
be unfamiliar with PSGI.

3 years agoextmsg: use ->ALL for "global" MID lookups
Eric Wong [Fri, 4 Dec 2020 22:03:49 +0000 (22:03 +0000)]
extmsg: use ->ALL for "global" MID lookups

As with NewsWWW and NNTP, we can use ->ALL to completely
avoid trying SQLite/Xapian lookups across hundreds/thousands
of inboxes.

3 years agonewswww: use ->ALL to avoid O(n) inbox scan
Eric Wong [Fri, 4 Dec 2020 22:03:48 +0000 (22:03 +0000)]
newswww: use ->ALL to avoid O(n) inbox scan

We can avoid doing a Message-ID lookup on every single inbox
by using ->ALL to scan its over.sqlite3 DB.  This mimics NNTP
behavior and picks the first message indexed, though redirecting
to /all/$MESSAGE_ID/ could be done.

With the current lore.kernel.org set of inboxes (~140), this
provides a 10-40% speedup depending on inbox ordering.

3 years agosearch: remove mdocid export
Eric Wong [Fri, 4 Dec 2020 22:03:47 +0000 (22:03 +0000)]
search: remove mdocid export

There's no need to export it, as shown by the change to
SearchView.  This should pave the way to making search
more flexible and allow per-Inbox search to reuse ->ALL.

3 years agonntp: small speed up for multi-line responses
Eric Wong [Fri, 4 Dec 2020 22:03:46 +0000 (22:03 +0000)]
nntp: small speed up for multi-line responses

Using a non-zero-length separator for `join' requires extra work
inside Perl.  We can shove the cost of appending "\r\n" into the
`map' loop, instead.  This speeds up the `join' operation.

The "deferred" log entry for a "LISTGROUP org.kernel.vger.linux-kernel"
command (with nearly 3.8 million messages) goes from ~3.96s to 3.86s
on my workstation.

3 years agonntp: xref_by_tc: simplify slightly
Eric Wong [Fri, 4 Dec 2020 22:03:45 +0000 (22:03 +0000)]
nntp: xref_by_tc: simplify slightly

We can invalidate ibx->{newsgroup} at config load-time to avoid
having to check ibx->{newsgroup} validity in To/Cc: matching.
This saves us some hash lookups in all cases.

3 years agoover: ensure old, merged {tid} is really gone
Eric Wong [Fri, 4 Dec 2020 12:09:29 +0000 (12:09 +0000)]
over: ensure old, merged {tid} is really gone

We must use the result of link_refs() since it can trigger
merge_threads() and invalidate $old_tid.  In case
merge_threads() isn't triggered, link_refs() will return
$old_tid anyways.

When rethreading and allocating new {tid}, we also must update
the row where the now-expired {tid} came from to ensure only the
new {tid} is seen when reindexing subsequent messages in
history.  Otherwise, every subsequently reindexed+rethreaded
message could end up getting a new {tid}.

Reported-by: Kyle Meyer <kyle@kyleam.com>
Link: https://public-inbox.org/meta/87360nlc44.fsf@kyleam.com/
3 years agonntp: make ->ALL Xref generation more fuzzy
Eric Wong [Mon, 30 Nov 2020 23:37:42 +0000 (23:37 +0000)]
nntp: make ->ALL Xref generation more fuzzy

For ->ALL users, this mitigates the regression introduced
by commit 811b8d3cbaa790f59b7b107140b86248da16499b
("nntp: xref: use ->ALL extindex if available"), since
it's common to cross post messages to some mailing
lists with per-list trailers for unsubscribe information.

We won't bother dealing with Bcc-ed messages since those
are nearly all spam when it comes to public mailing lists.

Fixes: 811b8d3cbaa790f5 ("nntp: xref: use ->ALL extindex if available")
Link: https://public-inbox.org/meta/20201130194201.GA6687@dcvr/
3 years agonntpd: move {newsgroup} name check to config
Eric Wong [Tue, 1 Dec 2020 01:35:46 +0000 (01:35 +0000)]
nntpd: move {newsgroup} name check to config

With 50K newsgroups in the config file, this doesn't slow down
`PublicInbox::Config->new->fill_all' any measurable amount on
my busy old workstation.

This should prevent invalid newsgroup names from getting into
into extindex and catch user errors sooner, rather than later.

v2:
  - delete {newsgroup} if invalid to avoid ->nntp_url link
  - simplify -imapd and explain remaining check

3 years agot/extsearch: test ->has_threadid
Eric Wong [Sun, 29 Nov 2020 20:19:47 +0000 (20:19 +0000)]
t/extsearch: test ->has_threadid

Since has_threadid predates the existence of ExtSearch, we can
be certain the Xapian DB can collapse by threadid.

3 years agogit: ensure subclassed ->fail gets called
Eric Wong [Sun, 29 Nov 2020 10:52:30 +0000 (10:52 +0000)]
git: ensure subclassed ->fail gets called

Some of these changes may not be strictly necessary, but it
makes code easier to maintain and change.  Hackers
using/modifying this code will no longer wonder if a particular
callsite needs to care about subclasses or not.

3 years agogit: set non-blocking flag in case of other bugs
Eric Wong [Sun, 29 Nov 2020 10:52:29 +0000 (10:52 +0000)]
git: set non-blocking flag in case of other bugs

This makes GitAsyncCat more resilient to bugs in Gcf2 or even
git-cat-file itself.  I noticed -imapd stuck on read(2) from
the Gcf2 pipe, so there may be a bug somewhere in Gcf2 or
PublicInbox::Git.  This should make us more resilient to them
and hopefully help us notice and fix them.

3 years agoextindex: support `--gc' to remove dead inboxes
Eric Wong [Sun, 29 Nov 2020 05:09:35 +0000 (05:09 +0000)]
extindex: support `--gc' to remove dead inboxes

Inboxes may be removed or newsgroups renamed over time.
Introduce a switch to do garbage collection and eliminate stale
search and xref3 results based on inboxes which remain in the
config file.

This may also fixup stale results leftover from any bugs which
may leave stale data around.

This is also useful in case a clumsy BOFH (me :P) is swapping
between several PI_CONFIGs and accidentally indexed a bunch of
inboxes they didn't intend to.

3 years agov2writable: detect shard count for ExtSearchIdx properly
Eric Wong [Sun, 29 Nov 2020 05:09:34 +0000 (05:09 +0000)]
v2writable: detect shard count for ExtSearchIdx properly

Otherwise, any explicitly set shard counts were ignored and
we'd be counting CPUs every single time.

3 years agonntpd: remove redundant {groups} shortcut
Eric Wong [Sat, 28 Nov 2020 05:09:16 +0000 (05:09 +0000)]
nntpd: remove redundant {groups} shortcut

It's not worth confusing hackers reading the source to have
two ways to access the same (large) hash table.  So just
go through PublicInbox::Config objects for now since the
extra hash lookup isn't going to be noticeable.

I've also started favoring "for" instead of "foreach"
since they're the equivalent perlop and less wear on
my fingers + keyboard.

3 years agonntp: XPATH uses ->ALL extindex, too
Eric Wong [Sat, 28 Nov 2020 05:09:15 +0000 (05:09 +0000)]
nntp: XPATH uses ->ALL extindex, too

Another 30-40% speedup when testing against a local
lore.kernel.org mirror.  In either case, we'll consistently sort
the response for ease-of-testing and client-side
cache-friendliness.

3 years agonntp: art_lookup: use mid_lookup and simplify
Eric Wong [Sat, 28 Nov 2020 05:09:14 +0000 (05:09 +0000)]
nntp: art_lookup: use mid_lookup and simplify

This lets us take advantage of mid_lookup speedup from the
previous commit.

While we're at it, start moving towards using `$ibx' as the
abbreviation for PublicInbox::Inbox objects even in the NNTP
code, since they've been shared with the WWW code for several
years, now.

3 years agonntp: speed up mid_lookup() using ->ALL extindex
Eric Wong [Sat, 28 Nov 2020 05:09:13 +0000 (05:09 +0000)]
nntp: speed up mid_lookup() using ->ALL extindex

We can reuse "xref3" information in extindex to quickly match
messages matching a given Message-ID across hundreds or
thousands of newsgroups with a few SQL statements.

"XHDR Xref $MESSAGE_ID" is around 40% faster, on top of
previous speedups.

3 years agonntp: NEWGROUPS uses long_response
Eric Wong [Sat, 28 Nov 2020 05:09:12 +0000 (05:09 +0000)]
nntp: NEWGROUPS uses long_response

We can amortize the cost of NEWGROUPS time filtering using the
long_response API.  This lets us handle hundreds/thousands of
inboxes without monopolizing the event loop for this command.

Further speedup is possible using MiscSearch, but that requires
not-yet-done indexing changes to MiscIdx.

3 years agoextindex: fix delete (`d') handling
Eric Wong [Sat, 28 Nov 2020 08:45:21 +0000 (08:45 +0000)]
extindex: fix delete (`d') handling

We need to completely remove a message from over.sqlite3 and
Xapian when no references remain, otherwise users will still see
the removed messages in NNTP overviews and WWW search
results/summaries.

References to messages are now solely handled by the `xref3'
table of over.sqlite3.  We can also trust `xref3' when deciding
whether to remove only the "O$eidx_key" and "G$lid" terms from a
document in Xapian or to remove the entire Xapian document.

3 years agosearchidxshard: chomp $eidx_key from pipe
Eric Wong [Sat, 28 Nov 2020 07:06:50 +0000 (07:06 +0000)]
searchidxshard: chomp $eidx_key from pipe

We were accidentally adding "\n" to terms (which Xapian happily
accepts), causing incompatibilities when enabling parallel
sharding in some invocations of -extindex but not others.

This is an extindex incompatibility and starting a new extindex
will be required to take advantage of in-development features,
so it's not urgent to start another one, either.
(other incompatible things may happen before a 1.7 release)

3 years ago*index: more consistent graceful shutdown checks
Eric Wong [Fri, 27 Nov 2020 21:33:55 +0000 (21:33 +0000)]
*index: more consistent graceful shutdown checks

v1 and v2 inbox indexing now supports graceful shutdown checks
just like ExtSearchIdx.  Additionally, we'll consistently
perform quit checks at the top of loops for consistency.

Interaction with the --xapian-only and --sequential-shard
options are a bit lacking, and will warn the user to use
"--reindex --xapian-only" to fix.

3 years agonntp: xref: use ->ALL extindex if available
Eric Wong [Fri, 27 Nov 2020 09:52:54 +0000 (09:52 +0000)]
nntp: xref: use ->ALL extindex if available

Getting Xref for cross-posted messages is an O(n) operation
where `n' is the number of newsgroups on the server.  This works
acceptably when there are dozens of groups, but would be
unnacceptable when there's tens of thousands of newsgroups.

With ~140 newsgroups, a lore.kernel.org mirror already handles
"XHDR Xref $MESSAGE_ID" requests around 30% faster after
creating the xref3.idx_nntp index.

The SQL additions to ExtSearch.pm may be a bit strange and
seem more appropriate for Over.pm; however it currently makes
sense to me since those bits of over.sqlite3 access are
exclusive to ExtSearch and can't be used by traditional
v1/v2 inboxes...

3 years agonntp: xref: simplify sub signature
Eric Wong [Fri, 27 Nov 2020 09:52:53 +0000 (09:52 +0000)]
nntp: xref: simplify sub signature

We'll be using the `xref3' table in extindex to speed up xref(),
and that'll require comparisons against $smsg->{blob}.  So pass
the entire $smsg through.

3 years agonntp: some minor golfing
Eric Wong [Fri, 27 Nov 2020 09:52:52 +0000 (09:52 +0000)]
nntp: some minor golfing

Reduce screen real estate usage to reduce human attention span
requirements.

3 years agot/extsearch: show a more realistic case
Eric Wong [Fri, 27 Nov 2020 09:52:51 +0000 (09:52 +0000)]
t/extsearch: show a more realistic case

Different messages to different public Inboxes are likely to
have different List-IDs, so show that we can deduplicate based
on content (but per-mailing-list trailers need to go through a
PublicInbox::Filter::* or be disabled by mailing list admins).

3 years agonntp: move LIST iterators to long_response
Eric Wong [Fri, 27 Nov 2020 09:52:50 +0000 (09:52 +0000)]
nntp: move LIST iterators to long_response

Iterating through many newsgroups can hog the event loop if many
random seeks are required.  Avoid monopolizing the event loop in
that case by using the long_response API.

For now, we can still rely on grep() since it seems to work
reasonably well with 50K test newsgroup names.

3 years agonntp: LIST ACTIVE.TIMES use angle brackets around address
Eric Wong [Fri, 27 Nov 2020 09:52:49 +0000 (09:52 +0000)]
nntp: LIST ACTIVE.TIMES use angle brackets around address

This matches the example shown in RFC 3977, section 7.6.1.3

3 years agomiscsearch: implement ->newsgroup_matches
Eric Wong [Fri, 27 Nov 2020 09:52:48 +0000 (09:52 +0000)]
miscsearch: implement ->newsgroup_matches

This may be used to speed up newsgroup searches down-the-line,
but the grep perlop isn't too shabby, at the moment.