diff options
Diffstat (limited to 'lib/PublicInbox/POP3D.pm')
-rw-r--r-- | lib/PublicInbox/POP3D.pm | 56 |
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 |