@@ -1,17 +1,73 @@
11module Network.Wai.Handler.Warp.Buffer where
22
3+import Control.Monad (when)
34import qualified Data.Streaming.ByteString.Builder.Buffer as B (Buffer (..))
45import Data.Word (Word8)
5−import Foreign.ForeignPtr (newForeignPtr_)
6−import Foreign.Marshal.Alloc (mallocBytes, free)
7−import Foreign.Ptr (Ptr, plusPtr)
6+import Data.IORef (IORef, newIORef, readIORef, writeIORef)
7+import Data.ByteString (ByteString, empty, length)
8+import Data.ByteString.Internal (ByteString(PS), mallocByteString)
9+import Data.ByteString.Unsafe (unsafeTake, unsafeDrop)
10+import Foreign.ForeignPtr (newForeignPtr, newForeignPtr_, withForeignPtr)
11+import Foreign.Marshal.Alloc (mallocBytes, free, finalizerFree)
12+import Foreign.Ptr (Ptr, castPtr, plusPtr)
13+
14+largeBufferSize :: Int
15+largeBufferSize = 16384
16+minBufferSize :: Int
17+minBufferSize = 2048
18+
19+type BufferPool = IORef ByteString
20+
21+newBufferPool :: IO BufferPool
22+newBufferPool = newIORef Data.ByteString.empty
23+
24+mallocBuffer :: Int -> IO ByteString
25+mallocBuffer size = do
26+ ptr <- mallocBytes size
27+ fptr <- newForeignPtr finalizerFree ptr
28+ return $! PS fptr 0 size
29+{-# INLINE mallocBuffer #-}
30+
31+createBuffer :: Int -> IO ByteString
32+createBuffer size = do
33+ fptr <- mallocByteString size
34+ return $! PS fptr 0 size
35+{-# INLINE createBuffer #-}
36+
37+usefulBuffer :: ByteString -> Bool
38+usefulBuffer buffer = Data.ByteString.length buffer >= minBufferSize
39+{-# INLINE usefulBuffer #-}
40+
41+getBuffer :: BufferPool -> IO ByteString
42+getBuffer pool = do
43+ buffer <- readIORef pool
44+ if usefulBuffer buffer then return buffer else mallocBuffer largeBufferSize
45+{-# INLINE getBuffer #-}
46+
47+putBuffer :: BufferPool -> ByteString -> IO ()
48+putBuffer pool buffer = when (usefulBuffer buffer) $ writeIORef pool buffer
49+{-# INLINE putBuffer #-}
50+
51+withForeignBuffer :: ByteString -> ((Ptr Word8, Int) -> IO Int) -> IO Int
52+withForeignBuffer (PS ps s l) f = withForeignPtr ps $ \p -> f (castPtr p `plusPtr` s, l)
53+{-# INLINE withForeignBuffer #-}
54+
55+withBufferPool :: BufferPool -> ((Ptr Word8, Int) -> IO Int) -> IO ByteString
56+withBufferPool pool f = do
57+ buffer <- getBuffer pool
58+ consumed <- withForeignBuffer buffer f
59+ putBuffer pool $! unsafeDrop consumed buffer
60+ return $! unsafeTake consumed buffer
61+{-# INLINE withBufferPool #-}
862
963type Buffer = Ptr Word8
1064type BufSize = Int
1165
12−-- FIXME come up with good values here
66+-- 2^14 = 1024 * 16
67+-- The maximum size of TLS record
68+-- The maximum size of HTTP/2 frame payload (excluding frame header)
1369bufferSize :: BufSize
14−bufferSize = 4096
70+bufferSize = 16384
1571
1672allocateBuffer :: Int -> IO Buffer
1773allocateBuffer = mallocBytes