{-# LANGUAGE DeriveAnyClass      #-}
{-# LANGUAGE LambdaCase          #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StaticPointers      #-}
module Hyperion.LockMap
  ( LockMap,
    withLock,
    withLocks,
    newLockMap,
    registerLockMap
  )
where
import qualified Control.Concurrent.STM                   as STM
import           Control.Distributed.Process              (DiedReason (..),
                                                           Process, ProcessId,
                                                           ProcessLinkException (..),
                                                           RemoteTable, call,
                                                           closure, getSelfPid,
                                                           liftIO, link,
                                                           spawnLocal, unStatic)
import           Control.Distributed.Process.Serializable (SerializableDict (..))
import           Control.Distributed.Static               (Static,
                                                           registerStatic,
                                                           staticLabel,
                                                           staticPtr)
import           Control.Monad                            (void)
import           Control.Monad.Catch                      (catch, bracket)
import           Control.Monad.Extra                      (unless)
import           Data.Binary                              (Binary, decode,
                                                           encode)
import           Data.ByteString.Lazy                     (ByteString)
import qualified Data.Map.Strict                          as Map
import           Data.Rank1Dynamic                        (toDynamic)
import           Data.Typeable                            (Typeable, typeOf)
import qualified Hyperion.Log                             as Log
import           Hyperion.Remote                          (getMasterNodeId)
type Lock = STM.TMVar ProcessId
newtype Key a = Key { Key a -> a
unKey :: a }
isLocked :: Lock -> STM.STM Bool
isLocked :: Lock -> STM Bool
isLocked Lock
l = Bool -> Bool
not (Bool -> Bool) -> STM Bool -> STM Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Lock -> STM Bool
forall a. TMVar a -> STM Bool
STM.isEmptyTMVar Lock
l
isUnlocked ::  Lock -> STM.STM Bool
isUnlocked :: Lock -> STM Bool
isUnlocked Lock
l = Bool -> Bool
not (Bool -> Bool) -> STM Bool -> STM Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Lock -> STM Bool
isLocked Lock
l
lock :: ProcessId -> Lock -> STM.STM ()
lock :: ProcessId -> Lock -> STM ()
lock = (Lock -> ProcessId -> STM ()) -> ProcessId -> Lock -> STM ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Lock -> ProcessId -> STM ()
forall a. TMVar a -> a -> STM ()
STM.putTMVar
unlock :: Lock -> STM.STM ()
unlock :: Lock -> STM ()
unlock = STM (Maybe ProcessId) -> STM ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (STM (Maybe ProcessId) -> STM ())
-> (Lock -> STM (Maybe ProcessId)) -> Lock -> STM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lock -> STM (Maybe ProcessId)
forall a. TMVar a -> STM (Maybe a)
STM.tryTakeTMVar
type LockMap = STM.TVar (Map.Map ByteString Lock)
lockMapLabel :: String
lockMapLabel :: String
lockMapLabel = String
"lockMapLabel"
lockMapStatic :: Static LockMap
lockMapStatic :: Static LockMap
lockMapStatic = String -> Static LockMap
forall a. String -> Static a
staticLabel String
lockMapLabel
getLockMap :: Process LockMap
getLockMap :: Process LockMap
getLockMap = Static LockMap -> Process LockMap
forall a. Typeable a => Static a -> Process a
unStatic Static LockMap
lockMapStatic
newLockMap :: IO LockMap
newLockMap :: IO LockMap
newLockMap = Map ByteString Lock -> IO LockMap
forall a. a -> IO (TVar a)
STM.newTVarIO Map ByteString Lock
forall k a. Map k a
Map.empty
registerLockMap :: LockMap -> RemoteTable -> RemoteTable
registerLockMap :: LockMap -> RemoteTable -> RemoteTable
registerLockMap LockMap
var = String -> Dynamic -> RemoteTable -> RemoteTable
registerStatic String
lockMapLabel (LockMap -> Dynamic
forall a. Typeable a => a -> Dynamic
toDynamic LockMap
var)
lockRemote_ :: ByteString -> Process ()
lockRemote_ :: ByteString -> Process ()
lockRemote_ ByteString
bs' = do
  Process (Maybe NodeId)
getMasterNodeId Process (Maybe NodeId)
-> (Maybe NodeId -> Process ()) -> Process ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Maybe NodeId
Nothing -> do
      let
        (ProcessId
pid, [ByteString]
bss) = ByteString -> (ProcessId, [ByteString])
forall a. Binary a => ByteString -> a
decode ByteString
bs'
      
      
      TMVar ()
sig  <- IO (TMVar ()) -> Process (TMVar ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (TMVar ()) -> Process (TMVar ()))
-> (STM (TMVar ()) -> IO (TMVar ()))
-> STM (TMVar ())
-> Process (TMVar ())
forall b c a. (b -> c) -> (a -> b) -> a -> c
. STM (TMVar ()) -> IO (TMVar ())
forall a. STM a -> IO a
STM.atomically (STM (TMVar ()) -> Process (TMVar ()))
-> STM (TMVar ()) -> Process (TMVar ())
forall a b. (a -> b) -> a -> b
$ STM (TMVar ())
forall a. STM (TMVar a)
STM.newEmptyTMVar
      
      TMVar [Lock]
lvar <- IO (TMVar [Lock]) -> Process (TMVar [Lock])
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (TMVar [Lock]) -> Process (TMVar [Lock]))
-> (STM (TMVar [Lock]) -> IO (TMVar [Lock]))
-> STM (TMVar [Lock])
-> Process (TMVar [Lock])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. STM (TMVar [Lock]) -> IO (TMVar [Lock])
forall a. STM a -> IO a
STM.atomically (STM (TMVar [Lock]) -> Process (TMVar [Lock]))
-> STM (TMVar [Lock]) -> Process (TMVar [Lock])
forall a b. (a -> b) -> a -> b
$ STM (TMVar [Lock])
forall a. STM (TMVar a)
STM.newEmptyTMVar
      
      ProcessId
_    <- Process () -> Process ProcessId
spawnLocal (Process () -> Process ProcessId)
-> Process () -> Process ProcessId
forall a b. (a -> b) -> a -> b
$ ProcessId -> TMVar [Lock] -> TMVar () -> Process ()
cleanup ProcessId
pid TMVar [Lock]
lvar TMVar ()
sig
      
      
      ()   <- IO () -> Process ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> (STM () -> IO ()) -> STM () -> Process ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. STM () -> IO ()
forall a. STM a -> IO a
STM.atomically (STM () -> Process ()) -> STM () -> Process ()
forall a b. (a -> b) -> a -> b
$ TMVar () -> STM ()
forall a. TMVar a -> STM a
STM.takeTMVar TMVar ()
sig
      LockMap
lmapvar <- Process LockMap
getLockMap
      
      
      
      
      
      
      [Lock]
locks <- IO [Lock] -> Process [Lock]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [Lock] -> Process [Lock])
-> (STM [Lock] -> IO [Lock]) -> STM [Lock] -> Process [Lock]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. STM [Lock] -> IO [Lock]
forall a. STM a -> IO a
STM.atomically (STM [Lock] -> Process [Lock]) -> STM [Lock] -> Process [Lock]
forall a b. (a -> b) -> a -> b
$ LockMap -> [ByteString] -> STM [Lock]
getLocks LockMap
lmapvar [ByteString]
bss
      IO () -> Process ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> (STM () -> IO ()) -> STM () -> Process ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. STM () -> IO ()
forall a. STM a -> IO a
STM.atomically (STM () -> Process ()) -> STM () -> Process ()
forall a b. (a -> b) -> a -> b
$ do
        [Bool]
unlocked <- (Lock -> STM Bool) -> [Lock] -> STM [Bool]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Lock -> STM Bool
isUnlocked [Lock]
locks
        if (Bool -> Bool) -> [Bool] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Bool -> Bool
forall a. a -> a
id [Bool]
unlocked then do
          (Lock -> STM ()) -> [Lock] -> STM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (ProcessId -> Lock -> STM ()
lock ProcessId
pid) [Lock]
locks
          TMVar [Lock] -> [Lock] -> STM ()
forall a. TMVar a -> a -> STM ()
STM.putTMVar TMVar [Lock]
lvar [Lock]
locks
        else STM ()
forall a. STM a
STM.retry
      () -> Process ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    Just NodeId
nid ->
      Static (SerializableDict ())
-> NodeId -> Closure (Process ()) -> Process ()
forall a.
Serializable a =>
Static (SerializableDict a)
-> NodeId -> Closure (Process a) -> Process a
call (StaticPtr (SerializableDict ()) -> Static (SerializableDict ())
forall a. Typeable a => StaticPtr a -> Static a
staticPtr (static SerializableDict ()
forall a. Serializable a => SerializableDict a
SerializableDict)) NodeId
nid (Closure (Process ()) -> Process ())
-> Closure (Process ()) -> Process ()
forall a b. (a -> b) -> a -> b
$
        Static (ByteString -> Process ())
-> ByteString -> Closure (Process ())
forall a. Static (ByteString -> a) -> ByteString -> Closure a
closure (StaticPtr (ByteString -> Process ())
-> Static (ByteString -> Process ())
forall a. Typeable a => StaticPtr a -> Static a
staticPtr (static ByteString -> Process ()
lockRemote_)) ByteString
bs'
  where
    getLocks :: LockMap -> [ByteString] -> STM.STM [Lock]
    getLocks :: LockMap -> [ByteString] -> STM [Lock]
getLocks LockMap
lmapvar [ByteString]
bss = do
      (ByteString -> STM Lock) -> [ByteString] -> STM [Lock]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ByteString -> STM Lock
lookupOrNew [ByteString]
bss
      where
        lookupOrNew :: ByteString -> STM.STM Lock
        lookupOrNew :: ByteString -> STM Lock
lookupOrNew ByteString
bs = do
          Map ByteString Lock
lmap <- LockMap -> STM (Map ByteString Lock)
forall a. TVar a -> STM a
STM.readTVar LockMap
lmapvar
          let
            mlock :: Maybe Lock
mlock = ByteString -> Map ByteString Lock -> Maybe Lock
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup ByteString
bs Map ByteString Lock
lmap
            new :: STM Lock
new = do
                Lock
l <- STM Lock
forall a. STM (TMVar a)
STM.newEmptyTMVar
                LockMap -> Map ByteString Lock -> STM ()
forall a. TVar a -> a -> STM ()
STM.writeTVar LockMap
lmapvar (Map ByteString Lock -> STM ()) -> Map ByteString Lock -> STM ()
forall a b. (a -> b) -> a -> b
$ ByteString -> Lock -> Map ByteString Lock -> Map ByteString Lock
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert ByteString
bs Lock
l Map ByteString Lock
lmap
                Lock -> STM Lock
forall (m :: * -> *) a. Monad m => a -> m a
return Lock
l
          STM Lock -> (Lock -> STM Lock) -> Maybe Lock -> STM Lock
forall b a. b -> (a -> b) -> Maybe a -> b
maybe STM Lock
new Lock -> STM Lock
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Lock
mlock
    cleanup :: ProcessId -> STM.TMVar [Lock] -> STM.TMVar () -> Process ()
    cleanup :: ProcessId -> TMVar [Lock] -> TMVar () -> Process ()
cleanup ProcessId
pid TMVar [Lock]
lvar TMVar ()
sig =
      Process () -> (ProcessLinkException -> Process ()) -> Process ()
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
catch 
        ( do
            ProcessId -> Process ()
link ProcessId
pid 
            IO () -> Process ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> (STM () -> IO ()) -> STM () -> Process ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. STM () -> IO ()
forall a. STM a -> IO a
STM.atomically (STM () -> Process ()) -> STM () -> Process ()
forall a b. (a -> b) -> a -> b
$ TMVar () -> () -> STM ()
forall a. TMVar a -> a -> STM ()
STM.putTMVar TMVar ()
sig () 
            IO () -> Process ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> (STM () -> IO ()) -> STM () -> Process ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. STM () -> IO ()
forall a. STM a -> IO a
STM.atomically (STM () -> Process ()) -> STM () -> Process ()
forall a b. (a -> b) -> a -> b
$ TMVar [Lock] -> STM [Lock]
forall a. TMVar a -> STM a
STM.readTMVar TMVar [Lock]
lvar STM [Lock] -> ([Lock] -> STM ()) -> STM ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Lock -> STM ()) -> [Lock] -> STM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Lock -> STM ()
wait 
        )
        ( \(ProcessLinkException ProcessId
_ DiedReason
reason) ->
            
            
            
            Bool -> Process () -> Process ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (DiedReason
reason DiedReason -> DiedReason -> Bool
forall a. Eq a => a -> a -> Bool
== DiedReason
DiedNormal) (Process () -> Process ()) -> Process () -> Process ()
forall a b. (a -> b) -> a -> b
$ do
              Bool
pidReleasedLock <- IO Bool -> Process Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> Process Bool)
-> (STM Bool -> IO Bool) -> STM Bool -> Process Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. STM Bool -> IO Bool
forall a. STM a -> IO a
STM.atomically (STM Bool -> Process Bool) -> STM Bool -> Process Bool
forall a b. (a -> b) -> a -> b
$ do
                Maybe [Lock]
mlocks <- TMVar [Lock] -> STM (Maybe [Lock])
forall a. TMVar a -> STM (Maybe a)
STM.tryReadTMVar TMVar [Lock]
lvar
                case Maybe [Lock]
mlocks of
                  Just [Lock]
locks -> do
                    [Bool]
releases <- ((Lock -> STM Bool) -> [Lock] -> STM [Bool])
-> [Lock] -> (Lock -> STM Bool) -> STM [Bool]
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Lock -> STM Bool) -> [Lock] -> STM [Bool]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM [Lock]
locks ((Lock -> STM Bool) -> STM [Bool])
-> (Lock -> STM Bool) -> STM [Bool]
forall a b. (a -> b) -> a -> b
$ \Lock
l -> do
                      Lock -> STM (Maybe ProcessId)
forall a. TMVar a -> STM (Maybe a)
STM.tryReadTMVar Lock
l STM (Maybe ProcessId) -> (Maybe ProcessId -> STM Bool) -> STM Bool
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                        Just ProcessId
pid' -> if ProcessId
pid ProcessId -> ProcessId -> Bool
forall a. Eq a => a -> a -> Bool
== ProcessId
pid' then do
                          Lock -> STM ()
unlock Lock
l
                          Bool -> STM Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
                          else Bool -> STM Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
                        Maybe ProcessId
Nothing   -> Bool -> STM Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
                    Bool -> STM Bool
forall (m :: * -> *) a. Monad m => a -> m a
return ((Bool -> Bool) -> [Bool] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Bool -> Bool
forall a. a -> a
id [Bool]
releases)
                  Maybe [Lock]
Nothing -> Bool -> STM Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
              Bool -> Process () -> Process ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
pidReleasedLock (Process () -> Process ()) -> Process () -> Process ()
forall a b. (a -> b) -> a -> b
$ Text -> ProcessId -> Process ()
forall a (m :: * -> *). (Show a, MonadIO m) => Text -> a -> m ()
Log.warn Text
"Process holding a lock died, released the locks it held" ProcessId
pid
        )
      where
        wait :: Lock -> STM.STM ()
        wait :: Lock -> STM ()
wait Lock
l = Lock -> STM (Maybe ProcessId)
forall a. TMVar a -> STM (Maybe a)
STM.tryReadTMVar Lock
l STM (Maybe ProcessId) -> (Maybe ProcessId -> STM ()) -> STM ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
          Just ProcessId
pid' -> if ProcessId
pid ProcessId -> ProcessId -> Bool
forall a. Eq a => a -> a -> Bool
== ProcessId
pid' then STM ()
forall a. STM a
STM.retry
                                      else () -> STM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
          Maybe ProcessId
Nothing   -> () -> STM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
unlockRemote_ :: ByteString -> Process ()
unlockRemote_ :: ByteString -> Process ()
unlockRemote_ ByteString
bss' =
  Process (Maybe NodeId)
getMasterNodeId Process (Maybe NodeId)
-> (Maybe NodeId -> Process ()) -> Process ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Maybe NodeId
Nothing -> do
      LockMap
lvar <- Process LockMap
getLockMap
      IO () -> Process ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> (STM () -> IO ()) -> STM () -> Process ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. STM () -> IO ()
forall a. STM a -> IO a
STM.atomically (STM () -> Process ()) -> STM () -> Process ()
forall a b. (a -> b) -> a -> b
$ do
        Map ByteString Lock
lmap <- LockMap -> STM (Map ByteString Lock)
forall a. TVar a -> STM a
STM.readTVar LockMap
lvar
        let
          unlock' :: ByteString -> STM ()
unlock' ByteString
bs = STM () -> (Lock -> STM ()) -> Maybe Lock -> STM ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> STM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) Lock -> STM ()
unlock (ByteString -> Map ByteString Lock -> Maybe Lock
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup ByteString
bs Map ByteString Lock
lmap)
        (ByteString -> STM ()) -> [ByteString] -> STM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ByteString -> STM ()
unlock' [ByteString]
bss
    Just NodeId
nid ->
      Static (SerializableDict ())
-> NodeId -> Closure (Process ()) -> Process ()
forall a.
Serializable a =>
Static (SerializableDict a)
-> NodeId -> Closure (Process a) -> Process a
call (StaticPtr (SerializableDict ()) -> Static (SerializableDict ())
forall a. Typeable a => StaticPtr a -> Static a
staticPtr (static SerializableDict ()
forall a. Serializable a => SerializableDict a
SerializableDict)) NodeId
nid (Closure (Process ()) -> Process ())
-> Closure (Process ()) -> Process ()
forall a b. (a -> b) -> a -> b
$
        Static (ByteString -> Process ())
-> ByteString -> Closure (Process ())
forall a. Static (ByteString -> a) -> ByteString -> Closure a
closure (StaticPtr (ByteString -> Process ())
-> Static (ByteString -> Process ())
forall a. Typeable a => StaticPtr a -> Static a
staticPtr (static ByteString -> Process ()
unlockRemote_)) ByteString
bss'
  where
    bss :: [ByteString]
    bss :: [ByteString]
bss = ByteString -> [ByteString]
forall a. Binary a => ByteString -> a
decode ByteString
bss'
serialize :: (Typeable a, Binary a) => a -> ByteString
serialize :: a -> ByteString
serialize a
a = (TypeRep, a) -> ByteString
forall a. Binary a => a -> ByteString
encode (a -> TypeRep
forall a. Typeable a => a -> TypeRep
typeOf a
a, a
a)
lockRemote :: (Typeable a, Binary a) => [a] -> Process [Key a]
lockRemote :: [a] -> Process [Key a]
lockRemote [a]
a = do
  ProcessId
pid <- Process ProcessId
getSelfPid
  ByteString -> Process ()
lockRemote_ (ByteString -> Process ()) -> ByteString -> Process ()
forall a b. (a -> b) -> a -> b
$ (ProcessId, [ByteString]) -> ByteString
forall a. Binary a => a -> ByteString
encode (ProcessId
pid, (a -> ByteString) -> [a] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map a -> ByteString
forall a. (Typeable a, Binary a) => a -> ByteString
serialize [a]
a)
  [Key a] -> Process [Key a]
forall (m :: * -> *) a. Monad m => a -> m a
return ((a -> Key a) -> [a] -> [Key a]
forall a b. (a -> b) -> [a] -> [b]
map a -> Key a
forall a. a -> Key a
Key [a]
a)
unlockRemote :: (Typeable a, Binary a) => [Key a] -> Process ()
unlockRemote :: [Key a] -> Process ()
unlockRemote [Key a]
a = ByteString -> Process ()
unlockRemote_ (ByteString -> Process ()) -> ByteString -> Process ()
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
forall a. Binary a => a -> ByteString
encode ((Key a -> ByteString) -> [Key a] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (a -> ByteString
forall a. (Typeable a, Binary a) => a -> ByteString
serialize (a -> ByteString) -> (Key a -> a) -> Key a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Key a -> a
forall a. Key a -> a
unKey) [Key a]
a)
withLocks :: (Typeable a, Binary a) => [a] -> Process r -> Process r
withLocks :: [a] -> Process r -> Process r
withLocks [a]
obj = Process [Key a]
-> ([Key a] -> Process ()) -> ([Key a] -> Process r) -> Process r
forall (m :: * -> *) a c b.
MonadMask m =>
m a -> (a -> m c) -> (a -> m b) -> m b
bracket ([a] -> Process [Key a]
forall a. (Typeable a, Binary a) => [a] -> Process [Key a]
lockRemote [a]
obj) [Key a] -> Process ()
forall a. (Typeable a, Binary a) => [Key a] -> Process ()
unlockRemote (([Key a] -> Process r) -> Process r)
-> (Process r -> [Key a] -> Process r) -> Process r -> Process r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Process r -> [Key a] -> Process r
forall a b. a -> b -> a
const
withLock :: (Typeable a, Binary a) => a -> Process r -> Process r
withLock :: a -> Process r -> Process r
withLock a
a = [a] -> Process r -> Process r
forall a r. (Typeable a, Binary a) => [a] -> Process r -> Process r
withLocks [a
a]