Only server should control fifo; client should wait for it to clear

On the a classic “concurrency is hard” front, I am slightly proud of
myself that I didn't hit this race condition but anticipated that it
might occur later.  Giving entire control to fifoName to the server
makes more sense here, and the client should not submit its query any
time either fifoName or question is set.

As an extra safeguard, the client will die if it gets the lock and
the state for submitting a query isn't right.

Finally, added some fifoName removal debugging on the server.
This commit is contained in:
Bradley M. Kuhn 2020-06-15 14:42:33 -07:00
parent 42800427f6
commit 8349b9610b
No known key found for this signature in database
GPG key ID: F15E8BD6D05E26B3
2 changed files with 15 additions and 2 deletions

View file

@ -17,8 +17,15 @@ sub BeancountQueryInitialize {
sub BeancountQuerySubmit($) { sub BeancountQuerySubmit($) {
my($question) = @_; my($question) = @_;
while (defined $BEANCOUNT_QUERY{fifoName} or defined $BEANCOUNT_QUERY{question}) { sleep 1; }
(tied %BEANCOUNT_QUERY)->shlock; (tied %BEANCOUNT_QUERY)->shlock;
$BEANCOUNT_QUERY{fifoName} = undef; if (defined $BEANCOUNT_QUERY{fifoName} or defined $BEANCOUNT_QUERY{question}) {
(tied %BEANCOUNT_QUERY)->shunlock;
no warnings 'uninitialized';
die("caught lock to submit a query, but either fifoName or question was defined, " .
"so something is wrong here. " .
"fifoName: \"$BEANCOUNT_QUERY{fifoName}\" question: \"$BEANCOUNT_QUERY{question}\"!");
}
$BEANCOUNT_QUERY{question} = $question; $BEANCOUNT_QUERY{question} = $question;
(tied %BEANCOUNT_QUERY)->shunlock; (tied %BEANCOUNT_QUERY)->shunlock;
while (not defined $BEANCOUNT_QUERY{fifoName}) { sleep 1; } while (not defined $BEANCOUNT_QUERY{fifoName}) { sleep 1; }

View file

@ -71,11 +71,17 @@ tie %beancountData, 'IPC::Shareable', $glue, { %options } or
while (1) { while (1) {
if (not defined $query{question}) { if (not defined $query{question}) {
print STDERR "No question posed, sleeping 2\n" if $VERBOSE > 2; print STDERR "No question posed..." if $VERBOSE > 2;
if (defined $query{fifoName}) { if (defined $query{fifoName}) {
print STDERR "fifo still active; locking to clear it..." if $VERBOSE > 2;
(tied %query)->shlock;
print STDERR "clearing fifo, $query{fifoName}..." if $VERBOSE > 2;
no autodie 'unlink'; unlink($query{fifoName}); no autodie 'unlink'; unlink($query{fifoName});
$query{fifoName} = undef; $query{fifoName} = undef;
(tied %query)->shunlock;
print STDERR "fifo cleared & lock released." if $VERBOSE > 2;
} }
print STDERR "sleep for 2 seconds\n" if $VERBOSE > 2;
sleep 2; sleep 2;
next; next;
} elsif ($query{question} !~ /^[\-\@\w.\s\"\'\_\(\)]+$/) { } elsif ($query{question} !~ /^[\-\@\w.\s\"\'\_\(\)]+$/) {