In this pseudocode block:
atomically $ do
if valueInLocalStorage key
then readValueFromLocalStorage key
else do
value <- unsafeIOToSTM $ fetchValueFromDatabase key
writeValueToLocalStorage key value
Is it safe to use unsafeIOToSTM
? The docs say:
The STM implementation will often run transactions multiple times, so you need to be prepared for this if your IO has any side effects.
Basically, if a transaction fails it is because some other thread wroteValueToLocalStorage
and when the transaction is retried it will return the stored value instead of fetching from the database again.
The STM implementation will abort transactions that are known to be invalid and need to be restarted. This may happen in the middle of unsafeIOToSTM, so make sure you don't acquire any resources that need releasing (exception handlers are ignored when aborting the transaction). That includes doing any IO using Handles, for example. Getting this wrong will probably lead to random deadlocks.
This worries me the most. Logically, if fetchValueFromDatabase
doesn't open a new connection (i.e. an existing connection is used) everything should be fine. Are there other pitfalls I am missing?
The transaction may have seen an inconsistent view of memory when the IO runs. Invariants that you expect to be true throughout your program may not be true inside a transaction, due to the way transactions are implemented. Normally this wouldn't be visible to the programmer, but using unsafeIOToSTM can expose it.
key
is a single value, no invariants to break.
I would suggest that doing I/O from an STM transaction is just a bad idea.
Presumably what you want is to avoid two threads doing the DB lookup at the same time. What I would do is this:
See if the item is already in the cache. If it is, we're done.
If it isn't, mark it with an "I'm fetching this" flag, commit the STM transaction, go get it from the DB, and do a second STM transaction to insert it into the cache (and remove the flag).
If the item is already flagged, retry
the transaction. This blocks the calling thread until the first thread inserts the value from the DB.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With