{- | Data.Hash.Consistent A consistent hash is a technique to manage the fair distribution of cacheable entities among hosts. Each host identifier has its crc32 hash calculated and stored in a Vector along with its canonical host name. The host identifier may be differentiated from its canonical host name by a multiplying factor, in our case a simple integer appeneded to the hostname to provide it with a number of entries in the consistent hash, all evenly distributed. This technique is explained in these links: http://en.wikipedia.org/wiki/Consistent_hashing http://www.tomkleinpeter.com/2008/03/17/programmers-toolbox-part-3-consistent-hashing/ Here is a small program illustrating its use: @ module Main where import qualified Data.Hash.Consistent as CH main = do let hosts = ["hi.example.net","bar.example.net","foo.example.net"] :: [CH.Host] let n = 2 :: Int let ch = CH.new print $ show $ ch ch <- return $ CH.add hosts n ch print $ show $ ch let fh = [head hosts] :: [CH.Host] let hh_fh = CH.hashHosts fh n print hh_fh ch <- return $ CH.del fh n ch print $ show $ ch let i = 770931073 let tgt = CH.targetHost i ch print tgt return () @ License info: The license is a simple BSD3-style license available here: https://www.b7j0c.org/stuff/license.txt -} module Data.Hash.Consistent (textCrc32,search,add,del,new,targetHost,hashHosts, Host,Hash,HashHost,ConsistentHash) where import qualified Control.Monad.ST as ST import qualified Data.Word as W import qualified Data.Ord as O import qualified Data.ByteString.UTF8 as BU import qualified Data.Digest.CRC32 as CRC import qualified Data.Vector as V import qualified Data.Vector.Algorithms.Intro as I import qualified Data.Vector.Algorithms.Search as S type Host = String type Hash = W.Word32 type HashHost = (Hash,Host) type ConsistentHash = V.Vector HashHost -- a convenience method to generate a crc for a string textCrc32 :: String -> Hash textCrc32 = CRC.crc32 . BU.fromString -- sort the consistent hash by the hash values sort :: ConsistentHash -> ConsistentHash sort v = ST.runST $ do m <- V.unsafeThaw v I.sortBy (O.comparing fst) m V.unsafeFreeze m -- find the index of the first host hash greater than i search :: Hash -> ConsistentHash -> Int search i v = ST.runST $ do m <- V.unsafeThaw v S.binarySearchBy (O.comparing fst) m (i,"") -- locate which host should cache the item with key hash i targetHost :: Hash -> ConsistentHash -> HashHost targetHost i ch = let idx = search i ch l = V.length ch in if idx >= l then ch V.! 0 else ch V.! idx new = V.empty :: ConsistentHash -- for a set of servers and a multiplying factor, return a list of -- crc hash values hashHosts :: [Host] -> Int -> ConsistentHash hashHosts hosts mult = V.fromList [(textCrc32 $ x++y,x)|x<-hosts,y<-map show [1..mult]] -- add a list of hosts to the consistent hash add :: [Host] -> Int -> ConsistentHash -> ConsistentHash add hosts mult ch = sort $ ch V.++ hashHosts hosts mult -- delete a list of hosts from the consistent hash del :: [Host] -> Int -> ConsistentHash -> ConsistentHash del hosts mult ch = let hh = hashHosts hosts mult in sort $ V.filter (`V.notElem` hh) ch