On Feb 23, 2021, at 10:19 AM, Wietse Venema <wie...@porcupine.org> wrote:

> Ron Garret:
>>>> Isn't SQLite supposed to deal with concurrent access?
>>>> https://sqlite.org/lockingv3.html
>>> 
>>> Yes, it does, but the way it ?deals? with it is to throw an error
>> if one connection tried to read while another is writing.  The net
> 
> Bleh, it does not retry the operation?

Nope.  See postfix-3.5.9/src/global/dict_sqlite.c.

It’s not clear that retrying would even be the right thing to do because you 
could just get unlucky again.  The failure can happen in three different 
places: the query itself (obviously) but also statement preparation and 
finalization.  I’ve seen all three actually happen in practice.  So you really 
want it to wait.  That’s a lot simpler, and it guarantees success as long as 
there are no slow writers (which is a reasonable constraint).

> What happens when you update the table while some Postfix code is
> READING from the DB? Does the writer also fail?

No idea, but because I control all the writers that would be easy for me to 
fix.  In any event I don’t think that’s something postfix should be worried 
about.

>> result of this is that if Postfix tries to read during a concurrent
>> update from somewhere else, it fails catastrophically (mail is
>> actually lost).
> 
> Losing mail would be a bug in the sending program. Postfix never
> loses mail because of a fatal error.

What can I say?  When this happens, I can’t find the message that was being 
processed anywhere.  It is not delivered (obviously) and it is not bounced.  
The way I first found out this was happening was an error notification in the 
root mailbox of the machine where postfix is running.

>> It would be nice if postfix would set a non-zero busy timeout.
>> It?s a simple code change, just a call to sqlite3_busy_timeout.
> 
> What about https://www.sqlite.org/pragma.html#pragma_busy_timeout ?
> I don't know if that is a DB property or a session property.

It’s a session/connection property.  The problem with trying to use a pragma in 
the config file is that the C interface to sqlite does not allow multiple 
semicolon-separated statements in a call to sqlite3_prepare_v2, so just putting 
the pragma in the postfix sql config as part of the query with a semicolon 
after will not work.  Postfix would have to know to separate multiple 
statements and prepare them separately.  Since a source code change would be 
needed anyway, a much simpler solution is just to call sqlite3_busy_timeout 
directly.

>> That would not be a guarantee, but it would at least make it
>> *possible* to safely update a sqliite database in-place.  I?m going
>> to head on over to the postfix-dev list to see if it?s possible
>> to get this done.
> 
> If we take this route, then there needs to be a new field in the
> Postfix sqlite config file that controls the time limit.

Not necessarily.  You could just hard-code a reasonable value (like 1 second), 
or make it a #define so you need a recompile to change it.  That’s sub-optimal, 
obviously, but still a major improvement over the current situation for very 
little effort and no down-side that I can see.

rg

Reply via email to