adjust joinOnNewEntreisThread to k-choices join

This commit is contained in:
Trolli Schmittlauch 2020-09-28 00:55:45 +02:00
parent 21ecf9b041
commit 0ee8f0dc43

View file

@ -133,9 +133,7 @@ fediChordInit initConf serviceRunner = do
placeholderVSSTM <- newTVarIO placeholderVS placeholderVSSTM <- newTVarIO placeholderVS
atomically . modifyTVar' realNodeSTM $ atomically . modifyTVar' realNodeSTM $
addVserver (getNid placeholderVS, placeholderVSSTM) addVserver (getNid placeholderVS, placeholderVSSTM)
-- TODO: on which bootstrap node vserver to join? (#77)
-- launch thread attempting to join on new cache entries -- launch thread attempting to join on new cache entries
-- TODO: adjust joinOnNewEntriesThread to k-choices
_ <- forkIO $ joinOnNewEntriesThread realNodeSTM _ <- forkIO $ joinOnNewEntriesThread realNodeSTM
async (fediMainThreads serverSock realNodeSTM) async (fediMainThreads serverSock realNodeSTM)
) )
@ -195,9 +193,12 @@ nodeStateInit realNodeSTM vsID' = do
pure initialState pure initialState
-- | Joins a 'RealNode' to the DHT by joining several vservers, trying to match
-- the own load target best.
-- Triggers 'kChoicesVsJoin'
kChoicesNodeJoin :: (MonadError String m, MonadIO m, Service s (RealNodeSTM s)) kChoicesNodeJoin :: (MonadError String m, MonadIO m, Service s (RealNodeSTM s))
=> RealNodeSTM s => RealNodeSTM s
-> (String, PortNumber) -- ^ domain and port of a bootstrapping node -> Maybe (String, PortNumber) -- ^ domain and port of a bootstrapping node, if bootstrap joining
-> m () -> m ()
kChoicesNodeJoin nodeSTM bootstrapNode = do kChoicesNodeJoin nodeSTM bootstrapNode = do
node <- liftIO $ readTVarIO nodeSTM node <- liftIO $ readTVarIO nodeSTM
@ -213,13 +214,14 @@ kChoicesNodeJoin nodeSTM bootstrapNode = do
joinLoadTarget = totalCapacity ownLoadStats * (confKChoicesUnderload conf + confKChoicesOverload conf) / 2 joinLoadTarget = totalCapacity ownLoadStats * (confKChoicesUnderload conf + confKChoicesOverload conf) / 2
initialJoins = confKChoicesMaxVS conf `div` 2 initialJoins = confKChoicesMaxVS conf `div` 2
-- edge case: however small the target is, at least join 1 vs -- edge case: however small the target is, at least join 1 vs
-- kCoicesVsJoin until target is met -- kCoicesVsJoin until target is met unless there's already an active & joined VS causing enough load
joinedVss <- vsJoins vs0STM (totalCapacity ownLoadStats) (vservers node) joinLoadTarget (fromIntegral initialJoins) nodeSTM alreadyJoinedVss <- liftIO $ foldM (\sumAcc vsSTM -> readTVarIO vsSTM >>= (\vs -> pure . (+) sumAcc $ if isJoined vs then 1 else 0)) 0 $ vservers node
if HMap.null joinedVss unless (alreadyJoinedVss > 0 && compensatedLoadSum ownLoadStats >= joinLoadTarget) $ do
then throwError "k-choices join unsuccessful, no vserver joined" joinedVss <- vsJoins vs0STM (totalCapacity ownLoadStats) (vservers node) joinLoadTarget (fromIntegral initialJoins - alreadyJoinedVss) nodeSTM
else liftIO . atomically . modifyTVar' nodeSTM $ \node' -> node' if HMap.null joinedVss
{ vservers = HMap.union (vservers node') joinedVss } then throwError "k-choices join unsuccessful, no vserver joined"
pure () else liftIO . atomically . modifyTVar' nodeSTM $ \node' -> node'
{ vservers = HMap.union (vservers node') joinedVss }
where where
vsJoins :: (MonadError String m, MonadIO m, Service s (RealNodeSTM s)) vsJoins :: (MonadError String m, MonadIO m, Service s (RealNodeSTM s))
@ -242,7 +244,7 @@ kChoicesNodeJoin nodeSTM bootstrapNode = do
kChoicesVsJoin :: (MonadError String m, MonadIO m, Service s (RealNodeSTM s)) kChoicesVsJoin :: (MonadError String m, MonadIO m, Service s (RealNodeSTM s))
=> LocalNodeStateSTM s -- ^ vserver to be used for querying => LocalNodeStateSTM s -- ^ vserver to be used for querying
-> (String, PortNumber) -- ^ domain and port of a bootstrapping node -> Maybe (String, PortNumber) -- ^ domain and port of a bootstrapping node, if bootstrappinG
-> Double -- ^ own capacity -> Double -- ^ own capacity
-> VSMap s -- ^ currently active VServers -> VSMap s -- ^ currently active VServers
-> RealNodeSTM s -- ^ parent node is needed for initialising a new vserver -> RealNodeSTM s -- ^ parent node is needed for initialising a new vserver
@ -262,7 +264,11 @@ kChoicesVsJoin queryVsSTM bootstrapNode capacity activeVss nodeSTM remainingTarg
-- simplification: treat each load lookup failure as a general unavailability of that segment -- simplification: treat each load lookup failure as a general unavailability of that segment
-- TODO: retries for transient failures -- TODO: retries for transient failures
segmentLoads <- fmap catMaybes . forM nonJoinedIDs $ (\(vsNid, vsId) -> (do segmentLoads <- fmap catMaybes . forM nonJoinedIDs $ (\(vsNid, vsId) -> (do
currentlyResponsible <- bootstrapQueryId queryVsSTM bootstrapNode vsNid -- if bootstrap node is provided, do initial lookup via that
currentlyResponsible <- maybe
(requestQueryID queryVs vsNid)
(\bs -> bootstrapQueryId queryVsSTM bs vsNid)
bootstrapNode
segment <- requestQueryLoad queryVs vsNid currentlyResponsible segment <- requestQueryLoad queryVs vsNid currentlyResponsible
pure $ Just (segment, vsId, currentlyResponsible) pure $ Just (segment, vsId, currentlyResponsible)
-- store segment stats and vserver ID together, so it's clear -- store segment stats and vserver ID together, so it's clear
@ -367,7 +373,7 @@ tryBootstrapJoining nodeSTM = do
bss = bootstrapNodes node bss = bootstrapNodes node
conf = nodeConfig node conf = nodeConfig node
if confEnableKChoices conf if confEnableKChoices conf
then tryJoining bss $ runExceptT . kChoicesNodeJoin nodeSTM then tryJoining bss $ runExceptT . kChoicesNodeJoin nodeSTM . Just
else do else do
firstVS <- nodeStateInit nodeSTM 0 firstVS <- nodeStateInit nodeSTM 0
firstVSSTM <- newTVarIO firstVS firstVSSTM <- newTVarIO firstVS
@ -517,9 +523,10 @@ joinOnNewEntriesThread nodeSTM = loop
-- periodic rebalance -- periodic rebalance
-- TODO: document this approach in the docs -- TODO: document this approach in the docs
loop = do loop = do
lookupResult <- atomically $ do (lookupResult, conf, firstVSSTM) <- atomically $ do
nodeSnap <- readTVar nodeSTM nodeSnap <- readTVar nodeSTM
case headMay (HMap.toList $ vservers nodeSnap) of let conf = nodeConfig nodeSnap
case headMay (HMap.elems $ vservers nodeSnap) of
Nothing -> retry Nothing -> retry
Just vsSTM -> do Just vsSTM -> do
-- take any active vserver as heuristic for whether this node has -- take any active vserver as heuristic for whether this node has
@ -532,7 +539,7 @@ joinOnNewEntriesThread nodeSTM = loop
-- …which, having no neighbours, returns an empty forward list -- …which, having no neighbours, returns an empty forward list
-- -> block until cache changes and then retry -- -> block until cache changes and then retry
(FORWARD s) | Set.null s -> retry (FORWARD s) | Set.null s -> retry
result -> pure result result -> pure (result, conf, vsSTM)
case lookupResult of case lookupResult of
-- already joined -- already joined
FOUND _ -> FOUND _ ->
@ -540,10 +547,13 @@ joinOnNewEntriesThread nodeSTM = loop
-- otherwise try joining -- otherwise try joining
FORWARD _ -> do FORWARD _ -> do
-- do normal join, but without bootstrap nodes -- do normal join, but without bootstrap nodes
joinResult <- runExceptT $ fediChordVserverJoin nsSTM joinResult <- if confEnableKChoices conf
then runExceptT $ kChoicesNodeJoin nodeSTM Nothing
else runExceptT $ fediChordVserverJoin firstVSSTM
>> pure ()
either either
-- on join failure, sleep and retry -- on join failure, sleep and retry
(const $ threadDelay (confJoinAttemptsInterval . nodeConfig $ parentNode) >> loop) (const $ threadDelay (confJoinAttemptsInterval conf) >> loop)
(const $ pure ()) (const $ pure ())
joinResult joinResult