diff options
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r-- | src/Network/BitTorrent/DHT/Routing.hs | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/src/Network/BitTorrent/DHT/Routing.hs b/src/Network/BitTorrent/DHT/Routing.hs index c230929e..38207be5 100644 --- a/src/Network/BitTorrent/DHT/Routing.hs +++ b/src/Network/BitTorrent/DHT/Routing.hs | |||
@@ -268,27 +268,47 @@ insertBucket curTime (TryInsert info) bucket | |||
268 | -- then one is replaced by the new node in the next insertBucket | 268 | -- then one is replaced by the new node in the next insertBucket |
269 | -- iteration. | 269 | -- iteration. |
270 | | not (L.null stales) | 270 | | not (L.null stales) |
271 | = pure ( [CheckPing stales], map_q $ pushBack bucketQ info ) | 271 | = pure ( [CheckPing stales] |
272 | , bucket { -- Update timestamps so that we don't redundantly ping. | ||
273 | bktNodes = updateStamps curTime stales $ bktNodes bucket | ||
274 | -- Update queue with the pending NodeInfo in case of ping fail. | ||
275 | , bktQ = runIdentity $ pushBack bucketQ info $ bktQ bucket } ) | ||
272 | -- When the bucket is full of good nodes, the new node is simply discarded. | 276 | -- When the bucket is full of good nodes, the new node is simply discarded. |
273 | -- We must return 'A.empty' here to ensure that bucket splitting happens | 277 | -- We must return 'A.empty' here to ensure that bucket splitting happens |
274 | -- inside 'modifyBucket'. | 278 | -- inside 'modifyBucket'. |
275 | | otherwise = A.empty | 279 | | otherwise = A.empty |
276 | where | 280 | where |
277 | stales = map key $ PSQ.atMost (curTime - delta) $ bktNodes bucket | 281 | -- We (take 1) to keep a 1-to-1 correspondence between pending pings and |
282 | -- waiting nodes in the bktQ. This way, we don't have to worry about what | ||
283 | -- to do with failed pings for which there is no ready replacements. | ||
284 | stales = -- One stale: | ||
285 | do (n :-> t) <- maybeToList $ PSQ.findMin (bktNodes bucket) | ||
286 | guard (t < curTime - delta) | ||
287 | return n | ||
288 | -- All stale: | ||
289 | -- map key $ PSQ.atMost (curTime - delta) $ bktNodes bucket | ||
278 | 290 | ||
279 | already_have = maybe False (const True) $ PSQ.lookup info (bktNodes bucket) | 291 | already_have = maybe False (const True) $ PSQ.lookup info (bktNodes bucket) |
280 | 292 | ||
281 | map_ns f = bucket { bktNodes = f (bktNodes bucket) } | 293 | map_ns f = bucket { bktNodes = f (bktNodes bucket) } |
282 | map_q f = bucket { bktQ = runIdentity $ f (bktQ bucket) } | 294 | -- map_q f = bucket { bktQ = runIdentity $ f (bktQ bucket) } |
283 | 295 | ||
284 | insertBucket curTime (PingResult bad_node got_response) bucket | 296 | insertBucket curTime (PingResult bad_node got_response) bucket |
285 | = pure ([], Bucket (upd $ bktNodes bucket) popped) | 297 | = pure ([], Bucket (upd $ bktNodes bucket) popped) |
286 | where | 298 | where |
287 | (top, popped) = runIdentity $ popFront bucketQ (bktQ bucket) | 299 | (top, popped) = runIdentity $ popFront bucketQ (bktQ bucket) |
288 | upd | got_response = id | 300 | upd | got_response = id |
289 | | Just info <- top = PSQ.insert info curTime . PSQ.delete bad_node | 301 | | Just info <- top = \nodes -> |
302 | fromMaybe nodes $ do | ||
303 | _ <- PSQ.lookup bad_node nodes -- Insert only if there's a removal. | ||
304 | let nodes' = PSQ.delete bad_node nodes | ||
305 | pure $ PSQ.insert info curTime nodes' | ||
290 | | otherwise = id | 306 | | otherwise = id |
291 | 307 | ||
308 | updateStamps :: Eq ip => Timestamp -> [NodeInfo ip] -> PSQ (NodeInfo ip) Timestamp -> PSQ (NodeInfo ip) Timestamp | ||
309 | updateStamps curTime stales nodes = foldl' (\q n -> PSQ.insert n curTime q) nodes stales | ||
310 | |||
311 | |||
292 | type BitIx = Word | 312 | type BitIx = Word |
293 | 313 | ||
294 | partitionQ :: Monad f => QueueMethods f elem b -> (elem -> Bool) -> b -> f (b, b) | 314 | partitionQ :: Monad f => QueueMethods f elem b -> (elem -> Bool) -> b -> f (b, b) |