start restructuring joinOnNewEntries flow

- overview comment on possible flow
- cache query
- doesn't compile yet
This commit is contained in:
Trolli Schmittlauch 2020-09-26 22:08:09 +02:00
parent 578cc362b9
commit 9a61c186e3
2 changed files with 45 additions and 14 deletions

View file

@ -127,9 +127,16 @@ fediChordInit initConf serviceRunner = do
either (\err -> do
-- handle unsuccessful join
putStrLn $ err <> " Error joining, start listening for incoming requests anyways"
-- add an unjoined placeholder vserver to be able to listen for
-- incoming request
placeholderVS <- nodeStateInit realNodeSTM 0
placeholderVSSTM <- newTVarIO placeholderVS
atomically . modifyTVar' realNodeSTM $
addVserver (getNid placeholderVS, placeholderVSSTM)
-- TODO: on which bootstrap node vserver to join? (#77)
-- launch thread attempting to join on new cache entries
-- TODO: adjust joinOnNewEntriesThread to k-choices
--_ <- forkIO $ joinOnNewEntriesThread firstVSSTM
_ <- forkIO $ joinOnNewEntriesThread realNodeSTM
async (fediMainThreads serverSock realNodeSTM)
)
(\_ -> do
@ -370,9 +377,8 @@ tryBootstrapJoining nodeSTM = do
joinResult <- tryJoining bss (fediChordBootstrapJoin firstVSSTM)
either
(pure . Left)
(\_ -> fmap Right . atomically . modifyTVar' nodeSTM $ (\rn -> rn
{ vservers = HMap.insert (getNid firstVS) firstVSSTM (vservers rn) }
)
(\_ -> fmap Right . atomically . modifyTVar' nodeSTM $
addVserver (getNid firstVS, firstVSSTM)
)
(joinResult :: Either String ())
@ -473,24 +479,44 @@ fediChordVserverLeave ns = do
-- | Wait for new cache entries to appear and then try joining on them.
-- Exits after successful joining.
joinOnNewEntriesThread :: Service s (RealNodeSTM s) => LocalNodeStateSTM s -> IO ()
joinOnNewEntriesThread nsSTM = loop
joinOnNewEntriesThread :: Service s (RealNodeSTM s) => RealNodeSTM s -> IO ()
joinOnNewEntriesThread nodeSTM = loop
where
-- situation 1: not joined yet -> vservers == empty
-- problem: empty vservers means not responding to incoming requests, so
-- another node cannot join on us an we not on them (as they're still
-- unjoined as well)
-- solution: on failure still join a dummy node, also add it as vserver
-- problem: once another node has joined on the dummy vserver, we shouldn't
-- just delete it again as it now relies on it as a neighbour
-- => either trigger a kChoicesNodeJoin with the flag that **not** at least one
-- single node needs to be joined (read vservers initially), or do an accelerated
-- periodic rebalance
-- TODO: document this approach in the docs
loop = do
nsSnap <- readTVarIO nsSTM
(lookupResult, parentNode) <- atomically $ do
cache <- readTVar $ nodeCacheSTM nsSnap
parentNode <- readTVar $ parentRealNode nsSnap
case queryLocalCache nsSnap cache 1 (getNid nsSnap) of
-- empty cache, block until cache changes and then retry
(FORWARD s) | Set.null s -> retry
result -> pure (result, parentNode)
lookupResult <- atomically $ do
nodeSnap <- readTVar nodeSTM
case headMay (HMap.toList $ vservers nodeSnap) of
Nothing -> retry
Just vsSTM -> do
-- take any active vserver as heuristic for whether this node has
-- successfully joined:
-- If the node hasn't joined yet, only a single placeholder node
-- is active…
firstVS <- readTVar vsSTM
cache <- readTVar $ globalNodeCacheSTM nodeSnap
case queryLocalCache firstVS cache 1 (getNid firstVS) of
-- …which, having no neighbours, returns an empty forward list
-- -> block until cache changes and then retry
(FORWARD s) | Set.null s -> retry
result -> pure result
case lookupResult of
-- already joined
FOUND _ ->
pure ()
-- otherwise try joining
FORWARD _ -> do
-- do normal join, but without bootstrap nodes
joinResult <- runExceptT $ fediChordVserverJoin nsSTM
either
-- on join failure, sleep and retry

View file

@ -22,6 +22,7 @@ module Hash2Pub.FediChordTypes
, LoadStats (..)
, emptyLoadStats
, remainingLoadTarget
, addVserver
, SegmentLoadStats (..)
, setSuccessors
, setPredecessors
@ -170,6 +171,10 @@ data RealNode s = RealNode
, nodeService :: s (RealNodeSTM s)
}
-- | insert a new vserver mapping into a node
addVserver :: (NodeID, LocalNodeStateSTM s) -> RealNode s -> RealNode s
addVserver (key, nstate) node = node
{ vservers = HMap.insert key nstate (vservers node) }
type VSMap s = HashMap NodeID (LocalNodeStateSTM s)
type RealNodeSTM s = TVar (RealNode s)