mirror of
https://github.com/commercialhaskell/stackage-server.git
synced 2026-01-22 17:01:57 +01:00
Got the whole two thread system working
This commit is contained in:
parent
cb3f1edffd
commit
3992ca4f38
@ -2,7 +2,7 @@ module Handler.Haddock where
|
|||||||
|
|
||||||
import Import
|
import Import
|
||||||
import Data.BlobStore
|
import Data.BlobStore
|
||||||
import Filesystem (removeTree, isDirectory, createTree, isFile, rename, removeFile)
|
import Filesystem (removeTree, isDirectory, createTree, isFile, rename, removeFile, removeDirectory)
|
||||||
import Control.Concurrent (forkIO)
|
import Control.Concurrent (forkIO)
|
||||||
import Control.Concurrent.Chan
|
import Control.Concurrent.Chan
|
||||||
import System.IO.Temp (withSystemTempFile, withTempFile)
|
import System.IO.Temp (withSystemTempFile, withTempFile)
|
||||||
@ -46,16 +46,14 @@ putUploadHaddockR = getUploadHaddockR
|
|||||||
|
|
||||||
getHaddockR :: PackageSetIdent -> [Text] -> Handler ()
|
getHaddockR :: PackageSetIdent -> [Text] -> Handler ()
|
||||||
getHaddockR ident rest = do
|
getHaddockR ident rest = do
|
||||||
error "getHaddockR"
|
|
||||||
{-
|
|
||||||
sanitize $ toPathPiece ident
|
sanitize $ toPathPiece ident
|
||||||
mapM_ sanitize rest
|
mapM_ sanitize rest
|
||||||
(gzdir, rawdir) <- getHaddockDir ident
|
dirs <- getDirs -- (gzdir, rawdir) <- getHaddockDir ident
|
||||||
master <- getYesod
|
master <- getYesod
|
||||||
liftIO $ unlessM (isDirectory dir) $ haddockUnpacker master ident
|
liftIO $ haddockUnpacker master False ident
|
||||||
|
|
||||||
let rawfp = mconcat $ rawdir : map fpFromText rest
|
let rawfp = dirRawFp dirs ident rest
|
||||||
gzfp = mconcat $ gzdir : map fpFromText rest
|
gzfp = dirGzFp dirs ident rest
|
||||||
mime = defaultMimeLookup $ fpToText $ filename rawfp
|
mime = defaultMimeLookup $ fpToText $ filename rawfp
|
||||||
|
|
||||||
whenM (liftIO $ isDirectory rawfp)
|
whenM (liftIO $ isDirectory rawfp)
|
||||||
@ -67,6 +65,9 @@ getHaddockR ident rest = do
|
|||||||
addHeader "Content-Encoding" "gzip"
|
addHeader "Content-Encoding" "gzip"
|
||||||
sendFile mime $ fpToString gzfp
|
sendFile mime $ fpToString gzfp
|
||||||
|
|
||||||
|
-- Note: There's a small race window here, where the compressor thread
|
||||||
|
-- could pull the rug out from under us. We can work around this by opening
|
||||||
|
-- the file and, if that fails, try the compressed version again.
|
||||||
whenM (liftIO $ isFile rawfp) $ sendFile mime $ fpToString rawfp
|
whenM (liftIO $ isFile rawfp) $ sendFile mime $ fpToString rawfp
|
||||||
|
|
||||||
notFound
|
notFound
|
||||||
@ -75,7 +76,6 @@ getHaddockR ident rest = do
|
|||||||
| ("/" `isInfixOf` p) || p `member` (asHashSet $ setFromList ["", ".", ".."]) =
|
| ("/" `isInfixOf` p) || p `member` (asHashSet $ setFromList ["", ".", ".."]) =
|
||||||
permissionDenied "Invalid request"
|
permissionDenied "Invalid request"
|
||||||
| otherwise = return ()
|
| otherwise = return ()
|
||||||
-}
|
|
||||||
|
|
||||||
getHaddockDir :: PackageSetIdent -> Handler (FilePath, FilePath)
|
getHaddockDir :: PackageSetIdent -> Handler (FilePath, FilePath)
|
||||||
getHaddockDir ident = do
|
getHaddockDir ident = do
|
||||||
@ -91,21 +91,28 @@ mkDirPair root ident =
|
|||||||
)
|
)
|
||||||
|
|
||||||
createCompressor
|
createCompressor
|
||||||
:: FilePath -- ^ uncompressed dir
|
:: Dirs
|
||||||
-> FilePath -- ^ compressed dir
|
|
||||||
-> FilePath -- ^ cache dir
|
|
||||||
-> IO (IO ()) -- ^ action to kick off compressor again
|
-> IO (IO ()) -- ^ action to kick off compressor again
|
||||||
createCompressor rawdir gzdir cachedir = do
|
createCompressor dirs = do
|
||||||
baton <- newMVar ()
|
baton <- newMVar ()
|
||||||
mask $ \restore -> void $ forkIO $ forever $ do
|
mask $ \restore -> void $ forkIO $ forever $ do
|
||||||
takeMVar baton
|
takeMVar baton
|
||||||
runResourceT $ sourceDirectoryDeep False rawdir $$ mapM_C go
|
runResourceT $ goDir (dirRawRoot dirs)
|
||||||
return $ void $ tryPutMVar baton ()
|
return $ void $ tryPutMVar baton ()
|
||||||
where
|
where
|
||||||
go fp = liftIO $ handle (print . asSomeException) $ do
|
goDir dir = do
|
||||||
gzipHash cachedir fp (gzdir </> suffix)
|
sourceDirectory dir $$ mapM_C goFP
|
||||||
|
liftIO $ void $ tryIO $ removeDirectory dir
|
||||||
|
|
||||||
|
goFP fp = do
|
||||||
|
e <- liftIO $ isFile fp
|
||||||
|
if e
|
||||||
|
then liftIO
|
||||||
|
$ handle (print . asSomeException)
|
||||||
|
$ gzipHash dirs suffix
|
||||||
|
else goDir fp
|
||||||
where
|
where
|
||||||
Just suffix = F.stripPrefix (rawdir </> "") fp
|
Just suffix = F.stripPrefix (dirRawRoot dirs </> "") fp
|
||||||
|
|
||||||
-- Procedure is to:
|
-- Procedure is to:
|
||||||
--
|
--
|
||||||
@ -113,12 +120,11 @@ createCompressor rawdir gzdir cachedir = do
|
|||||||
-- * If that hash doesn't exist in the cache, move the new file to the cache
|
-- * If that hash doesn't exist in the cache, move the new file to the cache
|
||||||
-- * Create a hard link from dst to the file in the cache
|
-- * Create a hard link from dst to the file in the cache
|
||||||
-- * Delete src
|
-- * Delete src
|
||||||
gzipHash :: FilePath -- ^ cache directory
|
gzipHash :: Dirs
|
||||||
-> FilePath -- ^ source
|
-> FilePath -- ^ suffix
|
||||||
-> FilePath -- ^ destination
|
|
||||||
-> IO ()
|
-> IO ()
|
||||||
gzipHash cachedir src dst = do
|
gzipHash dirs suffix = do
|
||||||
withTempFile (fpToString cachedir) "haddock-file.gz" $ \tempfp temph -> do
|
withTempFile (fpToString $ dirCacheRoot dirs) "haddock-file.gz" $ \tempfp temph -> do
|
||||||
digest <- withBinaryFile (fpToString src) ReadMode $ \inh ->
|
digest <- withBinaryFile (fpToString src) ReadMode $ \inh ->
|
||||||
sourceHandle inh
|
sourceHandle inh
|
||||||
$= gzip
|
$= gzip
|
||||||
@ -126,12 +132,45 @@ gzipHash cachedir src dst = do
|
|||||||
ZipSink (sinkHandle temph) *>
|
ZipSink (sinkHandle temph) *>
|
||||||
ZipSink sinkHash)
|
ZipSink sinkHash)
|
||||||
hClose temph
|
hClose temph
|
||||||
let name = decodeUtf8 $ B16.encode $ toBytes (digest :: Digest SHA1)
|
let fpcache = dirCacheFp dirs digest
|
||||||
let fpcache = cachedir </> fpFromText name <.> "gz"
|
unlessM (isFile fpcache) $ do
|
||||||
unlessM (isFile fpcache) $ rename (fpFromString tempfp) fpcache
|
createTree $ F.parent fpcache
|
||||||
|
rename (fpFromString tempfp) fpcache
|
||||||
|
createTree $ F.parent dst
|
||||||
createLink (fpToString fpcache) (fpToString dst)
|
createLink (fpToString fpcache) (fpToString dst)
|
||||||
removeFile src
|
removeFile src
|
||||||
|
where
|
||||||
|
src = dirRawRoot dirs </> suffix
|
||||||
|
dst = dirGzRoot dirs </> suffix
|
||||||
|
|
||||||
|
data Dirs = Dirs
|
||||||
|
{ dirRawRoot :: !FilePath
|
||||||
|
, dirGzRoot :: !FilePath
|
||||||
|
, dirCacheRoot :: !FilePath
|
||||||
|
}
|
||||||
|
|
||||||
|
getDirs :: Handler Dirs
|
||||||
|
getDirs = mkDirs . haddockRootDir <$> getYesod
|
||||||
|
|
||||||
|
mkDirs :: FilePath -> Dirs
|
||||||
|
mkDirs dir = Dirs
|
||||||
|
{ dirRawRoot = dir </> "idents-raw"
|
||||||
|
, dirGzRoot = dir </> "idents-gz"
|
||||||
|
, dirCacheRoot = dir </> "cachedir"
|
||||||
|
}
|
||||||
|
|
||||||
|
dirGzIdent dirs ident = dirGzRoot dirs </> fpFromText (toPathPiece ident)
|
||||||
|
dirRawIdent dirs ident = dirRawRoot dirs </> fpFromText (toPathPiece ident)
|
||||||
|
|
||||||
|
dirGzFp dirs ident rest = dirGzIdent dirs ident </> mconcat (map fpFromText rest)
|
||||||
|
dirRawFp dirs ident rest = dirRawIdent dirs ident </> mconcat (map fpFromText rest)
|
||||||
|
|
||||||
|
dirCacheFp :: Dirs -> Digest SHA1 -> FilePath
|
||||||
|
dirCacheFp dirs digest =
|
||||||
|
dirCacheRoot dirs </> fpFromText x </> fpFromText y <.> "gz"
|
||||||
|
where
|
||||||
|
name = decodeUtf8 $ B16.encode $ toBytes digest
|
||||||
|
(x, y) = splitAt 2 name
|
||||||
|
|
||||||
-- Should have two threads: one to unpack, one to convert. Never serve the
|
-- Should have two threads: one to unpack, one to convert. Never serve the
|
||||||
-- uncompressed files, only the compressed files. When serving, convert on
|
-- uncompressed files, only the compressed files. When serving, convert on
|
||||||
@ -140,44 +179,55 @@ createHaddockUnpacker :: FilePath -- ^ haddock root
|
|||||||
-> BlobStore StoreKey
|
-> BlobStore StoreKey
|
||||||
-> IO (ForceUnpack -> PackageSetIdent -> IO ())
|
-> IO (ForceUnpack -> PackageSetIdent -> IO ())
|
||||||
createHaddockUnpacker root store = do
|
createHaddockUnpacker root store = do
|
||||||
|
createTree $ dirCacheRoot dirs
|
||||||
|
createTree $ dirRawRoot dirs
|
||||||
|
createTree $ dirGzRoot dirs
|
||||||
|
|
||||||
chan <- newChan
|
chan <- newChan
|
||||||
compressor <- createCompressor
|
compressor <- createCompressor dirs
|
||||||
(root </> "idents-raw")
|
|
||||||
(root </> "idents-gz")
|
|
||||||
cacehdir
|
|
||||||
|
|
||||||
mask $ \restore -> void $ forkIO $ forever $ do
|
mask $ \restore -> void $ forkIO $ forever $ do
|
||||||
(forceUnpack, ident, res) <- readChan chan
|
(forceUnpack, ident, res) <- readChan chan
|
||||||
try (restore $ go forceUnpack ident) >>= putMVar res
|
try (restore $ go forceUnpack ident) >>= putMVar res
|
||||||
compressor
|
compressor
|
||||||
return $ \forceUnpack ident -> do
|
return $ \forceUnpack ident -> do
|
||||||
res <- newEmptyMVar
|
shouldAct <-
|
||||||
writeChan chan (forceUnpack, ident, res)
|
if forceUnpack
|
||||||
takeMVar res >>= either (throwM . asSomeException) return
|
then return True
|
||||||
|
else not <$> doDirsExist ident
|
||||||
|
if shouldAct
|
||||||
|
then do
|
||||||
|
res <- newEmptyMVar
|
||||||
|
writeChan chan (forceUnpack, ident, res)
|
||||||
|
takeMVar res >>= either (throwM . asSomeException) return
|
||||||
|
else return ()
|
||||||
where
|
where
|
||||||
cacehdir = root </> "cachedir"
|
dirs = mkDirs root
|
||||||
gzipHash = error "gzipHash"
|
|
||||||
go forceUnpack ident = do
|
|
||||||
error "go"
|
|
||||||
{- FIXME
|
|
||||||
unlessM (isDirectory dir) $
|
|
||||||
withSystemTempFile "haddock-bundle.tar.xz" $ \tempfp temph -> do
|
|
||||||
when forceUnpack
|
|
||||||
$ liftIO $ mapM_ (void . tryIO . removeTree) [dir1, dir2]
|
|
||||||
withAcquire (storeRead' store (HaddockBundle ident)) $ \msrc ->
|
|
||||||
case msrc of
|
|
||||||
Nothing -> error "No haddocks exist for that snapshot"
|
|
||||||
Just src -> src $$ sinkHandle temph
|
|
||||||
hClose temph
|
|
||||||
createTree dir
|
|
||||||
(Nothing, Nothing, Nothing, ph) <- createProcess
|
|
||||||
(proc "tar" ["xf", tempfp])
|
|
||||||
{ cwd = Just $ fpToString dir
|
|
||||||
}
|
|
||||||
ec <- waitForProcess ph
|
|
||||||
if ec == ExitSuccess then return () else throwM ec
|
|
||||||
where
|
|
||||||
dir = mkDir ident
|
|
||||||
|
|
||||||
mkDir ident = root </> "idents" </> fpFromText (toPathPiece ident)
|
doDirsExist ident = do
|
||||||
-}
|
e1 <- isDirectory $ dirGzIdent dirs ident
|
||||||
|
if e1
|
||||||
|
then return True
|
||||||
|
else isDirectory $ dirRawIdent dirs ident
|
||||||
|
go forceUnpack ident = do
|
||||||
|
toRun <-
|
||||||
|
if forceUnpack
|
||||||
|
then do
|
||||||
|
removeTree $ dirRawIdent dirs ident
|
||||||
|
removeTree $ dirGzIdent dirs ident
|
||||||
|
return True
|
||||||
|
else not <$> doDirsExist ident
|
||||||
|
when toRun $ do
|
||||||
|
withSystemTempFile "haddock-bundle.tar.xz" $ \tempfp temph -> do
|
||||||
|
withAcquire (storeRead' store (HaddockBundle ident)) $ \msrc ->
|
||||||
|
case msrc of
|
||||||
|
Nothing -> error "No haddocks exist for that snapshot"
|
||||||
|
Just src -> src $$ sinkHandle temph
|
||||||
|
hClose temph
|
||||||
|
createTree $ dirRawIdent dirs ident
|
||||||
|
(Nothing, Nothing, Nothing, ph) <- createProcess
|
||||||
|
(proc "tar" ["xf", tempfp])
|
||||||
|
{ cwd = Just $ fpToString $ dirRawIdent dirs ident
|
||||||
|
}
|
||||||
|
ec <- waitForProcess ph
|
||||||
|
if ec == ExitSuccess then return () else throwM ec
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user