random-access-file-0.1.0.0: src/System/IO/RandomAccessFile/Common.hs
{-# LANGUAGE TypeFamilies #-}
module System.IO.RandomAccessFile.Common where
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import qualified Control.Concurrent.ReadWriteLock as RWL
import Control.Exception
import qualified Data.Map as M
import qualified Data.ByteString as B
import Data.List
import Data.Word
type Offset = Word64
type Size = Word64
class FileAccess a where
data AccessParams a
initFile :: AccessParams a -> FilePath -> IO a
readBytes :: a -> Offset -> Size -> IO B.ByteString
writeBytes :: a -> Offset -> B.ByteString -> IO ()
currentFileSize :: a -> IO Size
syncFile :: a -> IO ()
syncFile _ = return ()
closeFile :: a -> IO ()
writeZeros :: FileAccess a => a -> Size -> IO ()
writeZeros h size =
writeBytes h 0 $ B.replicate (fromIntegral size) 0
data AccessType = ReadAccess | WriteAccess
type FileLocks = M.Map Offset RWL.RWLock
withQSem :: QSem -> IO a -> IO a
withQSem sem =
bracket_ (waitQSem sem) (signalQSem sem)
withLock :: RWL.RWLock -> AccessType -> IO a -> IO a
withLock lock ReadAccess action =
bracket_
(RWL.acquireRead lock)
(RWL.releaseRead lock)
action
withLock lock WriteAccess action =
bracket_
(RWL.acquireWrite lock)
(RWL.releaseWrite lock)
action
withLocks :: [RWL.RWLock] -> AccessType -> IO a -> IO a
withLocks locks ReadAccess action =
bracket_
(forM_ locks RWL.acquireRead)
(forM_ locks RWL.releaseRead)
action
withLocks locks WriteAccess action =
bracket_
(forM_ locks RWL.acquireWrite)
(forM_ locks RWL.releaseWrite)
action
withLock_ :: Bool -> RWL.RWLock -> AccessType -> IO a -> IO a
withLock_ False _ _ action = action
withLock_ True lock access action = withLock lock access action
underBlockLock :: TVar FileLocks -> AccessType -> Offset -> IO a -> IO a
underBlockLock locksVar access n action = do
newLock <- RWL.new
lock <- atomically $ do
locks <- readTVar locksVar
case M.lookup n locks of
Just lock -> return lock
Nothing -> do
writeTVar locksVar $ M.insert n newLock locks
return newLock
withLock lock access action
underBlockLocks :: TVar FileLocks -> AccessType -> [Offset] -> IO a -> IO a
underBlockLocks locksVar access ns action = do
newLocks <- replicateM (length ns) RWL.new
locks <- atomically $ do
locks <- readTVar locksVar
forM (zip [0..] $ sort ns) $ \(idx,n) ->
case M.lookup n locks of
Just lock -> return lock
Nothing -> do
let newLock = newLocks !! idx
writeTVar locksVar $ M.insert n newLock locks
return newLock
withLocks locks access action