packages feed

haxl 0.2.0.0 → 0.3.0.0

raw patch · 20 files changed

+608/−176 lines, 20 filesdep +deepseqdep ~basedep ~hashabledep ~timenew-component:exe:monadbenchPVP ok

version bump matches the API change (PVP)

Dependencies added: deepseq

Dependency ranges changed: base, hashable, time

API changes (from Hackage documentation)

- Haxl.Core.Exception: instance Eq DataSourceError
- Haxl.Core.Exception: instance Eq FetchError
- Haxl.Core.Exception: instance Exception CriticalError
- Haxl.Core.Exception: instance Exception DataSourceError
- Haxl.Core.Exception: instance Exception EmptyList
- Haxl.Core.Exception: instance Exception FetchError
- Haxl.Core.Exception: instance Exception HaxlException
- Haxl.Core.Exception: instance Exception InternalError
- Haxl.Core.Exception: instance Exception InvalidParameter
- Haxl.Core.Exception: instance Exception JSONError
- Haxl.Core.Exception: instance Exception LogicError
- Haxl.Core.Exception: instance Exception NotFound
- Haxl.Core.Exception: instance Exception TransientError
- Haxl.Core.Exception: instance Exception UnexpectedType
- Haxl.Core.Exception: instance MiddleException InternalError
- Haxl.Core.Exception: instance MiddleException LogicError
- Haxl.Core.Exception: instance MiddleException TransientError
- Haxl.Core.Exception: instance Show CriticalError
- Haxl.Core.Exception: instance Show DataSourceError
- Haxl.Core.Exception: instance Show EmptyList
- Haxl.Core.Exception: instance Show FetchError
- Haxl.Core.Exception: instance Show HaxlException
- Haxl.Core.Exception: instance Show InternalError
- Haxl.Core.Exception: instance Show InvalidParameter
- Haxl.Core.Exception: instance Show JSONError
- Haxl.Core.Exception: instance Show LogicError
- Haxl.Core.Exception: instance Show NotFound
- Haxl.Core.Exception: instance Show TransientError
- Haxl.Core.Exception: instance Show UnexpectedType
- Haxl.Core.Exception: instance ToJSON HaxlException
- Haxl.Core.Exception: instance Typeable CriticalError
- Haxl.Core.Exception: instance Typeable DataSourceError
- Haxl.Core.Exception: instance Typeable EmptyList
- Haxl.Core.Exception: instance Typeable FetchError
- Haxl.Core.Exception: instance Typeable HaxlException
- Haxl.Core.Exception: instance Typeable InternalError
- Haxl.Core.Exception: instance Typeable InvalidParameter
- Haxl.Core.Exception: instance Typeable JSONError
- Haxl.Core.Exception: instance Typeable LogicError
- Haxl.Core.Exception: instance Typeable NotFound
- Haxl.Core.Exception: instance Typeable TransientError
- Haxl.Core.Exception: instance Typeable UnexpectedType
- Haxl.Core.Monad: cacheRef :: Env u -> IORef (DataCache ResultVar)
- Haxl.Core.Monad: flags :: Env u -> Flags
- Haxl.Core.Monad: instance Applicative (GenHaxl u)
- Haxl.Core.Monad: instance Functor (GenHaxl u)
- Haxl.Core.Monad: instance IsString a => IsString (GenHaxl u a)
- Haxl.Core.Monad: instance Monad (GenHaxl u)
- Haxl.Core.Monad: instance Show a => Show (Result u a)
- Haxl.Core.Monad: memoRef :: Env u -> IORef (DataCache (MemoVar u))
- Haxl.Core.Monad: states :: Env u -> StateStore
- Haxl.Core.Monad: statsRef :: Env u -> IORef Stats
- Haxl.Core.Monad: unHaxl :: GenHaxl u a -> Env u -> IORef (RequestStore u) -> IO (Result u a)
- Haxl.Core.Monad: userEnv :: Env u -> u
- Haxl.Core.Types: FastInit :: InitStrategy
- Haxl.Core.Types: FullInit :: InitStrategy
- Haxl.Core.Types: data InitStrategy
- Haxl.Core.Types: dataSourceFetches :: DataSourceRoundStats -> Int
- Haxl.Core.Types: dataSourceTime :: DataSourceRoundStats -> Maybe Microseconds
- Haxl.Core.Types: instance Enum InitStrategy
- Haxl.Core.Types: instance Eq InitStrategy
- Haxl.Core.Types: instance Show InitStrategy
- Haxl.Core.Types: instance ToJSON DataSourceRoundStats
- Haxl.Core.Types: instance ToJSON RoundStats
- Haxl.Core.Types: instance ToJSON Stats
- Haxl.Core.Types: report :: Flags -> Int
- Haxl.Core.Types: roundDataSources :: RoundStats -> HashMap Text DataSourceRoundStats
- Haxl.Core.Types: roundTime :: RoundStats -> Microseconds
- Haxl.Core.Types: trace :: Flags -> Int
- Haxl.Prelude: (<$>) :: Functor f => (a -> b) -> f a -> f b
- Haxl.Prelude: instance Fractional a => Fractional (GenHaxl u a)
- Haxl.Prelude: instance IfThenElse Bool a
- Haxl.Prelude: instance Num a => Num (GenHaxl u a)
- Haxl.Prelude: instance u1 ~ u2 => IfThenElse (GenHaxl u1 Bool) (GenHaxl u2 a)
+ Haxl.Core: AsyncFetch :: (IO () -> IO ()) -> PerformFetch
+ Haxl.Core: BlockedFetch :: (r a) -> (ResultVar a) -> BlockedFetch r
+ Haxl.Core: DataSourceRoundStats :: Int -> Maybe Microseconds -> DataSourceRoundStats
+ Haxl.Core: Env :: IORef (DataCache ResultVar) -> IORef (DataCache (MemoVar u)) -> Flags -> u -> IORef Stats -> StateStore -> Env u
+ Haxl.Core: Flags :: Int -> Int -> Flags
+ Haxl.Core: GenHaxl :: (Env u -> IORef (RequestStore u) -> IO (Result u a)) -> GenHaxl u a
+ Haxl.Core: MemoFingerprintKey :: {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> MemoFingerprintKey a
+ Haxl.Core: ResultVar :: (MVar (Either SomeException a)) -> ResultVar a
+ Haxl.Core: RoundStats :: Microseconds -> HashMap Text DataSourceRoundStats -> RoundStats
+ Haxl.Core: Stats :: [RoundStats] -> Stats
+ Haxl.Core: SyncFetch :: (IO ()) -> PerformFetch
+ Haxl.Core: [cacheRef] :: Env u -> IORef (DataCache ResultVar)
+ Haxl.Core: [dataSourceFetches] :: DataSourceRoundStats -> Int
+ Haxl.Core: [dataSourceTime] :: DataSourceRoundStats -> Maybe Microseconds
+ Haxl.Core: [flags] :: Env u -> Flags
+ Haxl.Core: [memoRef] :: Env u -> IORef (DataCache (MemoVar u))
+ Haxl.Core: [report] :: Flags -> Int
+ Haxl.Core: [roundDataSources] :: RoundStats -> HashMap Text DataSourceRoundStats
+ Haxl.Core: [roundTime] :: RoundStats -> Microseconds
+ Haxl.Core: [states] :: Env u -> StateStore
+ Haxl.Core: [statsRef] :: Env u -> IORef Stats
+ Haxl.Core: [trace] :: Flags -> Int
+ Haxl.Core: [unHaxl] :: GenHaxl u a -> Env u -> IORef (RequestStore u) -> IO (Result u a)
+ Haxl.Core: [userEnv] :: Env u -> u
+ Haxl.Core: asyncFetch :: ((service -> IO ()) -> IO ()) -> (service -> IO ()) -> (forall a. service -> request a -> IO (IO (Either SomeException a))) -> State request -> Flags -> u -> [BlockedFetch request] -> PerformFetch
+ Haxl.Core: asyncFetchWithDispatch :: ((service -> IO ()) -> IO ()) -> (service -> IO ()) -> (service -> IO ()) -> (forall a. service -> request a -> IO (IO (Either SomeException a))) -> State request -> Flags -> u -> [BlockedFetch request] -> PerformFetch
+ Haxl.Core: cacheRequest :: (Request req a) => req a -> Either SomeException a -> GenHaxl u ()
+ Haxl.Core: cacheResult :: (Request r a) => r a -> IO a -> GenHaxl u a
+ Haxl.Core: cachedComputation :: (Eq (req a), Hashable (req a), Typeable (req a)) => req a -> GenHaxl u a -> GenHaxl u a
+ Haxl.Core: caches :: Env u -> Caches u
+ Haxl.Core: catch :: Exception e => GenHaxl u a -> (e -> GenHaxl u a) -> GenHaxl u a
+ Haxl.Core: catchIf :: Exception e => (e -> Bool) -> GenHaxl u a -> (e -> GenHaxl u a) -> GenHaxl u a
+ Haxl.Core: class (DataSourceName req, StateKey req, Show1 req) => DataSource u req
+ Haxl.Core: class DataSourceName req
+ Haxl.Core: class Show1 f
+ Haxl.Core: class Typeable f => StateKey (f :: * -> *) where data family State f
+ Haxl.Core: data BlockedFetch r
+ Haxl.Core: data DataSourceRoundStats
+ Haxl.Core: data Env u
+ Haxl.Core: data Flags
+ Haxl.Core: data MemoFingerprintKey a
+ Haxl.Core: data PerformFetch
+ Haxl.Core: data RoundStats
+ Haxl.Core: data StateStore
+ Haxl.Core: dataFetch :: (DataSource u r, Request r a) => r a -> GenHaxl u a
+ Haxl.Core: dataSourceName :: DataSourceName req => req a -> Text
+ Haxl.Core: defaultFlags :: Flags
+ Haxl.Core: dumpCacheAsHaskell :: GenHaxl u String
+ Haxl.Core: emptyEnv :: u -> IO (Env u)
+ Haxl.Core: emptyStats :: Stats
+ Haxl.Core: env :: (Env u -> a) -> GenHaxl u a
+ Haxl.Core: except :: (Exception e) => e -> Either SomeException a
+ Haxl.Core: fetch :: DataSource u req => State req -> Flags -> u -> [BlockedFetch req] -> PerformFetch
+ Haxl.Core: ifReport :: (Functor m, Monad m) => Flags -> Int -> m a -> m ()
+ Haxl.Core: ifTrace :: (Functor m, Monad m) => Flags -> Int -> m a -> m ()
+ Haxl.Core: initEnv :: StateStore -> u -> IO (Env u)
+ Haxl.Core: initEnvWithData :: StateStore -> u -> Caches u -> IO (Env u)
+ Haxl.Core: memo :: (Typeable a, Typeable k, Hashable k, Eq k) => k -> GenHaxl u a -> GenHaxl u a
+ Haxl.Core: memoFingerprint :: (Show a, Typeable a) => MemoFingerprintKey a -> GenHaxl u a -> GenHaxl u a
+ Haxl.Core: newEmptyResult :: IO (ResultVar a)
+ Haxl.Core: newResult :: a -> IO (ResultVar a)
+ Haxl.Core: newtype GenHaxl u a
+ Haxl.Core: newtype ResultVar a
+ Haxl.Core: newtype Stats
+ Haxl.Core: numFetches :: Stats -> Int
+ Haxl.Core: numRounds :: Stats -> Int
+ Haxl.Core: ppDataSourceRoundStats :: DataSourceRoundStats -> String
+ Haxl.Core: ppRoundStats :: RoundStats -> String
+ Haxl.Core: ppStats :: Stats -> String
+ Haxl.Core: putFailure :: (Exception e) => ResultVar a -> e -> IO ()
+ Haxl.Core: putResult :: ResultVar a -> Either SomeException a -> IO ()
+ Haxl.Core: putSuccess :: ResultVar a -> a -> IO ()
+ Haxl.Core: runHaxl :: Env u -> GenHaxl u a -> IO a
+ Haxl.Core: setError :: (Exception e) => (forall a. r a -> e) -> BlockedFetch r -> IO ()
+ Haxl.Core: show1 :: Show1 f => f a -> String
+ Haxl.Core: stateEmpty :: StateStore
+ Haxl.Core: stateGet :: StateKey r => StateStore -> Maybe (State r)
+ Haxl.Core: stateSet :: StateKey f => State f -> StateStore -> StateStore
+ Haxl.Core: stubFetch :: (Exception e) => (forall a. r a -> e) -> State r -> Flags -> u -> [BlockedFetch r] -> PerformFetch
+ Haxl.Core: syncFetch :: ((service -> IO ()) -> IO ()) -> (service -> IO ()) -> (forall a. service -> request a -> IO (IO (Either SomeException a))) -> State request -> Flags -> u -> [BlockedFetch request] -> PerformFetch
+ Haxl.Core: takeResult :: ResultVar a -> IO (Either SomeException a)
+ Haxl.Core: throw :: (Exception e) => e -> GenHaxl u a
+ Haxl.Core: try :: Exception e => GenHaxl u a -> GenHaxl u (Either e a)
+ Haxl.Core: tryReadResult :: ResultVar a -> IO (Maybe (Either SomeException a))
+ Haxl.Core: tryTakeResult :: ResultVar a -> IO (Maybe (Either SomeException a))
+ Haxl.Core: tryToHaxlException :: GenHaxl u a -> GenHaxl u (Either HaxlException a)
+ Haxl.Core: type Caches u = (IORef (DataCache ResultVar), IORef (DataCache (MemoVar u)))
+ Haxl.Core: type Microseconds = Int
+ Haxl.Core: type Request req a = (Eq (req a), Hashable (req a), Typeable (req a), Show (req a), Show a)
+ Haxl.Core: uncachedRequest :: (DataSource u r, Request r a) => r a -> GenHaxl u a
+ Haxl.Core: withEnv :: Env u -> GenHaxl u a -> GenHaxl u a
+ Haxl.Core.DataCache: insertNotShowable :: (Hashable (req a), Typeable (req a), Eq (req a)) => req a -> res a -> DataCache res -> DataCache res
+ Haxl.Core.Exception: instance Data.Aeson.Types.Class.ToJSON Haxl.Core.Exception.HaxlException
+ Haxl.Core.Exception: instance GHC.Classes.Eq Haxl.Core.Exception.CriticalError
+ Haxl.Core.Exception: instance GHC.Classes.Eq Haxl.Core.Exception.DataSourceError
+ Haxl.Core.Exception: instance GHC.Classes.Eq Haxl.Core.Exception.EmptyList
+ Haxl.Core.Exception: instance GHC.Classes.Eq Haxl.Core.Exception.FetchError
+ Haxl.Core.Exception: instance GHC.Classes.Eq Haxl.Core.Exception.InvalidParameter
+ Haxl.Core.Exception: instance GHC.Classes.Eq Haxl.Core.Exception.JSONError
+ Haxl.Core.Exception: instance GHC.Classes.Eq Haxl.Core.Exception.NotFound
+ Haxl.Core.Exception: instance GHC.Classes.Eq Haxl.Core.Exception.UnexpectedType
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.CriticalError
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.DataSourceError
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.EmptyList
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.FetchError
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.HaxlException
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.InternalError
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.InvalidParameter
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.JSONError
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.LogicError
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.NotFound
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.TransientError
+ Haxl.Core.Exception: instance GHC.Exception.Exception Haxl.Core.Exception.UnexpectedType
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.CriticalError
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.DataSourceError
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.EmptyList
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.FetchError
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.HaxlException
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.InternalError
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.InvalidParameter
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.JSONError
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.LogicError
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.NotFound
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.TransientError
+ Haxl.Core.Exception: instance GHC.Show.Show Haxl.Core.Exception.UnexpectedType
+ Haxl.Core.Exception: instance Haxl.Core.Exception.MiddleException Haxl.Core.Exception.InternalError
+ Haxl.Core.Exception: instance Haxl.Core.Exception.MiddleException Haxl.Core.Exception.LogicError
+ Haxl.Core.Exception: instance Haxl.Core.Exception.MiddleException Haxl.Core.Exception.TransientError
+ Haxl.Core.Memo: MemoFingerprintKey :: {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Word64 -> MemoFingerprintKey a
+ Haxl.Core.Memo: data MemoFingerprintKey a
+ Haxl.Core.Memo: instance Data.Hashable.Class.Hashable (Haxl.Core.Memo.MemoFingerprintKey a)
+ Haxl.Core.Memo: instance Data.Hashable.Class.Hashable (Haxl.Core.Memo.MemoKey k a)
+ Haxl.Core.Memo: instance Data.Hashable.Class.Hashable (Haxl.Core.Memo.MemoTextKey a)
+ Haxl.Core.Memo: instance GHC.Classes.Eq (Haxl.Core.Memo.MemoFingerprintKey a)
+ Haxl.Core.Memo: instance GHC.Classes.Eq (Haxl.Core.Memo.MemoKey k a)
+ Haxl.Core.Memo: instance GHC.Classes.Eq (Haxl.Core.Memo.MemoTextKey a)
+ Haxl.Core.Memo: instance GHC.Show.Show (Haxl.Core.Memo.MemoFingerprintKey a)
+ Haxl.Core.Memo: instance GHC.Show.Show (Haxl.Core.Memo.MemoTextKey a)
+ Haxl.Core.Memo: memo :: (Typeable a, Typeable k, Hashable k, Eq k) => k -> GenHaxl u a -> GenHaxl u a
+ Haxl.Core.Memo: memoFingerprint :: (Show a, Typeable a) => MemoFingerprintKey a -> GenHaxl u a -> GenHaxl u a
+ Haxl.Core.Monad: [cacheRef] :: Env u -> IORef (DataCache ResultVar)
+ Haxl.Core.Monad: [flags] :: Env u -> Flags
+ Haxl.Core.Monad: [memoRef] :: Env u -> IORef (DataCache (MemoVar u))
+ Haxl.Core.Monad: [states] :: Env u -> StateStore
+ Haxl.Core.Monad: [statsRef] :: Env u -> IORef Stats
+ Haxl.Core.Monad: [unHaxl] :: GenHaxl u a -> Env u -> IORef (RequestStore u) -> IO (Result u a)
+ Haxl.Core.Monad: [userEnv] :: Env u -> u
+ Haxl.Core.Monad: instance Data.String.IsString a => Data.String.IsString (Haxl.Core.Monad.GenHaxl u a)
+ Haxl.Core.Monad: instance GHC.Base.Applicative (Haxl.Core.Monad.GenHaxl u)
+ Haxl.Core.Monad: instance GHC.Base.Functor (Haxl.Core.Monad.GenHaxl u)
+ Haxl.Core.Monad: instance GHC.Base.Monad (Haxl.Core.Monad.GenHaxl u)
+ Haxl.Core.Monad: instance GHC.Show.Show a => GHC.Show.Show (Haxl.Core.Monad.Result u a)
+ Haxl.Core.Monad: type Caches u = (IORef (DataCache ResultVar), IORef (DataCache (MemoVar u)))
+ Haxl.Core.Monad: withEnv :: Env u -> GenHaxl u a -> GenHaxl u a
+ Haxl.Core.Types: [dataSourceFetches] :: DataSourceRoundStats -> Int
+ Haxl.Core.Types: [dataSourceTime] :: DataSourceRoundStats -> Maybe Microseconds
+ Haxl.Core.Types: [report] :: Flags -> Int
+ Haxl.Core.Types: [roundDataSources] :: RoundStats -> HashMap Text DataSourceRoundStats
+ Haxl.Core.Types: [roundTime] :: RoundStats -> Microseconds
+ Haxl.Core.Types: [trace] :: Flags -> Int
+ Haxl.Core.Types: instance Data.Aeson.Types.Class.ToJSON Haxl.Core.Types.DataSourceRoundStats
+ Haxl.Core.Types: instance Data.Aeson.Types.Class.ToJSON Haxl.Core.Types.RoundStats
+ Haxl.Core.Types: instance Data.Aeson.Types.Class.ToJSON Haxl.Core.Types.Stats
+ Haxl.Prelude: instance (u1 ~ u2) => Haxl.Prelude.IfThenElse (Haxl.Core.Monad.GenHaxl u1 GHC.Types.Bool) (Haxl.Core.Monad.GenHaxl u2 a)
+ Haxl.Prelude: instance GHC.Num.Num a => GHC.Num.Num (Haxl.Core.Monad.GenHaxl u a)
+ Haxl.Prelude: instance GHC.Real.Fractional a => GHC.Real.Fractional (Haxl.Core.Monad.GenHaxl u a)
+ Haxl.Prelude: instance Haxl.Prelude.IfThenElse GHC.Types.Bool a
+ Haxl.Prelude: memo :: (Typeable a, Typeable k, Hashable k, Eq k) => k -> GenHaxl u a -> GenHaxl u a
- Haxl.Core.Exception: internalErrorFromException :: Exception e => SomeException -> Maybe e
+ Haxl.Core.Exception: internalErrorFromException :: (Exception e) => SomeException -> Maybe e
- Haxl.Core.Exception: internalErrorToException :: Exception e => e -> SomeException
+ Haxl.Core.Exception: internalErrorToException :: (Exception e) => e -> SomeException
- Haxl.Core.Exception: logicErrorFromException :: Exception e => SomeException -> Maybe e
+ Haxl.Core.Exception: logicErrorFromException :: (Exception e) => SomeException -> Maybe e
- Haxl.Core.Exception: logicErrorToException :: Exception e => e -> SomeException
+ Haxl.Core.Exception: logicErrorToException :: (Exception e) => e -> SomeException
- Haxl.Core.Exception: transientErrorFromException :: Exception e => SomeException -> Maybe e
+ Haxl.Core.Exception: transientErrorFromException :: (Exception e) => SomeException -> Maybe e
- Haxl.Core.Exception: transientErrorToException :: Exception e => e -> SomeException
+ Haxl.Core.Exception: transientErrorToException :: (Exception e) => e -> SomeException
- Haxl.Core.Monad: cacheRequest :: Request req a => req a -> Either SomeException a -> GenHaxl u ()
+ Haxl.Core.Monad: cacheRequest :: (Request req a) => req a -> Either SomeException a -> GenHaxl u ()
- Haxl.Core.Monad: cacheResult :: Request r a => r a -> IO a -> GenHaxl u a
+ Haxl.Core.Monad: cacheResult :: (Request r a) => r a -> IO a -> GenHaxl u a
- Haxl.Core.Monad: cachedComputation :: Request req a => req a -> GenHaxl u a -> GenHaxl u a
+ Haxl.Core.Monad: cachedComputation :: (Eq (req a), Hashable (req a), Typeable (req a)) => req a -> GenHaxl u a -> GenHaxl u a
- Haxl.Core.Monad: throw :: Exception e => e -> GenHaxl u a
+ Haxl.Core.Monad: throw :: (Exception e) => e -> GenHaxl u a
- Haxl.Core.RequestStore: addRequest :: DataSource u r => BlockedFetch r -> RequestStore u -> RequestStore u
+ Haxl.Core.RequestStore: addRequest :: (DataSource u r) => BlockedFetch r -> RequestStore u -> RequestStore u
- Haxl.Core.Types: except :: Exception e => e -> Either SomeException a
+ Haxl.Core.Types: except :: (Exception e) => e -> Either SomeException a
- Haxl.Core.Types: putFailure :: Exception e => ResultVar a -> e -> IO ()
+ Haxl.Core.Types: putFailure :: (Exception e) => ResultVar a -> e -> IO ()
- Haxl.Core.Types: setError :: Exception e => (forall a. r a -> e) -> BlockedFetch r -> IO ()
+ Haxl.Core.Types: setError :: (Exception e) => (forall a. r a -> e) -> BlockedFetch r -> IO ()
- Haxl.Core.Types: stubFetch :: Exception e => (forall a. r a -> e) -> State r -> Flags -> u -> [BlockedFetch r] -> PerformFetch
+ Haxl.Core.Types: stubFetch :: (Exception e) => (forall a. r a -> e) -> State r -> Flags -> u -> [BlockedFetch r] -> PerformFetch
- Haxl.Prelude: foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
+ Haxl.Prelude: foldM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
- Haxl.Prelude: foldl' :: (b -> a -> b) -> b -> [a] -> b
+ Haxl.Prelude: foldl' :: Foldable t => forall b a. (b -> a -> b) -> b -> t a -> b
- Haxl.Prelude: throw :: Exception e => e -> GenHaxl u a
+ Haxl.Prelude: throw :: (Exception e) => e -> GenHaxl u a

Files

Haxl/Core.hs view
@@ -6,15 +6,84 @@ -- be found in the PATENTS file.  -- | Everything needed to define data sources and to invoke the--- engine. This module should not be imported by user code.-module Haxl.Core-  ( module Haxl.Core.Monad-  , module Haxl.Core.Types-  , module Haxl.Core.Exception-  , module Haxl.Core.StateStore-  , module Haxl.Core.Show1+-- engine.+--+module Haxl.Core (+  -- * The monad and operations+  GenHaxl (..), runHaxl,++  -- ** Env+  Env(..), Caches, caches,+  -- *** Operations in the monad+  env, withEnv,+  -- *** Building the Env+  initEnvWithData, initEnv, emptyEnv,+  -- *** Building the StateStore+  StateStore, stateGet, stateSet, stateEmpty,++  -- ** Exceptions+  throw, catch, catchIf, try, tryToHaxlException,++  -- ** Data fetching and caching+  dataFetch, uncachedRequest,+  cacheRequest, cacheResult, cachedComputation,+  dumpCacheAsHaskell,++  -- ** Memoization+  memo, memoFingerprint, MemoFingerprintKey(..),++  -- ** Statistics+  Stats(..),+  RoundStats(..),+  DataSourceRoundStats(..),+  Microseconds,+  emptyStats,+  numRounds,+  numFetches,+  ppStats,+  ppRoundStats,+  ppDataSourceRoundStats,++  -- ** Tracing flags+  Flags(..),+  defaultFlags,+  ifTrace,+  ifReport,++  -- * Building data sources+  DataSource(..),+  Show1(..),+  DataSourceName(..),+  Request,+  BlockedFetch(..),+  PerformFetch(..),+  StateKey(..),++  -- ** Result variables+  ResultVar(..),+  newEmptyResult,+  newResult,+  putFailure,+  putResult,+  putSuccess,+  takeResult,+  tryReadResult,+  tryTakeResult,++  -- ** Default fetch implementations+  asyncFetch, asyncFetchWithDispatch,+  stubFetch,+  syncFetch,++  -- ** Utilities+  except,+  setError,++  -- * Exceptions+  module Haxl.Core.Exception   ) where +import Haxl.Core.Memo import Haxl.Core.Monad hiding (unsafeLiftIO {- Ask nicely to get this! -}) import Haxl.Core.Types import Haxl.Core.Exception
Haxl/Core/DataCache.hs view
@@ -10,11 +10,14 @@ {-# LANGUAGE RankNTypes #-} {-# OPTIONS_GHC -fno-warn-orphans #-} --- | A cache mapping data requests to their results.+-- | A cache mapping data requests to their results.  This module is+-- provided for access to Haxl internals only; most users should not+-- need to import it. module Haxl.Core.DataCache   ( DataCache   , empty   , insert+  , insertNotShowable   , lookup   , showCache   ) where@@ -47,8 +50,8 @@ -- This works well because we only have to store the dictionaries for -- 'Hashable' and 'Eq' once per request type. data SubCache res =-  forall req a . (Hashable (req a), Eq (req a), Show (req a), Show a) =>-       SubCache ! (HashMap (req a) (res a))+  forall req a . (Hashable (req a), Eq (req a)) =>+       SubCache (req a -> String) (a -> String) ! (HashMap (req a) (res a))        -- NB. the inner HashMap is strict, to avoid building up        -- a chain of thunks during repeated insertions. @@ -67,13 +70,36 @@   -> DataCache res  insert req result (DataCache m) =-      DataCache $-        HashMap.insertWith fn (typeOf req)-                              (SubCache (HashMap.singleton req result)) m+  DataCache $+    HashMap.insertWith fn (typeOf req)+       (SubCache show show (HashMap.singleton req result)) m   where-    fn (SubCache new) (SubCache old) =-        SubCache (unsafeCoerce new `HashMap.union` old)+    fn (SubCache _ _ new) (SubCache showReq showRes old) =+      SubCache showReq showRes (unsafeCoerce new `HashMap.union` old) +-- | Inserts a request-result pair into the 'DataCache', without+-- requiring Show instances of the request or the result.  The cache+-- cannot be subsequently used with `showCache`.+insertNotShowable+  :: (Hashable (req a), Typeable (req a), Eq (req a))+  => req a+  -- ^ Request+  -> res a+  -- ^ Result+  -> DataCache res+  -> DataCache res++insertNotShowable req result (DataCache m) =+  DataCache $+    HashMap.insertWith fn (typeOf req)+       (SubCache notShowable notShowable (HashMap.singleton req result)) m+  where+    fn (SubCache _ _ new) (SubCache showReq showRes old) =+      SubCache showReq showRes (unsafeCoerce new `HashMap.union` old)++notShowable :: a+notShowable = error "insertNotShowable"+ -- | Looks up the cached result of a request. lookup   :: Typeable (req a)@@ -85,12 +111,13 @@ lookup req (DataCache m) =       case HashMap.lookup (typeOf req) m of         Nothing -> Nothing-        Just (SubCache sc) ->+        Just (SubCache _ _ sc) ->            unsafeCoerce (HashMap.lookup (unsafeCoerce req) sc)  -- | Dumps the contents of the cache, with requests and responses -- converted to 'String's using 'show'.  The entries are grouped by--- 'TypeRep'.+-- 'TypeRep'.  Note that this will fail if 'insertNotShowable' has+-- been used to insert any entries. -- showCache   :: DataCache ResultVar@@ -101,16 +128,14 @@   goSubCache     :: (TypeRep,SubCache ResultVar)     -> IO (TypeRep,[(String, Either SomeException String)])-  goSubCache (ty, SubCache hmap) = do+  goSubCache (ty, SubCache showReq showRes hmap) = do     elems <- catMaybes <$> mapM go (HashMap.toList hmap)     return (ty, elems)--  go :: (Show (req a), Show a)-     => (req a, ResultVar a)-     -> IO (Maybe (String, Either SomeException String))-  go (req, rvar) = do-    maybe_r <- tryReadResult rvar-    case maybe_r of-      Nothing -> return Nothing-      Just (Left e) -> return (Just (show req, Left e))-      Just (Right result) -> return (Just (show req, Right (show result)))+   where+    go  (req, rvar) = do+      maybe_r <- tryReadResult rvar+      case maybe_r of+        Nothing -> return Nothing+        Just (Left e) -> return (Just (showReq req, Left e))+        Just (Right result) ->+          return (Just (showReq req, Right (showRes result)))
Haxl/Core/Exception.hs view
@@ -24,7 +24,9 @@ -- 'withDefault' to be useful, for example, you'll want your -- exceptions to be children of 'LogicError' or 'TransientError' as -- appropriate.-+--+-- Most users should import "Haxl.Core" instead of importing this+-- module directly. module Haxl.Core.Exception (    HaxlException(..),@@ -188,7 +190,7 @@ -- | Generic \"critical\" exception. Something internal is -- borked. Panic. data CriticalError = CriticalError Text-  deriving (Typeable, Show)+  deriving (Typeable, Eq, Show)  instance Exception CriticalError where   toException   = internalErrorToException@@ -196,7 +198,7 @@  -- | Generic \"something was not found\" exception. data NotFound = NotFound Text-  deriving (Typeable, Show)+  deriving (Typeable, Eq, Show)  instance Exception NotFound where   toException = logicErrorToException@@ -204,7 +206,7 @@  -- | Generic \"something had the wrong type\" exception. data UnexpectedType = UnexpectedType Text-  deriving (Typeable, Show)+  deriving (Typeable, Eq, Show)  instance Exception UnexpectedType where   toException = logicErrorToException@@ -212,7 +214,7 @@  -- | Generic \"input list was empty\" exception. data EmptyList = EmptyList Text-  deriving (Typeable,Show)+  deriving (Typeable, Eq, Show)  instance Exception EmptyList where   toException = logicErrorToException@@ -220,7 +222,7 @@  -- | Generic \"Incorrect assumptions about JSON data\" exception. data JSONError = JSONError Text-  deriving (Typeable, Show)+  deriving (Typeable, Eq, Show)  instance Exception JSONError where   toException = logicErrorToException@@ -228,7 +230,7 @@  -- | Generic \"passing some invalid parameter\" exception. data InvalidParameter = InvalidParameter Text-  deriving (Typeable, Show)+  deriving (Typeable, Eq, Show)  instance Exception InvalidParameter where   toException = logicErrorToException
+ Haxl/Core/Memo.hs view
@@ -0,0 +1,93 @@+-- Copyright (c) 2014-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is distributed under the terms of a BSD license,+-- found in the LICENSE file. An additional grant of patent rights can+-- be found in the PATENTS file.++{-# LANGUAGE DeriveDataTypeable, GADTs, OverloadedStrings,+    StandaloneDeriving #-}++-- | Most users should import "Haxl.Core" instead of importing this+-- module directly.+module Haxl.Core.Memo (memo, memoFingerprint, MemoFingerprintKey(..)) where++import Data.Text (Text)+import Data.Typeable+import Data.Hashable+import Data.Word++import Haxl.Core.Monad (GenHaxl, cachedComputation)++-- -----------------------------------------------------------------------------+-- A key type that can be used for memoizing computations by a Text key++-- | Memoize a computation using an arbitrary key.  The result will be+-- calculated once; the second and subsequent time it will be returned+-- immediately.  It is the caller's responsibility to ensure that for+-- every two calls @memo key haxl@, if they have the same @key@ then+-- they compute the same result.+memo+  :: (Typeable a, Typeable k, Hashable k, Eq k)+  => k -> GenHaxl u a -> GenHaxl u a+memo key = cachedComputation (MemoKey key)++{-# RULES "memo/Text"+  memo = memoText :: (Typeable a) => Text -> GenHaxl u a -> GenHaxl u a+ #-}++{-# NOINLINE memo #-}++data MemoKey k a where+  MemoKey :: (Typeable k, Hashable k, Eq k) => k -> MemoKey k a+  deriving Typeable++deriving instance Eq (MemoKey k a)++instance Hashable (MemoKey k a) where+  hashWithSalt s (MemoKey t) = hashWithSalt s t++-- An optimised memo key for Text keys.  This is used automatically+-- when the key is Text, due to the RULES pragma above.++data MemoTextKey a where+  MemoText :: Text -> MemoTextKey a+  deriving Typeable++deriving instance Eq (MemoTextKey a)+deriving instance Show (MemoTextKey a)++instance Hashable (MemoTextKey a) where+  hashWithSalt s (MemoText t) = hashWithSalt s t++memoText :: (Typeable a) => Text -> GenHaxl u a -> GenHaxl u a+memoText key = cachedComputation (MemoText key)++-- | A memo key derived from a 128-bit MD5 hash.  Do not use this directly,+-- it is for use by automatically-generated memoization.++data MemoFingerprintKey a where+  MemoFingerprintKey+    :: {-# UNPACK #-} !Word64+    -> {-# UNPACK #-} !Word64  -> MemoFingerprintKey a+  deriving Typeable++deriving instance Eq (MemoFingerprintKey a)+deriving instance Show (MemoFingerprintKey a)++instance Hashable (MemoFingerprintKey a) where+  hashWithSalt s (MemoFingerprintKey x _) =+    hashWithSalt s (fromIntegral x :: Int)++-- This is optimised for cheap call sites: when we have a call+--+--   memoFingerprint (MemoFingerprintKey 1234 5678) e+--+-- then the MemoFingerprintKey constructor will be statically+-- allocated (with two 64-bit fields), and shared by all calls to+-- memo.  So the memo call will not allocate, unlike memoText.+--+{-# NOINLINE memoFingerprint #-}+memoFingerprint+   :: (Show a, Typeable a) => MemoFingerprintKey a -> GenHaxl u a -> GenHaxl u a+memoFingerprint key = cachedComputation key
Haxl/Core/Monad.hs view
@@ -16,14 +16,15 @@ {-# LANGUAGE PatternGuards #-} {-# LANGUAGE ScopedTypeVariables #-} --- | The implementation of the 'Haxl' monad.+-- | The implementation of the 'Haxl' monad.  Most users should+-- import "Haxl.Core" instead of importing this module directly. module Haxl.Core.Monad (     -- * The monad     GenHaxl (..), runHaxl,-    env,+    env, withEnv,      -- * Env-    Env(..), caches, initEnvWithData, initEnv, emptyEnv,+    Env(..), Caches, caches, initEnvWithData, initEnv, emptyEnv,      -- * Exceptions     throw, catch, catchIf, try, tryToHaxlException,@@ -55,15 +56,20 @@ #endif import Control.Monad import qualified Control.Exception as Exception+#if __GLASGOW_HASKELL__ < 710 import Control.Applicative hiding (Const)+#endif+import Control.DeepSeq import GHC.Exts (IsString(..)) #if __GLASGOW_HASKELL__ < 706 import Prelude hiding (catch) #endif+import Data.Hashable import Data.IORef import Data.List import Data.Monoid import Data.Time+import Data.Typeable import qualified Data.HashMap.Strict as HashMap import Text.Printf import Text.PrettyPrint hiding ((<>))@@ -107,7 +113,7 @@     , statsRef = sref     } --- | Initializes an environment with 'DataStates' and an input map.+-- | Initializes an environment with 'StateStore' and an input map. initEnv :: StateStore -> u -> IO (Env u) initEnv states e = do   cref <- newIORef DataCache.empty@@ -144,8 +150,46 @@ data Result u a   = Done a   | Throw SomeException-  | Blocked (GenHaxl u a)+  | Blocked (Cont u a) +data Cont u a+  = Cont (GenHaxl u a)+  | forall b. Cont u b :>>= (b -> GenHaxl u a)+  | forall b. (Cont u (b -> a)) :<*> (Cont u b)+  | forall b. (b -> a) :<$> (Cont u b)++toHaxl :: Cont u a -> GenHaxl u a+toHaxl (Cont haxl)           = haxl+toHaxl ((m :>>= k1) :>>= k2) = toHaxl (m :>>= (k1 >=> k2)) -- for seql+toHaxl (c :>>= k)            = toHaxl c >>= k+toHaxl ((f :<$> i) :<*> (g :<$> j)) =+  toHaxl (((\x y -> f x (g y)) :<$> i) :<*> j)          -- See Note [Tree]+toHaxl (f :<*> x)            = toHaxl f <*> toHaxl x+toHaxl (f :<$> (g :<$> x))   = toHaxl ((f . g) :<$> x)  -- fmap fusion+toHaxl (f :<$> x)            = fmap f (toHaxl x)++-- Note [Tree]+-- This implements the following re-association:+--+--           <*>+--          /   \+--       <$>     <$>+--      /   \   /   \+--     f     i g     j+--+-- to:+--+--           <*>+--          /   \+--       <$>     j+--      /   \         where h = (\x y -> f x (g y))+--     h     i+--+-- I suspect this is mostly useful because it eliminates one :<$> constructor+-- within the Blocked returned by `tree 1`, which is replicated a lot by the+-- tree benchmark (tree 1 is near the leaves). So this rule might just be+-- optimizing for a microbenchmark.+ instance (Show a) => Show (Result u a) where   show (Done a) = printf "Done(%s)" $ show a   show (Throw e) = printf "Throw(%s)" $ show e@@ -158,10 +202,18 @@     case e of       Done a       -> unHaxl (k a) env ref       Throw e      -> return (Throw e)-      Blocked cont -> return (Blocked (cont >>= k))+      Blocked cont -> return (Blocked (cont :>>= k)) +  -- We really want the Applicative version of >>+  (>>) = (*>)+ instance Functor (GenHaxl u) where-  fmap f m = pure f <*> m+  fmap f (GenHaxl m) = GenHaxl $ \env ref -> do+    r <- m env ref+    case r of+      Done a -> return (Done (f a))+      Throw e -> return (Throw e)+      Blocked a' -> return (Blocked (f :<$> a'))  instance Applicative (GenHaxl u) where   pure = return@@ -174,22 +226,22 @@         case ra of           Done a'    -> return (Done (f' a'))           Throw e    -> return (Throw e)-          Blocked a' -> return (Blocked (f' <$> a'))+          Blocked a' -> return (Blocked (f' :<$> a'))       Blocked f' -> do         ra <- a env ref  -- left is blocked, explore the right         case ra of-          Done a'    -> return (Blocked (f' <*> return a'))-          Throw e    -> return (Blocked (f' <*> throw e))-          Blocked a' -> return (Blocked (f' <*> a'))+          Done a'    -> return (Blocked (($ a') :<$> f'))+          Throw e    -> return (Blocked (f' :<*> Cont (throw e)))+          Blocked a' -> return (Blocked (f' :<*> a'))  -- | Runs a 'Haxl' computation in an 'Env'. runHaxl :: Env u -> GenHaxl u a -> IO a #ifdef EVENTLOG runHaxl env h = do-  let go !n env (GenHaxl haxl) = do+  let go !n env c = do         traceEventIO "START computation"         ref <- newIORef noRequests-        e <- haxl env ref+        e <- toHaxl c env ref         traceEventIO "STOP computation"         case e of           Done a       -> return a@@ -202,7 +254,7 @@             traceEventIO "STOP performFetches"             go n' env cont   traceEventIO "START runHaxl"-  r <- go 0 env h+  r <- go 0 env (Cont h)   traceEventIO "STOP runHaxl"   return r #else@@ -216,13 +268,23 @@       bs <- readIORef ref       writeIORef ref noRequests -- Note [RoundId]       void (performFetches 0 env bs)-      runHaxl env cont+      runHaxl env (toHaxl cont) #endif  -- | Extracts data from the 'Env'. env :: (Env u -> a) -> GenHaxl u a env f = GenHaxl $ \env _ref -> return (Done (f env)) +-- | Returns a version of the Haxl computation which always uses the+-- provided 'Env', ignoring the one specified by 'runHaxl'.+withEnv :: Env u -> GenHaxl u a -> GenHaxl u a+withEnv newEnv (GenHaxl m) = GenHaxl $ \_env ref -> do+  r <- m newEnv ref+  case r of+    Done a -> return (Done a)+    Throw e -> return (Throw e)+    Blocked k -> return (Blocked (Cont (withEnv newEnv (toHaxl k))))+ -- ----------------------------------------------------------------------------- -- Exceptions @@ -241,7 +303,7 @@      Done a    -> return (Done a)      Throw e | Just e' <- fromException e -> unHaxl (h e') env ref              | otherwise -> return (Throw e)-     Blocked k -> return (Blocked (catch k h))+     Blocked k -> return (Blocked (Cont (catch (toHaxl k) h)))  -- | Catch exceptions that satisfy a predicate catchIf@@ -272,7 +334,7 @@ unsafeToHaxlException (GenHaxl m) = GenHaxl $ \env ref -> do   r <- m env ref `Exception.catch` \e -> return (Throw e)   case r of-    Blocked c -> return (Blocked (unsafeToHaxlException c))+    Blocked c -> return (Blocked (Cont (unsafeToHaxlException (toHaxl c))))     other -> return other  -- | Like 'try', but lifts all exceptions into the 'HaxlException'@@ -331,12 +393,12 @@     -- will be fetched in the next round.     Uncached rvar -> do       modifyIORef' ref $ \bs -> addRequest (BlockedFetch req rvar) bs-      return $ Blocked (continueFetch req rvar)+      return $ Blocked (Cont (continueFetch req rvar))      -- Seen before but not fetched yet.  We're blocked, but we don't have     -- to add the request to the RequestStore.     CachedNotFetched rvar -> return-      $ Blocked (continueFetch req rvar)+      $ Blocked (Cont (continueFetch req rvar))      -- Cached: either a result, or an exception     Cached (Left ex) -> return (Throw ex)@@ -357,7 +419,7 @@ uncachedRequest req = GenHaxl $ \_env ref -> do   rvar <- newEmptyResult   modifyIORef' ref $ \bs -> addRequest (BlockedFetch req rvar) bs-  return $ Blocked (continueFetch req rvar)+  return $ Blocked (Cont (continueFetch req rvar))  continueFetch   :: (DataSource u r, Request r a, Show a)@@ -526,7 +588,7 @@   let roundtime = realToFrac (diffUTCTime t1 t0) :: Double    ifReport f 1 $-    modifyIORef' sref $ \(Stats rounds) ->+    modifyIORef' sref $ \(Stats rounds) -> roundstats `deepseq`       Stats (RoundStats (microsecs roundtime) dsroundstats: rounds)    ifTrace f 1 $@@ -645,21 +707,26 @@ -- of 'dumpCacheAsHaskell'. -- cachedComputation-   :: forall req u a. (Request req a)+   :: forall req u a.+      (Eq (req a)+      , Hashable (req a)+      , Typeable (req a))    => req a -> GenHaxl u a -> GenHaxl u a+ cachedComputation req haxl = GenHaxl $ \env ref -> do   cache <- readIORef (memoRef env)   case DataCache.lookup req cache of     Nothing -> do       memovar <- newIORef (MemoInProgress ref haxl)-      writeIORef (memoRef env) $! DataCache.insert req (MemoVar memovar) cache+      writeIORef (memoRef env) $!+        DataCache.insertNotShowable req (MemoVar memovar) cache       run memovar haxl env ref     Just (MemoVar memovar) -> do       status <- readIORef memovar       case status of         MemoDone r -> done r         MemoInProgress round cont-          | round == ref -> return (Blocked (retryMemo req))+          | round == ref -> return (Blocked (Cont (retryMemo req)))           | otherwise    -> run memovar cont env ref           -- was blocked in a previous round; run the saved continuation to           -- make more progress.@@ -688,8 +755,8 @@       Done a -> complete memovar (Right a)       Throw e -> complete memovar (Left e)       Blocked cont -> do-        writeIORef memovar (MemoInProgress ref cont)-        return (Blocked (retryMemo req))+        writeIORef memovar (MemoInProgress ref (toHaxl cont))+        return (Blocked (Cont (retryMemo req)))    -- We're finished: store the final result   complete memovar r = do
Haxl/Core/RequestStore.hs view
@@ -16,6 +16,8 @@ -- of requests, the 'contents' operation extracts the fetches, bucketed -- by 'DataSource'. --+-- This module is provided for access to Haxl internals only; most+-- users should not need to import it. module Haxl.Core.RequestStore (     BlockedFetches(..), RequestStore,     noRequests, addRequest, contents
Haxl/Core/Show1.hs view
@@ -5,6 +5,8 @@ -- found in the LICENSE file. An additional grant of patent rights can -- be found in the PATENTS file. +-- Most users should import "Haxl.Core" instead of importing this+-- module directly. module Haxl.Core.Show1   ( Show1(..)   ) where
Haxl/Core/StateStore.hs view
@@ -11,6 +11,8 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE CPP #-} +-- | Most users should import "Haxl.Core" instead of importing this+-- module directly. module Haxl.Core.StateStore (     StateKey(..), StateStore, stateGet, stateSet, stateEmpty   ) where
Haxl/Core/Types.hs view
@@ -17,12 +17,10 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} --- | Base types used by all of Haxl.+-- | Base types used by all of Haxl. Most users should import+-- "Haxl.Core" instead of importing this module directly. module Haxl.Core.Types ( -  -- * Initialization strategies-  InitStrategy(..),-   -- * Tracing flags   Flags(..),   defaultFlags,@@ -91,16 +89,6 @@ import Haxl.Core.Show1 import Haxl.Core.StateStore --- | Initialization strategy. 'FullInit' will do as much initialization as--- possible. 'FastInit' will postpone part of initialization or omit part of--- initialization by sharing more resources. Use 'FastInit' if you want--- fast initialization but don't care much about performance, for example, in--- interactive environment.-data InitStrategy-  = FullInit-  | FastInit-  deriving (Enum, Eq, Show)- -- | Flags that control the operation of the engine. data Flags = Flags   { trace :: Int@@ -201,7 +189,7 @@ class (DataSourceName req, StateKey req, Show1 req) => DataSource u req where    -- | Issues a list of fetches to this 'DataSource'. The 'BlockedFetch'-  -- objects contain both the request and the 'MVar's into which to put+  -- objects contain both the request and the 'ResultVar's into which to put   -- the results.   fetch     :: State req@@ -263,7 +251,7 @@ -- --   * The request to fetch (with result type @a@) -----   * An 'MVar' to store either the result or an error+--   * A 'ResultVar' to store either the result or an error -- -- We often want to collect together multiple requests, but they return -- different types, and the type system wouldn't let us put them@@ -271,10 +259,10 @@ -- same type. So we wrap up these types inside the 'BlockedFetch' type, -- so that they all look the same and we can put them in a list. ----- When we unpack the 'BlockedFetch' and get the request and the 'MVar'+-- When we unpack the 'BlockedFetch' and get the request and the 'ResultVar' -- out, the type system knows that the result type of the request--- matches the type parameter of the 'MVar', so it will let us take the--- result of the request and store it in the 'MVar'.+-- matches the type parameter of the 'ResultVar', so it will let us take the+-- result of the request and store it in the 'ResultVar'. -- data BlockedFetch r = forall a. BlockedFetch (r a) (ResultVar a) @@ -285,9 +273,11 @@ except :: (Exception e) => e -> Either SomeException a except = Left . toException --- | A sink for the result of a data fetch, used by 'BlockedFetch' and the--- 'DataCache'. Why do we need an 'MVar' here?  The reason is that the cache--- serves two purposes:+-- | A sink for the result of a data fetch in 'BlockedFetch'+newtype ResultVar a = ResultVar (MVar (Either SomeException a))++-- Why do we need an 'MVar' here?  The reason is that the+-- cache serves two purposes: -- --  1. To cache the results of requests that were submitted in a previous round. --@@ -304,8 +294,6 @@ --     current round, and after the round we can read the result of each request --     from its 'MVar'. All instances of identical requests will share the same --     'MVar' to obtain the result.----newtype ResultVar a = ResultVar (MVar (Either SomeException a))  newResult :: a -> IO (ResultVar a) newResult x = ResultVar <$> newMVar (Right x)
Haxl/Prelude.hs view
@@ -13,7 +13,7 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}  -- | Support for using Haxl as a DSL.  This module provides most of--- the standard Prelude, plus a selection of stuff that makes it+-- the standard Prelude, plus a selection of stuff that makes -- Haxl client code cleaner and more concise. -- -- We intend Haxl client code to:@@ -32,7 +32,7 @@     module Prelude,      -- * Haxl and Fetching data-    GenHaxl, dataFetch, DataSource,+    GenHaxl, dataFetch, DataSource, memo,      -- * Extra Monad and Applicative things     Applicative(..),@@ -66,6 +66,7 @@  import Haxl.Core.Types import Haxl.Core.Exception+import Haxl.Core.Memo import Haxl.Core.Monad  import Control.Applicative
PATENTS view
@@ -1,23 +1,33 @@-Additional Grant of Patent Rights+Additional Grant of Patent Rights Version 2  "Software" means the Haxl software distributed by Facebook, Inc. -Facebook hereby grants you a perpetual, worldwide, royalty-free, non-exclusive,-irrevocable (subject to the termination provision below) license under any-rights in any patent claims owned by Facebook, to make, have made, use, sell,-offer to sell, import, and otherwise transfer the Software. For avoidance of-doubt, no license is granted under Facebook's rights in any patent claims that-are infringed by (i) modifications to the Software made by you or a third party,-or (ii) the Software in combination with any software or other technology-provided by you or a third party.+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable+(subject to the termination provision below) license under any Necessary+Claims, to make, have made, use, sell, offer to sell, import, and otherwise+transfer the Software. For avoidance of doubt, no license is granted under+Facebook’s rights in any patent claims that are infringed by (i) modifications+to the Software made by you or any third party or (ii) the Software in+combination with any software or other technology.  The license granted hereunder will terminate, automatically and without notice,-for anyone that makes any claim (including by filing any lawsuit, assertion or-other action) alleging (a) direct, indirect, or contributory infringement or-inducement to infringe any patent: (i) by Facebook or any of its subsidiaries or-affiliates, whether or not such claim is related to the Software, (ii) by any-party if such claim arises in whole or in part from any software, product or-service of Facebook or any of its subsidiaries or affiliates, whether or not-such claim is related to the Software, or (iii) by any party relating to the-Software; or (b) that any right in any patent claim of Facebook is invalid or-unenforceable.+if you (or any of your subsidiaries, corporate affiliates or agents) initiate+directly or indirectly, or take a direct financial interest in, any Patent+Assertion: (i) against Facebook or any of its subsidiaries or corporate+affiliates, (ii) against any party if such Patent Assertion arises in whole or+in part from any software, technology, product or service of Facebook or any of+its subsidiaries or corporate affiliates, or (iii) against any party relating+to the Software. Notwithstanding the foregoing, if Facebook or any of its+subsidiaries or corporate affiliates files a lawsuit alleging patent+infringement against you in the first instance, and you respond by filing a+patent infringement counterclaim in that lawsuit against that party that is+unrelated to the Software, the license granted hereunder will not terminate+under section (i) of this paragraph due to such counterclaim.++A "Necessary Claim" is a claim of a patent owned by Facebook that is+necessarily infringed by the Software standing alone.++A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,+or contributory infringement or inducement to infringe any patent, including a+cross-claim or counterclaim.
+ changelog.md view
@@ -0,0 +1,19 @@+# Changes in version 0.3.0.0++  * Some performance improvements, including avoiding quadratic+    slowdown with left-associated binds.++  * Documentation cleanup; Haxl.Core is the single entry point for the+    core and engine docs.++  * (>>) is now defined to be (*>), and therefore no longer forces+    sequencing.  This can have surprising consequences if you are+    using Haxl with side-effecting data sources, so watch out!++  * New function withEnv, for running a sub-computation in a local Env++  * Add a higher-level memoization API, see 'memo'++  * Show is no longer required for keys in cachedComputation++  * Exceptions now have `Eq` instances
haxl.cabal view
@@ -1,5 +1,5 @@ name:                haxl-version:             0.2.0.0+version:             0.3.0.0 synopsis:            A Haskell library for efficient, concurrent,                      and concise data access. homepage:            https://github.com/facebook/Haxl@@ -17,11 +17,23 @@ description:   Haxl is a library and EDSL for efficient scheduling of concurrent data   accesses with a concise applicative API.+  .+  To use Haxl, you need to implement one or more /data sources/, which+  provide the means for accessing remote data or other I/O that you+  want to perform using Haxl.+  .+  Haxl provides two top-level modules:+  .+  * /Data-source implementations/ import "Haxl.Core",+  .+  * /Client code/ import your data sources and "Haxl.Prelude", or some+   other client-level API that you provide.  extra-source-files:   readme.md   PATENTS   tests/LoadCache.txt+  changelog.md  library @@ -31,6 +43,7 @@     base == 4.*,     bytestring >= 0.9 && < 0.11,     containers == 0.5.*,+    deepseq,     directory >= 1.1 && < 1.3,     filepath >= 1.3 && < 1.5,     hashable == 1.2.*,@@ -49,6 +62,7 @@     Haxl.Core.StateStore,     Haxl.Core.Show1,     Haxl.Core.Types,+    Haxl.Core.Memo,     Haxl.Prelude    other-modules:@@ -94,8 +108,26 @@     MockTAO     TestExampleDataSource     TestTypes+    TestUtils    type:     exitcode-stdio-1.0    default-language: Haskell2010++executable monadbench+  default-language:+    Haskell2010+  hs-source-dirs:+    tests+  build-depends:+    base,+    haxl,+    hashable,+    time+  main-is:+    MonadBench.hs+  other-modules:+    ExampleDataSource+  ghc-options:+    -O2 -main-is MonadBench -rtsopts
tests/BatchTests.hs view
@@ -2,13 +2,11 @@ module BatchTests (tests) where  import TestTypes+import TestUtils import MockTAO  import Control.Applicative-import Data.IORef-import Data.Aeson import Test.HUnit-import qualified Data.HashMap.Strict as HashMap  import Haxl.Core @@ -17,51 +15,6 @@  -- ----------------------------------------------------------------------------- -testinput :: Object-testinput = HashMap.fromList [-  "A" .= (1 :: Int),-  "B" .= (2 :: Int),-  "C" .= (3 :: Int),-  "D" .= (4 :: Int) ]--makeTestEnv :: IO (Env UserEnv)-makeTestEnv = do-  tao <- MockTAO.initGlobalState-  let st = stateSet tao stateEmpty-  initEnv st testinput--expectRoundsWithEnv-  :: (Eq a, Show a) => Int -> a -> Haxl a -> Env UserEnv -> Assertion-expectRoundsWithEnv n result haxl env = do-  a <- runHaxl env haxl-  assertEqual "result" result a-  stats <- readIORef (statsRef env)-  assertEqual "rounds" n (numRounds stats)--expectRounds :: (Eq a, Show a) => Int -> a -> Haxl a -> Assertion-expectRounds n result haxl = do-  env <- makeTestEnv-  expectRoundsWithEnv n result haxl env--expectFetches :: (Eq a, Show a) => Int -> Haxl a -> Assertion-expectFetches n haxl = do-  env <- makeTestEnv-  _ <- runHaxl env haxl-  stats <- readIORef (statsRef env)-  assertEqual "fetches" n (numFetches stats)--friendsOf :: Id -> Haxl [Id]-friendsOf = assocRangeId2s friendsAssoc--id1 :: Haxl Id-id1 = lookupInput "A"--id2 :: Haxl Id-id2 = lookupInput "B"--id3 :: Haxl Id-id3 = lookupInput "C"- -- -- Test batching over multiple arguments in liftA2 --@@ -142,6 +95,12 @@   b = length <$> (id2 >>= friendsOf)   c = length <$> (id3 >>= friendsOf) +-- (>>) should batch, so we expect one round+batching9 = expectRounds 1 6 batching9_++batching9_ :: Haxl Int+batching9_ = (id1 >>= friendsOf) >> (length <$> (id2 >>= friendsOf))+ -- -- Test data caching, numFetches --@@ -179,24 +138,6 @@   -- ensure no more data fetching rounds needed   expectRoundsWithEnv 0 12 batching7_ env2 -tests = TestList-  [ TestLabel "batching1" $ TestCase batching1-  , TestLabel "batching2" $ TestCase batching2-  , TestLabel "batching3" $ TestCase batching3-  , TestLabel "batching4" $ TestCase batching4-  , TestLabel "batching5" $ TestCase batching5-  , TestLabel "batching6" $ TestCase batching6-  , TestLabel "batching7" $ TestCase batching7-  , TestLabel "batching8" $ TestCase batching8-  , TestLabel "caching1" $ TestCase caching1-  , TestLabel "caching2" $ TestCase caching2-  , TestLabel "caching3" $ TestCase caching3-  , TestLabel "CacheReuse" $ TestCase cacheReuse-  , TestLabel "exceptionTest1" $ TestCase exceptionTest1-  , TestLabel "exceptionTest2" $ TestCase exceptionTest2-  , TestLabel "deterministicExceptions" $ TestCase deterministicExceptions-  ]- exceptionTest1 = expectRounds 1 []   $ withDefault [] $ friendsOf 101 @@ -224,3 +165,22 @@     case r of      Left (NotFound "xxx") -> True      _ -> False++tests = TestList+  [ TestLabel "batching1" $ TestCase batching1+  , TestLabel "batching2" $ TestCase batching2+  , TestLabel "batching3" $ TestCase batching3+  , TestLabel "batching4" $ TestCase batching4+  , TestLabel "batching5" $ TestCase batching5+  , TestLabel "batching6" $ TestCase batching6+  , TestLabel "batching7" $ TestCase batching7+  , TestLabel "batching8" $ TestCase batching8+  , TestLabel "batching9" $ TestCase batching9+  , TestLabel "caching1" $ TestCase caching1+  , TestLabel "caching2" $ TestCase caching2+  , TestLabel "caching3" $ TestCase caching3+  , TestLabel "CacheReuse" $ TestCase cacheReuse+  , TestLabel "exceptionTest1" $ TestCase exceptionTest1+  , TestLabel "exceptionTest2" $ TestCase exceptionTest2+  , TestLabel "deterministicExceptions" $ TestCase deterministicExceptions+  ]
tests/ExampleDataSource.hs view
@@ -12,7 +12,7 @@     initGlobalState,      -- * requests for this data source-    ExampleReq(..),+    Id(..), ExampleReq(..),     countAardvarks,     listWombats,   ) where@@ -142,8 +142,9 @@ fetch1 (BlockedFetch (CountAardvarks str) m) =   putSuccess m (length (filter (== 'a') str)) fetch1 (BlockedFetch (ListWombats a) r) =-  if a > 99 then putFailure r $ FetchError "too large"-            else putSuccess r $ take (fromIntegral a) [1..]+  if a > 999999+    then putFailure r $ FetchError "too large"+    else putSuccess r $ take (fromIntegral a) [1..]   -- Normally a data source will provide some convenient wrappers for
tests/Main.hs view
@@ -1,10 +1,13 @@-{-# LANGUAGE RebindableSyntax, OverloadedStrings #-}+{-# LANGUAGE CPP, RebindableSyntax, OverloadedStrings #-} module Main where  import TestExampleDataSource import BatchTests import CoreTests import DataCacheTest+#ifdef HAVE_APPLICATIVEDO+import AdoTests+#endif  import Data.String import Test.HUnit@@ -17,4 +20,7 @@   , TestLabel "BatchTests" BatchTests.tests   , TestLabel "CoreTests" CoreTests.tests   , TestLabel "DataCacheTests" DataCacheTest.tests+#ifdef HAVE_APPLICATIVEDO+  , TestLabel "AdoTests" AdoTests.tests+#endif   ]
tests/MockTAO.hs view
@@ -12,6 +12,7 @@     initGlobalState,     assocRangeId2s,     friendsAssoc,+    friendsOf,   ) where  import Data.Hashable@@ -72,3 +73,6 @@  assocRangeId2s :: Id -> Id -> Haxl [Id] assocRangeId2s a b = dataFetch (AssocRangeId2s a b)++friendsOf :: Id -> Haxl [Id]+friendsOf = assocRangeId2s friendsAssoc
+ tests/MonadBench.hs view
@@ -0,0 +1,64 @@+-- Copyright (c) 2014-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is distributed under the terms of a BSD license,+-- found in the LICENSE file. An additional grant of patent rights can+-- be found in the PATENTS file.++module MonadBench (main) where++import Control.Monad+import Data.Time.Clock+import System.Environment+import System.Exit+import System.IO+import Text.Printf++import Haxl.Prelude as Haxl+import Prelude()++import Haxl.Core++import ExampleDataSource++testEnv :: IO (Env ())+testEnv = do+  exstate <- ExampleDataSource.initGlobalState+  let st = stateSet exstate stateEmpty+  initEnv st ()++main = do+  [test,n_] <- getArgs+  let n = read n_+  env <- testEnv+  t0 <- getCurrentTime+  case test of+    -- parallel, identical queries+    "par1" -> runHaxl env $+       Haxl.sequence_ (replicate n (listWombats 3))+    -- parallel, distinct queries+    "par2" -> runHaxl env $+       Haxl.sequence_ (map listWombats [1..fromIntegral n])+    -- sequential, identical queries+    "seqr" -> runHaxl env $+       foldr andThen (return ()) (replicate n (listWombats 3))+    -- sequential, left-associated, distinct queries+    "seql" -> runHaxl env $ do+       foldl andThen (return []) (map listWombats [1.. fromIntegral n])+       return ()+    "tree" -> runHaxl env $ void $ tree n+    _ -> do+      hPutStrLn stderr "syntax: monadbench par1|par2|seqr|seql NUM"+      exitWith (ExitFailure 1)+  t1 <- getCurrentTime+  printf "%d reqs: %.2fs\n" n (realToFrac (t1 `diffUTCTime` t0) :: Double)+ where+  -- can't use >>, it is aliased to *> and we want the real bind here+  andThen x y = x >>= const y++tree :: Int -> GenHaxl () [Id]+tree 0 = listWombats 0+tree n = concat <$> Haxl.sequence+  [ tree (n-1)+  , listWombats (fromIntegral n), tree (n-1)+  ]
tests/TestExampleDataSource.hs view
@@ -31,6 +31,7 @@   TestLabel "orderTest" orderTest,   TestLabel "preCacheTest" preCacheTest,   TestLabel "cachedComputationTest" cachedComputationTest,+  TestLabel "memoTest" memoTest,   TestLabel "dataSourceExceptionTest" dataSourceExceptionTest,   TestLabel "dumpCacheAsHaskell" dumpCacheTest] @@ -118,6 +119,23 @@   r <- runHaxl env' $ x + x + countAardvarks "baba"    assertEqual "cachedComputationTest1" 62 r++  stats <- readIORef (statsRef env)+  assertEqual "fetches" 3 (numFetches stats)++-- Pretend CountAardvarks is a request computed by some Haxl code+memoTest = TestCase $ do+  env <- testEnv+  let env' = env { flags = (flags env){trace = 3} }++  let x = memo (CountAardvarks "ababa") $ do+        a <- length <$> listWombats 10+        b <- length <$> listWombats 20+        return (a + b)++  r <- runHaxl env' $ x + x + countAardvarks "baba"++  assertEqual "memoTest1" 62 r    stats <- readIORef (statsRef env)   assertEqual "fetches" 3 (numFetches stats)
+ tests/TestUtils.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE OverloadedStrings #-}+module TestUtils+  ( makeTestEnv+  , expectRoundsWithEnv+  , expectRounds+  , expectFetches+  , testinput+  , id1, id2, id3, id4+  ) where++import TestTypes+import MockTAO++import Data.IORef+import Data.Aeson+import Test.HUnit+import qualified Data.HashMap.Strict as HashMap++import Haxl.Core++import Prelude()+import Haxl.Prelude++testinput :: Object+testinput = HashMap.fromList [+  "A" .= (1 :: Int),+  "B" .= (2 :: Int),+  "C" .= (3 :: Int),+  "D" .= (4 :: Int) ]++id1 :: Haxl Id+id1 = lookupInput "A"++id2 :: Haxl Id+id2 = lookupInput "B"++id3 :: Haxl Id+id3 = lookupInput "C"++id4 :: Haxl Id+id4 = lookupInput "D"++makeTestEnv :: IO (Env UserEnv)+makeTestEnv = do+  tao <- MockTAO.initGlobalState+  let st = stateSet tao stateEmpty+  initEnv st testinput++expectRoundsWithEnv+  :: (Eq a, Show a) => Int -> a -> Haxl a -> Env UserEnv -> Assertion+expectRoundsWithEnv n result haxl env = do+  a <- runHaxl env haxl+  assertEqual "result" result a+  stats <- readIORef (statsRef env)+  assertEqual "rounds" n (numRounds stats)++expectRounds :: (Eq a, Show a) => Int -> a -> Haxl a -> Assertion+expectRounds n result haxl = do+  env <- makeTestEnv+  expectRoundsWithEnv n result haxl env++expectFetches :: (Eq a, Show a) => Int -> Haxl a -> Assertion+expectFetches n haxl = do+  env <- makeTestEnv+  _ <- runHaxl env haxl+  stats <- readIORef (statsRef env)+  assertEqual "fetches" n (numFetches stats)