module System.Rados.Error
(
RadosError(..),
checkError,
checkError',
checkError_,
maybeError,
checkErrorRetryBusy_,
) where
import Control.Exception
import Control.Monad
import Data.Typeable
import Foreign.C.Error
import Foreign.C.String
import Foreign.C.Types
import System.Rados.FFI as F
data RadosError = Unknown { errno :: Int
, cFunction :: String
, strerror :: String
}
| NoEntity { errno :: Int
, cFunction :: String
, strerror :: String
}
| Exists { errno :: Int
, cFunction :: String
, strerror :: String
}
| Canceled { errno :: Int
, cFunction :: String
, strerror :: String
}
| Range { errno :: Int
, cFunction :: String
, strerror :: String
}
| User { message :: String }
deriving (Eq, Ord, Typeable)
instance Show RadosError where
show Unknown{..} = "rados: unknown rados error in '" ++
cFunction ++ "', errno " ++ show errno ++ ": '" ++ strerror ++ "'"
show NoEntity{..} = cFunction ++ ": ENOENT: '" ++ strerror ++ "'"
show Exists{..} = cFunction ++ ": EEXIST: '" ++ strerror ++ "'"
show Canceled{..} = cFunction ++ ": ECANCELED: '" ++ strerror ++ "'"
show Range{..} = cFunction ++ ": ERANGE: '" ++ strerror ++ "'"
show User{..} = "Rados user error: '" ++ message ++ "'"
instance Exception RadosError
checkError :: String -> IO CInt -> IO Int
checkError function action = do
checkError' function action >>= either throwIO return
checkError' :: String -> IO CInt -> IO (Either RadosError Int)
checkError' function action = do
n <- action
if n < 0
then do
let errno = (n)
strerror <- peekCString =<< F.c_strerror (Errno errno)
return . Left $ makeError (fromIntegral errno) function strerror
else return . Right $ fromIntegral n
maybeError :: String -> IO CInt -> IO (Maybe RadosError)
maybeError function action =
checkError' function action >>= either (return . Just) (const $ return Nothing)
makeError :: Int -> String -> String -> RadosError
makeError 125 fun str = Canceled 125 fun str
makeError 2 fun str = NoEntity 2 fun str
makeError 17 fun str = Exists 17 fun str
makeError 34 fun str = Range 34 fun str
makeError n fun str = Unknown n fun str
checkError_ :: String -> IO CInt -> IO ()
checkError_ function action = void $ checkError function action
checkErrorRetryBusy_ :: String -> IO CInt -> IO ()
checkErrorRetryBusy_ function action = do
result <- checkError' function action
case result of
Left rados_error ->
if errno rados_error == 16
then checkErrorRetryBusy_ function action
else throwIO rados_error
Right _ -> return ()