on master help sign in
running the file info cache with reaper and register it to vault.
commit2ccadb96ccab29ed98057cf31777e1c39191a3be authorKazu Yamamoto <kazu@iij.ad.jp> dateMon 30 Nov 2015, 17:18 (11 years ago) parent999b17d
5 files changed+75−55
warp/Network/Wai/Handler/Warp/FileInfoCache.hs+51−35 warp/Network/Wai/Handler/Warp/Request.hs+4−3 warp/Network/Wai/Handler/Warp/Response.hs+1−1 warp/Network/Wai/Handler/Warp/Run.hs+17−16 warp/Network/Wai/Handler/Warp/Types.hs+2
warp/Network/Wai/Handler/Warp/FileInfoCache.hs+51−35
@@ -3,11 +3,12 @@
33module Network.Wai.Handler.Warp.FileInfoCache (
44 -- * Types
55 FileInfo(..)
6− -- * Starter
7− , fileCacheInit
6+ -- * Functions
7+ , withFileInfoCache
88 ) where
99
1010import Control.Exception as E
11+import Control.Monad (void)
1112import Control.Reaper
1213import Data.ByteString (ByteString)
1314import Data.HashMap.Strict (HashMap)
@@ -20,63 +21,75 @@ import Data.Time (UTCTime)
2021import Network.Wai.Handler.Warp.Date (uToH)
2122#endif
2223
24+----------------------------------------------------------------
25+
2326data FileInfo = FileInfo {
2427 fileInfoName :: !FilePath
2528 , fileInfoSize :: !Integer
26− , fileInfoTime :: !HTTPDate -- ^ Modification time
27− , fileInfoDate :: !ByteString -- ^ Modification time in the GMT format
29+ , fileInfoTime :: HTTPDate -- ^ Modification time
30+ , fileInfoDate :: ByteString -- ^ Modification time in the GMT format
2831 } deriving (Eq, Show)
2932
3033data Entry = Negative | Positive FileInfo
3134type Cache = HashMap FilePath Entry
32−type FileCache = Reaper Cache (FilePath,Entry)
35+type FileInfoCache = Reaper Cache (FilePath,Entry)
3336
34−fileInfo :: FileCache -> FilePath -> IO FileInfo
35−fileInfo reaper@Reaper{..} path = do
36− cache <- reaperRead
37− case M.lookup path cache of
38− Just Negative -> throwIO (userError "fileInfo")
39− Just (Positive x) -> return x
40− Nothing -> register reaper path `E.onException` negative reaper path
37+----------------------------------------------------------------
4138
42−register :: FileCache -> FilePath -> IO FileInfo
43−register reaper path = do
39+getInfo :: FilePath -> IO FileInfo
40+getInfo path = do
4441 fs <- getFileStatus path -- file access
4542 let regular = not (isDirectory fs)
4643 readable = fileMode fs `intersectFileModes` ownerReadMode /= 0
47− if regular && readable then
48− positive reaper fs path
44+ if regular && readable then do
45+ let time = epochTimeToHTTPDate $ modificationTime fs
46+ date = formatHTTPDate time
47+ size = fromIntegral $ fileSize fs
48+ info = FileInfo {
49+ fileInfoName = path
50+ , fileInfoSize = size
51+ , fileInfoTime = time
52+ , fileInfoDate = date
53+ }
54+ return info
4955 else
50− throwIO (userError "go to negative")
56+ throwIO (userError "FileInfoCache:getInfo")
57+
58+----------------------------------------------------------------
5159
52−positive :: FileCache -> FileStatus -> FilePath -> IO FileInfo
53−positive Reaper{..} fs path = do
54− reaperAdd (path,entry)
60+getAndRegisterInfo :: FileInfoCache -> FilePath -> IO FileInfo
61+getAndRegisterInfo reaper@Reaper{..} path = do
62+ cache <- reaperRead
63+ case M.lookup path cache of
64+ Just Negative -> throwIO (userError "FileInfoCache:getAndRegisterInfo")
65+ Just (Positive x) -> return x
66+ Nothing -> positive reaper path `E.onException` negative reaper path
67+
68+positive :: FileInfoCache -> FilePath -> IO FileInfo
69+positive Reaper{..} path = do
70+ info <- getInfo path
71+ reaperAdd (path, Positive info)
5572 return info
56− where
57− info = FileInfo {
58− fileInfoName = path
59− , fileInfoSize = size fs
60− , fileInfoTime = time
61− , fileInfoDate = formatHTTPDate time
62− }
63− size = fromIntegral . fileSize
64− time = epochTimeToHTTPDate (modificationTime fs)
65− entry = Positive info
6673
67−negative :: FileCache -> FilePath -> IO FileInfo
74+negative :: FileInfoCache -> FilePath -> IO FileInfo
6875negative Reaper{..} path = do
6976 reaperAdd (path,Negative)
70− throwIO (userError "fileInfo")
77+ throwIO (userError "FileInfoCache:negative")
7178
7279----------------------------------------------------------------
7380
74−fileCacheInit :: IO (FilePath -> IO FileInfo)
75−fileCacheInit = mkReaper settings >>= return . fileInfo
81+withFileInfoCache :: Int -> ((FilePath -> IO FileInfo) -> IO a) -> IO a
82+withFileInfoCache 0 action = action getInfo
83+withFileInfoCache duration action = E.bracket (initialize duration)
84+ terminate
85+ (\c -> action (getAndRegisterInfo c))
86+
87+initialize :: Int -> IO FileInfoCache
88+initialize duration = mkReaper settings
7689 where
7790 settings = defaultReaperSettings {
7891 reaperAction = override
79− , reaperDelay = 10000000 -- 10 seconds -- hard-coding: fixme
92+ , reaperDelay = duration * 1000000
8093 , reaperCons = uncurry M.insert
8194 , reaperNull = M.null
8295 , reaperEmpty = M.empty
@@ -84,3 +97,6 @@ fileCacheInit = mkReaper settings >>= return . fileInfo
8497
8598override :: Cache -> IO (Cache -> Cache)
8699override _ = return $ const M.empty
100+
101+terminate :: FileInfoCache -> IO ()
102+terminate x = void $ reaperStop x
warp/Network/Wai/Handler/Warp/Request.hs+4−3
@@ -83,9 +83,7 @@ recvRequest settings conn ii addr src = do
8383 , isSecure = False
8484 , remoteHost = addr
8585 , requestBody = rbody'
86− , vault = Vault.insert pauseTimeoutKey
87− (Timeout.pause th)
88− Vault.empty
86+ , vault = vaultValue
8987 , requestBodyLength = bodyLength
9088 , requestHeaderHost = idxhdr ! idxHost
9189 , requestHeaderRange = idxhdr ! idxRange
@@ -93,6 +91,9 @@ recvRequest settings conn ii addr src = do
9391 return (req, remainingRef, idxhdr, rbodyFlush)
9492 where
9593 th = threadHandle ii
94+ vaultValue = Vault.insert pauseTimeoutKey (Timeout.pause th)
95+ $ Vault.insert getFileInfoKey (fileInfo ii)
96+ Vault.empty
9697
9798----------------------------------------------------------------
9899
warp/Network/Wai/Handler/Warp/Response.hs+1−1
@@ -80,7 +80,7 @@ fileRange :: H.Status -> H.ResponseHeaders -> FilePath
8080 -> IO (Either IOException
8181 (H.Status, H.ResponseHeaders, Integer, Integer))
8282fileRange s0 hs0 path Nothing mRange =
83− fmap (fileRangeSized s0 hs0 Nothing mRange) <$> tryGetFileSize path
83+ fmap (fileRangeSized s0 hs0 Nothing mRange) <$> tryGetFileSize path -- fixme: using fileInfo
8484fileRange s0 hs0 _ mPart@(Just part) mRange =
8585 return . Right $ fileRangeSized s0 hs0 mPart mRange size
8686 where
warp/Network/Wai/Handler/Warp/Run.hs+17−16
@@ -29,6 +29,7 @@ import Network.Wai.Handler.Warp.Buffer
2929import Network.Wai.Handler.Warp.Counter
3030import qualified Network.Wai.Handler.Warp.Date as D
3131import qualified Network.Wai.Handler.Warp.FdCache as F
32+import qualified Network.Wai.Handler.Warp.FileInfoCache as I
3233import Network.Wai.Handler.Warp.HTTP2 (http2, isHTTP2)
3334import Network.Wai.Handler.Warp.Header
3435import Network.Wai.Handler.Warp.ReadInt
@@ -237,12 +238,16 @@ runServeSettingsConnectionMakerSecure :: Settings
237238runServeSettingsConnectionMakerSecure set getConnMaker serveConn = do
238239 settingsBeforeMainLoop set
239240 counter <- newCounter
240−
241− D.withDateCache $ \dc ->
242− F.withFdCache fdCacheDurationInSeconds $ \fc ->
243− withTimeoutManager $ \tm ->
244− acceptConnection set getConnMaker serveConn dc fc tm counter
241+ withII $ acceptConnection set getConnMaker serveConn counter
245242 where
243+ withII action =
244+ D.withDateCache $ \dc ->
245+ F.withFdCache fdCacheDurationInSeconds $ \fc ->
246+ I.withFileInfoCache 10 $ \get -> -- fixme: hard-coding
247+ withTimeoutManager $ \tm -> do
248+ let ii0 = InternalInfo undefined tm fc get dc -- fixme: undefined
249+ action ii0
250+
246251 fdCacheDurationInSeconds = settingsFdCacheDuration set * 1000000
247252 withTimeoutManager f = case settingsManager set of
248253 Just tm -> f tm
@@ -267,12 +272,10 @@ runServeSettingsConnectionMakerSecure set getConnMaker serveConn = do
267272acceptConnection :: Settings
268273 -> IO (IO (Connection, Transport), SockAddr)
269274 -> ServeConnection
270− -> D.DateCache
271− -> Maybe F.MutableFdCache
272− -> T.Manager
273275 -> Counter
276+ -> InternalInfo
274277 -> IO ()
275−acceptConnection set getConnMaker serveConn dc fc tm counter = do
278+acceptConnection set getConnMaker serveConn counter ii0 = do
276279 -- First mask all exceptions in acceptLoop. This is necessary to
277280 -- ensure that no async exception is throw between the call to
278281 -- acceptNewConnection and the registering of connClose.
@@ -294,7 +297,7 @@ acceptConnection set getConnMaker serveConn dc fc tm counter = do
294297 case mx of
295298 Nothing -> return ()
296299 Just (mkConn, addr) -> do
297− fork set mkConn addr serveConn dc fc tm counter
300+ fork set mkConn addr serveConn counter ii0
298301 acceptLoop
299302
300303 acceptNewConnection = do
@@ -319,12 +322,10 @@ fork :: Settings
319322 -> IO (Connection, Transport)
320323 -> SockAddr
321324 -> ServeConnection
322− -> D.DateCache
323− -> Maybe F.MutableFdCache
324− -> T.Manager
325325 -> Counter
326+ -> InternalInfo
326327 -> IO ()
327−fork set mkConn addr serveConn dc fc tm counter = settingsFork set $ \ unmask ->
328+fork set mkConn addr serveConn counter ii0 = settingsFork set $ \ unmask ->
328329 -- Run the connection maker to get a new connection, and ensure
329330 -- that the connection is closed. If the mkConn call throws an
330331 -- exception, we will leak the connection. If the mkConn call is
@@ -339,9 +340,9 @@ fork set mkConn addr serveConn dc fc tm counter = settingsFork set $ \ unmask ->
339340
340341 -- We need to register a timeout handler for this thread, and
341342 -- cancel that handler as soon as we exit.
342− bracket (T.registerKillThread tm) T.cancel $ \th ->
343+ bracket (T.registerKillThread (timeoutManager ii0)) T.cancel $ \th ->
343344
344− let ii = InternalInfo th tm fc dc
345+ let ii = ii0 { threadHandle = th }
345346 -- We now have fully registered a connection close handler
346347 -- in the case of all exceptions, so it is safe to one
347348 -- again allow async exceptions.
warp/Network/Wai/Handler/Warp/Types.hs+2
@@ -13,6 +13,7 @@ import Data.Word (Word16, Word8)
1313import Foreign.Ptr (Ptr)
1414import qualified Network.Wai.Handler.Warp.Date as D
1515import qualified Network.Wai.Handler.Warp.FdCache as F
16+import qualified Network.Wai.Handler.Warp.FileInfoCache as I
1617import qualified Network.Wai.Handler.Warp.Timeout as T
1718
1819#ifndef WINDOWS
@@ -118,6 +119,7 @@ data InternalInfo = InternalInfo {
118119 threadHandle :: T.Handle
119120 , timeoutManager :: T.Manager
120121 , fdCacher :: Maybe F.MutableFdCache
122+ , fileInfo :: FilePath -> IO I.FileInfo
121123 , dateCacher :: D.DateCache
122124 }
123125