diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Network/DHT/Routing.hs | 58 |
1 files changed, 53 insertions, 5 deletions
diff --git a/src/Network/DHT/Routing.hs b/src/Network/DHT/Routing.hs index ecd427b8..631761ac 100644 --- a/src/Network/DHT/Routing.hs +++ b/src/Network/DHT/Routing.hs | |||
@@ -173,8 +173,8 @@ bucketQ = seqQ | |||
173 | -- very unlikely that all nodes in bucket fail within an hour of | 173 | -- very unlikely that all nodes in bucket fail within an hour of |
174 | -- each other. | 174 | -- each other. |
175 | -- | 175 | -- |
176 | data Bucket ni = Bucket { bktNodes :: !(PSQ ni Timestamp) | 176 | data Bucket ni = Bucket { bktNodes :: !(PSQ ni Timestamp) -- current routing nodes |
177 | , bktQ :: !(BucketQueue ni) | 177 | , bktQ :: !(BucketQueue ni) -- replacements pending time-outs |
178 | } deriving Generic | 178 | } deriving Generic |
179 | 179 | ||
180 | deriving instance Show ni => Show (Bucket ni) | 180 | deriving instance Show ni => Show (Bucket ni) |
@@ -230,7 +230,12 @@ delta = 15 * 60 | |||
230 | insertBucket :: (Alternative f, Ord ni) => -- (Eq ip, Alternative f, Ord (NodeId)) => | 230 | insertBucket :: (Alternative f, Ord ni) => -- (Eq ip, Alternative f, Ord (NodeId)) => |
231 | Timestamp -> Event ni -> Bucket ni -> f ([CheckPing ni], Bucket ni) | 231 | Timestamp -> Event ni -> Bucket ni -> f ([CheckPing ni], Bucket ni) |
232 | insertBucket curTime (TryInsert info) bucket | 232 | insertBucket curTime (TryInsert info) bucket |
233 | -- just update timestamp if a node is already in bucket | 233 | -- Just update timestamp if a node is already in bucket. |
234 | -- | ||
235 | -- Note PingResult events should only occur for nodes we requested a ping for, | ||
236 | -- and those will always already be in the routing queue and will get their | ||
237 | -- timestamp updated here, since 'TryInsert' is called on every inbound packet, | ||
238 | -- including ping results. | ||
234 | | already_have | 239 | | already_have |
235 | = pure ( [], map_ns $ PSQ.insertWith max info curTime ) | 240 | = pure ( [], map_ns $ PSQ.insertWith max info curTime ) |
236 | -- bucket is good, but not full => we can insert a new node | 241 | -- bucket is good, but not full => we can insert a new node |
@@ -271,11 +276,20 @@ insertBucket curTime (PingResult bad_node got_response) bucket | |||
271 | = pure ([], Bucket (upd $ bktNodes bucket) popped) | 276 | = pure ([], Bucket (upd $ bktNodes bucket) popped) |
272 | where | 277 | where |
273 | (top, popped) = runIdentity $ popFront bucketQ (bktQ bucket) | 278 | (top, popped) = runIdentity $ popFront bucketQ (bktQ bucket) |
274 | upd | got_response = id | 279 | upd | got_response = id -- Timestamp was already updated by TryInsert. |
275 | | Just info <- top = \nodes -> | 280 | | Just info <- top = \nodes -> |
276 | fromMaybe nodes $ do | 281 | fromMaybe nodes $ do |
277 | _ <- PSQ.lookup bad_node nodes -- Insert only if there's a removal. | 282 | _ <- PSQ.lookup bad_node nodes -- Insert only if there's a removal. |
278 | let nodes' = PSQ.delete bad_node nodes | 283 | let nodes' = PSQ.delete bad_node nodes |
284 | -- XXX: curTime is the time somebody pinged out, not the time | ||
285 | -- of which the popped node was originally queued. That's not | ||
286 | -- quite right. | ||
287 | -- | ||
288 | -- It's the best we can do atm since the overflow BucketQueue | ||
289 | -- does not include timestamps. | ||
290 | -- | ||
291 | -- This means that initial time-outs for replacement nodes are up to | ||
292 | -- twice as long as for the originals. | ||
279 | pure $ PSQ.insert info curTime nodes' | 293 | pure $ PSQ.insert info curTime nodes' |
280 | | otherwise = id | 294 | | otherwise = id |
281 | 295 | ||
@@ -614,13 +628,47 @@ deriving instance ( Show ip | |||
614 | #endif | 628 | #endif |
615 | 629 | ||
616 | -- | Atomic 'Table' update | 630 | -- | Atomic 'Table' update |
631 | -- | ||
632 | -- Deprecated, use these two functions instead: | ||
633 | -- | ||
634 | -- [ 'updateForInbound' ] | ||
635 | -- | ||
636 | -- [ 'updateForPingResult' ] | ||
637 | -- | ||
617 | insert :: -- ( Eq ip , Applicative m , Ord (NodeId) , FiniteBits (NodeId)) => | 638 | insert :: -- ( Eq ip , Applicative m , Ord (NodeId) , FiniteBits (NodeId)) => |
618 | (Applicative m, Ord ni) => | 639 | (Applicative m, Ord ni) => |
619 | (nid -> Word -> Bool) | 640 | (nid -> Word -> Bool) |
620 | -> (ni -> nid) | 641 | -> (ni -> nid) |
621 | -> Timestamp -> Event ni -> Table ni nid -> m ([CheckPing ni], Table ni nid) | 642 | -> Timestamp -> Event ni -> Table ni nid -> m ([CheckPing ni], Table ni nid) |
622 | insert testIdBit nodeId tm event tbl = pure $ fromMaybe ([],tbl) $ modifyBucket testIdBit (\ni -> testIdBit $ nodeId ni) (eventId nodeId event) (insertBucket tm event) tbl | 643 | insert testIdBit nodeId tm event tbl |
644 | = pure $ fromMaybe ([],tbl) | ||
645 | $ modifyBucket testIdBit (\ni -> testIdBit $ nodeId ni) | ||
646 | (eventId nodeId event) | ||
647 | (insertBucket tm event) | ||
648 | tbl | ||
649 | |||
650 | |||
651 | -- | Call on every inbound packet (including requested ping results). Returns | ||
652 | -- a list of nodes to ping and an updated routing table. The caller should | ||
653 | -- also invoke 'updateForPingResult' on each node in the to-ping list to update | ||
654 | -- the routing table with that information as it becomes available. | ||
655 | updateForInbound :: Ord ni => | ||
656 | (nid -> Word -> Bool) | ||
657 | -> (ni -> nid) | ||
658 | -> Timestamp -> ni -> Table ni nid -> ([ni], Table ni nid) | ||
659 | updateForInbound testIdBit nodeId tm ni tbl = | ||
660 | let Identity (ps, tbl') = Network.DHT.Routing.insert testIdBit nodeId tm (TryInsert ni) tbl | ||
661 | decon (CheckPing ns) = ns | ||
662 | in (concatMap decon ps, tbl') | ||
623 | 663 | ||
664 | updateForPingResult :: Ord ni => | ||
665 | (nid -> Word -> Bool) | ||
666 | -> (ni -> nid) | ||
667 | -> Timestamp -> ni -> Bool -> Table ni nid -> Table ni nid | ||
668 | updateForPingResult testIdBit nodeId tm ni got_reply tbl = | ||
669 | -- The _ should always be empty in this case. | ||
670 | let Identity (_, tbl') = Network.DHT.Routing.insert testIdBit nodeId tm (PingResult ni got_reply) tbl | ||
671 | in tbl' | ||
624 | 672 | ||
625 | 673 | ||
626 | {----------------------------------------------------------------------- | 674 | {----------------------------------------------------------------------- |