forked from marko/svitak
add LRU cache
This commit is contained in:
parent
81c2caaf67
commit
da70b3ccf2
3 changed files with 31 additions and 3 deletions
|
|
@ -19,5 +19,7 @@ initialState title path =
|
|||
stZoom = 1.0,
|
||||
stTitle = title,
|
||||
stBookPath = path,
|
||||
stGen = 0
|
||||
stGen = 0,
|
||||
stUse = M.empty,
|
||||
stTick = 0,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,9 @@ data AppState = AppState
|
|||
stZoom :: Double,
|
||||
stTitle :: T.Text,
|
||||
stBookPath :: FilePath,
|
||||
stGen :: Int
|
||||
stGen :: Int,
|
||||
stUse :: M.Map ChapterIndex Int,
|
||||
stTick :: Int,
|
||||
}
|
||||
|
||||
-- | A user request, produced by the keyboard / sidebar and handled centrally.
|
||||
|
|
|
|||
26
app/UI.hs
26
app/UI.hs
|
|
@ -51,6 +51,10 @@ data Ctx = Ctx
|
|||
ctxRender :: TVar (ChapterRef -> IO (Either String Chapter))
|
||||
}
|
||||
|
||||
-- | The cache will start evicting after exceeding this number using LRU.
|
||||
cacheCap :: Int
|
||||
cacheCap = 7
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Widget tree
|
||||
--------------------------------------------------------------------------------
|
||||
|
|
@ -257,12 +261,32 @@ goto ctx target frag = do
|
|||
case rendered of
|
||||
Left err -> putStrLn ("render failed: " ++ err)
|
||||
Right chapter -> do
|
||||
atomically $ modifyTVar' (ctxState ctx) $ \s -> s {stCache = M.insert idx chapter (stCache s)}
|
||||
atomically $ modifyTVar' (ctxState ctx) $ \s -> insertLRU idx chapter s
|
||||
postGtk $ do
|
||||
cur <- stIndex <$> readTVarIO (ctxState ctx)
|
||||
when (cur == idx) (display ctx chapter frag)
|
||||
preload ctx
|
||||
|
||||
-- | Bump the tick of an index to track frequency for cache eviction.
|
||||
touch :: ChapterIndex -> AppState -> AppState
|
||||
touch idx s =
|
||||
let t = stTick s + 1
|
||||
in s { stTick = t, stUse = M.insert idx t (stUse s) }
|
||||
|
||||
-- | Insert a rendered chapter as MRU or evict the LRU entry.
|
||||
insertLRU :: ChapterIndex -> Chapter -> AppState -> AppState
|
||||
insertLRU idx chapter s0 =
|
||||
let s = touch idx (s0 {stCache = M.insert idx chapter (stCache s0) })
|
||||
in if M.size (stCache s) <= cacheCap then s else evictLRU s
|
||||
|
||||
evictLRU :: AppState -> AppState
|
||||
evictLRU s =
|
||||
case M.toList (stUse s) of
|
||||
[] -> s
|
||||
xs ->
|
||||
let victim = fst (minimumBy (comparing snd) xs)
|
||||
in s {stCache = M.delete victim (stCache s), stUse = M.delete victim (stUse s)}
|
||||
|
||||
-- | Render the chapters on either side of the current one into the cache.
|
||||
preload :: Ctx -> IO ()
|
||||
preload ctx = do
|
||||
|
|
|
|||
Loading…
Reference in a new issue