EpiChord: create a stub cache-invariant checker
rough logic is implemented, but only for successors and not predecessors. Additionally it just returns empty IO actions instead of lookup operations, until those are implemented. part of #1 Untested!
This commit is contained in:
parent
88897ea741
commit
0e33d442f9
|
@ -58,7 +58,7 @@ library
|
||||||
exposed-modules: Hash2Pub.FediChord
|
exposed-modules: Hash2Pub.FediChord
|
||||||
|
|
||||||
-- Modules included in this library but not exported.
|
-- Modules included in this library but not exported.
|
||||||
-- other-modules:
|
other-modules: Hash2Pub.Utils
|
||||||
|
|
||||||
-- LANGUAGE extensions used by modules in this package.
|
-- LANGUAGE extensions used by modules in this package.
|
||||||
other-extensions: GeneralizedNewtypeDeriving, DataKinds, OverloadedStrings
|
other-extensions: GeneralizedNewtypeDeriving, DataKinds, OverloadedStrings
|
||||||
|
|
|
@ -36,6 +36,8 @@ import qualified Data.ByteString.Lazy as BL
|
||||||
import qualified Data.ByteString.UTF8 as BSU
|
import qualified Data.ByteString.UTF8 as BSU
|
||||||
import qualified Data.ByteArray as BA
|
import qualified Data.ByteArray as BA
|
||||||
|
|
||||||
|
import Hash2Pub.Utils
|
||||||
|
|
||||||
-- define protocol constants
|
-- define protocol constants
|
||||||
-- | static definition of ID length in bits
|
-- | static definition of ID length in bits
|
||||||
idBits :: Integer
|
idBits :: Integer
|
||||||
|
@ -94,7 +96,7 @@ data NodeState = NodeState {
|
||||||
, apPort :: Maybe PortNumber
|
, apPort :: Maybe PortNumber
|
||||||
-- ^ port of the ActivityPub relay and storage service
|
-- ^ port of the ActivityPub relay and storage service
|
||||||
-- might have to be queried first
|
-- might have to be queried first
|
||||||
, nodeCache :: Map.Map NodeID CacheEntry
|
, nodeCache :: NodeCache
|
||||||
-- ^ EpiChord node cache with expiry times for nodes
|
-- ^ EpiChord node cache with expiry times for nodes
|
||||||
-- as the map is ordered, lookups for the closes preceding node can be done using @lookupLT@
|
-- as the map is ordered, lookups for the closes preceding node can be done using @lookupLT@
|
||||||
, successors :: [NodeID]
|
, successors :: [NodeID]
|
||||||
|
@ -110,8 +112,13 @@ data NodeState = NodeState {
|
||||||
, pNumParallelQueries :: Int
|
, pNumParallelQueries :: Int
|
||||||
-- ^ number of parallel sent queries
|
-- ^ number of parallel sent queries
|
||||||
-- needs to be parameterisable for simulation purposes
|
-- needs to be parameterisable for simulation purposes
|
||||||
|
, jEntriesPerSlice :: Int
|
||||||
|
-- ^ number of desired entries per cache slice
|
||||||
|
-- needs to be parameterisable for simulation purposes
|
||||||
} deriving (Show)
|
} deriving (Show)
|
||||||
|
|
||||||
|
type NodeCache = Map.Map NodeID CacheEntry
|
||||||
|
|
||||||
-- |an entry of the 'nodeCache'
|
-- |an entry of the 'nodeCache'
|
||||||
type CacheEntry = (
|
type CacheEntry = (
|
||||||
NodeState
|
NodeState
|
||||||
|
@ -168,6 +175,44 @@ byteStringToUInteger bs = sum $ parsedBytes 0 bs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO: needs testing
|
||||||
|
-- |checks wether the cache entries fulfill the logarithmic EpiChord invariant
|
||||||
|
-- of having j entries per slice, and creates a list of necessary lookup actions.
|
||||||
|
-- Should be invoked periodically.
|
||||||
|
checkCacheSlices :: NodeState -> [IO ()]
|
||||||
|
checkCacheSlices state =
|
||||||
|
checkSlice jEntries (nid state) startBound lastSucc cache'
|
||||||
|
-- TODO: do the same for predecessors
|
||||||
|
where
|
||||||
|
jEntries = jEntriesPerSlice state
|
||||||
|
cache' = nodeCache state
|
||||||
|
lastSucc = last <$> maybeEmpty (successors state)
|
||||||
|
startBound = NodeID 2^(255::Integer) + nid state
|
||||||
|
checkSlice :: Int -> NodeID -> NodeID -> Maybe NodeID -> NodeCache -> [IO ()]
|
||||||
|
checkSlice _ _ _ Nothing _ = []
|
||||||
|
checkSlice j ownID upperBound (Just lastSuccNode) cache
|
||||||
|
| upperBound < lastSuccNode = []
|
||||||
|
| otherwise =
|
||||||
|
-- continuously half the DHT namespace, take the upper part as a slice,
|
||||||
|
-- check for existing entries in that slice and create a lookup action
|
||||||
|
-- and recursively do this on the lower half.
|
||||||
|
-- recursion edge case: all successors/ predecessors need to be in the
|
||||||
|
-- first slice.
|
||||||
|
let
|
||||||
|
diff = getNodeID $ upperBound - ownID
|
||||||
|
lowerBound = ownID + NodeID (diff `div` 2)
|
||||||
|
in
|
||||||
|
-- TODO: replace empty IO actions with actual lookups
|
||||||
|
-- TODO: validate ID before adding to cache
|
||||||
|
case Map.lookupLT upperBound cache of
|
||||||
|
Nothing -> return () : checkSlice j ownID lowerBound (Just lastSuccNode) cache
|
||||||
|
Just (matchID, _) ->
|
||||||
|
if
|
||||||
|
matchID <= lowerBound then return () : checkSlice j ownID lowerBound (Just lastSuccNode) cache
|
||||||
|
else
|
||||||
|
checkSlice j ownID lowerBound (Just lastSuccNode) cache
|
||||||
|
|
||||||
|
|
||||||
-- Todo: DHT backend can learn potential initial bootstrapping points through the instances mentioned in the received AP-relay messages
|
-- Todo: DHT backend can learn potential initial bootstrapping points through the instances mentioned in the received AP-relay messages
|
||||||
-- needs to know its own domain anyways for ID generation
|
-- needs to know its own domain anyways for ID generation
|
||||||
-- persist them on disk so they can be used for all following bootstraps
|
-- persist them on disk so they can be used for all following bootstraps
|
||||||
|
|
6
Hash2Pub/src/Hash2Pub/Utils.hs
Normal file
6
Hash2Pub/src/Hash2Pub/Utils.hs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module Hash2Pub.Utils where
|
||||||
|
|
||||||
|
-- |wraps a list into a Maybe, by replacing empty lists with Nothing
|
||||||
|
maybeEmpty :: [a] -> Maybe [a]
|
||||||
|
maybeEmpty [] = Nothing
|
||||||
|
maybeEmpty nonemptyList = Just nonemptyList
|
Loading…
Reference in a new issue