about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/PublicInbox/Inbox.pm14
-rw-r--r--lib/PublicInbox/NNTP.pm4
-rw-r--r--lib/PublicInbox/NNTPD.pm12
-rw-r--r--lib/PublicInbox/Over.pm36
4 files changed, 53 insertions, 13 deletions
diff --git a/lib/PublicInbox/Inbox.pm b/lib/PublicInbox/Inbox.pm
index b2b0b56f..7d5e0483 100644
--- a/lib/PublicInbox/Inbox.pm
+++ b/lib/PublicInbox/Inbox.pm
@@ -31,7 +31,7 @@ sub cleanup_task () {
         for my $ibx (values %$CLEANUP) {
                 my $again;
                 if ($have_devel_peek) {
-                        foreach my $f (qw(mm search over)) {
+                        foreach my $f (qw(mm search)) {
                                 # we bump refcnt by assigning tmp, here:
                                 my $tmp = $ibx->{$f} or next;
                                 next if Devel::Peek::SvREFCNT($tmp) > 2;
@@ -45,9 +45,9 @@ sub cleanup_task () {
                                 $again = 1 if $git->cleanup;
                         }
                 }
+                check_inodes($ibx);
                 if ($have_devel_peek) {
-                        $again ||= !!($ibx->{over} || $ibx->{mm} ||
-                                      $ibx->{search});
+                        $again ||= !!($ibx->{mm} || $ibx->{search});
                 }
                 $next->{"$ibx"} = $ibx if $again;
         }
@@ -407,9 +407,17 @@ sub unsubscribe_unlock {
         delete $self->{unlock_subs}->{$ident};
 }
 
+sub check_inodes ($) {
+        my ($self) = @_;
+        for (qw(over)) { # TODO: search, mm
+                $self->{$_}->check_inodes if $self->{$_};
+        }
+}
+
 # called by inotify
 sub on_unlock {
         my ($self) = @_;
+        check_inodes($self);
         my $subs = $self->{unlock_subs} or return;
         for (values %$subs) {
                 eval { $_->on_inbox_unlock($self) };
diff --git a/lib/PublicInbox/NNTP.pm b/lib/PublicInbox/NNTP.pm
index ac13c7df..bffd773c 100644
--- a/lib/PublicInbox/NNTP.pm
+++ b/lib/PublicInbox/NNTP.pm
@@ -334,7 +334,9 @@ sub cmd_newnews ($$$$;$$) {
 sub cmd_group ($$) {
         my ($self, $group) = @_;
         my $no_such = '411 no such news group';
-        my $ng = $self->{nntpd}->{groups}->{$group} or return $no_such;
+        my $nntpd = $self->{nntpd};
+        my $ng = $nntpd->{groups}->{$group} or return $no_such;
+        $nntpd->idler_start;
 
         $self->{ng} = $ng;
         my ($min, $max) = $ng->mm->minmax;
diff --git a/lib/PublicInbox/NNTPD.pm b/lib/PublicInbox/NNTPD.pm
index ed5cf7cc..6b762d89 100644
--- a/lib/PublicInbox/NNTPD.pm
+++ b/lib/PublicInbox/NNTPD.pm
@@ -8,6 +8,7 @@ use strict;
 use warnings;
 use Sys::Hostname;
 use PublicInbox::Config;
+use PublicInbox::InboxIdle;
 
 sub new {
         my ($class) = @_;
@@ -24,15 +25,17 @@ sub new {
                 err => \*STDERR,
                 out => \*STDOUT,
                 grouplist => [],
+                pi_config => $pi_config,
                 servername => $name,
                 greet => \"201 $name ready - post via email\r\n",
                 # accept_tls => { SSL_server => 1, ..., SSL_reuse_ctx => ... }
+                # idler => PublicInbox::InboxIdle
         }, $class;
 }
 
 sub refresh_groups {
-        my ($self, $pi_config) = @_;
-        $pi_config //= PublicInbox::Config->new;
+        my ($self, $sig) = @_;
+        my $pi_config = $sig ? PublicInbox::Config->new : $self->{pi_config};
         my $new = {};
         my @list;
         $pi_config->each_inbox(sub {
@@ -59,8 +62,13 @@ sub refresh_groups {
         });
         @list =        sort { $a->{newsgroup} cmp $b->{newsgroup} } @list;
         $self->{grouplist} = \@list;
+        $self->{pi_config} = $pi_config;
         # this will destroy old groups that got deleted
         %{$self->{groups}} = %$new;
 }
 
+sub idler_start {
+        $_[0]->{idler} //= PublicInbox::InboxIdle->new($_[0]->{pi_config});
+}
+
 1;
diff --git a/lib/PublicInbox/Over.pm b/lib/PublicInbox/Over.pm
index e32104f0..74c8fb86 100644
--- a/lib/PublicInbox/Over.pm
+++ b/lib/PublicInbox/Over.pm
@@ -19,13 +19,23 @@ sub dbh_new {
         if ($rw && !-f $f) { # SQLite defaults mode to 0644, we want 0666
                 open my $fh, '+>>', $f or die "failed to open $f: $!";
         }
-        my $dbh = DBI->connect("dbi:SQLite:dbname=$f",'','', {
-                AutoCommit => 1,
-                RaiseError => 1,
-                PrintError => 0,
-                ReadOnly => !$rw,
-                sqlite_use_immediate_transaction => 1,
-        });
+        my (@st, $st, $dbh);
+        my $tries = 0;
+        do {
+                @st = stat($f) or die "failed to stat $f: $!";
+                $st = pack('dd', $st[0], $st[1]); # 0: dev, 1: inode
+                $dbh = DBI->connect("dbi:SQLite:dbname=$f",'','', {
+                        AutoCommit => 1,
+                        RaiseError => 1,
+                        PrintError => 0,
+                        ReadOnly => !$rw,
+                        sqlite_use_immediate_transaction => 1,
+                });
+                $self->{st} = $st;
+                @st = stat($f) or die "failed to stat $f: $!";
+                $st = pack('dd', $st[0], $st[1]);
+        } while ($st ne $self->{st} && $tries++ < 3);
+        warn "W: $f: .st_dev, .st_ino unstable\n" if $st ne $self->{st};
         $dbh->{sqlite_unicode} = 1;
         $dbh;
 }
@@ -259,4 +269,16 @@ SELECT MAX(num) FROM over WHERE num > 0
         ($exists, $uidnext, $sth->fetchrow_array // 0);
 }
 
+sub check_inodes {
+        my ($self) = @_;
+        if (my @st = stat($self->{filename})) { # did st_dev, st_ino change?
+                my $st = pack('dd', $st[0], $st[1]);
+
+                # don't actually reopen, just let {dbh} be recreated later
+                delete($self->{dbh}) if ($st ne ($self->{st} // $st));
+        } else {
+                warn "W: stat $self->{filename}: $!\n";
+        }
+}
+
 1;