-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Thread-safe hash tables for multi-cores! -- -- Please see the README on GitHub at -- https://github.com/pwrobinson/concurrent-hashtable#readme. -- Benchmarks can be found at -- https://lowerbound.io/blog/2019-10-24_concurrent_hash_table_performance.html @package concurrent-hashtable @version 0.1.8 -- | 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 module Data.HashTable.Internal data MigrationStatus NotStarted :: MigrationStatus Ongoing :: MigrationStatus Finished :: MigrationStatus -- | Used for chain-hashing. data Chain k v Chain :: TVar [(k, v)] -> TVar MigrationStatus -> Chain k v -- | stores the items for this index [_itemsTV] :: Chain k v -> TVar [(k, v)] -- | used internally for resizing [_migrationStatusTV] :: Chain k v -> TVar MigrationStatus -- | Create a new empty chain. newChainIO :: IO (Chain k v) -- | A thread-safe hash table that supports dynamic resizing. data HashTable k v HashTable :: TVar (Vector (Chain k v)) -> IORef Int -> Config k -> HashTable k v -- | vector of linked lists [_chainsVecTV] :: HashTable k v -> TVar (Vector (Chain k v)) -- | the current load of the hash table [_totalLoad] :: HashTable k v -> IORef Int -- | the configuration options [_config] :: HashTable k v -> Config k -- | Configuration options that may affect the performance of the hash -- table data Config k Config :: Float -> Float -> Int -> (k -> Int) -> Config k -- | scale factor for resizing [_scaleFactor] :: Config k -> Float -- | load threshold for initiating resizing. [_threshold] :: Config k -> Float -- | maximum number of worker threads used during resizing [_numResizeWorkers] :: Config k -> Int [_hashFunc] :: Config k -> k -> Int -- | Default configuration: scale factor = 2.0; resizing threshold = 0.75; -- number of worker threads for resizing = getNumCapabilities; -- hash function = use hashWithSalt with a random salt. mkDefaultConfig :: Hashable k => IO (Config k) -- | Creates a new hash table with an initial size. See -- newWithDefaults for more details. new :: Eq k => Int -> Config k -> IO (HashTable k v) -- | Creates a new hash table with the given initial vector size, scale -- factor 2.0, a resizing load threshold of 0.75, and we use as many -- threads for resizing as we have cores available. This will use a hash -- function with a (single) random salt. For security sensitive -- applications, you MUST supply your own hash function. (To be replaced -- by universal hashing in future versions.) newWithDefaults :: (Eq k, Hashable k) => Int -> IO (HashTable k v) -- | Returns the size of the vector representing the hash table. readSizeIO :: HashTable k v -> IO Int -- | Returns the size of the vector representing the hash table. readSize :: HashTable k v -> STM Int -- | Increases the size of the hash table by scaling the current size it -- according to the _scaleFactor in the configuration. resize :: Eq k => HashTable k v -> IO () -- | Lookup the value for the given key in the hash table. lookup :: Eq k => HashTable k v -> k -> IO (Maybe v) -- | An action to be executed atomically for the content of the chain (i.e. -- list) stored at a specific table index. Used in genericModify. type STMAction k v a = TVar [(k, v)] -> STM a -- | Used by various write-operations (e.g. insert, add, -- delete, update). Searches the hash table for the given -- key and then applies the given STMAction to the contents of the -- chain. genericModify :: Eq k => HashTable k v -> k -> STMAction k v a -> IO a -- | Inserts a key-value pair k,v into the hash table. -- Uses chain hashing to resolve collisions. If you want to update the -- entry only if it already exists, use update. If you want to -- update the entry only if it does *not* exist, use add. insert :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Adds a key and value pair into the hash table only if the key does not -- exist yet. Returns True if the insertion was successful, i.e., -- the hash table does not yet contain this key. To get the same -- behaviour as insert, use insert. If you want to update -- an already-existing item, use update. add :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Updates the value for key k. If k is not in the hash -- table, it skips the update and returns False. update :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Applies an update-function to the value for key k. Returns -- the old value if it exists. If k is not in the hash table, it -- returns Nothing. modify :: Eq k => HashTable k v -> k -> (v -> v) -> IO (Maybe v) -- | Atomically replaces the value for the given key k in the hash -- table with the new value. Returns the old value. Throws -- AssertionFailed if k is not in the hash table. swapValues :: Eq k => HashTable k v -> k -> v -> IO v -- | Deletes the entry for the given key from the hash table. Returns -- True if and only if an entry was deleted from the table. delete :: Eq k => HashTable k v -> k -> IO Bool -- | Atomically increment/decrement the table load value by adding the -- provided integer offest to the current value. Forks a thread that -- executes resize if the load passes the configured threshold. atomicallyChangeLoad :: Eq k => HashTable k v -> Int -> IO () -- | 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 -- | Returns an atomic snapshot of the hash table as a list of key-value -- pairs. If there is a lot of contention going on, this may be very -- inefficient. readAssocs :: Eq k => HashTable k v -> STM [(k, v)] -- | Returns the content of the hash table as a list of key-value pairs. -- This is *not* an atomic operation! If you need atomicity, use -- readAssoc instead. readAssocsIO :: Eq k => HashTable k v -> IO [(k, v)] -- | Takes a key k and an assocation list ys, and deletes -- the first entry with key k in ys. Used internally. deleteFirstKey :: Eq a => a -> [(a, b)] -> [(a, b)] -- | Atomically read the chain for the given key. readChainForKeyIO :: HashTable k v -> k -> IO (Chain k v) -- | Atomically read the chain for the given index. (Warning: bounds are -- not checked.) readChainForIndexIO :: HashTable k v -> Int -> IO (Chain k v) -- | Atomically read the chain for the given index. (Warning: bounds are -- not checked.) readChainForIndex :: HashTable k v -> Int -> STM (Chain k v) debug :: Show a => a -> IO () instance GHC.Classes.Eq (Data.HashTable.Internal.Chain k v) instance GHC.Classes.Eq Data.HashTable.Internal.MigrationStatus instance GHC.Show.Show Data.HashTable.Internal.MigrationStatus instance GHC.Show.Show (Data.HashTable.Internal.Config k) -- | 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 -- -- Usage Example: -- --
--   > ht <- newWithDefaults 4     -- 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 since load/size is ≥ 0.75
--   > readSizeIO ht               -- returns 8
--   > atomically $ readAssocs ht  -- convert to a key-value list
--    [(1,"hello"),(3,"!"),(2,"world")]
--   
module Data.HashTable -- | A thread-safe hash table that supports dynamic resizing. data HashTable k v -- | Used for chain-hashing. data Chain k v -- | Creates a new hash table with an initial size. See -- newWithDefaults for more details. new :: Eq k => Int -> Config k -> IO (HashTable k v) -- | Creates a new hash table with the given initial vector size, scale -- factor 2.0, a resizing load threshold of 0.75, and we use as many -- threads for resizing as we have cores available. This will use a hash -- function with a (single) random salt. For security sensitive -- applications, you MUST supply your own hash function. (To be replaced -- by universal hashing in future versions.) newWithDefaults :: (Eq k, Hashable k) => Int -> IO (HashTable k v) -- | Default configuration: scale factor = 2.0; resizing threshold = 0.75; -- number of worker threads for resizing = getNumCapabilities; -- hash function = use hashWithSalt with a random salt. mkDefaultConfig :: Hashable k => IO (Config k) -- | Configuration options that may affect the performance of the hash -- table data Config k Config :: Float -> Float -> Int -> (k -> Int) -> Config k -- | scale factor for resizing [_scaleFactor] :: Config k -> Float -- | load threshold for initiating resizing. [_threshold] :: Config k -> Float -- | maximum number of worker threads used during resizing [_numResizeWorkers] :: Config k -> Int [_hashFunc] :: Config k -> k -> Int -- | Lookup the value for the given key in the hash table. lookup :: Eq k => HashTable k v -> k -> IO (Maybe v) -- | Returns an atomic snapshot of the hash table as a list of key-value -- pairs. If there is a lot of contention going on, this may be very -- inefficient. readAssocs :: Eq k => HashTable k v -> STM [(k, v)] -- | Returns the content of the hash table as a list of key-value pairs. -- This is *not* an atomic operation! If you need atomicity, use -- readAssoc instead. readAssocsIO :: Eq k => HashTable k v -> IO [(k, v)] -- | Inserts a key-value pair k,v into the hash table. -- Uses chain hashing to resolve collisions. If you want to update the -- entry only if it already exists, use update. If you want to -- update the entry only if it does *not* exist, use add. insert :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Adds a key and value pair into the hash table only if the key does not -- exist yet. Returns True if the insertion was successful, i.e., -- the hash table does not yet contain this key. To get the same -- behaviour as insert, use insert. If you want to update -- an already-existing item, use update. add :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Updates the value for key k. If k is not in the hash -- table, it skips the update and returns False. update :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Applies an update-function to the value for key k. Returns -- the old value if it exists. If k is not in the hash table, it -- returns Nothing. modify :: Eq k => HashTable k v -> k -> (v -> v) -> IO (Maybe v) -- | Deletes the entry for the given key from the hash table. Returns -- True if and only if an entry was deleted from the table. delete :: Eq k => HashTable k v -> k -> IO Bool -- | Atomically replaces the value for the given key k in the hash -- table with the new value. Returns the old value. Throws -- AssertionFailed if k is not in the hash table. swapValues :: Eq k => HashTable k v -> k -> v -> IO v -- | Returns the size of the vector representing the hash table. readSizeIO :: HashTable k v -> IO Int -- | Returns the size of the vector representing the hash table. readSize :: HashTable k v -> STM Int -- | 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 -- | Increases the size of the hash table by scaling the current size it -- according to the _scaleFactor in the configuration. resize :: Eq k => HashTable k v -> IO ()