packages feed

ttl-hashtables 1.2.2.0 → 1.3.0.0

raw patch · 3 files changed

+82/−24 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.TTLHashTable: mutate :: (Eq k, Hashable k, MonadIO m, Failable m) => TTLHashTable h k v -> k -> (Maybe v -> (Maybe v, a)) -> m a

Files

src/Data/TTLHashTable.hs view
@@ -47,6 +47,7 @@                           getSettings,                           Data.TTLHashTable.mapM_,                           lookup,+                          mutate,                           new,                           newWithSettings,                           reconfigure,@@ -56,9 +57,11 @@ import Prelude                 hiding (lookup) import Control.Exception              (Exception) import Control.Monad                  (void, when)+import Control.Monad.Except           (runExcept, throwError) import Control.Monad.Failable         (Failable, failure) import Control.Monad.IO.Class         (MonadIO, liftIO) import Control.Monad.Trans.Maybe      (MaybeT(..), runMaybeT)+import Data.Bifunctor                 (first) import Data.Bits                      (finiteBitSize) import Data.Default                   (Default, def) import Data.Hashable                  (Hashable)@@ -258,15 +261,15 @@         liftIO $ modifyIORef' timeStampsRef_ $ M.insert expiresAt k         return value     where refreshEntry _ Nothing =-              ((Nothing, 0), (Nothing, Nothing))+              (Nothing, (Nothing, Nothing))           refreshEntry now (Just v@Value{..}) =               if expiresAt > now then                   let v' = Value { expiresAt = now + ttl * 1000000, -- nanoseconds                                    ttl = ttl,                                    value = value }-                  in ((Just v', 0), (Just expiresAt, Just v'))+                  in (Just v', (Just expiresAt, Just v'))               else-                  ((Nothing, 1), (Nothing, Just v))+                  (Nothing, (Nothing, Just v))           removeTimeStamp Nothing =               return ()           removeTimeStamp (Just timeStamp) =@@ -295,31 +298,41 @@  -- | delete an entry from the hash table. delete :: (C.HashTable h, Eq k, Hashable k, MonadIO m) => TTLHashTable h k v -> k -> m ()-delete = mutateWith simpleDeletion-    where simpleDeletion Nothing           = ((Nothing, 0), ())-          simpleDeletion (Just Value {..}) = ((Nothing, 1), ())+delete = ((.).(.)) (void . runMaybeT) (mutateWith (\_ -> (Nothing, ()))) -deleteExpired :: Int -> Maybe (Value v) -> ((Maybe (Value v), Int), Maybe ())+deleteExpired :: Int -> Maybe (Value v) -> (Maybe (Value v), Maybe ()) deleteExpired _ Nothing =-  ((Nothing, 0), Nothing)+  (Nothing, Nothing) deleteExpired timeStamp (Just v@Value {..}) =   if expiresAt == timeStamp-    then ((Nothing, 1), Just ())-    else ((Just v, 0), Nothing)+    then (Nothing, Just ())+    else (Just v, Nothing) -mutateWith :: (Eq k, Hashable k, MonadIO m)-              => (Maybe (Value v) -> ((Maybe (Value v), Int), a))+mutateWith :: (Eq k, Hashable k, MonadIO m, Failable m)+              => (Maybe (Value v) -> (Maybe (Value v), a))               -> TTLHashTable h k v               -> k               -> m a-mutateWith mutator TTLHashTable {..} k =-    liftIO $ do-      (n, result) <- H.mutate hashTable_ k mutate'-      modifyIORef' numEntriesRef_ $ flip (-) n-      return result-          where mutate' mValue =-                  let ((mValue', n), result) = mutator mValue-                  in (mValue', (n, result))+mutateWith mutator TTLHashTable {..} k = do+  iResult <- liftIO $ do+              numEntries <- readIORef numEntriesRef_+              maxSize    <- readIORef maxSizeRef_+              H.mutate hashTable_ k $ mutate_ numEntries maxSize+  flip (either failure) iResult $ \(n, result) -> do+    liftIO $ modifyIORef' numEntriesRef_ $ (+) n+    return result+        where mutate_ numEntries maxSize mValue =+                  let (mValue', result) = mutator mValue+                      result' = runExcept $ do+                                  n <- case (mValue, mValue') of+                                        (Nothing, Just _) -> do+                                          if numEntries < maxSize+                                            then return 1+                                            else throwError HashTableFull+                                        (Just _, Nothing) -> return (-1)+                                        _                 -> return 0+                                  return (n, result)+                  in either (\_ -> (mValue, result')) (\_ -> (mValue', result')) result'  -- | Report the current number of entries in the table, including those who have expired but -- haven't been garbage collected yet@@ -388,3 +401,28 @@                     renewUponRead = renewUponRead,                     defaultTTL = defaultTTL,                     gcMaxEntries = gcMaxEntries }++-- | mutate an entry with the provided modification function. The tuple returned corresponds+-- to the new value mapped to the key and a result to return from the mutate operation. Note+-- that if the new value is @Nothing@ then the entry is deleted if it exists or no change is+-- performed if it didn't. If the value is @Just v@ then the value is replaced or inserted+-- depending on whether it was found or not respectively for that key.+mutate :: (Eq k, Hashable k, MonadIO m, Failable m)+          => TTLHashTable h k v+          -> k+          -> (Maybe v -> (Maybe v, a))+          -> m a+mutate ht@TTLHashTable {..} k f = do+  now <- getTimeStamp+  defaultTTL <- liftIO $ readIORef defaultTTLRef_+  mutateWith (mutate' now defaultTTL f) ht k++mutate' :: Int -> Int -> (Maybe v -> (Maybe v, a)) -> Maybe (Value v) -> (Maybe (Value v), a)+mutate' now defaultTTL f mV =+    let (expiresAt, ttl, mValue) = metaFrom mV+        vFrom mValue' = do+          value <- mValue'+          return Value {expiresAt = expiresAt, ttl = ttl, value = value }+    in first vFrom $ f mValue+        where metaFrom Nothing            = (now + defaultTTL * 1000000, defaultTTL, Nothing)+              metaFrom (Just Value {..})  = (now + ttl * 1000000, ttl, Just value)
test/Spec.hs view
@@ -4,7 +4,7 @@ import Control.Exception         (Exception(..), SomeException(..)) import Control.Monad.Except      (runExceptT) import Control.Monad.Trans.Maybe (runMaybeT)-import Data.Default              (Default, def)+import Data.Default              (def) import Data.TTLHashTable import Test.Hspec @@ -72,9 +72,25 @@            \ht -> do             insertWithTTL ht 100 2 "foo" -- TTL is 100 milliseconds             threadDelay 200000 -- wait 200 mS-            removeExpired ht+            left <- removeExpired ht+            left `shouldBe` 0             s <- size ht             s `shouldBe` 0+        it "Checks mutation" $+           \ht -> do+             mutate ht 1 $ \_ -> (Just "foo", ())+             s <- size ht+             s `shouldBe` 1+             mutate ht 1 $ \(Just "foo") -> (Just "bar", ())+             s' <- size ht+             s' `shouldBe` 1+             v <- find ht 1+             v `shouldBe` Just "bar"+             mutate ht 1 $ \(Just "bar") -> (Nothing, ())+             s'' <- size ht+             s'' `shouldBe` 0+             v' <- find ht 1+             v' `shouldBe` Nothing     before withSizedRenewableTTLHashTable $       describe "Renewable TTL Hash Table with max size" $ do         it "Checks that max size is respected" $@@ -83,6 +99,10 @@             insert ht 2 "bar"             r <- runExceptT $ insert ht 3 "baz"             r `shouldSatisfy` hashTableError HashTableFull+            r' <- runExceptT $ mutate ht 3 $ \Nothing -> (Just "baz", ())+            r' `shouldSatisfy` hashTableError HashTableFull+            s <- size ht+            s `shouldBe` 2         it "Checks that lookup renews entry" $           \ht -> do             insert ht 1 "foo"
ttl-hashtables.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 7f24064c13cfbd206d12c76b27fd473341e87ce71c17f45f0561136bb2302ac8+-- hash: 6d188e88f27e2de1091cb1fb49b9690c340c15938c684dcb0081715cfebe48b9  name:           ttl-hashtables-version:        1.2.2.0+version:        1.3.0.0 synopsis:       Extends hashtables so that entries added can be expired after a TTL description:    Please see the README on Gitlab at <https://gitlab.com/codemonkeylabs/ttl-hashtables#readme> category:       Data