module ZooKeeper.Recipe.Election
( election
) where
import Control.Exception (catch, throwIO)
import Control.Monad
import Z.Data.CBytes (CBytes)
import ZooKeeper
import ZooKeeper.Exception (ZNODEEXISTS)
import ZooKeeper.Recipe.Utils (ZkRecipeException (..),
SequenceNumWithGUID (..),
createSeqEphemeralZNode,
mkSequenceNumWithGUID)
import ZooKeeper.Types
election :: ZHandle
-> CBytes
-> CBytes
-> IO ()
-> (DataCompletion -> IO ())
-> IO ()
election :: ZHandle
-> CBytes -> CBytes -> IO () -> (DataCompletion -> IO ()) -> IO ()
election ZHandle
zk CBytes
electionPath CBytes
guid IO ()
leaderApp DataCompletion -> IO ()
watchSetApp = do
let electionSeqPath :: CBytes
electionSeqPath = CBytes
electionPath CBytes -> CBytes -> CBytes
forall a. Semigroup a => a -> a -> a
<> CBytes
"/" CBytes -> CBytes -> CBytes
forall a. Semigroup a => a -> a -> a
<> CBytes
guid CBytes -> CBytes -> CBytes
forall a. Semigroup a => a -> a -> a
<> CBytes
"_"
do Maybe StatCompletion
electionExists <- HasCallStack => ZHandle -> CBytes -> IO (Maybe StatCompletion)
ZHandle -> CBytes -> IO (Maybe StatCompletion)
zooExists ZHandle
zk CBytes
electionPath
case Maybe StatCompletion
electionExists of
Just StatCompletion
_ -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Maybe StatCompletion
Nothing -> IO StringCompletion -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO StringCompletion -> IO ()) -> IO StringCompletion -> IO ()
forall a b. (a -> b) -> a -> b
$ HasCallStack =>
ZHandle
-> CBytes
-> Maybe Bytes
-> AclVector
-> CreateMode
-> IO StringCompletion
ZHandle
-> CBytes
-> Maybe Bytes
-> AclVector
-> CreateMode
-> IO StringCompletion
zooCreate ZHandle
zk CBytes
electionPath Maybe Bytes
forall a. Maybe a
Nothing AclVector
zooOpenAclUnsafe CreateMode
ZooPersistent
IO () -> (ZNODEEXISTS -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` (\(ZNODEEXISTS
_ :: ZNODEEXISTS) -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
(StringCompletion CBytes
this) <- ZHandle -> CBytes -> CBytes -> IO StringCompletion
createSeqEphemeralZNode ZHandle
zk CBytes
electionPath CBytes
guid
let thisSeqNumWithGUID :: SequenceNumWithGUID
thisSeqNumWithGUID = CBytes -> SequenceNumWithGUID
mkSequenceNumWithGUID CBytes
this
(StringsCompletion (StringVector [CBytes]
children)) <- HasCallStack => ZHandle -> CBytes -> IO StringsCompletion
ZHandle -> CBytes -> IO StringsCompletion
zooGetChildren ZHandle
zk CBytes
electionPath
let childrenSeqNumWithGUID :: [SequenceNumWithGUID]
childrenSeqNumWithGUID = CBytes -> SequenceNumWithGUID
mkSequenceNumWithGUID (CBytes -> SequenceNumWithGUID)
-> [CBytes] -> [SequenceNumWithGUID]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [CBytes]
children
case (SequenceNumWithGUID -> Bool)
-> [SequenceNumWithGUID] -> [SequenceNumWithGUID]
forall a. (a -> Bool) -> [a] -> [a]
filter (SequenceNumWithGUID -> SequenceNumWithGUID -> Bool
forall a. Ord a => a -> a -> Bool
< SequenceNumWithGUID
thisSeqNumWithGUID) [SequenceNumWithGUID]
childrenSeqNumWithGUID of
[] -> do
let _smallest :: SequenceNumWithGUID
_smallest = [SequenceNumWithGUID] -> SequenceNumWithGUID
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [SequenceNumWithGUID]
childrenSeqNumWithGUID
IO ()
leaderApp
[SequenceNumWithGUID]
xs -> do
let toWatch :: CBytes
toWatch = CBytes
electionPath CBytes -> CBytes -> CBytes
forall a. Semigroup a => a -> a -> a
<> CBytes
"/" CBytes -> CBytes -> CBytes
forall a. Semigroup a => a -> a -> a
<> SequenceNumWithGUID -> CBytes
unSequenceNumWithGUID ([SequenceNumWithGUID] -> SequenceNumWithGUID
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [SequenceNumWithGUID]
xs)
HasCallStack =>
ZHandle
-> CBytes
-> (HsWatcherCtx -> IO ())
-> (DataCompletion -> IO ())
-> IO ()
ZHandle
-> CBytes
-> (HsWatcherCtx -> IO ())
-> (DataCompletion -> IO ())
-> IO ()
zooWatchGet ZHandle
zk CBytes
toWatch (CBytes -> SequenceNumWithGUID -> HsWatcherCtx -> IO ()
forall t. t -> SequenceNumWithGUID -> HsWatcherCtx -> IO ()
callback CBytes
electionSeqPath SequenceNumWithGUID
thisSeqNumWithGUID) DataCompletion -> IO ()
watchSetApp
where
callback :: t -> SequenceNumWithGUID -> HsWatcherCtx -> IO ()
callback t
electionSeqPath SequenceNumWithGUID
thisSeqNumWithGUID HsWatcherCtx{Maybe CBytes
ZooEvent
ZooState
ZHandle
watcherCtxPath :: HsWatcherCtx -> Maybe CBytes
watcherCtxState :: HsWatcherCtx -> ZooState
watcherCtxType :: HsWatcherCtx -> ZooEvent
watcherCtxZHandle :: HsWatcherCtx -> ZHandle
watcherCtxPath :: Maybe CBytes
watcherCtxState :: ZooState
watcherCtxType :: ZooEvent
watcherCtxZHandle :: ZHandle
..} = do
(StringsCompletion (StringVector [CBytes]
children)) <- HasCallStack => ZHandle -> CBytes -> IO StringsCompletion
ZHandle -> CBytes -> IO StringsCompletion
zooGetChildren ZHandle
watcherCtxZHandle CBytes
electionPath
let childrenSeqNumWithGUID :: [SequenceNumWithGUID]
childrenSeqNumWithGUID = CBytes -> SequenceNumWithGUID
mkSequenceNumWithGUID (CBytes -> SequenceNumWithGUID)
-> [CBytes] -> [SequenceNumWithGUID]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [CBytes]
children
let smallest :: SequenceNumWithGUID
smallest = [SequenceNumWithGUID] -> SequenceNumWithGUID
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [SequenceNumWithGUID]
childrenSeqNumWithGUID
if SequenceNumWithGUID
smallest SequenceNumWithGUID -> SequenceNumWithGUID -> Bool
forall a. Eq a => a -> a -> Bool
== SequenceNumWithGUID
thisSeqNumWithGUID
then do
IO ()
leaderApp
else do
case (SequenceNumWithGUID -> Bool)
-> [SequenceNumWithGUID] -> [SequenceNumWithGUID]
forall a. (a -> Bool) -> [a] -> [a]
filter (SequenceNumWithGUID -> SequenceNumWithGUID -> Bool
forall a. Ord a => a -> a -> Bool
< SequenceNumWithGUID
thisSeqNumWithGUID) [SequenceNumWithGUID]
childrenSeqNumWithGUID of
[] -> ZkRecipeException -> IO ()
forall e a. Exception e => e -> IO a
throwIO (ZkRecipeException -> IO ()) -> ZkRecipeException -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> ZkRecipeException
ZkRecipeException String
"The 'impossible' happened!"
[SequenceNumWithGUID]
xs -> do
let toWatch :: CBytes
toWatch = CBytes
electionPath CBytes -> CBytes -> CBytes
forall a. Semigroup a => a -> a -> a
<> CBytes
"/" CBytes -> CBytes -> CBytes
forall a. Semigroup a => a -> a -> a
<> SequenceNumWithGUID -> CBytes
unSequenceNumWithGUID ([SequenceNumWithGUID] -> SequenceNumWithGUID
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [SequenceNumWithGUID]
xs )
HasCallStack =>
ZHandle
-> CBytes
-> (HsWatcherCtx -> IO ())
-> (DataCompletion -> IO ())
-> IO ()
ZHandle
-> CBytes
-> (HsWatcherCtx -> IO ())
-> (DataCompletion -> IO ())
-> IO ()
zooWatchGet ZHandle
zk CBytes
toWatch (t -> SequenceNumWithGUID -> HsWatcherCtx -> IO ()
callback t
electionSeqPath SequenceNumWithGUID
thisSeqNumWithGUID) DataCompletion -> IO ()
watchSetApp