From d293cc05d148ebe7b9019afffcfdab5ff44719d5 Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Tue, 7 Jul 2020 17:34:42 +0200 Subject: [PATCH] data structure for RealNode holds common config and management data contributes to #56, #34, #2 --- app/Main.hs | 5 ++++- src/Hash2Pub/FediChord.hs | 25 ++++++++++++++++++------- src/Hash2Pub/FediChordTypes.hs | 17 +++++++++++++++++ test/FediChordSpec.hs | 22 ++++++++++++++++------ 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/app/Main.hs b/app/Main.hs index eb54359..03f72f1 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -16,10 +16,13 @@ main = do -- ToDo: parse and pass config -- probably use `tomland` for that conf <- readConfig + -- TODO: first initialise 'RealNode', then the vservers -- ToDo: load persisted caches, bootstrapping nodes … (serverSock, thisNode) <- fediChordInit conf -- currently no masking is necessary, as there is nothing to clean up cacheWriterThread <- forkIO $ cacheWriter thisNode + thisNodeSnap <- readTVarIO thisNode + realNode <- readTVarIO $ parentRealNode thisNodeSnap -- try joining the DHT using one of the provided bootstrapping nodes let tryJoining (bn:bns) = do @@ -28,7 +31,7 @@ main = do Left err -> putStrLn ("join error: " <> err) >> tryJoining bns Right joined -> pure $ Right joined tryJoining [] = pure $ Left "Exhausted all bootstrap points for joining." - joinedState <- tryJoining $ confBootstrapNodes conf + joinedState <- tryJoining $ bootstrapNodes realNode either (\err -> do -- handle unsuccessful join diff --git a/src/Hash2Pub/FediChord.hs b/src/Hash2Pub/FediChord.hs index 1e992bc..ba7edb4 100644 --- a/src/Hash2Pub/FediChord.hs +++ b/src/Hash2Pub/FediChord.hs @@ -41,6 +41,7 @@ module Hash2Pub.FediChord ( , fediChordJoin , fediChordBootstrapJoin , fediMainThreads + , RealNode (..) , nodeStateInit , mkServerSocket , mkSendSocket @@ -90,27 +91,36 @@ import Debug.Trace (trace) -- | initialise data structures, compute own IDs and bind to listening socket -- ToDo: load persisted state, thus this function already operates in IO fediChordInit :: FediChordConf -> IO (Socket, LocalNodeStateSTM) -fediChordInit conf = do - initialState <- nodeStateInit conf +fediChordInit initConf = do + let realNode = RealNode { + vservers = [] + , nodeConfig = initConf + , bootstrapNodes = confBootstrapNodes initConf + } + realNodeSTM <- newTVarIO realNode + initialState <- nodeStateInit realNodeSTM initialStateSTM <- newTVarIO initialState serverSock <- mkServerSocket (getIpAddr initialState) (getDhtPort initialState) pure (serverSock, initialStateSTM) -- | initialises the 'NodeState' for this local node. -- Separated from 'fediChordInit' to be usable in tests. -nodeStateInit :: FediChordConf -> IO LocalNodeState -nodeStateInit conf = do +nodeStateInit :: RealNodeSTM -> IO LocalNodeState +nodeStateInit realNodeSTM = do + realNode <- readTVarIO realNodeSTM cacheSTM <- newTVarIO initCache q <- atomically newTQueue let + conf = nodeConfig realNode + vsID = 0 containedState = RemoteNodeState { domain = confDomain conf , ipAddr = confIP conf - , nid = genNodeID (confIP conf) (confDomain conf) 0 + , nid = genNodeID (confIP conf) (confDomain conf) $ fromInteger vsID , dhtPort = toEnum $ confDhtPort conf , servicePort = 0 - , vServerID = 0 - } + , vServerID = vsID + } initialState = LocalNodeState { nodeState = containedState , nodeCacheSTM = cacheSTM @@ -121,6 +131,7 @@ nodeStateInit conf = do , lNumBestNodes = 3 , pNumParallelQueries = 2 , jEntriesPerSlice = 2 + , parentRealNode = realNodeSTM } pure initialState diff --git a/src/Hash2Pub/FediChordTypes.hs b/src/Hash2Pub/FediChordTypes.hs index 660eb49..8351eba 100644 --- a/src/Hash2Pub/FediChordTypes.hs +++ b/src/Hash2Pub/FediChordTypes.hs @@ -13,6 +13,8 @@ module Hash2Pub.FediChordTypes ( , LocalNodeState (..) , LocalNodeStateSTM , RemoteNodeState (..) + , RealNode (..) + , RealNodeSTM , setSuccessors , setPredecessors , NodeCache @@ -132,6 +134,19 @@ a `localCompare` b wayForwards = getNodeID (b - a) wayBackwards = getNodeID (a - b) +-- | Data for managing the virtual server nodes of this real node. +-- Also contains shared data and config values. +-- TODO: more data structures for k-choices bookkeeping +data RealNode = RealNode + { vservers :: [LocalNodeStateSTM] + -- ^ references to all active versers + , nodeConfig :: FediChordConf + -- ^ holds the initial configuration read at program start + , bootstrapNodes :: [(String, PortNumber)] + -- ^ nodes to be used as bootstrapping points, new ones learned during operation + } + +type RealNodeSTM = TVar RealNode -- | represents a node and all its important state data RemoteNodeState = RemoteNodeState @@ -172,6 +187,8 @@ data LocalNodeState = LocalNodeState -- ^ number of parallel sent queries , jEntriesPerSlice :: Int -- ^ number of desired entries per cache slice + , parentRealNode :: RealNodeSTM + -- ^ the parent node managing this vserver instance } deriving (Show, Eq) diff --git a/test/FediChordSpec.hs b/test/FediChordSpec.hs index 1e94628..1cace7a 100644 --- a/test/FediChordSpec.hs +++ b/test/FediChordSpec.hs @@ -1,12 +1,13 @@ {-# LANGUAGE OverloadedStrings #-} module FediChordSpec where +import Control.Concurrent.STM.TVar import Control.Exception -import Data.ASN1.Parse (runParseASN1) -import qualified Data.ByteString as BS -import qualified Data.Map.Strict as Map -import Data.Maybe (fromJust, isJust) -import qualified Data.Set as Set +import Data.ASN1.Parse (runParseASN1) +import qualified Data.ByteString as BS +import qualified Data.Map.Strict as Map +import Data.Maybe (fromJust, isJust) +import qualified Data.Set as Set import Data.Time.Clock.POSIX import Network.Socket import Test.Hspec @@ -292,11 +293,20 @@ exampleNodeState = RemoteNodeState { } exampleLocalNode :: IO LocalNodeState -exampleLocalNode = nodeStateInit $ FediChordConf { +exampleLocalNode = nodeStateInit =<< (newTVarIO $ RealNode { + vservers = [] + , nodeConfig = exampleFediConf + , bootstrapNodes = confBootstrapNodes exampleFediConf + }) + + +exampleFediConf :: FediChordConf +exampleFediConf = FediChordConf { confDomain = "example.social" , confIP = exampleIp , confDhtPort = 2342 } + exampleNodeDomain :: String exampleNodeDomain = "example.social" exampleVs :: (Integral i) => i