From 0494ddd696de5086ee46b6d4a1a006ea60847f95 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Sat, 20 Jun 2020 21:20:32 +0200 Subject: [PATCH 1/2] stabilise periodically contributes to #44 --- app/Main.hs | 1 + src/Hash2Pub/FediChord.hs | 13 +++++++++---- src/Hash2Pub/FediChordTypes.hs | 1 + test/FediChordSpec.hs | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/Main.hs b/app/Main.hs index fc9299d..c712f55 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -55,4 +55,5 @@ readConfig = do , confIP = toHostAddress6 . read $ ipString , confDhtPort = read portString , confBootstrapNodes = [(bootstrapHost, read bootstrapPortString)] + --, confStabiliseInterval = 60 } diff --git a/src/Hash2Pub/FediChord.hs b/src/Hash2Pub/FediChord.hs index 7a184f4..9767aa2 100644 --- a/src/Hash2Pub/FediChord.hs +++ b/src/Hash2Pub/FediChord.hs @@ -181,11 +181,16 @@ cacheWriter nsSTM = modifyTVar' (nodeCacheSTM ns) cacheModifier stabiliseThread :: LocalNodeStateSTM -> IO () -stabiliseThread nsSTM = do +stabiliseThread nsSTM = forever $ do + ns <- readTVarIO nsSTM -- TODO: update successfully stabilised nodes in cache - -- placeholder - stabiliseNeighbour nsSTM successors 1 - pure () + -- first stabilise immediate neihbours, then the next ones + forM_ [1..(kNeighbours ns)] (\num -> do + stabiliseNeighbour nsSTM predecessors num + stabiliseNeighbour nsSTM successors num + ) + -- TODO: make delay configurable + threadDelay (60 * 1000) where stabiliseNeighbour :: LocalNodeStateSTM -> (LocalNodeState -> [RemoteNodeState]) diff --git a/src/Hash2Pub/FediChordTypes.hs b/src/Hash2Pub/FediChordTypes.hs index 363e300..26a13f8 100644 --- a/src/Hash2Pub/FediChordTypes.hs +++ b/src/Hash2Pub/FediChordTypes.hs @@ -613,6 +613,7 @@ data FediChordConf = FediChordConf , confIP :: HostAddress6 , confDhtPort :: Int , confBootstrapNodes :: [(String, PortNumber)] + --, confStabiliseInterval :: Int } deriving (Show, Eq) diff --git a/test/FediChordSpec.hs b/test/FediChordSpec.hs index dbb8e8b..4f05e72 100644 --- a/test/FediChordSpec.hs +++ b/test/FediChordSpec.hs @@ -154,7 +154,7 @@ spec = do describe "successors and predecessors do not disturb the ring characteristics of EpiChord operations (see #48)" $ do let emptyCache = initCache - -- implicitly relies on kNieghbours to be <= 3 + -- implicitly relies on kNeighbours to be <= 3 thisNid = toNodeID 1000 thisNode = setNid thisNid <$> exampleLocalNode nid2 = toNodeID 1003 From d5f502c05c25ea2c4cba712df340bb9f25dacf8c Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Sat, 20 Jun 2020 22:28:01 +0200 Subject: [PATCH 2/2] ping potential neighbours before adding to list for #44 --- src/Hash2Pub/FediChord.hs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Hash2Pub/FediChord.hs b/src/Hash2Pub/FediChord.hs index 9767aa2..e1ec96b 100644 --- a/src/Hash2Pub/FediChord.hs +++ b/src/Hash2Pub/FediChord.hs @@ -61,12 +61,13 @@ import Crypto.Hash import qualified Data.ByteArray as BA import qualified Data.ByteString as BS import qualified Data.ByteString.UTF8 as BSU +import Data.Either (rights) import Data.Foldable (foldr') import Data.IP (IPv6, fromHostAddress6, toHostAddress6) import qualified Data.Map.Strict as Map -import Data.Maybe (fromJust, fromMaybe, isJust, - mapMaybe) +import Data.Maybe (catMaybes, fromJust, fromMaybe, + isJust, mapMaybe) import qualified Data.Set as Set import Data.Time.Clock.POSIX import Data.Typeable (Typeable (..), typeOf) @@ -212,10 +213,25 @@ stabiliseThread nsSTM = forever $ do -> m () parseNeighbourResponse (Left err) = throwError err parseNeighbourResponse (Right (succs, preds)) = liftIO $ do + -- ping each returned node before actually inserting them + -- send pings in parallel, check whether ID is part of the returned IDs + nsSnap <- readTVarIO nsSTM + pingThreads <- mapM (async . checkReachability nsSnap) $ preds <> succs + -- ToDo: exception handling, maybe log them + -- filter out own node + checkedNeighbours <- filter (/= toRemoteNodeState nsSnap) . catMaybes . rights <$> mapM waitCatch pingThreads + atomically $ do newerNsSnap <- readTVar nsSTM - writeTVar nsSTM $ addPredecessors preds . addSuccessors succs $ newerNsSnap + writeTVar nsSTM $ addPredecessors checkedNeighbours . addSuccessors checkedNeighbours $ newerNsSnap pure () + checkReachability :: LocalNodeState -> RemoteNodeState -> IO (Maybe RemoteNodeState) + checkReachability ns toCheck = do + resp <- requestPing ns toCheck + pure $ either (const Nothing) (\vss -> + if toCheck `elem` vss then Just toCheck else Nothing + ) resp + -- periodically contact immediate successor and predecessor -- If they respond, see whether there is a closer neighbour in between