diff options
author | Joe Crayne <joe@jerkface.net> | 2018-06-27 20:35:14 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2018-06-27 20:35:14 -0400 |
commit | edd93b41c519ddf32ed34f495f4b9a14828d71a3 (patch) | |
tree | 8897e03592a603de71a3001e5669c5d6d31842e8 | |
parent | 2305a022c97b561cadcfdfa068f6bdb182dfe7c1 (diff) |
More performant routeMap (IntMap -> Array).
-rw-r--r-- | OnionRouter.hs | 45 | ||||
-rw-r--r-- | examples/dhtd.hs | 3 |
2 files changed, 29 insertions, 19 deletions
diff --git a/OnionRouter.hs b/OnionRouter.hs index 330e083a..2391e13c 100644 --- a/OnionRouter.hs +++ b/OnionRouter.hs | |||
@@ -12,8 +12,10 @@ import Network.Tox.NodeId | |||
12 | import Network.Tox.Onion.Transport | 12 | import Network.Tox.Onion.Transport |
13 | 13 | ||
14 | import Control.Concurrent.STM | 14 | import Control.Concurrent.STM |
15 | import Control.Concurrent.STM.TArray | ||
15 | import Control.Monad | 16 | import Control.Monad |
16 | import Crypto.Random | 17 | import Crypto.Random |
18 | import Data.Array.MArray | ||
17 | import Data.Bits | 19 | import Data.Bits |
18 | import qualified Data.ByteString as B | 20 | import qualified Data.ByteString as B |
19 | import qualified Data.HashMap.Strict as HashMap | 21 | import qualified Data.HashMap.Strict as HashMap |
@@ -47,7 +49,7 @@ data OnionRouter = OnionRouter | |||
47 | -- so we can decrypt the response. | 49 | -- so we can decrypt the response. |
48 | pendingQueries :: TVar (Word64Map PendingQuery) | 50 | pendingQueries :: TVar (Word64Map PendingQuery) |
49 | -- | The current 12 routes that may be assigned to outgoing packets. | 51 | -- | The current 12 routes that may be assigned to outgoing packets. |
50 | , routeMap :: TVar (IntMap RouteRecord) | 52 | , routeMap :: TArray Int (Maybe RouteRecord) |
51 | -- | A set of nodes used to query for random route nodes. These aren't | 53 | -- | A set of nodes used to query for random route nodes. These aren't |
52 | -- used directly in onion routes, they are queried for route nodes that | 54 | -- used directly in onion routes, they are queried for route nodes that |
53 | -- are nearby randomly selected ids. | 55 | -- are nearby randomly selected ids. |
@@ -115,6 +117,12 @@ freshRoute birthday r mrec = Just $ RouteRecord | |||
115 | , routeBirthTime = birthday | 117 | , routeBirthTime = birthday |
116 | } | 118 | } |
117 | 119 | ||
120 | modifyArray :: TArray Int r -> (r -> r) -> Int -> STM () | ||
121 | modifyArray a f i = do | ||
122 | mx <- readArray a i | ||
123 | writeArray a i $ f mx | ||
124 | {-# INLINE modifyArray #-} | ||
125 | |||
118 | gotResponse :: RouteRecord -> RouteRecord | 126 | gotResponse :: RouteRecord -> RouteRecord |
119 | gotResponse rr = rr | 127 | gotResponse rr = rr |
120 | { responseCount = succ $ responseCount rr | 128 | { responseCount = succ $ responseCount rr |
@@ -136,7 +144,7 @@ newOnionRouter perror = do | |||
136 | drg <- newTVar drg0 | 144 | drg <- newTVar drg0 |
137 | -- forM_ [0..11] $ \n -> writeTChan chan $ BuildRoute (RouteId n) | 145 | -- forM_ [0..11] $ \n -> writeTChan chan $ BuildRoute (RouteId n) |
138 | pq <- newTVar W64.empty | 146 | pq <- newTVar W64.empty |
139 | rm <- newTVar IntMap.empty | 147 | rm <- newArray (0,11) Nothing |
140 | tn <- newTVar IntMap.empty | 148 | tn <- newTVar IntMap.empty |
141 | ti <- newTVar HashMap.empty | 149 | ti <- newTVar HashMap.empty |
142 | tc <- newTVar 0 | 150 | tc <- newTVar 0 |
@@ -164,7 +172,7 @@ forkRouteBuilder or getnodes = do | |||
164 | forever $ do | 172 | forever $ do |
165 | let checkRebuild rid want_build stm = flip orElse stm $ do | 173 | let checkRebuild rid want_build stm = flip orElse stm $ do |
166 | wanted_ver <- readTVar want_build | 174 | wanted_ver <- readTVar want_build |
167 | current_ver <- fmap routeVersion . IntMap.lookup rid <$> readTVar (routeMap or) | 175 | current_ver <- fmap routeVersion <$> readArray (routeMap or) rid |
168 | writeTChan (routeLog or) $ "ONION checkRebuild "++show(current_ver,wanted_ver) | 176 | writeTChan (routeLog or) $ "ONION checkRebuild "++show(current_ver,wanted_ver) |
169 | check $ maybe True (< wanted_ver) current_ver | 177 | check $ maybe True (< wanted_ver) current_ver |
170 | return $ BuildRoute $ RouteId rid | 178 | return $ BuildRoute $ RouteId rid |
@@ -335,9 +343,10 @@ handleEvent getnodes or e@(BuildRoute (RouteId rid)) = do | |||
335 | return $ getr | 343 | return $ getr |
336 | now <- getPOSIXTime | 344 | now <- getPOSIXTime |
337 | atomically $ maybe (return ()) -- writeTVar (pendingRoutes or IntMap.! rid) True) | 345 | atomically $ maybe (return ()) -- writeTVar (pendingRoutes or IntMap.! rid) True) |
338 | (\r -> do modifyTVar' (routeMap or) | 346 | (\r -> do modifyArray (routeMap or) |
339 | (IntMap.alter (freshRoute now r) rid) | 347 | (freshRoute now r) |
340 | v <- routeVersion . (IntMap.! rid) <$> readTVar (routeMap or) | 348 | rid |
349 | v <- routeVersion . fromJust <$> readArray (routeMap or) rid | ||
341 | writeTVar (pendingRoutes or IntMap.! rid) v | 350 | writeTVar (pendingRoutes or IntMap.! rid) v |
342 | ) | 351 | ) |
343 | mb | 352 | mb |
@@ -362,14 +371,14 @@ lookupSender or saddr (Nonce8 w8) = do | |||
362 | 371 | ||
363 | lookupRoute :: OnionRouter -> NodeInfo -> RouteId -> IO (Maybe OnionRoute) | 372 | lookupRoute :: OnionRouter -> NodeInfo -> RouteId -> IO (Maybe OnionRoute) |
364 | lookupRoute or ni (RouteId rid) = do | 373 | lookupRoute or ni (RouteId rid) = do |
365 | mb <- atomically $ IntMap.lookup rid <$> readTVar (routeMap or) | 374 | mb <- atomically $ readArray (routeMap or) rid |
366 | return $ storedRoute <$> mb | 375 | return $ storedRoute <$> mb |
367 | 376 | ||
368 | lookupTimeout :: OnionRouter -> Nonce8 -> OnionDestination r -> STM (OnionDestination RouteId, Int) | 377 | lookupTimeout :: OnionRouter -> Nonce8 -> OnionDestination r -> STM (OnionDestination RouteId, Int) |
369 | lookupTimeout or n8 (OnionDestination asel ni Nothing) = do | 378 | lookupTimeout or n8 (OnionDestination asel ni Nothing) = do |
370 | let RouteId rid = routeId (nodeId ni) | 379 | let RouteId rid = routeId (nodeId ni) |
371 | mrr <- IntMap.lookup rid <$> readTVar (routeMap or) | 380 | mrr <- readArray (routeMap or) rid |
372 | readTVar (routeMap or) >>= \rm -> writeTChan (routeLog or) $ "ONION lookupTimeout " ++ unwords [show rid,show (IntMap.keys rm)] | 381 | writeTChan (routeLog or) $ unwords ["ONION lookupTimeout " ,show rid] |
373 | case mrr of | 382 | case mrr of |
374 | Just rr -> return ( OnionDestination asel ni (Just $ RouteId rid), timeoutForRoute rr) | 383 | Just rr -> return ( OnionDestination asel ni (Just $ RouteId rid), timeoutForRoute rr) |
375 | Nothing -> return ( OnionDestination asel ni Nothing , 0 ) | 384 | Nothing -> return ( OnionDestination asel ni Nothing , 0 ) |
@@ -378,7 +387,7 @@ hookQueries :: OnionRouter -> (tid -> Nonce8) | |||
378 | -> TransactionMethods d tid (OnionDestination RouteId) x | 387 | -> TransactionMethods d tid (OnionDestination RouteId) x |
379 | -> TransactionMethods d tid (OnionDestination RouteId) x | 388 | -> TransactionMethods d tid (OnionDestination RouteId) x |
380 | hookQueries or t8 tmethods = TransactionMethods | 389 | hookQueries or t8 tmethods = TransactionMethods |
381 | { dispatchRegister = \mvar od d -> do -- :: MVar x -> d -> STM (tid, d) | 390 | { dispatchRegister = \mvar od d -> {-# SCC "hookQ.dispatchRegister" #-} do -- :: MVar x -> d -> STM (tid, d) |
382 | (tid,d') <- dispatchRegister tmethods mvar od d | 391 | (tid,d') <- dispatchRegister tmethods mvar od d |
383 | let Nonce8 w8 = t8 tid | 392 | let Nonce8 w8 = t8 tid |
384 | ni = onionNodeInfo od | 393 | ni = onionNodeInfo od |
@@ -386,11 +395,11 @@ hookQueries or t8 tmethods = TransactionMethods | |||
386 | od' = case od of | 395 | od' = case od of |
387 | OnionDestination {} -> od { onionRouteSpec = Just rid } | 396 | OnionDestination {} -> od { onionRouteSpec = Just rid } |
388 | OnionToOwner a b -> OnionToOwner a b -- Type cast. | 397 | OnionToOwner a b -> OnionToOwner a b -- Type cast. |
389 | wanted <- readTVar (pendingRoutes or IntMap.! ridn) | 398 | wanted <- {-# SCC "hookQ.wanted" #-} (readTVar (pendingRoutes or IntMap.! ridn)) |
390 | mr <- IntMap.lookup ridn <$> readTVar (routeMap or) | 399 | mr <- {-# SCC "hookQ.mr_action" #-} (readArray (routeMap or) ridn) |
391 | -- Block query until a route is ready. | 400 | -- Block query until a route is ready. |
392 | check $ fromMaybe False $ do | 401 | check $ fromMaybe False $ do |
393 | RouteRecord{routeVersion=rv} <- mr | 402 | RouteRecord{routeVersion=rv} <- {-# SCC "hookQ.mr" #-} mr |
394 | return $ wanted <= rv | 403 | return $ wanted <= rv |
395 | let pq = PendingQuery { pendingDestination = od' | 404 | let pq = PendingQuery { pendingDestination = od' |
396 | , pendingVersion = maybe 0 routeVersion mr | 405 | , pendingVersion = maybe 0 routeVersion mr |
@@ -400,7 +409,7 @@ hookQueries or t8 tmethods = TransactionMethods | |||
400 | modifyTVar' (pendingQueries or) (W64.insert w8 pq) | 409 | modifyTVar' (pendingQueries or) (W64.insert w8 pq) |
401 | writeTChan (routeLog or) $ "ONION query add " ++ unwords [ show (Just $ pendingVersion pq,w8), ":=", show ni ] | 410 | writeTChan (routeLog or) $ "ONION query add " ++ unwords [ show (Just $ pendingVersion pq,w8), ":=", show ni ] |
402 | return (tid,d') | 411 | return (tid,d') |
403 | , dispatchResponse = \tid x d -> do -- :: tid -> x -> d -> STM (d, IO ()) | 412 | , dispatchResponse = \tid x d -> {-# SCC "hookQ.dispatchResponse" #-} do -- :: tid -> x -> d -> STM (d, IO ()) |
404 | let Nonce8 w8 = t8 tid | 413 | let Nonce8 w8 = t8 tid |
405 | mb <- W64.lookup w8 <$> readTVar (pendingQueries or) | 414 | mb <- W64.lookup w8 <$> readTVar (pendingQueries or) |
406 | modifyTVar' (pendingQueries or) (W64.delete w8) | 415 | modifyTVar' (pendingQueries or) (W64.delete w8) |
@@ -408,10 +417,10 @@ hookQueries or t8 tmethods = TransactionMethods | |||
408 | let od = pendingDestination pq | 417 | let od = pendingDestination pq |
409 | RouteId rid = fromMaybe (routeId (nodeId (onionNodeInfo od))) | 418 | RouteId rid = fromMaybe (routeId (nodeId (onionNodeInfo od))) |
410 | $ onionRouteSpec od | 419 | $ onionRouteSpec od |
411 | modifyTVar' (routeMap or) (IntMap.adjust gotResponse rid) | 420 | modifyArray (routeMap or) (fmap gotResponse) rid |
412 | writeTChan (routeLog or) $ "ONION query del " ++ show (fmap pendingVersion mb, w8) | 421 | writeTChan (routeLog or) $ "ONION query del " ++ show (fmap pendingVersion mb, w8) |
413 | dispatchResponse tmethods tid x d | 422 | dispatchResponse tmethods tid x d |
414 | , dispatchCancel = \tid d -> do -- :: tid -> d -> STM d | 423 | , dispatchCancel = \tid d -> {-# SCC "hookQ.dispatchCancel" #-} do -- :: tid -> d -> STM d |
415 | let Nonce8 w8 = t8 tid | 424 | let Nonce8 w8 = t8 tid |
416 | mb <- W64.lookup w8 <$> readTVar (pendingQueries or) | 425 | mb <- W64.lookup w8 <$> readTVar (pendingQueries or) |
417 | modifyTVar' (pendingQueries or) (W64.delete w8) | 426 | modifyTVar' (pendingQueries or) (W64.delete w8) |
@@ -419,13 +428,13 @@ hookQueries or t8 tmethods = TransactionMethods | |||
419 | let od = pendingDestination pq | 428 | let od = pendingDestination pq |
420 | RouteId rid = fromMaybe (routeId (nodeId (onionNodeInfo od))) | 429 | RouteId rid = fromMaybe (routeId (nodeId (onionNodeInfo od))) |
421 | $ onionRouteSpec od | 430 | $ onionRouteSpec od |
422 | mrr <- IntMap.lookup rid <$> readTVar (routeMap or) | 431 | mrr <- readArray (routeMap or) rid |
423 | forM_ mrr $ \rr -> do | 432 | forM_ mrr $ \rr -> do |
424 | when (routeVersion rr == pendingVersion pq) $ do | 433 | when (routeVersion rr == pendingVersion pq) $ do |
425 | let expireRoute = modifyTVar' (pendingRoutes or IntMap.! rid) expire | 434 | let expireRoute = modifyTVar' (pendingRoutes or IntMap.! rid) expire |
426 | expire ver | ver <= succ (pendingVersion pq) = succ (pendingVersion pq) | 435 | expire ver | ver <= succ (pendingVersion pq) = succ (pendingVersion pq) |
427 | | otherwise = ver | 436 | | otherwise = ver |
428 | modifyTVar' (routeMap or) (IntMap.adjust gotTimeout rid) | 437 | modifyArray (routeMap or) (fmap gotTimeout) rid |
429 | case rr of | 438 | case rr of |
430 | RouteRecord{ responseCount = 0 | 439 | RouteRecord{ responseCount = 0 |
431 | , timeoutCount = c | 440 | , timeoutCount = c |
diff --git a/examples/dhtd.hs b/examples/dhtd.hs index 3f2a6a63..8e9e7692 100644 --- a/examples/dhtd.hs +++ b/examples/dhtd.hs | |||
@@ -27,6 +27,7 @@ import Control.Concurrent.STM.TMChan | |||
27 | import Control.Exception | 27 | import Control.Exception |
28 | import Control.Monad | 28 | import Control.Monad |
29 | import Control.Monad.IO.Class (liftIO) | 29 | import Control.Monad.IO.Class (liftIO) |
30 | import Data.Array.MArray (getAssocs) | ||
30 | import Data.Bool | 31 | import Data.Bool |
31 | import Data.Char | 32 | import Data.Char |
32 | import Data.Conduit as C | 33 | import Data.Conduit as C |
@@ -930,7 +931,7 @@ clientSession s@Session{..} sock cnum h = do | |||
930 | ("onion", s) -> cmd0 $ do | 931 | ("onion", s) -> cmd0 $ do |
931 | now <- getPOSIXTime | 932 | now <- getPOSIXTime |
932 | join $ atomically $ do | 933 | join $ atomically $ do |
933 | rm <- readTVar $ routeMap onionRouter | 934 | rm <- IntMap.fromList . catMaybes . map (\(i,m) -> fmap (i,) m) <$> getAssocs (routeMap onionRouter) |
934 | ts <- readTVar $ trampolineNodes onionRouter | 935 | ts <- readTVar $ trampolineNodes onionRouter |
935 | tcnt <- readTVar $ trampolineCount onionRouter | 936 | tcnt <- readTVar $ trampolineCount onionRouter |
936 | icnt <- HashMap.size <$> readTVar (trampolineIds onionRouter) | 937 | icnt <- HashMap.size <$> readTVar (trampolineIds onionRouter) |