6

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.

4

1 回答 1

3

我建议从 STM 事务中执行 I/O 只是一个坏主意。

大概您想要的是避免两个线程同时进行数据库查找。我要做的是:

  • 查看该项目是否已在缓存中。如果是,我们就完成了。

  • 如果不是,则用“我正在获取此”标志对其进行标记,提交 STM 事务,从数据库中获取它,然后执行第二个 STM 事务以将其插入缓存(并删除该标志)。

  • 如果该项目已被标记,retry则交易。这会阻塞调用线程,直到第一个线程插入数据库中的值。

于 2015-12-07T14:10:06.053 回答