blob: 53d2185ff034855d58409332471a0a025fbb4e33 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
module Cache where
import Control.Concurrent.STM
import Control.Monad (forM_)
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import ZNC
-- value, previous (more recently accessed), next (less recently accessed)
data LRUNode a = LRUNode a (TVar (Maybe (LRUNode a))) (TVar (Maybe (LRUNode a)))
-- head (most recent), last (least recent)
data LRUChain a = LRUChain (TVar (Maybe (LRUNode a))) (TVar (Maybe (LRUNode a)))
lruchainNew :: IO (LRUChain a)
lruchainNew = LRUChain <$> newTVarIO Nothing <*> newTVarIO Nothing
lruchainAdd :: LRUChain a -> a -> STM (LRUNode a)
lruchainAdd (LRUChain hd tl) x = do
mhdnode <- readTVar hd
case mhdnode of
Nothing -> do -- chain empty
node <- LRUNode x <$> newTVar Nothing <*> newTVar Nothing
writeTVar hd (Just node)
writeTVar tl (Just node)
return node
Just hdnode -> do
node <- LRUNode x <$> newTVar Nothing <*> newTVar (Just hdnode)
writeTVar hd (Just node)
return node
lruchainBump :: LRUChain a -> LRUNode a -> STM ()
lruchainBump (LRUChain hd _) node@(LRUNode _ prevvar nextvar) = do
mprev <- readTVar prevvar
case mprev of
Nothing -> return () -- already most recent
Just (LRUNode _ _ prevnextvar) -> do
-- remove node from chain where it is now
mnext <- readTVar nextvar
writeTVar prevnextvar mnext
case mnext of
Nothing -> return ()
Just (LRUNode _ nextprevvar _) -> writeTVar nextprevvar mprev
-- add node to chain at head
writeTVar nextvar =<< readTVar hd
writeTVar hd (Just node)
lruchainEvict :: LRUChain a -> STM (Maybe a)
lruchainEvict (LRUChain _ tl) = do
mtlnode <- readTVar tl
case mtlnode of
Nothing -> return Nothing
Just (LRUNode x prevvar _) -> do
mprev <- readTVar prevvar
writeTVar tl mprev
case mprev of
Nothing -> return ()
Just (LRUNode _ _ prevnextvar) -> writeTVar prevnextvar Nothing
return (Just x)
-- maxsize, elements in cache, linked list
data LRU a = LRU Int (TVar (Map a (LRUNode a))) (LRUChain a)
lruNew :: Ord a => Int -> IO (LRU a)
lruNew maxsize = LRU maxsize <$> newTVarIO mempty <*> lruchainNew
-- | If a value got evicted, it is returned
lruBump :: Ord a => LRU a -> a -> IO (Maybe a)
lruBump (LRU maxsize mapvar chain) value = atomically $ do
mp <- readTVar mapvar
case Map.lookup value mp of
Nothing -> do
node <- lruchainAdd chain value
writeTVar mapvar $! Map.insert value node mp
if Map.size mp >= maxsize
then do
mret <- lruchainEvict chain
forM_ mret $ \ret -> writeTVar mapvar $! Map.delete ret mp
return mret
else return Nothing
Just node -> do
lruchainBump chain node
return Nothing
|