diff options
author | Sam T <pxqr.sta@gmail.com> | 2013-05-05 04:50:50 +0400 |
---|---|---|
committer | Sam T <pxqr.sta@gmail.com> | 2013-05-05 04:50:50 +0400 |
commit | f4122eec550671a646310106224ee6523ea8e369 (patch) | |
tree | 50d27be299adaf3f267c927b9f0737f26e4a34bc /src/Network/BitTorrent | |
parent | 950d728dc12302858f0c20d9890dc97975f4e9a9 (diff) |
+ Add bitfield completeness function.
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r-- | src/Network/BitTorrent/PeerWire/Bitfield.hs | 62 | ||||
-rw-r--r-- | src/Network/BitTorrent/PeerWire/Selection.hs | 4 |
2 files changed, 61 insertions, 5 deletions
diff --git a/src/Network/BitTorrent/PeerWire/Bitfield.hs b/src/Network/BitTorrent/PeerWire/Bitfield.hs index 9d88e784..03273899 100644 --- a/src/Network/BitTorrent/PeerWire/Bitfield.hs +++ b/src/Network/BitTorrent/PeerWire/Bitfield.hs | |||
@@ -22,12 +22,14 @@ module Network.BitTorrent.PeerWire.Bitfield | |||
22 | , fromByteString, toByteString | 22 | , fromByteString, toByteString |
23 | 23 | ||
24 | -- * Query | 24 | -- * Query |
25 | , haveCount, completeness | ||
25 | , findMin, findMax | 26 | , findMin, findMax |
26 | , union, intersection, difference, combine | 27 | , union, intersection, difference, combine |
27 | , frequencies | 28 | , frequencies |
28 | 29 | ||
29 | -- * Serialization | 30 | -- * Serialization |
30 | , getBitfield, putBitfield, bitfieldByteCount | 31 | , getBitfield, putBitfield |
32 | , bitfieldByteCount, bitfieldBitCount | ||
31 | 33 | ||
32 | 34 | ||
33 | , aligned, alignLow, alignedZip | 35 | , aligned, alignLow, alignedZip |
@@ -46,9 +48,11 @@ import Data.Word | |||
46 | 48 | ||
47 | import Foreign | 49 | import Foreign |
48 | 50 | ||
49 | import Network.BitTorrent.PeerWire.Block | 51 | --import Network.BitTorrent.PeerWire.Block |
50 | import Data.Torrent | 52 | import Data.Torrent |
51 | 53 | ||
54 | -- one good idea is to aggregate frequently used stats in reducer | ||
55 | -- it should give a big boost | ||
52 | newtype Bitfield = MkBitfield { | 56 | newtype Bitfield = MkBitfield { |
53 | bfBits :: ByteString | 57 | bfBits :: ByteString |
54 | -- , bfSize :: Int | 58 | -- , bfSize :: Int |
@@ -90,6 +94,11 @@ bitfieldByteCount :: Bitfield -> Int | |||
90 | bitfieldByteCount = B.length . bfBits | 94 | bitfieldByteCount = B.length . bfBits |
91 | {-# INLINE bitfieldByteCount #-} | 95 | {-# INLINE bitfieldByteCount #-} |
92 | 96 | ||
97 | -- WARN | ||
98 | -- TODO | ||
99 | bitfieldBitCount :: Bitfield -> Int | ||
100 | bitfieldBitCount bf = bitSize (undefined :: Word8) * bitfieldByteCount bf | ||
101 | {-# INLINE bitfieldBitCount #-} | ||
93 | 102 | ||
94 | align :: Storable a => Ptr a -> (Ptr a, Int) | 103 | align :: Storable a => Ptr a -> (Ptr a, Int) |
95 | align p = tie (alignPtr p) undefined | 104 | align p = tie (alignPtr p) undefined |
@@ -235,7 +244,44 @@ findSet b = | |||
235 | else go (succ i) | 244 | else go (succ i) |
236 | | otherwise = Nothing | 245 | | otherwise = Nothing |
237 | 246 | ||
247 | foldBS :: (Word8 -> Int -> Int) -> (Word -> Int -> Int) -> Int -> ByteString -> Int | ||
248 | foldBS f g acc b = | ||
249 | let (fptr, off, len) = B.toForeignPtr b in | ||
250 | B.inlinePerformIO $ withForeignPtr fptr $ \_ptr -> do | ||
251 | let ptr = _ptr `advancePtr` off | ||
252 | |||
253 | let (low, mid, hgh) = aligned (ptr, len) | ||
254 | let resL = goFold low acc | ||
255 | let resM = goFoldW (mid :: Mem Word) resL | ||
256 | let resH = goFold hgh resM | ||
257 | |||
258 | -- computation of res should not escape withForeignPtr | ||
259 | case resH of | ||
260 | 0 -> return () | ||
261 | _ -> return () | ||
238 | 262 | ||
263 | return resH | ||
264 | |||
265 | where | ||
266 | goFold :: Mem Word8 -> Int -> Int | ||
267 | goFold (ptr, n) = go 0 | ||
268 | where | ||
269 | go :: Int -> Int -> Int | ||
270 | go i !a | ||
271 | | i < n = | ||
272 | let v = B.inlinePerformIO (peekElemOff ptr i) | ||
273 | in go (succ i) (f v a) | ||
274 | | otherwise = a | ||
275 | |||
276 | goFoldW :: Mem Word -> Int -> Int | ||
277 | goFoldW (ptr, n) = go 0 | ||
278 | where | ||
279 | go :: Int -> Int -> Int | ||
280 | go i !a | ||
281 | | i < n = | ||
282 | let v = B.inlinePerformIO (peekElemOff ptr i) | ||
283 | in go (succ i) (g v a) | ||
284 | | otherwise = a | ||
239 | 285 | ||
240 | union :: Bitfield -> Bitfield -> Bitfield | 286 | union :: Bitfield -> Bitfield -> Bitfield |
241 | union = zipWithBF (.|.) | 287 | union = zipWithBF (.|.) |
@@ -257,8 +303,16 @@ combine :: [Bitfield] -> Maybe Bitfield | |||
257 | combine [] = Nothing | 303 | combine [] = Nothing |
258 | combine as = return $ foldr1 intersection as | 304 | combine as = return $ foldr1 intersection as |
259 | 305 | ||
306 | haveCount :: Bitfield -> Int | ||
307 | haveCount (MkBitfield b) = foldBS f f 0 b | ||
308 | where | ||
309 | f byte count = popCount byte + count | ||
310 | |||
311 | completeness :: Bitfield -> (Int, Int) | ||
312 | completeness bf = (haveCount bf, bitfieldBitCount bf) | ||
313 | |||
260 | -- | Get min index of piece that the peer have. | 314 | -- | Get min index of piece that the peer have. |
261 | findMin :: Bitfield -> Maybe PieceIx | 315 | findMin :: Bitfield -> Maybe Int |
262 | findMin (MkBitfield b) = do | 316 | findMin (MkBitfield b) = do |
263 | byteIx <- findSet b | 317 | byteIx <- findSet b |
264 | bitIx <- findMinWord8 (B.index b byteIx) | 318 | bitIx <- findMinWord8 (B.index b byteIx) |
@@ -271,7 +325,7 @@ findMin (MkBitfield b) = do | |||
271 | {-# INLINE findMin #-} | 325 | {-# INLINE findMin #-} |
272 | 326 | ||
273 | 327 | ||
274 | findMax :: Bitfield -> Maybe PieceIx | 328 | findMax :: Bitfield -> Maybe Int |
275 | findMax (MkBitfield b) = do | 329 | findMax (MkBitfield b) = do |
276 | -- TODO avoid reverse | 330 | -- TODO avoid reverse |
277 | byteIx <- (pred (B.length b) -) <$> findSet (B.reverse b) | 331 | byteIx <- (pred (B.length b) -) <$> findSet (B.reverse b) |
diff --git a/src/Network/BitTorrent/PeerWire/Selection.hs b/src/Network/BitTorrent/PeerWire/Selection.hs index 92285501..2e17317e 100644 --- a/src/Network/BitTorrent/PeerWire/Selection.hs +++ b/src/Network/BitTorrent/PeerWire/Selection.hs | |||
@@ -24,7 +24,9 @@ | |||
24 | module Network.BitTorrent.PeerWire.Selection | 24 | module Network.BitTorrent.PeerWire.Selection |
25 | ( Selector | 25 | ( Selector |
26 | , strictFirst, strictLast | 26 | , strictFirst, strictLast |
27 | , rarestFirst, randomFirst, endGame, autoSelector | 27 | , rarestFirst, randomFirst, endGame |
28 | |||
29 | , autoSelector | ||
28 | ) where | 30 | ) where |
29 | 31 | ||
30 | import Network.BitTorrent.PeerWire.Block | 32 | import Network.BitTorrent.PeerWire.Block |