Skip to content

Commit d647df3

Browse files
committed
Some Yesod cleanup/optimization
* Use sendWaiResponse * Simplify the Mongo code to avoid persistent-mongoDB * Avoid InternalState acquisition * Use runInUnboundThread for Yesod
1 parent fc9d013 commit d647df3

File tree

2 files changed

+56
-37
lines changed

2 files changed

+56
-37
lines changed

frameworks/Haskell/yesod/bench/bench.cabal

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@ executable bench
2020

2121
build-depends: base >= 4.7 && < 5
2222
, yesod >= 1.4 && < 1.5
23-
, yesod-core >= 1.4 && < 1.5
23+
, yesod-core >= 1.4.2 && < 1.5
2424
, text >= 0.11 && < 1.3
2525
, persistent >= 2.1 && < 2.2
2626
, persistent-mysql >= 2.1 && < 2.2
27-
, persistent-mongoDB >= 2.1 && < 2.2
2827
, warp >= 3.0.2.2 && < 3.1
2928
, auto-update >= 0.1.1.4 && < 0.2
3029
, primitive >= 0.5
@@ -34,3 +33,10 @@ executable bench
3433
, mongoDB
3534
, monad-logger
3635
, mtl
36+
, wai
37+
, http-types
38+
, aeson
39+
, blaze-builder
40+
, bytestring >= 0.10
41+
, resource-pool
42+
, resourcet

frameworks/Haskell/yesod/bench/src/yesod.hs

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,41 @@
1313
{-# LANGUAGE FlexibleContexts #-}
1414
{-# OPTIONS_GHC -fno-warn-orphans #-}
1515
module Main (main, resourcesApp, Widget, WorldId) where
16+
import Blaze.ByteString.Builder
17+
import Control.Concurrent (runInUnboundThread)
1618
import Control.Monad (replicateM)
1719
import Control.Monad.Logger (runNoLoggingT)
1820
import Control.Monad.Primitive (PrimState)
1921
import Control.Monad.Reader (ReaderT)
20-
import Data.Conduit.Pool (Pool)
22+
import Control.Monad.Trans.Resource (InternalState)
23+
import Data.Aeson (encode)
24+
import qualified Data.ByteString.Lazy as L
25+
import Data.Conduit.Pool (Pool, createPool)
2126
import Data.Int (Int64)
27+
import Data.Pool (withResource)
2228
import Data.Text (Text)
2329
import Database.MongoDB (Field ((:=)), (=:))
2430
import qualified Database.MongoDB as Mongo
25-
import qualified Database.Persist.MongoDB as Mongo
2631
import qualified Database.Persist.MySQL as My
2732
import Network (PortID (PortNumber))
33+
import Network.HTTP.Types
34+
import Network.Wai
2835
import qualified Network.Wai.Handler.Warp as Warp
2936
import System.Environment (getArgs)
3037
import qualified System.Random.MWC as R
3138
import Yesod hiding (Field)
39+
import Data.IORef (newIORef)
40+
import System.IO.Unsafe (unsafePerformIO)
3241

3342
mkPersist sqlSettings { mpsGeneric = True } [persistLowerCase|
3443
World sql=World
3544
randomNumber Int sql=randomNumber
36-
#ifdef MONGODB
37-
id Int64
38-
UniqueId
39-
#endif
4045
|]
4146

4247
data App = App
4348
{ appGen :: !(R.Gen (PrimState IO))
4449
, mySqlPool :: !(Pool My.SqlBackend)
45-
, mongoDBPool :: !(Pool Mongo.Connection)
50+
, mongoDBPool :: !(Pool Mongo.Pipe)
4651
}
4752

4853
-- | Not actually using the non-raw mongoDB.
@@ -53,15 +58,14 @@ mkYesod "App" [parseRoutes|
5358
/db DbR GET
5459
/dbs/#Int DbsR GET
5560

56-
#ifdef MONGODB
57-
/mongo/db MongoDbR GET
58-
/mongo/dbs/#Int MongoDbsR GET
59-
#endif
60-
6161
/mongo/raw/db MongoRawDbR GET
6262
/mongo/raw/dbs/#Int MongoRawDbsR GET
6363
|]
6464

65+
fakeInternalState :: InternalState
66+
fakeInternalState = unsafePerformIO $ newIORef $ error "fakeInternalState forced"
67+
{-# NOINLINE fakeInternalState #-}
68+
6569
instance Yesod App where
6670
makeSessionBackend _ = return Nothing
6771
{-# INLINE makeSessionBackend #-}
@@ -71,20 +75,25 @@ instance Yesod App where
7175
{-# INLINE yesodMiddleware #-}
7276
cleanPath _ = Right
7377
{-# INLINE cleanPath #-}
74-
75-
getJsonR :: Handler TypedContent
76-
getJsonR = return $ TypedContent typeJson
77-
$ toContent $ object ["message" .= ("Hello, World!" :: Text)]
78+
yesodWithInternalState _ _ = ($ fakeInternalState)
79+
{-# INLINE yesodWithInternalState #-}
80+
maximumContentLength _ _ = Nothing
81+
{-# INLINE maximumContentLength #-}
82+
83+
getJsonR :: Handler ()
84+
getJsonR = sendWaiResponse
85+
$ responseBuilder
86+
status200
87+
[("Content-Type", typeJson)]
88+
$ copyByteString
89+
$ L.toStrict
90+
$ encode
91+
$ object ["message" .= ("Hello, World!" :: Text)]
7892

7993

8094
getDbR :: Handler Value
8195
getDbR = getDb (intQuery runMySQL My.toSqlKey)
8296

83-
#ifdef MONGODB
84-
getMongoDbR :: Handler Value
85-
getMongoDbR = getDb (intQuery runMongoDB (getBy . UniqueId))
86-
#endif
87-
8897
getMongoRawDbR :: Handler Value
8998
getMongoRawDbR = getDb rawMongoIntQuery
9099

@@ -93,11 +102,6 @@ getDbsR cnt = do
93102
App {..} <- getYesod
94103
multiRandomHandler (intQuery runMySQL My.toSqlKey) cnt
95104

96-
#ifdef MONGODB
97-
getMongoDbsR :: Int -> Handler Value
98-
getMongoDbsR cnt = multiRandomHandler (intQuery runMongoDB (getBy . UniqueId)) cnt
99-
#endif
100-
101105
getMongoRawDbsR :: Int -> Handler Value
102106
getMongoRawDbsR cnt = multiRandomHandler rawMongoIntQuery cnt
103107

@@ -109,13 +113,21 @@ getDb :: (Int64 -> Handler Value) -> Handler Value
109113
getDb query = do
110114
app <- getYesod
111115
i <- liftIO (randomNumber (appGen app))
112-
query i
116+
value <- query i
117+
sendWaiResponse
118+
$ responseBuilder
119+
status200
120+
[("Content-Type", typeJson)]
121+
$ copyByteString
122+
$ L.toStrict
123+
$ encode value
113124

114125

115126
runMongoDB :: Mongo.Action Handler b -> Handler b
116127
runMongoDB f = do
117128
App {..} <- getYesod
118-
Mongo.runMongoDBPoolDef f mongoDBPool
129+
withResource mongoDBPool $ \pipe ->
130+
Mongo.access pipe Mongo.ReadStaleOk "hello_world" f
119131

120132
runMySQL :: My.SqlPersistT Handler b -> Handler b
121133
runMySQL f = do
@@ -167,26 +179,27 @@ instance ToJSON Mongo.Value where
167179

168180
main :: IO ()
169181
main = R.withSystemRandom $ \gen -> do
170-
[_cores, host] <- getArgs
182+
[cores, host] <- getArgs
171183
myPool <- runNoLoggingT $ My.createMySQLPool My.defaultConnectInfo
172184
{ My.connectUser = "benchmarkdbuser"
173185
, My.connectPassword = "benchmarkdbpass"
174186
, My.connectDatabase = "hello_world"
175187
, My.connectHost = host
176188
} 1000
177189

178-
mongoPool <- Mongo.createMongoDBPool "hello_world" host (PortNumber 27017)
179-
(Just (Mongo.MongoAuth "benchmarkdbuser" "benchmarkdbpass"))
180-
1 -- what is the optimal stripe count? 1 is said to be a good default
181-
1000
182-
3 -- 3 second timeout
190+
mongoPool <- createPool
191+
(Mongo.connect $ Mongo.Host host $ PortNumber 27017)
192+
Mongo.close
193+
(read cores) -- what is the optimal stripe count? 1 is said to be a good default
194+
3 -- 3 second timeout
195+
1000
183196

184197
app <- toWaiAppPlain App
185198
{ appGen = gen
186199
, mySqlPool = myPool
187200
, mongoDBPool = mongoPool
188201
}
189-
Warp.runSettings
202+
runInUnboundThread $ Warp.runSettings
190203
( Warp.setPort 8000
191204
$ Warp.setHost "*"
192205
$ Warp.setOnException (\_ _ -> return ())

0 commit comments

Comments
 (0)