packages feed

concurrent-hashtable 0.1.2 → 0.1.3

raw patch · 4 files changed

+40/−14 lines, 4 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.HashTable: _itemsTV :: Chain k v -> TVar [(k, v)]
- Data.HashTable: getAssocs :: Eq k => HashTable k v -> STM [(k, v)]
- Data.HashTable.Internal: getAssocs :: Eq k => HashTable k v -> STM [(k, v)]
+ Data.HashTable: readAssocs :: Eq k => HashTable k v -> STM [(k, v)]
+ Data.HashTable: readSize :: HashTable k v -> STM Int
+ Data.HashTable: readSizeIO :: HashTable k v -> IO Int
+ Data.HashTable.Internal: readAssocs :: Eq k => HashTable k v -> STM [(k, v)]
+ Data.HashTable.Internal: readLoad :: HashTable k v -> IO Int
+ Data.HashTable.Internal: readSize :: HashTable k v -> STM Int

Files

concurrent-hashtable.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: dfbcbe83f4c3c52e2cf5b9e2db5e3898ada41cfbaf1f37a912b4cdd634a4bc05+-- hash: cd9377375669850e36b4505949d445efc12cf57a2c9bb8ea352987259c507369  name:           concurrent-hashtable-version:        0.1.2+version:        0.1.3 synopsis:       Thread-safe hash tables for multi-cores! description:    Please see the README on GitHub at <https://github.com/pwrobinson/concurrent-hashtable#readme> category:       Concurrency@@ -39,7 +39,6 @@       async >=2.2.2 && <3     , atomic-primops >=0.8.3 && <2     , base >=4.7 && <5-    , containers >=0.6.0.1 && <1     , hashable >=1.2.7.0 && <2     , random >=1.1 && <2     , stm >=2.4.5.1 && <3
src/Data/HashTable.hs view
@@ -9,12 +9,29 @@ -- Portability :  non-portable (requires concurrency, stm) -- -- You can find benchmarks and more information about the internals of this package here:  <https://lowerbound.io/blog/2019-10-24_concurrent_hash_table_performance.html>+--+--+-- Example usage:+--+-- >> ht <- newWithDefaults 2     -- creates hash table of initial size 4+-- >> insert ht 1 "hello"         -- adds key-value pair (1,"hello")+-- >> insert ht 2 "world"         -- adds key-value pair (2,"world")+-- >> atomically $ readAssocs ht  -- convert to a key-value list+-- > [(1,"hello"),(2,"world")]+-- >> readSizeIO ht               -- returns 4+-- >> insert ht 3 "!"             -- adds key-value pair (3,"!") and triggers a resize as the load fraction is ≥ 0.75+-- >> readSizeIO ht               -- returns 8+-- >> atomically $ readAssocs ht  -- convert to a key-value list+-- > [(1,"hello"),(3,"!"),(2,"world")]+--+-- List of atomic operations:+-- /insert/, /insertIfNotExists/, /lookup/, /delete/, /getAssocs/, /resize/+-- ----------------------------------------------------------------------  module Data.HashTable(         HashTable,         Chain,-        _itemsTV,         new,         newWithDefaults,         mkDefaultConfig,@@ -23,7 +40,9 @@         insert,         insertIfNotExists,         delete,-        getAssocs+        readAssocs,+        readSizeIO,+        readSize     ) where import Data.HashTable.Internal
src/Data/HashTable/Internal.hs view
@@ -11,7 +11,7 @@ -- You can find benchmarks and more information about the internals of this package here:  <https://lowerbound.io/blog/2019-10-24_concurrent_hash_table_performance.html> -- -- List of atomic operations:--- /insert/, /insertIfNotExists/, /lookup/, /delete/, /getAssocs/, /resize/+-- /insert/, /insertIfNotExists/, /lookup/, /delete/, /readAssocs/, /resize/ ---------------------------------------------------------------------- {-# LANGUAGE MultiParamTypeClasses, ScopedTypeVariables #-} module Data.HashTable.Internal@@ -38,7 +38,7 @@  -- | Used for chain-hashing. data Chain k v = Chain-    { _itemsTV           :: TVar [(k,v)]   -- ^ stores the+    { _itemsTV           :: TVar [(k,v)]   -- ^ stores the items for this index     , _migrationStatusTV :: TVar MigrationStatus -- ^ used internally for resizing     }     deriving (Eq)@@ -104,9 +104,12 @@ {-# INLINABLE readSizeIO #-} readSizeIO :: HashTable k v -> IO Int readSizeIO ht = do-    chainsVec <- readTVarIO $ _chainsVecTV ht-    return $ V.length chainsVec+    V.length <$> readTVarIO (_chainsVecTV ht) +{-# INLINABLE readSize #-}+readSize :: HashTable k v -> STM Int+readSize ht = do+    V.length <$> readTVar (_chainsVecTV ht)  -- | Resizes the hash table by scaling it according to the _scaleFactor in the configuration. resize :: (Eq k)@@ -163,7 +166,7 @@                                writeTVar (_itemsTV newChain) ((k,v):newList)                       | (k,v) <- listOfNodes ] -                      + -- | Lookup the value for the key in the hash table if it exists. {-# INLINABLE lookup #-} lookup :: (Eq k) => HashTable k v -> k -> IO (Maybe v)@@ -268,16 +271,21 @@         when (migrationStatus == NotStarted) $             void $ forkIO (resize htable) +-- | The load (i.e. number of stored items) in the table. Note that this is not synchronized for performance reasons and hence might be somewhat out of date if a lot of contention is happening.+readLoad :: HashTable k v -> IO Int+readLoad htable = readIORef (_totalLoad htable)+ -- Atomically retrieves list of key-value pairs. If there is a lot of contention going on, this may be very inefficient.-getAssocs :: (Eq k)+readAssocs :: (Eq k)             => HashTable k v -> STM [(k,v)]-getAssocs htable = do+readAssocs htable = do     chainsVec <- readTVar $ _chainsVecTV htable     let len = V.length chainsVec     let getItemsForChain k = do             chain <- readChainForIndex htable k             readTVar (_itemsTV chain)     msum <$> mapM getItemsForChain [0..len-1]+  {-# INLINABLE deleteFirstKey #-} deleteFirstKey ::  Eq a => a -> [(a,b)] -> [(a,b)]
test/Spec.hs view
@@ -88,7 +88,7 @@                     [ do res <-  H.lookup chainTable k                          return $ (isJust res) && (fromJust res == a)                     | (k,a) <- mapAssocs ]-    list2 <- run $ atomically $ H.getAssocs chainTable+    list2 <- run $ atomically $ H.readAssocs chainTable     -- test if there aren't any duplicates in the Hash Table:     let res2 = (not . hasDuplicates) list2     mymap <- run $ readIORef ioref@@ -106,4 +106,4 @@     print "------- Map ASSOCS List ----"     print =<< (M.assocs <$> readIORef ioref)     print "--------Hashtable AFTER --------"-    print =<< atomically (H.getAssocs ctable)+    print =<< atomically (H.readAssocs ctable)