grapesy-1.0.0: kvstore/KVStore/Server.hs
module KVStore.Server (withKeyValueServer) where
import Control.Concurrent (threadDelay)
import Control.Monad
import Network.GRPC.Common
import Network.GRPC.Common.Compression qualified as Compr
import Network.GRPC.Server
import Network.GRPC.Server.Run
import KVStore.API
import KVStore.API.JSON qualified as JSON
import KVStore.API.Protobuf qualified as Protobuf
import KVStore.Cmdline
import KVStore.Util.Store (Store)
import KVStore.Util.Store qualified as Store
import Paths_grapesy
{-------------------------------------------------------------------------------
Server proper
-------------------------------------------------------------------------------}
withKeyValueServer :: Cmdline -> (RunningServer -> IO ()) -> IO ()
withKeyValueServer cmdline@Cmdline{
cmdJSON
, cmdSecure
, cmdDisableTcpNoDelay
, cmdPingRateLimit
} k = do
store <- Store.new
config :: ServerConfig <-
if cmdSecure then do
pub <- getDataFileName "grpc-demo.pem"
priv <- getDataFileName "grpc-demo.key"
return ServerConfig {
serverInsecure = Nothing
, serverSecure = Just $ SecureConfig {
secureHost = "0.0.0.0"
, securePort = defaultSecurePort
, securePubCert = pub
, secureChainCerts = []
, securePrivKey = priv
, secureSslKeyLog = SslKeyLogFromEnv
}
}
else
return ServerConfig {
serverInsecure = Just $ InsecureConfig (Just "127.0.0.1") defaultInsecurePort
, serverSecure = Nothing
}
let rpcHandlers :: [SomeRpcHandler IO]
rpcHandlers
| cmdJSON = JSON.server $ handlers cmdline store
| otherwise = Protobuf.server $ handlers cmdline store
server <- mkGrpcServer params rpcHandlers
forkServer http2 config server k
where
http2 :: HTTP2Settings
http2 = def {
http2TcpNoDelay = not cmdDisableTcpNoDelay
, http2OverridePingRateLimit = cmdPingRateLimit
}
params :: ServerParams
params = def {
-- The Java benchmark does not use compression (unclear if the Java
-- implementation supports compression at all; the compression Interop
-- tests are also disabled for Java). For a fair comparison, we
-- therefore disable compression here also.
serverCompression = Compr.none
}
{-------------------------------------------------------------------------------
Handlers
-------------------------------------------------------------------------------}
handlers :: Cmdline -> Store Key Value -> KVStore
handlers cmdline store = KVStore {
create = \(key, value) -> do
simulateWork cmdline writeDelayMillis
inserted <- Store.putIfAbsent store key value
unless inserted $ throwGrpcError GrpcAlreadyExists
, update = \(key, value) -> do
simulateWork cmdline writeDelayMillis
replaced <- Store.replace store key value
unless replaced $ throwGrpcError GrpcNotFound
, retrieve = \key -> do
simulateWork cmdline readDelayMillis
mValue <- Store.get store key
case mValue of
Just value -> return value
Nothing -> throwGrpcError GrpcNotFound
, delete = \key -> do
simulateWork cmdline writeDelayMillis
Store.remove store key
}
{-------------------------------------------------------------------------------
Delays
-------------------------------------------------------------------------------}
simulateWork :: Cmdline -> Int -> IO ()
simulateWork Cmdline{cmdSimulateWork} n
| cmdSimulateWork = threadDelay (n * 1_000)
| otherwise = return ()
readDelayMillis, writeDelayMillis :: Int
readDelayMillis = 10
writeDelayMillis = 50