summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Network/Kademlia/Bootstrap.hs69
1 files changed, 61 insertions, 8 deletions
diff --git a/src/Network/Kademlia/Bootstrap.hs b/src/Network/Kademlia/Bootstrap.hs
index f160000d..8ca0bb83 100644
--- a/src/Network/Kademlia/Bootstrap.hs
+++ b/src/Network/Kademlia/Bootstrap.hs
@@ -189,6 +189,48 @@ checkBucketFull space var resultCounter fin n found_node = do
189 _ | Set.size resultCount < fullcount -> True -- we haven't got many results, keep going 189 _ | Set.size resultCount < fullcount -> True -- we haven't got many results, keep going
190 _ -> False -- okay, good enough, let's quit. 190 _ -> False -- okay, good enough, let's quit.
191 191
192-- | Called from 'refreshBucket' with the current time when a refresh of the
193-- supplied bucket number finishes.
194onFinishedRefresh :: BucketRefresher nid ni -> Int -> POSIXTime -> STM (IO ())
195onFinishedRefresh BucketRefresher { bootstrapCountdown
196 , bootstrapMode
197 , refreshQueue
198 , refreshBuckets } num now = do
199 bootstrapping <- readTVar bootstrapMode
200 if not bootstrapping then return $ hPutStrLn stderr $ "Finished non-boostrapping refresh: "++show num
201 else do
202 tbl <- readTVar refreshBuckets
203 action <-
204 if num /= R.bktCount tbl - 1
205 then do modifyTVar' bootstrapCountdown (fmap pred)
206 return $ hPutStrLn stderr $ "BOOTSTRAP decrement"
207 else do
208 -- The last bucket finished.
209 cnt <- readTVar bootstrapCountdown
210 case cnt of
211 Nothing -> do
212 let fullsize = R.defaultBucketSize
213 notfull (n,len) | n==num = False
214 | len>=fullsize = False
215 | otherwise = True
216 unfull = case filter notfull $ zip [0..] (R.shape tbl) of
217 [] -> [(0,0)] -- Schedule at least 1 more refresh.
218 xs -> xs
219 forM_ unfull $ \(n,_) -> do
220 -- Schedule immediate refresh for unfull buckets (other than this one).
221 modifyTVar' refreshQueue $ Int.insert n (now - 1)
222 writeTVar bootstrapCountdown $! Just $! length unfull
223 return $ hPutStrLn stderr $ "BOOTSTRAP scheduling: "++show unfull
224 Just n -> do writeTVar bootstrapCountdown $! Just $! pred n
225 return $ hPutStrLn stderr "BOOTSTRAP decrement (last bucket)"
226 cnt <- readTVar bootstrapCountdown
227 if (cnt == Just 0)
228 then do
229 -- Boostrap finished!
230 writeTVar bootstrapMode False
231 writeTVar bootstrapCountdown Nothing
232 return $ do action ; hPutStrLn stderr $ "BOOTSTRAP complete (" ++ show num ++ ")."
233 else return $ do action ; hPutStrLn stderr $ "BOOTSTRAP progress " ++ show (num,R.bktCount tbl,cnt)
192 234
193refreshBucket :: (Show nid, Ord ni, Ord nid, Hashable nid, Hashable ni) => 235refreshBucket :: (Show nid, Ord ni, Ord nid, Hashable nid, Hashable ni) =>
194 BucketRefresher nid ni -> Int -> IO Int 236 BucketRefresher nid ni -> Int -> IO Int
@@ -217,6 +259,8 @@ refreshBucket r@BucketRefresher{ refreshSearch = sch
217 atomically $ searchIsFinished s >>= check 259 atomically $ searchIsFinished s >>= check
218 atomically $ searchCancel s 260 atomically $ searchCancel s
219 hPutStrLn stderr $ "Finish refresh " ++ show (n,sample) 261 hPutStrLn stderr $ "Finish refresh " ++ show (n,sample)
262 now <- getPOSIXTime
263 join $ atomically $ onFinishedRefresh r n now
220 rcount <- atomically $ do 264 rcount <- atomically $ do
221 c <- Set.size <$> readTVar resultCounter 265 c <- Set.size <$> readTVar resultCounter
222 b <- readTVar fin 266 b <- readTVar fin
@@ -336,21 +380,30 @@ effectiveRefreshInterval BucketRefresher{ refreshInterval
336-- 380--
337-- We embed the result in the STM monad but currently, no STM state changes 381-- We embed the result in the STM monad but currently, no STM state changes
338-- occur until the returned IO action is invoked. TODO: simplify? 382-- occur until the returned IO action is invoked. TODO: simplify?
339touchBucket :: BucketRefresher nid ni 383touchBucket :: SensibleNodeId nid ni
384 => BucketRefresher nid ni
340 -> RoutingTransition ni -- ^ What happened to the bucket? 385 -> RoutingTransition ni -- ^ What happened to the bucket?
341 -> STM (IO ()) 386 -> STM (IO ())
342touchBucket BucketRefresher{ refreshSearch 387touchBucket r@BucketRefresher{ refreshSearch
343 , refreshInterval 388 , refreshInterval
344 , refreshBuckets 389 , refreshBuckets
345 , refreshQueue } 390 , refreshQueue
391 , refreshLastTouch
392 , bootstrapMode
393 , bootstrapCountdown }
346 RoutingTransition{ transitionedTo 394 RoutingTransition{ transitionedTo
347 , transitioningNode } 395 , transitioningNode }
348 = case transitionedTo of 396 = case transitionedTo of
349 Applicant -> return $ return () -- Ignore transition to applicant. 397 Applicant -> return $ return () -- Ignore transition to applicant.
350 _ -> return $ do -- Reschedule for any other transition. 398 _ -> return $ do -- Reschedule for any other transition.
351 now <- getPOSIXTime 399 now <- getPOSIXTime
352 atomically $ do 400 join $ atomically $ do
353 let space = searchSpace refreshSearch 401 let space = searchSpace refreshSearch
354 nid = kademliaLocation space transitioningNode 402 nid = kademliaLocation space transitioningNode
355 num <- R.bucketNumber space nid <$> readTVar refreshBuckets 403 tbl <- readTVar refreshBuckets
356 modifyTVar' refreshQueue $ Int.insert num (now + refreshInterval) 404 let num = R.bucketNumber space nid tbl
405 let action = return ()
406 interval <- effectiveRefreshInterval r num
407 modifyTVar' refreshQueue $ Int.insert num (now + interval)
408 writeTVar refreshLastTouch now
409 return action