mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-09-01 20:18:26 +00:00
* agent: batch sending messages (attempt 4) * handle errors in batch sending * batch attempt 5 (#923) * attempt 5 * remove IORefs * add liftA2 for 8.10 compat * remove db-related zipping * traversable --------- Co-authored-by: IC Rainbow <aenor.realm@gmail.com> * s/mapE/bindRight/ * name Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> * comment Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> * remove unused funcs --------- Co-authored-by: IC Rainbow <aenor.realm@gmail.com> Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
50 lines
1.6 KiB
Haskell
50 lines
1.6 KiB
Haskell
{-# LANGUAGE NamedFieldPuns #-}
|
|
|
|
module Simplex.Messaging.Agent.Lock
|
|
( Lock,
|
|
createLock,
|
|
withLock,
|
|
withGetLock,
|
|
withGetLocks,
|
|
)
|
|
where
|
|
|
|
import Control.Monad (void)
|
|
import Control.Monad.IO.Unlift
|
|
import Data.Functor (($>))
|
|
import UnliftIO.Async (forConcurrently)
|
|
import qualified UnliftIO.Exception as E
|
|
import UnliftIO.STM
|
|
|
|
type Lock = TMVar String
|
|
|
|
createLock :: STM Lock
|
|
createLock = newEmptyTMVar
|
|
{-# INLINE createLock #-}
|
|
|
|
withLock :: MonadUnliftIO m => Lock -> String -> m a -> m a
|
|
withLock lock name =
|
|
E.bracket_
|
|
(atomically $ putTMVar lock name)
|
|
(void . atomically $ takeTMVar lock)
|
|
|
|
withGetLock :: MonadUnliftIO m => (k -> STM Lock) -> k -> String -> m a -> m a
|
|
withGetLock getLock key name a =
|
|
E.bracket
|
|
(atomically $ getPutLock getLock key name)
|
|
(atomically . takeTMVar)
|
|
(const a)
|
|
|
|
withGetLocks :: MonadUnliftIO m => (k -> STM Lock) -> [k] -> String -> m a -> m a
|
|
withGetLocks getLock keys name = E.bracket holdLocks releaseLocks . const
|
|
where
|
|
holdLocks = forConcurrently keys $ \key -> atomically $ getPutLock getLock key name
|
|
-- only this withGetLocks would be holding the locks,
|
|
-- so it's safe to combine all lock releases into one transaction
|
|
releaseLocks = atomically . mapM_ takeTMVar
|
|
|
|
-- getLock and putTMVar can be in one transaction on the assumption that getLock doesn't write in case the lock already exists,
|
|
-- and in case it is created and added to some shared resource (we use TMap) it also helps avoid contention for the newly created lock.
|
|
getPutLock :: (k -> STM Lock) -> k -> String -> STM Lock
|
|
getPutLock getLock key name = getLock key >>= \l -> putTMVar l name $> l
|