]> Sergey Matveev's repositories - public-inbox.git/commitdiff
lei_mail_sync: rely on flock(2), avoid IPC
authorEric Wong <e@80x24.org>
Sat, 18 Sep 2021 09:33:25 +0000 (09:33 +0000)
committerEric Wong <e@80x24.org>
Sat, 18 Sep 2021 20:25:27 +0000 (20:25 +0000)
Since 44917fdd24a8bec1 ("lei_mail_sync: do not use transactions"),
relying on lei/store to serialize access was a pointless endeavor.

Rely on flock(2) to serialize multiple writers since (in my
experience) it's the easiest way to deal with parallel writers
when using SQLite.  This allows us to simplify existing callers
while speeding up 'lei refresh-mail-sync --all=local' by 5% or
so.

12 files changed:
lib/PublicInbox/LEI.pm
lib/PublicInbox/LeiExportKw.pm
lib/PublicInbox/LeiForgetMailSync.pm
lib/PublicInbox/LeiImport.pm
lib/PublicInbox/LeiInput.pm
lib/PublicInbox/LeiInspect.pm
lib/PublicInbox/LeiLsMailSync.pm
lib/PublicInbox/LeiMailSync.pm
lib/PublicInbox/LeiNoteEvent.pm
lib/PublicInbox/LeiRefreshMailSync.pm
lib/PublicInbox/LeiStore.pm
lib/PublicInbox/LeiToMail.pm

index 41e761f8aabf939e81af2afb0b82bf7058b83e5e..053b6174d808514f04227b32f3bef982e72b3498 100644 (file)
@@ -1442,20 +1442,16 @@ sub refresh_watches {
        }
 
        # add all known Maildir folders as implicit watches
-       my $sto = $lei->_lei_store;
-       my $renames = 0;
-       if (my $lms = $sto ? $sto->search->lms : undef) {
+       my $lms = $lei->lms;
+       if ($lms) {
+               $lms->lms_write_prepare;
                for my $d ($lms->folders('maildir:')) {
                        substr($d, 0, length('maildir:')) = '';
-                       my $cd = canonpath_harder($d);
-                       my $f = "maildir:$cd";
 
                        # fixup old bugs while we're iterating:
-                       if ($d ne $cd) {
-                               $sto->ipc_do('lms_rename_folder',
-                                               "maildir:$d", $f);
-                               ++$renames;
-                       }
+                       my $cd = canonpath_harder($d);
+                       my $f = "maildir:$cd";
+                       $lms->rename_folder("maildir:$d", $f) if $d ne $cd;
                        next if $watches->{$f}; # may be set to pause
                        require PublicInbox::LeiWatch;
                        $watches->{$f} = PublicInbox::LeiWatch->new($f);
@@ -1463,7 +1459,6 @@ sub refresh_watches {
                        add_maildir_watch($cd, $cfg_f);
                }
        }
-       $lei->sto_done_request if $renames;
        if ($old) { # cull old non-existent entries
                for my $url (keys %$old) {
                        next if exists $seen{$url};
@@ -1490,13 +1485,12 @@ sub git_oid {
        git_sha(1, $eml);
 }
 
-sub lms { # read-only LeiMailSync
-       my ($lei) = @_;
-       my $lse = $lei->{lse} // do {
-               my $sto = $lei->{sto} // _lei_store($lei);
-               $sto ? $sto->search : undef
-       };
-       $lse ? $lse->lms : undef;
+sub lms {
+       my ($lei, $rw) = @_;
+       my $sto = $lei->{sto} // _lei_store($lei) // return;
+       require PublicInbox::LeiMailSync;
+       my $f = "$sto->{priv_eidx}->{topdir}/mail_sync.sqlite3";
+       (-f $f || $rw) ? PublicInbox::LeiMailSync->new($f) : undef;
 }
 
 sub sto_done_request { # only call this from lei-daemon process (not workers)
index 8b8aa373a37199c1705835f8deb254c7e43f0f5b..8c5fbc13079eedc83445df7382a3432a3f268ec6 100644 (file)
@@ -40,7 +40,7 @@ sub export_kw_md { # LeiMailSync->each_src callback
                        if (!unlink($src) and $! != ENOENT) {
                                $lei->child_error(1, "E: unlink($src): $!");
                        }
-                       $lei->{sto}->ipc_do('lms_mv_src', "maildir:$mdir",
+                       $self->{lms}->mv_src("maildir:$mdir",
                                                $oidbin, $id, $bn);
                        return; # success anyways if link(2) worked
                } elsif ($! == EEXIST) { # lost race with lei/store?
@@ -55,7 +55,7 @@ sub export_kw_md { # LeiMailSync->each_src callback
        my $src = "$mdir/{".join(',', @try)."}/$$id";
        $lei->child_error(1, "link($src -> $dst) ($oidhex): $e");
        for (@try) { return if -e "$mdir/$_/$$id" }
-       $lei->{sto}->ipc_do('lms_clear_src', "maildir:$mdir", $id);
+       $self->{lms}->clear_src("maildir:$mdir", $id);
 }
 
 sub export_kw_imap { # LeiMailSync->each_src callback
@@ -67,18 +67,17 @@ sub export_kw_imap { # LeiMailSync->each_src callback
 # overrides PublicInbox::LeiInput::input_path_url
 sub input_path_url {
        my ($self, $input, @args) = @_;
-       my $lms = $self->{-lms_ro} //= $self->{lse}->lms;
+       $self->{lms}->lms_write_prepare;
        if ($input =~ /\Amaildir:(.+)/i) {
                my $mdir = $1;
                require PublicInbox::LeiToMail; # kw2suffix
-               $lms->each_src($input, \&export_kw_md, $self, $mdir);
+               $self->{lms}->each_src($input, \&export_kw_md, $self, $mdir);
        } elsif ($input =~ m!\Aimaps?://!i) {
                my $uri = PublicInbox::URIimap->new($input);
                my $mic = $self->{nwr}->mic_for_folder($uri);
-               $lms->each_src($$uri, \&export_kw_imap, $self, $mic);
+               $self->{lms}->each_src($$uri, \&export_kw_imap, $self, $mic);
                $mic->expunge;
        } else { die "BUG: $input not supported" }
-       my $wait = $self->{lei}->{sto}->ipc_do('done');
 }
 
 sub lei_export_kw {
@@ -86,26 +85,25 @@ sub lei_export_kw {
        my $sto = $lei->_lei_store or return $lei->fail(<<EOM);
 lei/store uninitialized, see lei-import(1)
 EOM
-       my $lse = $sto->search;
-       my $lms = $lse->lms or return $lei->fail(<<EOM);
+       my $lms = $lei->lms or return $lei->fail(<<EOM);
 lei mail_sync uninitialized, see lei-import(1)
 EOM
-       my $opt = $lei->{opt};
-       if (defined(my $all = $opt->{all})) { # --all=<local|remote>
+       if (defined(my $all = $lei->{opt}->{all})) { # --all=<local|remote>
                $lms->group2folders($lei, $all, \@folders) or return;
+               @folders = grep(/\A(?:maildir|imaps?):/i, @folders);
        } else {
                my $err = $lms->arg2folder($lei, \@folders);
                $lei->qerr(@{$err->{qerr}}) if $err->{qerr};
                return $lei->fail($err->{fail}) if $err->{fail};
        }
-       my $self = bless { lse => $lse }, __PACKAGE__;
+       $lms->lms_pause;
+       my $self = bless { lse => $sto->search, lms => $lms }, __PACKAGE__;
        $lei->{opt}->{'mail-sync'} = 1; # for prepare_inputs
        $self->prepare_inputs($lei, \@folders) or return;
-       my $j = $opt->{jobs} // scalar(@{$self->{inputs}}) || 1;
        if (my @ro = grep(!/\A(?:maildir|imaps?):/i, @folders)) {
                return $lei->fail("cannot export to read-only folders: @ro");
        }
-       my $m = $opt->{mode} // 'merge';
+       my $m = $lei->{opt}->{mode} // 'merge';
        if ($m eq 'merge') { # default
                $self->{-merge_kw} = 1;
        } elsif ($m eq 'set') {
@@ -120,11 +118,9 @@ EOM
                $self->{imap_mod_kw} = $net->can($self->{-merge_kw} ?
                                        'imap_add_kw' : 'imap_set_kw');
        }
-       undef $lms; # for fork
        my $ops = {};
-       $sto->write_prepare($lei);
        $lei->{auth}->op_merge($ops, $self) if $lei->{auth};
-       (my $op_c, $ops) = $lei->workers_start($self, $j, $ops);
+       (my $op_c, $ops) = $lei->workers_start($self, 1, $ops);
        $lei->{wq1} = $self;
        $lei->{-err_type} = 'non-fatal';
        net_merge_all_done($self) unless $lei->{auth};
@@ -133,8 +129,7 @@ EOM
 
 sub _complete_export_kw {
        my ($lei, @argv) = @_;
-       my $sto = $lei->_lei_store or return;
-       my $lms = $sto->search->lms or return;
+       my $lms = $lei->lms or return;
        my $match_cb = $lei->complete_url_prepare(\@argv);
        map { $match_cb->($_) } $lms->folders;
 }
index 2b4e58a9b39a7c3ed69e53341920489d81d8f44c..701f48d2fbbb278e4bffcb79871d7608ba1fa630 100644 (file)
@@ -15,13 +15,11 @@ use PublicInbox::LeiExportKw;
 sub lei_forget_mail_sync {
        my ($lei, @folders) = @_;
        my $lms = $lei->lms or return;
-       my $sto = $lei->_lei_store or return; # may disappear due to race
-       $sto->write_prepare($lei);
+       $lms->lms_write_prepare;
        my $err = $lms->arg2folder($lei, \@folders);
        $lei->qerr(@{$err->{qerr}}) if $err->{qerr};
        return $lei->fail($err->{fail}) if $err->{fail};
-       $sto->ipc_do('lms_forget_folders', @folders);
-       $lei->sto_done_request;
+       $lms->forget_folders(@folders);
 }
 
 *_complete_forget_mail_sync = \&PublicInbox::LeiExportKw::_complete_export_kw;
index b1cb3940ee365cfe7f65e26585b53658cb576ea8..9084d771cf521cefd8b64c738f0ceec07020bca5 100644 (file)
@@ -36,7 +36,7 @@ sub pmdir_cb { # called via wq_io_do from LeiPmdir->each_mdir_fn
        my $kw = PublicInbox::MdirReader::flags2kw($fl);
        substr($folder, 0, 0) = 'maildir:'; # add prefix
        my $lse = $self->{lse} //= $self->{lei}->{sto}->search;
-       my $lms = $self->{-lms_ro} //= $lse->lms; # may be 0 or undef
+       my $lms = $self->{-lms_ro} //= $self->{lei}->lms; # may be 0 or undef
        my $oidbin = $lms ? $lms->name_oidbin($folder, $bn) : undef;
        my @docids = defined($oidbin) ? $lse->over->oidbin_exists($oidbin) : ();
        my $vmd = $self->{-import_kw} ? { kw => $kw } : undef;
@@ -83,7 +83,7 @@ sub do_import_index ($$@) {
                # $j = $net->net_concurrency($j); TODO
                if ($lei->{opt}->{incremental} // 1) {
                        $net->{incremental} = 1;
-                       $net->{-lms_ro} = $sto->search->lms // 0;
+                       $net->{-lms_ro} = $lei->lms // 0;
                        if ($self->{-import_kw} && $net->{-lms_ro} &&
                                        !$lei->{opt}->{'new-only'} &&
                                        $net->{imap_order}) {
@@ -120,8 +120,7 @@ sub _complete_import {
        my $match_cb = $lei->complete_url_prepare(\@argv);
        my @m = map { $match_cb->($_) } $lei->url_folder_cache->keys;
        my %f = map { $_ => 1 } @m;
-       my $sto = $lei->_lei_store;
-       if (my $lms = $sto ? $sto->search->lms : undef) {
+       if (my $lms = $lei->lms) {
                @m = map { $match_cb->($_) } $lms->folders;
                @f{@m} = @m;
        }
index 372e0fe19f3ae6d2ba1f7b2461383b1d10ad0f4c..fe736981ba6565d111871f6778b11838d1ecf83d 100644 (file)
@@ -360,7 +360,7 @@ $input is `eml', not --in-format=$in_fmt
                # start watching Maildirs ASAP
                if ($may_sync && $lei->{sto}) {
                        grep(!m!\Amaildir:/!i, @md) and die "BUG: @md (no pfx)";
-                       my $wait = $lei->{sto}->ipc_do('add_sync_folders', @md);
+                       $lei->lms(1)->lms_write_prepare->add_folders(@md);
                        $lei->refresh_watches;
                }
        }
index 2385f7f82fe6499aae4941ab9961e00a59a14697..f06cea613e600c266190d33ef2e496cfa05d8987 100644 (file)
@@ -18,7 +18,7 @@ sub inspect_blob ($$) {
                my $oidbin = pack('H*', $oidhex);
                my @docids = $lse ? $lse->over->oidbin_exists($oidbin) : ();
                $ent->{'lei/store'} = \@docids if @docids;
-               my $lms = $lse->lms;
+               my $lms = $lei->lms;
                if (my $loc = $lms ? $lms->locations_for($oidbin) : undef) {
                        $ent->{'mail-sync'} = $loc;
                }
@@ -29,8 +29,7 @@ sub inspect_blob ($$) {
 sub inspect_imap_uid ($$) {
        my ($lei, $uid_uri) = @_;
        my $ent = {};
-       my $lse = $lei->{lse} or return $ent;
-       my $lms = $lse->lms or return $ent;
+       my $lms = $lei->lms or return $ent;
        my $oidhex = $lms->imap_oid($lei, $uid_uri);
        if (ref(my $err = $oidhex)) { # art2folder error
                $lei->qerr(@{$err->{qerr}}) if $err->{qerr};
index 505c0b3f55fcd95202c87ef3701f54785fd52730..2b167b1d68ff34edb2d071174ed71421416cfb17 100644 (file)
@@ -9,8 +9,7 @@ use PublicInbox::LeiMailSync;
 
 sub lei_ls_mail_sync {
        my ($lei, $filter) = @_;
-       my $sto = $lei->_lei_store or return;
-       my $lms = $sto->search->lms or return;
+       my $lms = $lei->lms or return;
        my $opt = $lei->{opt};
        my $re = $opt->{globoff} ? undef : $lei->glob2re($filter // '*');
        $re //= qr/\Q$filter\E/;
index 8f584ccbb7ad8f68a7c1d0af4aaf8f4d4026f7a8..690c6477efa9c3be76242392d39fcdad90d1378e 100644 (file)
@@ -5,6 +5,7 @@
 package PublicInbox::LeiMailSync;
 use strict;
 use v5.10.1;
+use parent qw(PublicInbox::Lock);
 use DBI;
 use PublicInbox::ContentHash qw(git_sha);
 use Carp ();
@@ -21,7 +22,7 @@ sub dbh_new {
                sqlite_use_immediate_transaction => 1,
        });
        # no sqlite_unicode, here, all strings are binary
-       create_tables($dbh) if $rw;
+       create_tables($self, $dbh) if $rw;
        $dbh->do('PRAGMA journal_mode = WAL') if $creat;
        $dbh->do('PRAGMA case_sensitive_like = ON');
        $dbh;
@@ -29,13 +30,24 @@ sub dbh_new {
 
 sub new {
        my ($cls, $f) = @_;
-       bless { filename => $f, fmap => {} }, $cls;
+       bless {
+               filename => $f,
+               fmap => {},
+               lock_path => "$f.flock",
+       }, $cls;
 }
 
-sub lms_write_prepare { ($_[0]->{dbh} //= dbh_new($_[0], 1)) };
+sub lms_write_prepare { ($_[0]->{dbh} //= dbh_new($_[0], 1)); $_[0] }
+
+sub lms_pause {
+       my ($self) = @_;
+       $self->{fmap} = {};
+       delete $self->{dbh};
+}
 
 sub create_tables {
-       my ($dbh) = @_;
+       my ($self, $dbh) = @_;
+       my $lk = $self->lock_for_scope;
 
        $dbh->do(<<'');
 CREATE TABLE IF NOT EXISTS folders (
@@ -115,8 +127,15 @@ EOM
        $fid;
 }
 
+sub add_folders {
+       my ($self, @folders) = @_;
+       my $lk = $self->lock_for_scope;
+       for my $f (@folders) { $self->{fmap}->{$f} //= fid_for($self, $f, 1) }
+}
+
 sub set_src {
        my ($self, $oidbin, $folder, $id) = @_;
+       my $lk = $self->lock_for_scope;
        my $fid = $self->{fmap}->{$folder} //= fid_for($self, $folder, 1);
        my $sth;
        if (ref($id)) { # scalar name
@@ -134,6 +153,7 @@ INSERT OR IGNORE INTO blob2num (oidbin, fid, uid) VALUES (?, ?, ?)
 
 sub clear_src {
        my ($self, $folder, $id) = @_;
+       my $lk = $self->lock_for_scope;
        my $fid = $self->{fmap}->{$folder} //= fid_for($self, $folder, 1);
        my $sth;
        if (ref($id)) { # scalar name
@@ -152,6 +172,7 @@ DELETE FROM blob2num WHERE fid = ? AND uid = ?
 # Maildir-only
 sub mv_src {
        my ($self, $folder, $oidbin, $id, $newbn) = @_;
+       my $lk = $self->lock_for_scope;
        my $fid = $self->{fmap}->{$folder} //= fid_for($self, $folder, 1);
        my $sth = $self->{dbh}->prepare_cached(<<'');
 UPDATE blob2name SET name = ? WHERE fid = ? AND oidbin = ? AND name = ?
@@ -421,18 +442,23 @@ EOF
        $err;
 }
 
-sub forget_folder {
-       my ($self, $folder) = @_;
-       my $fid = delete($self->{fmap}->{$folder}) //
-               fid_for($self, $folder) // return;
-       for my $t (qw(blob2name blob2num folders)) {
-               $self->{dbh}->do("DELETE FROM $t WHERE fid = ?", undef, $fid);
+sub forget_folders {
+       my ($self, @folders) = @_;
+       my $lk = $self->lock_for_scope;
+       for my $folder (@folders) {
+               my $fid = delete($self->{fmap}->{$folder}) //
+                       fid_for($self, $folder) // next;
+               for my $t (qw(blob2name blob2num folders)) {
+                       $self->{dbh}->do("DELETE FROM $t WHERE fid = ?",
+                                       undef, $fid);
+               }
        }
 }
 
 # only used for changing canonicalization errors
 sub rename_folder {
        my ($self, $old, $new) = @_;
+       my $lk = $self->lock_for_scope;
        my $ofid = delete($self->{fmap}->{$old}) //
                fid_for($self, $old) // return;
        eval {
index 414153468b22599ba153d24a9f23c6790fb52550..c03c53193b032297da2d9abee056c3892a9844ab 100644 (file)
@@ -2,6 +2,7 @@
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 
 # internal command for dealing with inotify, kqueue vnodes, etc
+# it is a semi-persistent worker
 package PublicInbox::LeiNoteEvent;
 use strict;
 use v5.10.1;
@@ -12,11 +13,8 @@ our $to_flush; # { cfgpath => $lei }
 
 sub flush_lei ($) {
        my ($lei) = @_;
-       if (my $lne = delete $lei->{cfg}->{-lei_note_event}) {
-               $lne->wq_close(1, undef, $lei); # runs _lei_wq_eof;
-       } elsif ($lei->{sto}) { # lms_clear_src calls only:
-               $lei->sto_done_request;
-       }
+       my $lne = delete $lei->{cfg}->{-lei_note_event};
+       $lne->wq_close(1, undef, $lei) if $lne; # runs _lei_wq_eof;
 }
 
 # we batch up writes and flush every 5s (matching Linux default
@@ -38,14 +36,14 @@ sub note_event_arm_done ($) {
 sub eml_event ($$$$) {
        my ($self, $eml, $vmd, $state) = @_;
        my $sto = $self->{lei}->{sto};
-       my $lse = $self->{lse} //= $sto->search;
        if ($state =~ /\Aimport-(?:rw|ro)\z/) {
                $sto->ipc_do('set_eml', $eml, $vmd);
        } elsif ($state =~ /\Aindex-(?:rw|ro)\z/) {
                my $xoids = $self->{lei}->ale->xoids_for($eml);
                $sto->ipc_do('index_eml_only', $eml, $vmd, $xoids);
        } elsif ($state =~ /\Atag-(?:rw|ro)\z/) {
-               my $c = $lse->kw_changed($eml, $vmd->{kw}, my $docids = []);
+               my $docids = [];
+               my $c = $self->{lse}->kw_changed($eml, $vmd->{kw}, $docids);
                if (scalar @$docids) { # already in lei/store
                        $sto->ipc_do('set_eml_vmd', undef, $vmd, $docids) if $c;
                } elsif (my $xoids = $self->{lei}->ale->xoids_for($eml)) {
@@ -69,21 +67,19 @@ sub lei_note_event {
        my $cfg = $lei->_lei_cfg or return; # gone (race)
        my $sto = $lei->_lei_store or return; # gone
        return flush_lei($lei) if $folder eq 'done'; # special case
-       my $lms = $sto->search->lms or return;
+       my $lms = $lei->lms or return;
+       $lms->lms_write_prepare if $new_cur eq ''; # for ->clear_src below
        my $err = $lms->arg2folder($lei, [ $folder ]);
        return if $err->{fail};
-       undef $lms;
        my $state = $cfg->get_1("watch.$folder", 'state') // 'tag-rw';
        return if $state eq 'pause';
+       return $lms->clear_src($folder, \$bn) if $new_cur eq '';
+       $lms->lms_pause;
        $lei->ale; # prepare
        $sto->write_prepare($lei);
-       if ($new_cur eq '') {
-               $sto->ipc_do('lms_clear_src', $folder, \$bn);
-               return note_event_arm_done($lei);
-       }
        require PublicInbox::MdirReader;
        my $self = $cfg->{-lei_note_event} //= do {
-               my $wq = bless {}, __PACKAGE__;
+               my $wq = bless { lms => $lms }, __PACKAGE__;
                # MUAs such as mutt can trigger massive rename() storms so
                # use all CPU power available:
                my $jobs = $wq->detect_nproc // 1;
@@ -105,6 +101,8 @@ sub lei_note_event {
 sub ipc_atfork_child {
        my ($self) = @_;
        $self->{lei}->_lei_atfork_child(1); # persistent, for a while
+       $self->{lms}->lms_write_prepare;
+       $self->{lse} = $self->{lei}->{sto}->search;
        $self->SUPER::ipc_atfork_child;
 }
 
index cdd997253a609dc5871bdb7e9b17c88aa1468bce..72b8fe6367e9b6f479140472095cb52ac46d5247 100644 (file)
@@ -11,9 +11,9 @@ use PublicInbox::LeiExportKw;
 use PublicInbox::InboxWritable qw(eml_from_path);
 use PublicInbox::Import;
 
-sub folder_missing {
+sub folder_missing { # may be called by LeiInput
        my ($self, $folder) = @_;
-       $self->{lei}->{sto}->ipc_do('lms_forget_folders', $folder);
+       $self->{lms}->forget_folders($folder);
 }
 
 sub prune_mdir { # lms->each_src callback
@@ -21,13 +21,13 @@ sub prune_mdir { # lms->each_src callback
        my @try = $$id =~ /:2,[a-zA-Z]*\z/ ? qw(cur new) : qw(new cur);
        for (@try) { return if -f "$mdir/$_/$$id" }
        # both tries failed
-       $self->{lei}->{sto}->ipc_do('lms_clear_src', "maildir:$mdir", $id);
+       $self->{lms}->clear_src("maildir:$mdir", $id);
 }
 
 sub prune_imap { # lms->each_src callback
        my ($oidbin, $uid, $self, $uids, $url) = @_;
        return if exists $uids->{$uid};
-       $self->{lei}->{sto}->ipc_do('lms_clear_src', $url, $uid);
+       $self->{lms}->clear_src($url, $uid);
 }
 
 # detects missed file moves
@@ -36,18 +36,16 @@ sub pmdir_cb { # called via LeiPmdir->each_mdir_fn
        my ($folder, $bn) = ($f =~ m!\A(.+?)/(?:new|cur)/([^/]+)\z!) or
                die "BUG: $f was not from a Maildir?";
        substr($folder, 0, 0) = 'maildir:'; # add prefix
-       my $lms = $self->{-lms_ro} //= $self->{lei}->lms;
-       return if defined($lms->name_oidbin($folder, $bn));
+       return if defined($self->{lms}->name_oidbin($folder, $bn));
        my $eml = eml_from_path($f) // return;
        my $oidbin = $self->{lei}->git_oid($eml)->digest;
-       $self->{lei}->{sto}->ipc_do('lms_set_src', $oidbin, $folder, \$bn);
+       $self->{lms}->set_src($oidbin, $folder, \$bn);
 }
 
 sub input_path_url { # overrides PublicInbox::LeiInput::input_path_url
        my ($self, $input, @args) = @_;
-       my $lms = $self->{-lms_ro} //= $self->{lei}->lms;
        if ($input =~ /\Amaildir:(.+)/i) {
-               $lms->each_src($input, \&prune_mdir, $self, my $mdir = $1);
+               $self->{lms}->each_src($input, \&prune_mdir, $self, $1);
                $self->{lse} //= $self->{lei}->{sto}->search;
                # call pmdir_cb (via maildir_each_file -> each_mdir_fn)
                PublicInbox::LeiInput::input_path_url($self, $input);
@@ -56,7 +54,8 @@ sub input_path_url { # overrides PublicInbox::LeiInput::input_path_url
                if (my $mic = $self->{lei}->{net}->mic_for_folder($uri)) {
                        my $uids = $mic->search('UID 1:*');
                        $uids = +{ map { $_ => undef } @$uids };
-                       $lms->each_src($$uri, \&prune_imap, $self, $uids, $$uri)
+                       $self->{lms}->each_src($$uri, \&prune_imap, $self,
+                                               $uids, $$uri)
                } else {
                        $self->folder_missing($$uri);
                }
@@ -79,9 +78,9 @@ EOM
                $lei->qerr(@{$err->{qerr}}) if $err->{qerr};
                return $lei->fail($err->{fail}) if $err->{fail};
        }
-       undef $lms; # must be done before fork
+       $lms->lms_pause; # must be done before fork
        $sto->write_prepare($lei);
-       my $self = bless { missing_ok => 1 }, __PACKAGE__;
+       my $self = bless { missing_ok => 1, lms => $lms }, __PACKAGE__;
        $lei->{opt}->{'mail-sync'} = 1; # for prepare_inputs
        $self->prepare_inputs($lei, \@folders) or return;
        my $ops = {};
@@ -93,9 +92,15 @@ EOM
        $lei->wait_wq_events($op_c, $ops); # net_merge_all_done if !{auth}
 }
 
+sub ipc_atfork_child { # needed for PublicInbox::LeiPmdir
+       my ($self) = @_;
+       PublicInbox::LeiInput::input_only_atfork_child($self);
+       $self->{lms}->lms_write_prepare;
+       undef;
+}
+
 no warnings 'once';
 *_complete_refresh_mail_sync = \&PublicInbox::LeiExportKw::_complete_export_kw;
-*ipc_atfork_child = \&PublicInbox::LeiInput::input_only_atfork_child;
 *net_merge_all_done = \&PublicInbox::LeiInput::input_only_net_merge_all_done;
 
 1;
index 32f55abd2ad7384e52e2481b4ed96a5cb004d80a..08add8f5a05496ab234f5cfad9737903de0c009a 100644 (file)
@@ -190,7 +190,7 @@ sub export1_kw_md ($$$$$) {
                                syslog('warning', "unlink($src): $!");
                        }
                        # TODO: verify oidbin?
-                       lms_mv_src($self, "maildir:$mdir",
+                       $self->{lms}->mv_src("maildir:$mdir",
                                        $oidbin, \$orig, $bn);
                        return;
                } elsif ($! == EEXIST) { # lost race with "lei export-kw"?
@@ -200,7 +200,7 @@ sub export1_kw_md ($$$$$) {
                }
        }
        for (@try) { return if -e "$mdir/$_/$orig" };
-       lms_clear_src($self, "maildir:$mdir", \$orig);
+       $self->{lms}->clear_src("maildir:$mdir", \$orig);
 }
 
 sub sto_export_kw ($$$) {
@@ -255,7 +255,7 @@ sub remove_eml_vmd { # remove just the VMD
        \@docids;
 }
 
-sub _lms_rw ($) {
+sub _lms_rw ($) { # it is important to have eidx processes open before lms
        my ($self) = @_;
        my ($eidx, $tl) = eidx_init($self);
        $self->{lms} //= do {
@@ -267,37 +267,11 @@ sub _lms_rw ($) {
        };
 }
 
-sub lms_clear_src {
-       my ($self, $folder, $id) = @_;
-       _lms_rw($self)->clear_src($folder, $id);
-}
-
-sub lms_mv_src {
-       my ($self, $folder, $oidbin, $id, $newbn) = @_;
-       _lms_rw($self)->mv_src($folder, $oidbin, $id, $newbn);
-}
-
-sub lms_forget_folders {
-       my ($self, @folders) = @_;
-       my $lms = _lms_rw($self);
-       for my $f (@folders) { $lms->forget_folder($f) }
-}
-
-sub lms_rename_folder {
-       my ($self, $old, $new) = @_;
-       _lms_rw($self)->rename_folder($old, $new);
-}
-
 sub set_sync_info {
        my ($self, $oidhex, $folder, $id) = @_;
        _lms_rw($self)->set_src(pack('H*', $oidhex), $folder, $id);
 }
 
-sub lms_set_src {
-       my ($self, $oidbin, $folder, $id) = @_;
-       _lms_rw($self)->set_src($oidbin, $folder, $id);
-}
-
 sub _remove_if_local { # git->cat_async arg
        my ($bref, $oidhex, $type, $size, $self) = @_;
        $self->{im}->remove($bref) if $bref;
@@ -608,11 +582,4 @@ sub write_prepare {
        $lei->{sto} = $self;
 }
 
-# called by lei-daemon before lei->refresh_watches
-sub add_sync_folders {
-       my ($self, @folders) = @_;
-       my $lms = _lms_rw($self);
-       for my $f (@folders) { $lms->fid_for($f, 1) }
-}
-
 1;
index 15729bdafe57c45f3eab749dd5a8079b4d20cb01..d3253d9b01139bf6a2ea7b29cd0a5619485d2f41 100644 (file)
@@ -458,8 +458,10 @@ sub _pre_augment_maildir {
 
 sub clobber_dst_prepare ($;$) {
        my ($lei, $f) = @_;
-       my $wait = (defined($f) && $lei->{sto}) ?
-                       $lei->{sto}->ipc_do('lms_forget_folders', $f) : undef;
+       if (my $lms = defined($f) ? $lei->lms : undef) {
+               $lms->lms_write_prepare;
+               $lms->forget_folders($f);
+       }
        my $dedupe = $lei->{dedupe} or return;
        $dedupe->reset_dedupe if $dedupe->can('reset_dedupe');
 }