From: Eric Wong Date: Fri, 26 Jul 2024 21:31:09 +0000 (+0000) Subject: msgmap: mid_insert: reraise on unexpected errors X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=14107750377f6bcff5ff60fa5a69c7dedbec1c6b;p=thirdparty%2Fpublic-inbox.git msgmap: mid_insert: reraise on unexpected errors SQLITE_CONSTRAINT is the only SQLite error we really expect under normal circumstances. This avoids infinite loops when writing to inboxes after hitting ENOSPC. Reported-by: Robin H. Johnson Link: https://public-inbox.org/git/robbat2-20240722T060013-765939809Z@orbis-terrarum.net/ --- diff --git a/lib/PublicInbox/Msgmap.pm b/lib/PublicInbox/Msgmap.pm index cb4bb2956..c4bc766d2 100644 --- a/lib/PublicInbox/Msgmap.pm +++ b/lib/PublicInbox/Msgmap.pm @@ -12,6 +12,7 @@ use strict; use v5.10.1; use DBI; use DBD::SQLite; +use DBD::SQLite::Constants qw(SQLITE_CONSTRAINT); use PublicInbox::Over; use Scalar::Util qw(blessed); @@ -113,7 +114,10 @@ sub mid_insert { my $sth = $self->{dbh}->prepare_cached(<<''); INSERT INTO msgmap (mid) VALUES (?) - return unless eval { $sth->execute($mid) }; + unless (eval { $sth->execute($mid) }) { + return if $self->{dbh}->err == SQLITE_CONSTRAINT; + die $@; + } my $num = $self->{dbh}->last_insert_id(undef, undef, 'msgmap', 'num'); $self->num_highwater($num) if defined($num); $num; diff --git a/t/msgmap.t b/t/msgmap.t index 124d3b103..fb9c2d933 100644 --- a/t/msgmap.t +++ b/t/msgmap.t @@ -3,6 +3,9 @@ # License: AGPL-3.0+ use v5.12; use PublicInbox::TestCommon; +use autodie; +use Config; +use PublicInbox::Spawn qw(popen_rd); require_mods('DBD::SQLite'); use_ok 'PublicInbox::Msgmap'; my ($tmpdir, $for_destroy) = tmpdir(); @@ -70,4 +73,17 @@ is(eval { 'ok' }, 'ok', 'atfork_* work on tmp_clone'); -done_testing(); +SKIP: { + my $strace = strace_inject; + open my $fh, '>', my $trace = "$tmpdir/trace.out"; + my $rd = popen_rd([ $strace, '-p', $$, '-o', $trace, + '-e', 'inject=pwrite64:error=ENOSPC'], undef, { 2 => 1 }); + $rd->poll_in(10) or die 'strace not ready'; + is eval { $d->mid_insert('this-better-trigger-ENOSPC@error') }, + undef, 'insert fails w/ ENOSPC'; + like $@, qr/ disk is full/, '$@ reports ENOSPC'; + kill 'TERM', $rd->attached_pid; + $rd->close; +} + +done_testing; diff --git a/t/v2writable.t b/t/v2writable.t index 1b7e9e7d3..a062d1b3a 100644 --- a/t/v2writable.t +++ b/t/v2writable.t @@ -6,6 +6,8 @@ use Test::More; use PublicInbox::Eml; use PublicInbox::ContentHash qw(content_digest content_hash); use PublicInbox::TestCommon; +use PublicInbox::Spawn qw(popen_rd); +use Config; use Cwd qw(abs_path); require_git(2.6); require_mods(qw(DBD::SQLite Xapian)); @@ -335,4 +337,18 @@ ok($@, 'V2Writable fails on non-existent dir'); is($mode, 0664, sprintf('0%03o', $mode).' is 0664'); } -done_testing(); +SKIP: { + my $strace = strace_inject; + my $eml = eml_load 't/plack-qp.eml'; + open my $fh, '>', my $trace = "$inboxdir/trace.out"; + my $rd = popen_rd([ $strace, '-p', $$, '-o', $trace, + '-e', 'inject=pwrite64:error=ENOSPC'], undef, { 2 => 1 }); + $rd->poll_in(10) or die 'strace not ready'; + ok ! eval { $im->add($eml) }, 'v2w->add fails on ENOSPC'; + like $@, qr/ disk is full/, 'set $@ for ENOSPC'; + $im->done; + kill 'TERM', $rd->attached_pid; + $rd->close; +} + +done_testing;