|
@@ -2,19 +2,24 @@
|
|
{-# LANGUAGE GADTs #-}
|
|
{-# LANGUAGE GADTs #-}
|
|
{-# LANGUAGE RecordWildCards #-}
|
|
{-# LANGUAGE RecordWildCards #-}
|
|
{-# LANGUAGE EmptyDataDecls #-}
|
|
{-# LANGUAGE EmptyDataDecls #-}
|
|
|
|
+{-# LANGUAGE RankNTypes #-}
|
|
import Yesod
|
|
import Yesod
|
|
import System.Environment (getArgs)
|
|
import System.Environment (getArgs)
|
|
import qualified Network.Wai.Handler.Warp as Warp
|
|
import qualified Network.Wai.Handler.Warp as Warp
|
|
import Data.Text (Text)
|
|
import Data.Text (Text)
|
|
import Data.Conduit.Pool (Pool)
|
|
import Data.Conduit.Pool (Pool)
|
|
-import Database.Persist.Store (get, PersistValue (PersistInt64))
|
|
|
|
-import Database.Persist.MySQL
|
|
|
|
|
|
+import Database.Persist.Store (PersistValue (PersistInt64))
|
|
|
|
+import qualified Database.Persist.MySQL as My
|
|
|
|
+import qualified Database.Persist.MongoDB as Mongo
|
|
import qualified System.Random.MWC as R
|
|
import qualified System.Random.MWC as R
|
|
import Control.Monad.Primitive (PrimState)
|
|
import Control.Monad.Primitive (PrimState)
|
|
import Control.Monad (replicateM)
|
|
import Control.Monad (replicateM)
|
|
import Data.Conduit.Network (bindPort)
|
|
import Data.Conduit.Network (bindPort)
|
|
import System.Posix.Process (forkProcess)
|
|
import System.Posix.Process (forkProcess)
|
|
import Control.Monad (replicateM_)
|
|
import Control.Monad (replicateM_)
|
|
|
|
+import Network (PortID (PortNumber))
|
|
|
|
+import Control.Concurrent.Async.Lifted (mapConcurrently)
|
|
|
|
+import Data.Int (Int64)
|
|
|
|
|
|
mkPersist sqlSettings [persist|
|
|
mkPersist sqlSettings [persist|
|
|
World sql=World
|
|
World sql=World
|
|
@@ -22,14 +27,19 @@ World sql=World
|
|
|]
|
|
|]
|
|
|
|
|
|
data App = App
|
|
data App = App
|
|
- { appConnPool :: Pool Connection
|
|
|
|
- , appGen :: R.Gen (PrimState IO)
|
|
|
|
|
|
+ { appGen :: R.Gen (PrimState IO)
|
|
|
|
+ , mySqlPool :: Pool My.Connection
|
|
|
|
+ , mongoDBPool :: Pool Mongo.Connection
|
|
}
|
|
}
|
|
|
|
|
|
mkYesod "App" [parseRoutes|
|
|
mkYesod "App" [parseRoutes|
|
|
-/json JsonR GET
|
|
|
|
-/db DbR GET
|
|
|
|
-/dbs/#Int DbsR GET
|
|
|
|
|
|
+/json JsonR GET
|
|
|
|
+
|
|
|
|
+/db DbR GET
|
|
|
|
+/dbs/#Int DbsR GET
|
|
|
|
+
|
|
|
|
+/mongo/db MongoDbR GET
|
|
|
|
+/mongo/dbs/#Int MongoDbsR GET
|
|
|]
|
|
|]
|
|
|
|
|
|
instance Yesod App where
|
|
instance Yesod App where
|
|
@@ -44,31 +54,66 @@ getDbR :: Handler RepJson
|
|
getDbR = do
|
|
getDbR = do
|
|
App {..} <- getYesod
|
|
App {..} <- getYesod
|
|
i <- liftIO $ R.uniformR (1, 10000) appGen
|
|
i <- liftIO $ R.uniformR (1, 10000) appGen
|
|
- Just x <- flip runSqlPool appConnPool $ get (Key $ PersistInt64 i :: WorldId)
|
|
|
|
- jsonToRepJson $ object ["id" .= i, "randomNumber" .= worldRandomNumber x]
|
|
|
|
|
|
+ jsonToRepJson =<< intQuery (flip My.runSqlPool mySqlPool) i
|
|
|
|
|
|
getDbsR :: Int -> Handler RepJson
|
|
getDbsR :: Int -> Handler RepJson
|
|
getDbsR cnt = do
|
|
getDbsR cnt = do
|
|
|
|
+ App {..} <- getYesod
|
|
|
|
+ multiRandomHandler (flip My.runSqlPool mySqlPool) appGen cnt
|
|
|
|
+
|
|
|
|
+getMongoDbR :: Handler RepJson
|
|
|
|
+getMongoDbR = do
|
|
App {..} <- getYesod
|
|
App {..} <- getYesod
|
|
- objs <- replicateM cnt $ do
|
|
|
|
- i <- liftIO $ R.uniformR (1, 10000) appGen
|
|
|
|
- Just x <- flip runSqlPool appConnPool $ get (Key $ PersistInt64 i :: WorldId)
|
|
|
|
- return $ object ["id" .= i, "randomNumber" .= worldRandomNumber x]
|
|
|
|
- jsonToRepJson $ array objs
|
|
|
|
|
|
+ i <- liftIO $ R.uniformR (1, 10000) appGen
|
|
|
|
+ jsonToRepJson =<< intQuery (flip Mongo.runMongoDBPoolDef mongoDBPool) i
|
|
|
|
+
|
|
|
|
+getMongoDbsR :: Int -> Handler RepJson
|
|
|
|
+getMongoDbsR cnt = do
|
|
|
|
+ App {..} <- getYesod
|
|
|
|
+ multiRandomHandler (flip Mongo.runMongoDBPoolDef mongoDBPool) appGen cnt
|
|
|
|
+
|
|
|
|
+multiRandomHandler :: forall (m :: * -> *) backend.
|
|
|
|
+ (PersistStore m, PersistMonadBackend m ~ PersistEntityBackend (WorldGeneric backend))
|
|
|
|
+ => (m (Maybe (WorldGeneric backend))
|
|
|
|
+ -> Handler (Maybe (WorldGeneric backend)))
|
|
|
|
+ -> R.Gen (PrimState IO)
|
|
|
|
+ -> Int
|
|
|
|
+ -> Handler RepJson
|
|
|
|
+multiRandomHandler db appGen cnt = do
|
|
|
|
+ nums <- liftIO $ replicateM cnt $ R.uniformR (1, 10000) appGen
|
|
|
|
+ jsonToRepJson . array =<< mapConcurrently (intQuery db) nums
|
|
|
|
+
|
|
|
|
+intQuery :: forall (m :: * -> *) backend.
|
|
|
|
+ (PersistStore m, PersistMonadBackend m ~ PersistEntityBackend (WorldGeneric backend))
|
|
|
|
+ => (m (Maybe (WorldGeneric backend))
|
|
|
|
+ -> Handler (Maybe (WorldGeneric backend)))
|
|
|
|
+ -> Int64
|
|
|
|
+ -> Handler Value
|
|
|
|
+intQuery db i = do
|
|
|
|
+ Just x <- db $ get (Key $ PersistInt64 i)
|
|
|
|
+ return $ object ["id" .= i, "randomNumber" .= worldRandomNumber x]
|
|
|
|
|
|
main :: IO ()
|
|
main :: IO ()
|
|
main = R.withSystemRandom $ \gen -> do
|
|
main = R.withSystemRandom $ \gen -> do
|
|
socket <- bindPort 8000 "*"
|
|
socket <- bindPort 8000 "*"
|
|
[cores, host] <- getArgs
|
|
[cores, host] <- getArgs
|
|
- pool <- createMySQLPool defaultConnectInfo
|
|
|
|
- { connectUser = "benchmarkdbuser"
|
|
|
|
- , connectPassword = "benchmarkdbpass"
|
|
|
|
- , connectDatabase = "hello_world"
|
|
|
|
- , connectHost = host
|
|
|
|
|
|
+ myPool <- My.createMySQLPool My.defaultConnectInfo
|
|
|
|
+ { My.connectUser = "benchmarkdbuser"
|
|
|
|
+ , My.connectPassword = "benchmarkdbpass"
|
|
|
|
+ , My.connectDatabase = "hello_world"
|
|
|
|
+ , My.connectHost = host
|
|
} 1000
|
|
} 1000
|
|
|
|
+
|
|
|
|
+ mongoPool <- Mongo.createMongoDBPool "hello_world" host (PortNumber 27017)
|
|
|
|
+ (Just (Mongo.MongoAuth "benchmarkdbuser" "benchmarkdbpass"))
|
|
|
|
+ 1 -- what is the optimal stripe count? 1 is said to be a good default
|
|
|
|
+ 1000
|
|
|
|
+ 3 -- 3 second timeout
|
|
|
|
+
|
|
app <- toWaiAppPlain App
|
|
app <- toWaiAppPlain App
|
|
- { appConnPool = pool
|
|
|
|
- , appGen = gen
|
|
|
|
|
|
+ { appGen = gen
|
|
|
|
+ , mySqlPool = myPool
|
|
|
|
+ , mongoDBPool = mongoPool
|
|
}
|
|
}
|
|
let run = Warp.runSettingsSocket Warp.defaultSettings
|
|
let run = Warp.runSettingsSocket Warp.defaultSettings
|
|
{ Warp.settingsPort = 8000
|
|
{ Warp.settingsPort = 8000
|