{-# LANGUAGE PackageImports #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} module System.IO.RandomAccessFile.Threaded where import Control.Monad import Control.Concurrent.STM import Control.Exception import qualified Data.Map as M import qualified Data.ByteString as B import Data.Int import System.Posix.Types import System.Posix.IO import System.IO import "unix-bytestring" System.Posix.IO.ByteString import Text.Printf import System.IO.RandomAccessFile.Common data Threaded = Threaded { tFile :: Fd , tFileSize :: TVar Size , tLockSize :: Size , tLocks :: TVar FileLocks } instance FileAccess Threaded where data AccessParams Threaded = ThreadedParams Size initFile (ThreadedParams lockPageSize) path = do locks <- atomically $ newTVar M.empty let fileMode = Just 0o644 let flags = defaultFileFlags handle <- openFile path ReadWriteMode size <- hFileSize handle -- printf "Size: %d\n" size sizeVar <- newTVarIO (fromIntegral size) fd <- handleToFd handle -- fd <- openFd path ReadWrite fileMode flags return $ Threaded fd sizeVar lockPageSize locks readBytes (Threaded fd fileSizeVar lockPageSize locks) offset size = do let dataOffset0 = offset `mod` lockPageSize pageOffset0 = offset - dataOffset0 dataOffset1 = (offset + size) `mod` lockPageSize pageOffset1 = (offset + size) - dataOffset1 pageOffsets = [pageOffset0, pageOffset0 + lockPageSize .. pageOffset1] underBlockLocks locks ReadAccess pageOffsets $ fdPread fd (fromIntegral size) (fromIntegral offset) `catch` (\(e :: SomeException) -> do printf "pread: offset %d, len %d: %s\n" offset size (show e) throw e) writeBytes (Threaded fd fileSizeVar lockPageSize locks) offset bstr = do let size = fromIntegral $ B.length bstr dataOffset0 = offset `mod` lockPageSize pageOffset0 = offset - dataOffset0 dataOffset1 = (offset + size) `mod` lockPageSize pageOffset1 = (offset + size) - dataOffset1 pageOffsets = [pageOffset0, pageOffset0 + lockPageSize .. pageOffset1] pwrite bytes off = (fdPwrite fd bytes (fromIntegral off) >> return ()) `catch` (\(e :: SomeException) -> printf "pwrite: offset %d, len %d: %s\n" offset (B.length bstr) (show e)) fsize <- atomically $ readTVar fileSizeVar underBlockLocks locks WriteAccess pageOffsets $ do let delta :: Int64 delta = max 0 $ fromIntegral (offset + size) - fromIntegral fsize when (delta > 0) $ pwrite (B.replicate (fromIntegral delta) 0) fsize pwrite bstr offset when (delta > 0) $ do -- printf "New size: %d+%d\n" fsize delta atomically $ writeTVar fileSizeVar $ fromIntegral (fromIntegral fsize + delta) currentFileSize h = do let var = tFileSize h atomically $ readTVar var closeFile (Threaded fd _ _ _) = closeFd fd dfltThreaded :: AccessParams Threaded dfltThreaded = ThreadedParams 4096