diff options
author | joe <joe@jerkface.net> | 2017-11-08 02:28:08 -0500 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-11-08 02:30:43 -0500 |
commit | 29e10ec3a1fce5071d342bb02c286aecb3066868 (patch) | |
tree | c8becc7fa66a5aaccd9cf5c8ac443038d9c5422d /src/Network/Kademlia | |
parent | 8e1aad3e0abaacd11e5e95dbd21400ad06c88375 (diff) |
Finished reworked bootstrap algorithm.
Diffstat (limited to 'src/Network/Kademlia')
-rw-r--r-- | src/Network/Kademlia/Bootstrap.hs | 55 |
1 files changed, 39 insertions, 16 deletions
diff --git a/src/Network/Kademlia/Bootstrap.hs b/src/Network/Kademlia/Bootstrap.hs index 8ca0bb83..93cf08f3 100644 --- a/src/Network/Kademlia/Bootstrap.hs +++ b/src/Network/Kademlia/Bootstrap.hs | |||
@@ -138,7 +138,7 @@ forkPollForRefresh r@BucketRefresher{ refreshInterval | |||
138 | where | 138 | where |
139 | refresh :: Int -> IO Int | 139 | refresh :: Int -> IO Int |
140 | refresh n = do | 140 | refresh n = do |
141 | hPutStrLn stderr $ "Refresh time! "++ show n | 141 | -- hPutStrLn stderr $ "Refresh time! "++ show n |
142 | refreshBucket r n | 142 | refreshBucket r n |
143 | 143 | ||
144 | go again ( bktnum :-> refresh_time ) = do | 144 | go again ( bktnum :-> refresh_time ) = do |
@@ -157,7 +157,7 @@ forkPollForRefresh r@BucketRefresher{ refreshInterval | |||
157 | return () | 157 | return () |
158 | return () | 158 | return () |
159 | picoseconds -> do | 159 | picoseconds -> do |
160 | hPutStrLn stderr $ show (picoseconds `div` 10^12) ++ " seconds until refresh " ++ show bktnum | 160 | -- hPutStrLn stderr $ show (picoseconds `div` 10^12) ++ " seconds until refresh " ++ show bktnum |
161 | threadDelay ( picoseconds `div` 10^6 ) | 161 | threadDelay ( picoseconds `div` 10^6 ) |
162 | again | 162 | again |
163 | 163 | ||
@@ -197,13 +197,13 @@ onFinishedRefresh BucketRefresher { bootstrapCountdown | |||
197 | , refreshQueue | 197 | , refreshQueue |
198 | , refreshBuckets } num now = do | 198 | , refreshBuckets } num now = do |
199 | bootstrapping <- readTVar bootstrapMode | 199 | bootstrapping <- readTVar bootstrapMode |
200 | if not bootstrapping then return $ hPutStrLn stderr $ "Finished non-boostrapping refresh: "++show num | 200 | if not bootstrapping then return $ return () -- hPutStrLn stderr $ "Finished non-boostrapping refresh: "++show num |
201 | else do | 201 | else do |
202 | tbl <- readTVar refreshBuckets | 202 | tbl <- readTVar refreshBuckets |
203 | action <- | 203 | action <- |
204 | if num /= R.bktCount tbl - 1 | 204 | if num /= R.bktCount tbl - 1 |
205 | then do modifyTVar' bootstrapCountdown (fmap pred) | 205 | then do modifyTVar' bootstrapCountdown (fmap pred) |
206 | return $ hPutStrLn stderr $ "BOOTSTRAP decrement" | 206 | return $ return () -- hPutStrLn stderr $ "BOOTSTRAP decrement" |
207 | else do | 207 | else do |
208 | -- The last bucket finished. | 208 | -- The last bucket finished. |
209 | cnt <- readTVar bootstrapCountdown | 209 | cnt <- readTVar bootstrapCountdown |
@@ -220,17 +220,17 @@ onFinishedRefresh BucketRefresher { bootstrapCountdown | |||
220 | -- Schedule immediate refresh for unfull buckets (other than this one). | 220 | -- Schedule immediate refresh for unfull buckets (other than this one). |
221 | modifyTVar' refreshQueue $ Int.insert n (now - 1) | 221 | modifyTVar' refreshQueue $ Int.insert n (now - 1) |
222 | writeTVar bootstrapCountdown $! Just $! length unfull | 222 | writeTVar bootstrapCountdown $! Just $! length unfull |
223 | return $ hPutStrLn stderr $ "BOOTSTRAP scheduling: "++show unfull | 223 | return $ return () -- hPutStrLn stderr $ "BOOTSTRAP scheduling: "++show unfull |
224 | Just n -> do writeTVar bootstrapCountdown $! Just $! pred n | 224 | Just n -> do writeTVar bootstrapCountdown $! Just $! pred n |
225 | return $ hPutStrLn stderr "BOOTSTRAP decrement (last bucket)" | 225 | return $ return () -- hPutStrLn stderr "BOOTSTRAP decrement (last bucket)" |
226 | cnt <- readTVar bootstrapCountdown | 226 | cnt <- readTVar bootstrapCountdown |
227 | if (cnt == Just 0) | 227 | if (cnt == Just 0) |
228 | then do | 228 | then do |
229 | -- Boostrap finished! | 229 | -- Boostrap finished! |
230 | writeTVar bootstrapMode False | 230 | writeTVar bootstrapMode False |
231 | writeTVar bootstrapCountdown Nothing | 231 | writeTVar bootstrapCountdown Nothing |
232 | return $ do action ; hPutStrLn stderr $ "BOOTSTRAP complete (" ++ show num ++ ")." | 232 | return $ do action ; hPutStrLn stderr $ "BOOTSTRAP complete (" ++ show (R.shape tbl) ++ ")." |
233 | else return $ do action ; hPutStrLn stderr $ "BOOTSTRAP progress " ++ show (num,R.bktCount tbl,cnt) | 233 | else return $ do action ; hPutStrLn stderr $ "BOOTSTRAP progress " ++ show (num,R.shape tbl,cnt) |
234 | 234 | ||
235 | refreshBucket :: (Show nid, Ord ni, Ord nid, Hashable nid, Hashable ni) => | 235 | refreshBucket :: (Show nid, Ord ni, Ord nid, Hashable nid, Hashable ni) => |
236 | BucketRefresher nid ni -> Int -> IO Int | 236 | BucketRefresher nid ni -> Int -> IO Int |
@@ -268,9 +268,25 @@ refreshBucket r@BucketRefresher{ refreshSearch = sch | |||
268 | return rcount | 268 | return rcount |
269 | 269 | ||
270 | refreshLastBucket :: SensibleNodeId nid ni => BucketRefresher nid ni -> IO () | 270 | refreshLastBucket :: SensibleNodeId nid ni => BucketRefresher nid ni -> IO () |
271 | refreshLastBucket r@BucketRefresher { refreshBuckets } = do | 271 | refreshLastBucket r@BucketRefresher { refreshBuckets |
272 | cnt <- atomically $ bktCount <$> readTVar refreshBuckets | 272 | , refreshQueue } = do |
273 | void $ refreshBucket r (cnt - 1) | 273 | |
274 | now <- getPOSIXTime | ||
275 | atomically $ do | ||
276 | cnt <- bktCount <$> readTVar refreshBuckets | ||
277 | -- Schedule immediate refresh. | ||
278 | modifyTVar' refreshQueue $ Int.insert (cnt-1) (now - 1) | ||
279 | |||
280 | restartBootstrap :: (Hashable ni, Hashable nid, Ord ni, Ord nid, Show nid) => | ||
281 | BucketRefresher nid ni -> STM (IO ()) | ||
282 | restartBootstrap r@BucketRefresher{ bootstrapMode, bootstrapCountdown } = do | ||
283 | unchanged <- readTVar bootstrapMode | ||
284 | writeTVar bootstrapMode True | ||
285 | writeTVar bootstrapCountdown Nothing | ||
286 | if not unchanged then return $ do | ||
287 | hPutStrLn stderr "BOOTSTRAP entered bootstrap mode" | ||
288 | refreshLastBucket r | ||
289 | else return $ hPutStrLn stderr "BOOTSTRAP already bootstrapping" | ||
274 | 290 | ||
275 | bootstrap :: (Ord ni, Ord nid, Hashable nid, Hashable ni, Foldable t, Foldable t1, Show nid) => | 291 | bootstrap :: (Ord ni, Ord nid, Hashable nid, Hashable ni, Foldable t, Foldable t1, Show nid) => |
276 | BucketRefresher nid ni | 292 | BucketRefresher nid ni |
@@ -279,7 +295,8 @@ bootstrap :: (Ord ni, Ord nid, Hashable nid, Hashable ni, Foldable t, Foldable t | |||
279 | -> IO () | 295 | -> IO () |
280 | bootstrap r@BucketRefresher { refreshSearch = sch | 296 | bootstrap r@BucketRefresher { refreshSearch = sch |
281 | , refreshBuckets = var | 297 | , refreshBuckets = var |
282 | , refreshPing = ping } ns ns0 = do | 298 | , refreshPing = ping |
299 | , bootstrapMode } ns ns0 = do | ||
283 | gotPing <- atomically $ newTVar False | 300 | gotPing <- atomically $ newTVar False |
284 | 301 | ||
285 | -- First, ping the given nodes so that they are added to | 302 | -- First, ping the given nodes so that they are added to |
@@ -300,9 +317,10 @@ bootstrap r@BucketRefresher { refreshSearch = sch | |||
300 | forkTask g (show $ kademliaLocation (searchSpace sch) n) | 317 | forkTask g (show $ kademliaLocation (searchSpace sch) n) |
301 | (void $ ping n) | 318 | (void $ ping n) |
302 | hPutStrLn stderr "Finished bootstrap pings." | 319 | hPutStrLn stderr "Finished bootstrap pings." |
303 | -- Now search our own Id by refreshing the last bucket. | 320 | -- Now search our own Id by entering bootstrap mode from non-bootstrap mode. |
304 | refreshLastBucket r | 321 | join $ atomically $ do |
305 | -- That's it. | 322 | writeTVar bootstrapMode False |
323 | restartBootstrap r | ||
306 | -- | 324 | -- |
307 | -- Hopefully 'forkPollForRefresh' was invoked and can take over | 325 | -- Hopefully 'forkPollForRefresh' was invoked and can take over |
308 | -- maintenance. | 326 | -- maintenance. |
@@ -402,7 +420,12 @@ touchBucket r@BucketRefresher{ refreshSearch | |||
402 | nid = kademliaLocation space transitioningNode | 420 | nid = kademliaLocation space transitioningNode |
403 | tbl <- readTVar refreshBuckets | 421 | tbl <- readTVar refreshBuckets |
404 | let num = R.bucketNumber space nid tbl | 422 | let num = R.bucketNumber space nid tbl |
405 | let action = return () | 423 | stamp <- readTVar refreshLastTouch |
424 | action <- case stamp /= 0 && (now - stamp > 60) of | ||
425 | True -> do | ||
426 | -- It's been one minute since any bucket has been touched, re-enter bootstrap mode. | ||
427 | restartBootstrap r | ||
428 | False -> return $ return () | ||
406 | interval <- effectiveRefreshInterval r num | 429 | interval <- effectiveRefreshInterval r num |
407 | modifyTVar' refreshQueue $ Int.insert num (now + interval) | 430 | modifyTVar' refreshQueue $ Int.insert num (now + interval) |
408 | writeTVar refreshLastTouch now | 431 | writeTVar refreshLastTouch now |