@@ -30,20 +30,41 @@ import GHC.Conc (numCapabilities)
3030import Protolude hiding (head )
3131import qualified StmHamt.SizedHamt as SH
3232
33- data Node = Node {
34- getVisited :: STM Bool ,
35- visit :: STM () ,
36- clear :: STM () ,
37- remove :: STM () ,
38- next :: TVar Node ,
39- prev :: TVar Node
40- }
33+ data Node = Head {
34+ next :: TVar Node ,
35+ prev :: TVar Node
36+ } |
37+ Node {
38+ next :: TVar Node ,
39+ prev :: TVar Node ,
40+ visited :: TVar Bool
41+ } deriving Eq
42+
43+ getVisited :: Node -> STM Bool
44+ getVisited (Head _ _) = pure True
45+ getVisited Node {visited} = readTVar visited
46+
47+ visit :: Node -> STM ()
48+ visit (Head _ _) = pure ()
49+ visit Node {visited} = writeTVar visited True
50+
51+ clear :: Node -> STM ()
52+ clear (Head _ _) = pure ()
53+ clear Node {visited} = writeTVar visited False
54+
55+ remove :: Node -> STM ()
56+ remove (Head _ _) = pure ()
57+ remove Node {next= currNext, prev= currPrev} = do
58+ nextEntry <- readTVar currNext
59+ prevEntry <- readTVar currPrev
60+ writeTVar (next prevEntry) nextEntry
61+ writeTVar (prev nextEntry) prevEntry
4162
4263data Entry k v = Entry {
4364 ekey :: k ,
4465 value :: v ,
4566 node :: Node
46- }
67+ } deriving Eq
4768
4869data Cache m k v =
4970 Cache {
@@ -76,11 +97,10 @@ cacheIO maxSize = atomically . cache maxSize
7697
7798cache :: Hashable k => TVar Int -> (k -> m v ) -> STM (Cache m k v )
7899cache maxSize load = mdo
79- let noop = pure ()
80- advanceFinger = modifyTVarM fingerTVar (readTVar . next)
100+ let advanceFinger = modifyTVarM fingerTVar (readTVar . next)
81101 reset = SH. reset entries *> writeTVar fingerTVar head
82102 lookupAndVisit = traverse visitEntry <=< flip (SH. lookup ekey) entries
83- head <- Node ( pure True ) noop advanceFinger advanceFinger <$> newTVar head <*> newTVar head
103+ head <- Head <$> newTVar head <*> newTVar head
84104 entries <- SH. new
85105 fingerTVar <- newTVar head
86106 cache <- Cache
@@ -101,7 +121,13 @@ cache maxSize load = mdo
101121 visitEntry Entry {node, value} = visit node $> value
102122
103123delete :: Hashable k => Cache m k v -> k -> STM ()
104- delete Cache {entries} k = whenJustM (SH. lookup ekey k entries) (remove . node)
124+ delete Cache {entries, getFinger, advanceFinger} k =
125+ whenJustM (SH. focus F. lookupAndDelete ekey k entries) (removeAndCheckFinger . node)
126+ where
127+ removeAndCheckFinger node = do
128+ remove node
129+ whenM ((node == ) <$> getFinger)
130+ advanceFinger
105131
106132deleteIO :: Hashable k => Cache m k v -> k -> IO ()
107133deleteIO c = atomically . delete c
@@ -157,15 +183,16 @@ cached Cache{..} k =
157183 if currDiff >= 0 then do
158184 -- no space in the cache
159185 -- need to evict an entry
160- Node {getVisited, clear, remove} <- getFinger
161- visited <- getVisited
186+ node <- getFinger
187+ visited <- getVisited node
162188 if visited then
163189 -- clear and skip visited entry
164190 -- not done yet
165- clear $> empty
191+ clear node *> advanceFinger $> empty
166192 else do
167193 -- found entry to evict
168- remove
194+ SH. focus F. delete ekey k entries
195+ remove node *> advanceFinger
169196 modifyTVar evictions (+ 1 )
170197 if currDiff == 0 then
171198 -- now there is space
@@ -182,27 +209,9 @@ cached Cache{..} k =
182209
183210 addEntry v = do
184211 oldNeck <- readTVar $ prev head
185- nextTVar <- newTVar head
186- prevTVar <- newTVar oldNeck
187- visitedTVar <- newTVar False
188- let
189- removeEntry = do
190- nextEntry <- readTVar nextTVar
191- prevEntry <- readTVar prevTVar
192- writeTVar (next prevEntry) nextEntry
193- writeTVar (prev nextEntry) prevEntry
194- SH. focus F. delete ekey k entries
195- newNeck = Node
196- (readTVar visitedTVar)
197- (writeTVar visitedTVar True )
198- -- both clear and remove advance the finger
199- (writeTVar visitedTVar False *> advanceFinger)
200- (removeEntry *> advanceFinger)
201- nextTVar
202- prevTVar
203- newEntry = Entry k v newNeck
212+ newNeck <- Node <$> newTVar head <*> newTVar oldNeck <*> newTVar False
204213 -- add cache entry
205- SH. insert ekey newEntry entries
214+ SH. insert ekey ( Entry k v newNeck) entries
206215 -- update pointers
207216 writeTVar (next oldNeck) newNeck
208217 writeTVar (prev head ) newNeck
0 commit comments