summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-01-22 03:14:35 -0500
committerjoe <joe@jerkface.net>2017-01-22 05:10:46 -0500
commit1c8cbe8fc66466936b4f889b3893ca3c23478631 (patch)
treeb55998407cbf057acb3f997d526ec747b767bbd8 /src
parent3f49cc7b02f8d470100a0da270777f986824067f (diff)
Avoid overfilling buckets in DHT routing table.
Diffstat (limited to 'src')
-rw-r--r--src/Network/BitTorrent/DHT/Routing.hs28
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
284insertBucket curTime (PingResult bad_node got_response) bucket 296insertBucket 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
308updateStamps :: Eq ip => Timestamp -> [NodeInfo ip] -> PSQ (NodeInfo ip) Timestamp -> PSQ (NodeInfo ip) Timestamp
309updateStamps curTime stales nodes = foldl' (\q n -> PSQ.insert n curTime q) nodes stales
310
311
292type BitIx = Word 312type BitIx = Word
293 313
294partitionQ :: Monad f => QueueMethods f elem b -> (elem -> Bool) -> b -> f (b, b) 314partitionQ :: Monad f => QueueMethods f elem b -> (elem -> Bool) -> b -> f (b, b)