-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #45 from anton-k/lru-cache
Implements LRU cache
- Loading branch information
Showing
8 changed files
with
170 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
.PHONY: build test run docs | ||
|
||
build: | ||
stack build | ||
stack build | ||
|
||
test: | ||
stack test | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
cabal-version: 1.12 | ||
cabal-version: 1.12 | ||
|
||
-- This file has been generated from package.yaml by hpack version 0.35.2. | ||
-- | ||
|
@@ -7,16 +7,18 @@ cabal-version: 1.12 | |
name: mig | ||
version: 0.2.0.0 | ||
synopsis: Build lightweight and composable servers | ||
description: Core for the mig server library. | ||
With library mig we can build lightweight and composable servers. | ||
There are only couple of combinators to assemble servers from parts. | ||
It supports generic handler functions as servant does. But strives to use more | ||
simple model for API. It does not go to describing Server API at type level which | ||
leads to simpler error messages. | ||
. | ||
* quick start guide at <https://github.com/anton-k/mig#readme> | ||
. | ||
* examples directory for more fun servers: at <https://github.com/anton-k/mig/tree/main/examples/mig-example-apps#readme> | ||
description: | ||
Core for the mig server library. | ||
With library mig we can build lightweight and composable servers. | ||
There are only couple of combinators to assemble servers from parts. | ||
It supports generic handler functions as servant does. But strives to use more | ||
simple model for API. It does not go to describing Server API at type level which | ||
leads to simpler error messages. | ||
. | ||
* quick start guide at <https://github.com/anton-k/mig#readme> | ||
. | ||
* examples directory for more fun servers: at <https://github.com/anton-k/mig/tree/main/examples/mig-example-apps#readme> | ||
|
||
category: Web | ||
homepage: https://github.com/anton-k/mig#readme | ||
bug-reports: https://github.com/anton-k/mig/issues | ||
|
@@ -25,45 +27,50 @@ maintainer: [email protected] | |
copyright: 2023 Anton Kholomiov | ||
license: BSD3 | ||
build-type: Simple | ||
extra-source-files: | ||
README.md | ||
extra-source-files: README.md | ||
|
||
source-repository head | ||
type: git | ||
type: git | ||
location: https://github.com/anton-k/mig | ||
|
||
library | ||
exposed-modules: | ||
Mig.Core | ||
Mig.Core.Api | ||
Mig.Core.Class | ||
Mig.Core.Class.MediaType | ||
Mig.Core.Class.Monad | ||
Mig.Core.Class.Plugin | ||
Mig.Core.Class.Response | ||
Mig.Core.Class.Route | ||
Mig.Core.Class.Server | ||
Mig.Core.OpenApi | ||
Mig.Core.Server | ||
Mig.Core.ServerFun | ||
Mig.Core.Types | ||
Mig.Core.Types.Http | ||
Mig.Core.Types.Info | ||
Mig.Core.Types.Route | ||
other-modules: | ||
Paths_mig | ||
hs-source-dirs: | ||
src | ||
Mig.Core | ||
Mig.Core.Api | ||
Mig.Core.Class | ||
Mig.Core.Class.MediaType | ||
Mig.Core.Class.Monad | ||
Mig.Core.Class.Plugin | ||
Mig.Core.Class.Response | ||
Mig.Core.Class.Route | ||
Mig.Core.Class.Server | ||
Mig.Core.OpenApi | ||
Mig.Core.Server | ||
Mig.Core.Server.Cache | ||
Mig.Core.ServerFun | ||
Mig.Core.Types | ||
Mig.Core.Types.Http | ||
Mig.Core.Types.Info | ||
Mig.Core.Types.Route | ||
|
||
other-modules: Paths_mig | ||
hs-source-dirs: src | ||
default-extensions: | ||
OverloadedStrings | ||
TypeFamilies | ||
OverloadedRecordDot | ||
DuplicateRecordFields | ||
LambdaCase | ||
DerivingStrategies | ||
StrictData | ||
AllowAmbiguousTypes | ||
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -Wunused-packages | ||
AllowAmbiguousTypes | ||
DerivingStrategies | ||
DuplicateRecordFields | ||
LambdaCase | ||
OverloadedRecordDot | ||
OverloadedStrings | ||
StrictData | ||
TypeFamilies | ||
|
||
ghc-options: | ||
-Wall -Wcompat -Widentities -Wincomplete-record-updates | ||
-Wincomplete-uni-patterns -Wmissing-export-lists | ||
-Wmissing-home-modules -Wpartial-fields -Wredundant-constraints | ||
-Wunused-packages | ||
|
||
build-depends: | ||
aeson | ||
, base >=4.7 && <5 | ||
|
@@ -79,8 +86,10 @@ library | |
, http-types | ||
, insert-ordered-containers | ||
, lens | ||
, lrucache | ||
, mtl | ||
, openapi3 | ||
, safe | ||
, text | ||
default-language: GHC2021 | ||
|
||
default-language: GHC2021 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
-- | LRU cache to speedup fetching of the route handler | ||
module Mig.Core.Server.Cache ( | ||
CacheConfig (..), | ||
CacheKey (..), | ||
CacheValue (..), | ||
RouteCache (..), | ||
newRouteCache, | ||
withCache, | ||
) where | ||
|
||
import Control.Monad | ||
import Control.Monad.IO.Class | ||
import Data.ByteString (ByteString) | ||
import Data.Cache.LRU.IO (AtomicLRU) | ||
import Data.Cache.LRU.IO qualified as Lru | ||
import Data.Text (Text) | ||
import Mig.Core.Api (CaptureMap) | ||
import Mig.Core.Class.Route (Route) | ||
import Network.HTTP.Types.Method (Method) | ||
|
||
data CacheConfig = CacheConfig | ||
{ size :: Int | ||
, cacheFilter :: CacheKey -> Bool | ||
} | ||
|
||
data CacheKey = CacheKey | ||
{ inputType :: ByteString | ||
, outputType :: ByteString | ||
, method :: Method | ||
, path :: [Text] | ||
} | ||
deriving (Show, Eq, Ord) | ||
|
||
data CacheValue m = CacheValue | ||
{ captures :: CaptureMap | ||
, route :: Route m | ||
} | ||
|
||
data RouteCache m = RouteCache | ||
{ cacheFilter :: CacheKey -> Bool | ||
, cache :: AtomicLRU CacheKey (CacheValue m) | ||
} | ||
|
||
newRouteCache :: CacheConfig -> IO (RouteCache m) | ||
newRouteCache config = | ||
RouteCache config.cacheFilter <$> Lru.newAtomicLRU (Just (fromIntegral config.size)) | ||
|
||
withCache :: RouteCache m -> (CacheKey -> Maybe (CacheValue m)) -> CacheKey -> IO (Maybe (CacheValue m)) | ||
withCache (RouteCache cacheFilter cache) f key = do | ||
mCacheResult <- liftIO $ Lru.lookup key cache | ||
case mCacheResult of | ||
Just result -> pure (Just result) | ||
Nothing -> do | ||
case f key of | ||
Just result -> do | ||
when (cacheFilter key) $ Lru.insert key result cache | ||
pure (Just result) | ||
Nothing -> pure Nothing |