about summary refs log tree commit homepage
path: root/lib/PublicInbox/Over.pm
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2020-06-11 00:57:53 +0000
committerEric Wong <e@yhbt.net>2020-06-13 07:58:30 +0000
commit2a717d13f10fcdc69921d80cf94c47a694a175d4 (patch)
tree188b2834628fd448f9397daefb4a8a77c00cdce1 /lib/PublicInbox/Over.pm
parent3d52c093ad5ce7a32f8842d9ae020712f9786352 (diff)
downloadpublic-inbox-2a717d13f10fcdc69921d80cf94c47a694a175d4.tar.gz
For v1 inboxes (and possibly v2 in the future, for VACUUM),
public-inbox-compact replaces over.sqlite3 with a new file.

This currently doesn't need an extra inotify watch descriptor
(or FD for kevent) at the moment, so it can coexist nicely for
systems w/o IO::KQueue or Linux::Inotify2.
Diffstat (limited to 'lib/PublicInbox/Over.pm')
-rw-r--r--lib/PublicInbox/Over.pm36
1 files changed, 29 insertions, 7 deletions
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;