-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
178 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,11 @@ | ||
(tests | ||
(names dllist_test hashtbl_test mvar_test queue_test stack_test xt_test) | ||
(names | ||
dllist_test | ||
hashtbl_test | ||
lru_cache_example | ||
mvar_test | ||
queue_test | ||
stack_test | ||
xt_test) | ||
(libraries alcotest kcas kcas_data domain_shims) | ||
(package kcas_data)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
open Kcas | ||
open Kcas_data | ||
|
||
type ('k, 'v) t = { | ||
space : int Loc.t; | ||
table : ('k, 'k Dllist.node * 'v) Hashtbl.t; | ||
order : 'k Dllist.t; | ||
} | ||
|
||
let check_capacity capacity = | ||
if capacity < 0 then invalid_arg "Lru_cache: capacity must be non-negative" | ||
|
||
let create ?hashed_type capacity = | ||
check_capacity capacity; | ||
{ | ||
space = Loc.make capacity; | ||
table = Hashtbl.create ?hashed_type (); | ||
order = Dllist.create (); | ||
} | ||
|
||
module Xt = struct | ||
let capacity_of ~xt c = Xt.get ~xt c.space + Hashtbl.Xt.length ~xt c.table | ||
|
||
let set_capacity ~xt c new_capacity = | ||
check_capacity new_capacity; | ||
let old_length = Hashtbl.Xt.length ~xt c.table in | ||
let old_space = Xt.get ~xt c.space in | ||
let old_capacity = old_space + old_length in | ||
for _ = 1 to old_length - new_capacity do | ||
Dllist.Xt.take_blocking_r ~xt c.order |> Hashtbl.Xt.remove ~xt c.table | ||
done; | ||
Xt.set ~xt c.space (Int.max 0 (old_space + new_capacity - old_capacity)) | ||
|
||
let get_opt ~xt c key = | ||
Hashtbl.Xt.find_opt ~xt c.table key | ||
|> Option.map @@ fun (node, datum) -> | ||
Dllist.Xt.move_l ~xt node c.order; | ||
datum | ||
|
||
let set_blocking ~xt c key datum = | ||
let node = | ||
match Hashtbl.Xt.find_opt ~xt c.table key with | ||
| None -> | ||
if 0 = Xt.update ~xt c.space (fun n -> Int.max 0 (n - 1)) then | ||
Dllist.Xt.take_blocking_r ~xt c.order | ||
|> Hashtbl.Xt.remove ~xt c.table; | ||
Dllist.Xt.add_l ~xt key c.order | ||
| Some (node, _) -> | ||
Dllist.Xt.move_l ~xt node c.order; | ||
node | ||
in | ||
Hashtbl.Xt.replace ~xt c.table key (node, datum) | ||
|
||
let remove ~xt c key = | ||
Hashtbl.Xt.find_opt ~xt c.table key | ||
|> Option.iter @@ fun (node, _) -> | ||
Hashtbl.Xt.remove ~xt c.table key; | ||
Dllist.Xt.remove ~xt node; | ||
Xt.incr ~xt c.space | ||
end | ||
|
||
let capacity_of c = Kcas.Xt.commit { tx = Xt.capacity_of c } | ||
let set_capacity c n = Kcas.Xt.commit { tx = Xt.set_capacity c n } | ||
let get_opt c k = Kcas.Xt.commit { tx = Xt.get_opt c k } | ||
|
||
let set_blocking ?timeoutf c k v = | ||
Kcas.Xt.commit ?timeoutf { tx = Xt.set_blocking c k v } | ||
|
||
let remove c k = Kcas.Xt.commit { tx = Xt.remove c k } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
open Kcas | ||
open Kcas_data | ||
|
||
type ('k, 'v) t | ||
|
||
val create : ?hashed_type:'k Hashtbl.hashed_type -> int -> ('k, 'v) t | ||
|
||
module Xt : | ||
Lru_cache_intf.Ops | ||
with type ('k, 'v) t := ('k, 'v) t | ||
with type ('x, 'fn) fn := xt:'x Xt.t -> 'fn | ||
with type ('x, 'fn) blocking_fn := xt:'x Xt.t -> 'fn | ||
|
||
include | ||
Lru_cache_intf.Ops | ||
with type ('k, 'v) t := ('k, 'v) t | ||
with type ('x, 'fn) fn := 'fn | ||
with type ('x, 'fn) blocking_fn := ?timeoutf:float -> 'fn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
open Kcas | ||
|
||
module Lru_cache = struct | ||
include Lru_cache | ||
|
||
module Xt = struct | ||
include Xt | ||
|
||
let get ~xt c key = Kcas.Xt.to_blocking ~xt (get_opt c key) | ||
|
||
let get_if ~xt c key predicate = | ||
let snap = Kcas.Xt.snapshot ~xt in | ||
let datum = get ~xt c key in | ||
if predicate datum then datum else Retry.later (Kcas.Xt.rollback ~xt snap) | ||
|
||
let try_set ~xt c key datum = | ||
match set_blocking ~xt c key datum with | ||
| () -> true | ||
| exception Retry.Later -> false | ||
end | ||
|
||
let get ?timeoutf c k = Kcas.Xt.commit ?timeoutf { tx = Xt.get c k } | ||
let get_if ?timeoutf c k p = Kcas.Xt.commit ?timeoutf { tx = Xt.get_if c k p } | ||
let try_set c k d = Kcas.Xt.commit { tx = Xt.try_set c k d } | ||
end | ||
|
||
let () = | ||
let c = Lru_cache.create 10 in | ||
let domain = | ||
Domain.spawn @@ fun () -> | ||
let tx ~xt = Lru_cache.Xt.get ~xt c "a" + Lru_cache.Xt.get ~xt c "b" in | ||
Xt.commit { tx } | ||
in | ||
Lru_cache.set_blocking c "b" 30; | ||
Lru_cache.set_blocking c "a" 12; | ||
assert (Domain.join domain = 42); | ||
() | ||
|
||
let () = | ||
let c = Lru_cache.create 10 in | ||
assert (Lru_cache.try_set c "a" 1); | ||
Lru_cache.set_blocking c "c" 2; | ||
assert (Lru_cache.capacity_of c = 10); | ||
assert (Lru_cache.get_opt c "b" = None); | ||
assert (Lru_cache.get c "a" = 1); | ||
Lru_cache.set_capacity c 3; | ||
assert (Lru_cache.get c "c" = 2); | ||
Lru_cache.set_capacity c 1; | ||
assert (Lru_cache.capacity_of c = 1); | ||
assert (Lru_cache.get_opt c "a" = None); | ||
assert (Lru_cache.get_if c "c" (( <> ) 0) = 2); | ||
Lru_cache.remove c "c"; | ||
assert (Lru_cache.get_opt c "c" = None); | ||
() | ||
|
||
let () = Printf.printf "LRU Cache OK!\n%!" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module type Ops = sig | ||
type ('k, 'v) t | ||
type ('x, 'fn) fn | ||
type ('x, 'fn) blocking_fn | ||
|
||
val capacity_of : ('x, ('k, 'v) t -> int) fn | ||
val set_capacity : ('x, ('k, 'v) t -> int -> unit) fn | ||
val get_opt : ('x, ('k, 'v) t -> 'k -> 'v option) fn | ||
val set_blocking : ('x, ('k, 'v) t -> 'k -> 'v -> unit) blocking_fn | ||
val remove : ('x, ('k, 'v) t -> 'k -> unit) fn | ||
end |