summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bittorrent/src/Network/BitTorrent/Exchange/Bitfield.hs20
-rw-r--r--bittorrent/src/System/Torrent/FileMap.hs16
2 files changed, 27 insertions, 9 deletions
diff --git a/bittorrent/src/Network/BitTorrent/Exchange/Bitfield.hs b/bittorrent/src/Network/BitTorrent/Exchange/Bitfield.hs
index 7bae3475..1be9f970 100644
--- a/bittorrent/src/Network/BitTorrent/Exchange/Bitfield.hs
+++ b/bittorrent/src/Network/BitTorrent/Exchange/Bitfield.hs
@@ -9,7 +9,7 @@
9-- bitfields. Bitfields are used to keep track indices of complete 9-- bitfields. Bitfields are used to keep track indices of complete
10-- pieces either this peer have or remote peer have. 10-- pieces either this peer have or remote peer have.
11-- 11--
12-- There are also commonly used piece seletion algorithms 12-- There are also commonly used piece selection algorithms
13-- which used to find out which one next piece to download. 13-- which used to find out which one next piece to download.
14-- Selectors considered to be used in the following order: 14-- Selectors considered to be used in the following order:
15-- 15--
@@ -108,12 +108,17 @@ import Data.Torrent
108 108
109-- TODO cache some operations 109-- TODO cache some operations
110 110
111-- | Bitfields are represented just as integer sets but with 111-- | Bitfields are represented just as integer sets but with a restriction:
112-- restriction: the each set should be within given interval (or 112-- each integer in the set should be within the given interval. The greatest
113-- subset of the specified interval). Size is used to specify 113-- lower bound of the interval must be zero, so intervals may be specified by
114-- interval, so bitfield of size 10 might contain only indices in 114-- providing a maximum set size. For example, a bitfield of size 10 might
115-- interval [0..9]. 115-- contain only indices in interval [0..9].
116-- 116--
117-- By convention, we use the following aliases for Int:
118--
119-- [ PieceIx ] an Int member of the Bitfield.
120--
121-- [ PieceCount ] maximum set size for a Bitfield.
117data Bitfield = Bitfield { 122data Bitfield = Bitfield {
118 bfSize :: !PieceCount 123 bfSize :: !PieceCount
119 , bfSet :: !IntSet 124 , bfSet :: !IntSet
@@ -257,6 +262,7 @@ rarest xs
257 = Just $ fst $ V.ifoldr' minIx (0, freqMap V.! 0) freqMap 262 = Just $ fst $ V.ifoldr' minIx (0, freqMap V.! 0) freqMap
258 where 263 where
259 freqMap = frequencies xs 264 freqMap = frequencies xs
265 {-# NOINLINE freqMap #-}
260 266
261 minIx :: PieceIx -> Frequency 267 minIx :: PieceIx -> Frequency
262 -> (PieceIx, Frequency) 268 -> (PieceIx, Frequency)
@@ -393,7 +399,7 @@ rarestFirst h a xs = rarest (map (intersection want) xs)
393randomFirst :: Selector 399randomFirst :: Selector
394randomFirst = do 400randomFirst = do
395-- randomIO 401-- randomIO
396 error "randomFirst" 402 error "TODO: randomFirst"
397 403
398endGame :: Selector 404endGame :: Selector
399endGame = strictLast 405endGame = strictLast
diff --git a/bittorrent/src/System/Torrent/FileMap.hs b/bittorrent/src/System/Torrent/FileMap.hs
index 6e8d7f5a..38c475e8 100644
--- a/bittorrent/src/System/Torrent/FileMap.hs
+++ b/bittorrent/src/System/Torrent/FileMap.hs
@@ -39,7 +39,7 @@ import Data.Torrent
39 39
40data FileEntry = FileEntry 40data FileEntry = FileEntry
41 { filePosition :: {-# UNPACK #-} !FileOffset 41 { filePosition :: {-# UNPACK #-} !FileOffset
42 , fileBytes :: {-# UNPACK #-} !BS.ByteString 42 , fileBytes :: {-# UNPACK #-} !BS.ByteString -- XXX: mutable buffer (see 'writeBytes').
43 } deriving (Show, Eq) 43 } deriving (Show, Eq)
44 44
45type FileMap = Vector FileEntry 45type FileMap = Vector FileEntry
@@ -62,6 +62,7 @@ unmapFiles = V.mapM_ unmapEntry
62 where 62 where
63 unmapEntry (FileEntry _ (PS fptr _ _)) = finalizeForeignPtr fptr 63 unmapEntry (FileEntry _ (PS fptr _ _)) = finalizeForeignPtr fptr
64 64
65-- Unsafe: FileMap 'writeBytes' will modify supplied bytestrings in place.
65fromLazyByteString :: BL.ByteString -> FileMap 66fromLazyByteString :: BL.ByteString -> FileMap
66fromLazyByteString lbs = V.unfoldr f (0, lbs) 67fromLazyByteString lbs = V.unfoldr f (0, lbs)
67 where 68 where
@@ -70,6 +71,8 @@ fromLazyByteString lbs = V.unfoldr f (0, lbs)
70 where chunkSize = fromIntegral $ BS.length x 71 where chunkSize = fromIntegral $ BS.length x
71 72
72-- | /O(n)/. 73-- | /O(n)/.
74--
75-- Unsafe: mutable buffers are returned without copy.
73toLazyByteString :: FileMap -> BL.ByteString 76toLazyByteString :: FileMap -> BL.ByteString
74toLazyByteString = V.foldr f Empty 77toLazyByteString = V.foldr f Empty
75 where 78 where
@@ -82,6 +85,7 @@ size m
82 | FileEntry {..} <- V.unsafeLast m 85 | FileEntry {..} <- V.unsafeLast m
83 = filePosition + fromIntegral (BS.length fileBytes) 86 = filePosition + fromIntegral (BS.length fileBytes)
84 87
88-- | Find the file number for a particular byte offset within a torrent.
85bsearch :: FileOffset -> FileMap -> Maybe Int 89bsearch :: FileOffset -> FileMap -> Maybe Int
86bsearch x m 90bsearch x m
87 | V.null m = Nothing 91 | V.null m = Nothing
@@ -114,12 +118,17 @@ take len m
114 s = System.Torrent.FileMap.size m 118 s = System.Torrent.FileMap.size m
115 119
116-- | /O(log n + m)/. Do not use this function with 'unmapFiles'. 120-- | /O(log n + m)/. Do not use this function with 'unmapFiles'.
121--
122-- The returned bytestring points directly into an area memory mapped from a
123-- file.
117unsafeReadBytes :: FileOffset -> FileSize -> FileMap -> BL.ByteString 124unsafeReadBytes :: FileOffset -> FileSize -> FileMap -> BL.ByteString
118unsafeReadBytes off s m 125unsafeReadBytes off s m
119 | (l , m') <- System.Torrent.FileMap.drop off m 126 | (l , m') <- System.Torrent.FileMap.drop off m
120 , (m'', _ ) <- System.Torrent.FileMap.take (off + s) m' 127 , (m'', _ ) <- System.Torrent.FileMap.take (off + s) m'
121 = BL.take (fromIntegral s) $ BL.drop (fromIntegral l) $ toLazyByteString m'' 128 = BL.take (fromIntegral s) $ BL.drop (fromIntegral l) $ toLazyByteString m''
122 129
130-- The returned bytestring is copied and safe to use after the file is
131-- unmapped.
123readBytes :: FileOffset -> FileSize -> FileMap -> IO BL.ByteString 132readBytes :: FileOffset -> FileSize -> FileMap -> IO BL.ByteString
124readBytes off s m = do 133readBytes off s m = do
125 let bs_copy = BL.copy $ unsafeReadBytes off s m 134 let bs_copy = BL.copy $ unsafeReadBytes off s m
@@ -129,6 +138,8 @@ readBytes off s m = do
129 forceLBS Empty = return () 138 forceLBS Empty = return ()
130 forceLBS (Chunk _ x) = forceLBS x 139 forceLBS (Chunk _ x) = forceLBS x
131 140
141-- UNSAFE: Uses the first byte string as a pointer to mutable data and writes
142-- the contents of the second bytestring there.
132bscpy :: BL.ByteString -> BL.ByteString -> IO () 143bscpy :: BL.ByteString -> BL.ByteString -> IO ()
133bscpy (PS _ _ 0 `Chunk` dest_rest) src = bscpy dest_rest src 144bscpy (PS _ _ 0 `Chunk` dest_rest) src = bscpy dest_rest src
134bscpy dest (PS _ _ 0 `Chunk` src_rest) = bscpy dest src_rest 145bscpy dest (PS _ _ 0 `Chunk` src_rest) = bscpy dest src_rest
@@ -144,8 +155,9 @@ bscpy (PS dest_fptr dest_off dest_size `Chunk` dest_rest)
144 (PS src_fptr (src_off + csize) (src_size - csize) `Chunk` src_rest) 155 (PS src_fptr (src_off + csize) (src_size - csize) `Chunk` src_rest)
145bscpy _ _ = return () 156bscpy _ _ = return ()
146 157
158-- UNSAFE: Mutates bytestring contents within the provided FileMap.
147writeBytes :: FileOffset -> BL.ByteString -> FileMap -> IO () 159writeBytes :: FileOffset -> BL.ByteString -> FileMap -> IO ()
148writeBytes off lbs m = bscpy dest src 160writeBytes off lbs m = bscpy dest src
149 where 161 where
150 src = BL.take (fromIntegral (BL.length dest)) lbs 162 src = BL.take (fromIntegral (BL.length dest)) lbs
151 dest = unsafeReadBytes off (fromIntegral (BL.length lbs)) m \ No newline at end of file 163 dest = unsafeReadBytes off (fromIntegral (BL.length lbs)) m