about summary refs log tree commit homepage
path: root/lib/PublicInbox/POP3D.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox/POP3D.pm')
-rw-r--r--lib/PublicInbox/POP3D.pm56
1 files changed, 39 insertions, 17 deletions
diff --git a/lib/PublicInbox/POP3D.pm b/lib/PublicInbox/POP3D.pm
index 764f9ffe..bd440434 100644
--- a/lib/PublicInbox/POP3D.pm
+++ b/lib/PublicInbox/POP3D.pm
@@ -13,27 +13,42 @@ use PublicInbox::POP3;
 use PublicInbox::Syscall;
 use File::Temp 0.19 (); # 0.19 for ->newdir
 use Fcntl qw(F_SETLK F_UNLCK F_WRLCK SEEK_SET);
-my @FLOCK;
-if ($^O eq 'linux' || $^O eq 'freebsd') {
+my ($FLOCK_TMPL, @FLOCK_ORDER);
+# are all BSDs the same "struct flock"? tested Free+Net+Open...
+if ($^O =~ /\A(?:linux|dragonfly)\z/ || $^O =~ /bsd/) {
         require Config;
         my $off_t;
+        my @LE_pad = ('', '');
         my $sz = $Config::Config{lseeksize};
-
-        if ($sz == 8 && eval('length(pack("q", 1)) == 8')) { $off_t = 'q' }
-        elsif ($sz == 4) { $off_t = 'l' }
-        else { warn "sizeof(off_t)=$sz requires File::FcntlLock\n" }
-
+        if ($sz == 8) {
+                if (eval('length(pack("q", 1)) == 8')) {
+                        $off_t = 'q';
+                } elsif ($Config::Config{byteorder} == 1234) { # OpenBSD i386
+                        $off_t = 'l';
+                        @LE_pad = ('@8', '@16');
+                } else { # I have no 32-bit BE machine to test on...
+                        warn <<EOM;
+Perl built with 64-bit file support but not 64-bit int (pack("q")) support.
+byteorder=$Config::Config{byteorder}
+EOM
+                }
+        } elsif ($sz == 4) {
+                $off_t = 'l';
+        } else {
+                warn "sizeof(off_t)=$sz requires File::FcntlLock\n"
+        }
         if (defined($off_t)) {
                 if ($^O eq 'linux') {
-                        @FLOCK = ("ss\@8$off_t$off_t\@32",
-                                qw(l_type l_whence l_start l_len));
-                } elsif ($^O eq 'freebsd') {
-                        @FLOCK = ("${off_t}${off_t}lss\@256",
-                                qw(l_start l_len l_pid l_type l_whence));
+                        $FLOCK_TMPL = 'ss@8'.$off_t.$LE_pad[0].$off_t.'@32';
+                        @FLOCK_ORDER = qw(l_type l_whence l_start l_len);
+                } else { # *bsd including dragonfly
+                        $FLOCK_TMPL = $off_t.$LE_pad[0].$off_t.$LE_pad[1].
+                                        'lss@256';
+                        @FLOCK_ORDER = qw(l_start l_len l_pid l_type l_whence);
                 }
         }
 }
-@FLOCK or eval { require File::FcntlLock } or
+@FLOCK_ORDER or eval { require File::FcntlLock } or
         die "File::FcntlLock required for POP3 on $^O: $@\n";
 
 sub new {
@@ -140,9 +155,9 @@ sub _setlk ($%) {
         my ($self, %lk) = @_;
         $lk{l_pid} = 0; # needed for *BSD
         $lk{l_whence} = SEEK_SET;
-        if (@FLOCK) {
+        if (@FLOCK_ORDER) {
                 fcntl($self->{txn_fh}, F_SETLK,
-                        pack($FLOCK[0], @lk{@FLOCK[1..$#FLOCK]}));
+                        pack($FLOCK_TMPL, @lk{@FLOCK_ORDER}));
         } else {
                 my $fs = File::FcntlLock->new(%lk);
                 $fs->lock($self->{txn_fh}, F_SETLK);
@@ -156,6 +171,7 @@ sub lock_mailbox {
         my ($user_id, $ngid, $mbid, $txn_id);
         my $uuid = delete $pop3->{uuid};
         $dbh->begin_work;
+        my $creat = 0;
 
         # 1. make sure the user exists, update `last_seen'
         my $sth = $dbh->prepare_cached(<<'');
@@ -218,13 +234,13 @@ SELECT mailbox_id FROM mailboxes WHERE newsgroup_id = ? AND slice = ?
         $sth = $dbh->prepare_cached(<<'');
 INSERT OR IGNORE INTO deletes (user_id,mailbox_id) VALUES (?,?)
 
-        if ($sth->execute($user_id, $mbid) == 0) {
+        if ($sth->execute($user_id, $mbid) == 0) { # fetching into existing
                 $sth = $dbh->prepare_cached(<<'', undef, 1);
 SELECT txn_id,uid_dele FROM deletes WHERE user_id = ? AND mailbox_id = ?
 
                 $sth->execute($user_id, $mbid);
                 ($txn_id, $pop3->{uid_dele}) = $sth->fetchrow_array;
-        } else {
+        } else { # new user/mailbox combo
                 $txn_id = $dbh->last_insert_id(undef, undef,
                                                 'deletes', 'txn_id');
         }
@@ -245,6 +261,12 @@ SELECT txn_id,uid_dele FROM deletes WHERE user_id = ? AND mailbox_id = ?
 sub unlock_mailbox {
         my ($self, $pop3) = @_;
         my $txn_id = delete($pop3->{txn_id}) // return;
+        if (!$pop3->{did_quit}) { # deal with QUIT-less disconnects
+                my $lk = $self->lock_for_scope;
+                $self->{-state_dbh}->begin_work;
+                $pop3->__cleanup_state($txn_id);
+                $self->{-state_dbh}->commit;
+        }
         delete $self->{txn_locks}->{$txn_id}; # same worker
 
         # other workers