-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathconsistent_hash.ml
58 lines (48 loc) · 1.45 KB
/
consistent_hash.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
module IntMap = Map.Make (Int64)
module type DIGEST =
sig
type t = string
val string: string -> t
end
module Make (Digest: DIGEST) = struct
type +'a t = {
map: (string * 'a) IntMap.t;
interleave_count: int;
}
let make ?(interleave_count = 40) () =
{map = IntMap.empty; interleave_count}
let hash_val digested entry_fn =
let slc i sw =
Int64.shift_left (Int64.of_int (int_of_char digested.[entry_fn i])) sw
and (lor) = Int64.logor in
(slc 3 24) lor (slc 2 16) lor (slc 1 8) lor (slc 0 0)
let hash s =
hash_val (Digest.string s) (fun x -> x)
let add ?(weight = 1) key value m =
let insert digested i map =
IntMap.add
(hash_val digested (fun x -> x + i * 4))
(key, value)
map
and factor = m.interleave_count * weight in
let rec aux accum = function
| x when x = factor -> accum
| j ->
let f = Printf.sprintf "%s-%d" key j |> Digest.string |> insert in
aux
(accum |> f 0 |> f 1 |> f 2)
(succ j)
in
{m with map = aux m.map 0}
let remove key m =
{m with map = IntMap.filter (fun _ (ks, _) -> ks <> key) m.map}
let find key m =
let l, data, r = IntMap.split (hash key) m.map in
match data with
| Some (_, x) -> x
| None when IntMap.is_empty r -> IntMap.min_binding l |> snd |> snd
| None -> IntMap.min_binding r |> snd |> snd
let iter f m =
let f' ki (ks, v) = f ki ks v in
IntMap.iter f' m.map
end