diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2013-12-05 04:22:32 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2013-12-05 04:22:32 +0400 |
commit | 36d3f9b1d3e536035a02bf0afd33c2f0efa6e892 (patch) | |
tree | 5f24d419e9b6dfbccfb2557124b698a4ed2e0327 | |
parent | 74df228e2d8cbe27049f65a70253a59e67c7acc0 (diff) |
Move piece selection algorithms to separate module
-rw-r--r-- | bittorrent.cabal | 7 | ||||
-rw-r--r-- | src/Data/Torrent/Bitfield.hs | 72 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Selection.hs | 85 |
3 files changed, 90 insertions, 74 deletions
diff --git a/bittorrent.cabal b/bittorrent.cabal index e4dbd626..5bca228c 100644 --- a/bittorrent.cabal +++ b/bittorrent.cabal | |||
@@ -42,7 +42,7 @@ library | |||
42 | , RecordWildCards | 42 | , RecordWildCards |
43 | hs-source-dirs: src | 43 | hs-source-dirs: src |
44 | exposed-modules: Data.Torrent | 44 | exposed-modules: Data.Torrent |
45 | -- Data.Torrent.Bitfield | 45 | Data.Torrent.Bitfield |
46 | Data.Torrent.Client | 46 | Data.Torrent.Client |
47 | Data.Torrent.InfoHash | 47 | Data.Torrent.InfoHash |
48 | Data.Torrent.Layout | 48 | Data.Torrent.Layout |
@@ -62,12 +62,13 @@ library | |||
62 | -- Network.BitTorrent.Exchange.Assembler | 62 | -- Network.BitTorrent.Exchange.Assembler |
63 | Network.BitTorrent.Exchange.Block | 63 | Network.BitTorrent.Exchange.Block |
64 | Network.BitTorrent.Exchange.Message | 64 | Network.BitTorrent.Exchange.Message |
65 | Network.BitTorrent.Exchange.Selection | ||
65 | -- Network.BitTorrent.Exchange.Session | 66 | -- Network.BitTorrent.Exchange.Session |
66 | Network.BitTorrent.Exchange.Status | 67 | Network.BitTorrent.Exchange.Status |
67 | -- Network.BitTorrent.Exchange.Wire | 68 | Network.BitTorrent.Exchange.Wire |
68 | -- Network.BitTorrent.Tracker | 69 | -- Network.BitTorrent.Tracker |
69 | -- Network.BitTorrent.Tracker.RPC | ||
70 | Network.BitTorrent.Tracker.Message | 70 | Network.BitTorrent.Tracker.Message |
71 | -- Network.BitTorrent.Tracker.RPC | ||
71 | Network.BitTorrent.Tracker.RPC.HTTP | 72 | Network.BitTorrent.Tracker.RPC.HTTP |
72 | Network.BitTorrent.Tracker.RPC.UDP | 73 | Network.BitTorrent.Tracker.RPC.UDP |
73 | Network.BitTorrent.Tracker.Wai | 74 | Network.BitTorrent.Tracker.Wai |
diff --git a/src/Data/Torrent/Bitfield.hs b/src/Data/Torrent/Bitfield.hs index c7ef0998..17278a2c 100644 --- a/src/Data/Torrent/Bitfield.hs +++ b/src/Data/Torrent/Bitfield.hs | |||
@@ -55,13 +55,6 @@ module Data.Torrent.Bitfield | |||
55 | , fromBitmap, toBitmap | 55 | , fromBitmap, toBitmap |
56 | , toList | 56 | , toList |
57 | 57 | ||
58 | -- * Selection | ||
59 | , Selector | ||
60 | , selector, strategyClass | ||
61 | |||
62 | , strictFirst, strictLast | ||
63 | , rarestFirst, randomFirst, endGame | ||
64 | |||
65 | #if defined (TESTING) | 58 | #if defined (TESTING) |
66 | -- * Debug | 59 | -- * Debug |
67 | , mkBitfield | 60 | , mkBitfield |
@@ -78,7 +71,7 @@ import qualified Data.Vector.Unboxed as V | |||
78 | import qualified Data.Vector.Unboxed.Mutable as VM | 71 | import qualified Data.Vector.Unboxed.Mutable as VM |
79 | import Data.IntervalSet (IntSet) | 72 | import Data.IntervalSet (IntSet) |
80 | import qualified Data.IntervalSet as S | 73 | import qualified Data.IntervalSet as S |
81 | import qualified Data.IntervalSet.ByteString as S | 74 | import qualified Data.IntervalSet.ByteString as S |
82 | import Data.List (foldl') | 75 | import Data.List (foldl') |
83 | import Data.Monoid | 76 | import Data.Monoid |
84 | import Data.Ratio | 77 | import Data.Ratio |
@@ -289,66 +282,3 @@ mkBitfield s ixs = Bitfield { | |||
289 | bfSize = s | 282 | bfSize = s |
290 | , bfSet = S.splitGT (-1) $ S.splitLT s $ S.fromList ixs | 283 | , bfSet = S.splitGT (-1) $ S.splitLT s $ S.fromList ixs |
291 | } | 284 | } |
292 | |||
293 | {----------------------------------------------------------------------- | ||
294 | Selection | ||
295 | -----------------------------------------------------------------------} | ||
296 | |||
297 | type Selector = Bitfield -- ^ Indices of client /have/ pieces. | ||
298 | -> Bitfield -- ^ Indices of peer /have/ pieces. | ||
299 | -> [Bitfield] -- ^ Indices of other peers /have/ pieces. | ||
300 | -> Maybe PieceIx -- ^ Zero-based index of piece to request | ||
301 | -- to, if any. | ||
302 | |||
303 | selector :: Selector -- ^ Selector to use at the start. | ||
304 | -> Ratio PieceCount | ||
305 | -> Selector -- ^ Selector to use after the client have | ||
306 | -- the C pieces. | ||
307 | -> Selector -- ^ Selector that changes behaviour based | ||
308 | -- on completeness. | ||
309 | selector start pt ready h a xs = | ||
310 | case strategyClass pt h of | ||
311 | SCBeginning -> start h a xs | ||
312 | SCReady -> ready h a xs | ||
313 | SCEnd -> endGame h a xs | ||
314 | |||
315 | data StartegyClass | ||
316 | = SCBeginning | ||
317 | | SCReady | ||
318 | | SCEnd | ||
319 | deriving (Show, Eq, Ord, Enum, Bounded) | ||
320 | |||
321 | |||
322 | strategyClass :: Ratio PieceCount -> Bitfield -> StartegyClass | ||
323 | strategyClass threshold = classify . completeness | ||
324 | where | ||
325 | classify c | ||
326 | | c < threshold = SCBeginning | ||
327 | | c + 1 % numerator c < 1 = SCReady | ||
328 | -- FIXME numerator have is not total count | ||
329 | | otherwise = SCEnd | ||
330 | |||
331 | |||
332 | -- | Select the first available piece. | ||
333 | strictFirst :: Selector | ||
334 | strictFirst h a _ = Just $ findMin (difference a h) | ||
335 | |||
336 | -- | Select the last available piece. | ||
337 | strictLast :: Selector | ||
338 | strictLast h a _ = Just $ findMax (difference a h) | ||
339 | |||
340 | -- | | ||
341 | rarestFirst :: Selector | ||
342 | rarestFirst h a xs = rarest (map (intersection want) xs) | ||
343 | where | ||
344 | want = difference h a | ||
345 | |||
346 | -- | In average random first is faster than rarest first strategy but | ||
347 | -- only if all pieces are available. | ||
348 | randomFirst :: Selector | ||
349 | randomFirst = do | ||
350 | -- randomIO | ||
351 | error "randomFirst" | ||
352 | |||
353 | endGame :: Selector | ||
354 | endGame = strictLast | ||
diff --git a/src/Network/BitTorrent/Exchange/Selection.hs b/src/Network/BitTorrent/Exchange/Selection.hs new file mode 100644 index 00000000..2724fabc --- /dev/null +++ b/src/Network/BitTorrent/Exchange/Selection.hs | |||
@@ -0,0 +1,85 @@ | |||
1 | -- | | ||
2 | -- Copyright : (c) Sam Truzjan 2013 | ||
3 | -- License : BSD3 | ||
4 | -- Maintainer : pxqr.sta@gmail.com | ||
5 | -- Stability : experimental | ||
6 | -- Portability : portable | ||
7 | -- | ||
8 | -- Piece selection algorithms. | ||
9 | -- | ||
10 | module Network.BitTorrent.Exchange.Selection | ||
11 | ( -- * Selection | ||
12 | Selector | ||
13 | , selector | ||
14 | , strategyClass | ||
15 | |||
16 | , strictFirst | ||
17 | , strictLast | ||
18 | , rarestFirst | ||
19 | , randomFirst | ||
20 | , endGame | ||
21 | ) where | ||
22 | |||
23 | import Data.Ratio | ||
24 | |||
25 | import Data.Torrent.Bitfield | ||
26 | |||
27 | |||
28 | type Selector = Bitfield -- ^ Indices of client /have/ pieces. | ||
29 | -> Bitfield -- ^ Indices of peer /have/ pieces. | ||
30 | -> [Bitfield] -- ^ Indices of other peers /have/ pieces. | ||
31 | -> Maybe PieceIx -- ^ Zero-based index of piece to request | ||
32 | -- to, if any. | ||
33 | |||
34 | selector :: Selector -- ^ Selector to use at the start. | ||
35 | -> Ratio PieceCount | ||
36 | -> Selector -- ^ Selector to use after the client have | ||
37 | -- the C pieces. | ||
38 | -> Selector -- ^ Selector that changes behaviour based | ||
39 | -- on completeness. | ||
40 | selector start pt ready h a xs = | ||
41 | case strategyClass pt h of | ||
42 | SCBeginning -> start h a xs | ||
43 | SCReady -> ready h a xs | ||
44 | SCEnd -> endGame h a xs | ||
45 | |||
46 | data StartegyClass | ||
47 | = SCBeginning | ||
48 | | SCReady | ||
49 | | SCEnd | ||
50 | deriving (Show, Eq, Ord, Enum, Bounded) | ||
51 | |||
52 | |||
53 | strategyClass :: Ratio PieceCount -> Bitfield -> StartegyClass | ||
54 | strategyClass threshold = classify . completeness | ||
55 | where | ||
56 | classify c | ||
57 | | c < threshold = SCBeginning | ||
58 | | c + 1 % numerator c < 1 = SCReady | ||
59 | -- FIXME numerator have is not total count | ||
60 | | otherwise = SCEnd | ||
61 | |||
62 | |||
63 | -- | Select the first available piece. | ||
64 | strictFirst :: Selector | ||
65 | strictFirst h a _ = Just $ findMin (difference a h) | ||
66 | |||
67 | -- | Select the last available piece. | ||
68 | strictLast :: Selector | ||
69 | strictLast h a _ = Just $ findMax (difference a h) | ||
70 | |||
71 | -- | | ||
72 | rarestFirst :: Selector | ||
73 | rarestFirst h a xs = rarest (map (intersection want) xs) | ||
74 | where | ||
75 | want = difference h a | ||
76 | |||
77 | -- | In average random first is faster than rarest first strategy but | ||
78 | -- only if all pieces are available. | ||
79 | randomFirst :: Selector | ||
80 | randomFirst = do | ||
81 | -- randomIO | ||
82 | error "randomFirst" | ||
83 | |||
84 | endGame :: Selector | ||
85 | endGame = strictLast | ||