aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/BranchIndex.ml29
-rw-r--r--lib/kernel/BranchIndex.mli28
-rw-r--r--lib/kernel/BranchManager.ml63
-rw-r--r--lib/kernel/BranchManager.mli9
-rw-r--r--lib/kernel/Lifecycle.ml29
-rw-r--r--lib/kernel/Lifecycle.mli12
-rw-r--r--lib/kernel/Merkle.ml39
-rw-r--r--lib/kernel/Namespace.ml49
-rw-r--r--lib/kernel/Namespace.mli7
-rw-r--r--lib/kernel/Storage.ml22
-rw-r--r--lib/kernel/Storage.mli5
11 files changed, 221 insertions, 71 deletions
diff --git a/lib/kernel/BranchIndex.ml b/lib/kernel/BranchIndex.ml
deleted file mode 100644
index d1efa9a..0000000
--- a/lib/kernel/BranchIndex.ml
+++ /dev/null
@@ -1,29 +0,0 @@
-type address = Concepts.Hash.hash
-type root = address
-type branch_name = string
-type branch_state_root = address
-
-let default_branch_name = "master"
-
-module Branch_name = struct
- type t = branch_name
-
- let encode name = Concepts.Codec.Bencode.(String name |> to_blob)
- let compare left right = Concepts.Ordering.of_int (String.compare left right)
-
- let decode blob =
- Concepts.Codec.Bencode.of_blob blob |> Utilities.Result.fmap Concepts.Codec.Bencode.as_string
-end
-
-module Make (Store : Abstract.Storage.STORAGE) = struct
- module Tree = Merkle.Make (Store) (Branch_name)
-
- type tree = Tree.node
-
- let empty = Tree.empty
- let hash_of = Tree.hash_of
- let persist = Tree.persist
- let find = Tree.find
- let find_branch = Tree.lookup
- let put_branch = Tree.insert
-end
diff --git a/lib/kernel/BranchIndex.mli b/lib/kernel/BranchIndex.mli
deleted file mode 100644
index 5a867bf..0000000
--- a/lib/kernel/BranchIndex.mli
+++ /dev/null
@@ -1,28 +0,0 @@
-type address = Concepts.Hash.hash
-type root = address
-type branch_name = string
-type branch_state_root = address
-
-val default_branch_name : branch_name
-
-module Make (Store : Abstract.Storage.STORAGE) : sig
- type tree
-
- val empty : tree
- val hash_of : tree -> root
- val persist : Store.transaction -> tree -> (root, Concepts.Condition.condition) result
- val find : Store.transaction -> root -> (tree option, Concepts.Condition.condition) result
-
- val find_branch :
- Store.transaction ->
- branch_name ->
- tree ->
- (branch_state_root option, Concepts.Condition.condition) result
-
- val put_branch :
- Store.transaction ->
- branch_name ->
- branch_state_root ->
- tree ->
- (tree, Concepts.Condition.condition) result
-end
diff --git a/lib/kernel/BranchManager.ml b/lib/kernel/BranchManager.ml
new file mode 100644
index 0000000..03a2765
--- /dev/null
+++ b/lib/kernel/BranchManager.ml
@@ -0,0 +1,63 @@
+module Error = struct
+ open Concepts.Condition
+
+ let invalid_root head =
+ condition "invalid-root" "The root hash for the database state is missing from the backend. Either your storage is corrupted, or this is a bug in RNT!"
+ ("hash" |=| (Concepts.Value.String (Concepts.Hash.to_hum_string head)))
+
+ let no_such_branch branch_name =
+ condition "no-such-branch" "A branch with the specified name was not found"
+ ("branch" |=| Concepts.Value.String branch_name)
+
+ let comparison_failed branch_name reference head =
+ condition "comparison-failed" "The HEAD of the branch did not match what was expected"
+ ("branch" |=| Concepts.Value.String branch_name &
+ "reference" |=| Concepts.Value.String (Concepts.Hash.to_hum_string reference) &
+ "head" |=| Concepts.Value.String (Concepts.Hash.to_hum_string head))
+end
+
+module Make (S : Abstract.Storage.STORAGE) = struct
+ module M = Merkle.Make (S) (Merkle.StringKey)
+ module SI = Storage.Make (S)
+
+ type manager = { storage: S.connection;
+ label : string;
+ head: M.node Atomic.t }
+
+ let root_for tx label =
+ let open Utilities.Result in
+ let* label = S.get tx (S.Label label) in
+ let label = Option.map Concepts.Hash.hash_of_blob label in
+ Ok label
+
+ let initialize storage label =
+ let open Utilities.Result in
+ SI.with_transaction storage (fun tx ->
+ let* addr = root_for tx label in
+ match addr with
+ | None -> failwith "TODO"
+ | Some addr ->
+ let* head = M.find tx addr in
+ let* head = Option.to_result ~none:(Error.invalid_root addr) head in
+ Ok { storage; label; head = Atomic.make head })
+
+ let fetch { storage; head; _ } branch_name =
+ SI.with_transaction storage (fun tx ->
+ let head = Atomic.get head in
+ M.lookup tx branch_name head)
+
+ let update { storage; head; label } branch_name reference new_branch =
+ let open Utilities.Result in
+ let* _ = SI.with_transaction storage (fun tx ->
+ Utilities.Atomic.mswap head (fun head ->
+ let* branch = M.lookup tx branch_name head
+ |> Result.map (Option.to_result ~none:(Error.no_such_branch branch_name))
+ |> Result.join in
+ if branch = reference then
+ let* new_head = M.insert tx label new_branch head in
+ Ok new_head
+ else
+ Error (Error.comparison_failed branch_name reference branch))) in
+ Ok ()
+
+end
diff --git a/lib/kernel/BranchManager.mli b/lib/kernel/BranchManager.mli
new file mode 100644
index 0000000..052f9a1
--- /dev/null
+++ b/lib/kernel/BranchManager.mli
@@ -0,0 +1,9 @@
+module Make (S : Abstract.Storage.STORAGE) : sig
+ type manager
+
+ val initialize : S.connection -> string -> (manager, Concepts.Condition.condition) result
+ val fetch : manager -> string -> (Concepts.Hash.hash option, Concepts.Condition.condition) result
+ val update : manager -> string -> Concepts.Hash.hash -> Concepts.Hash.hash -> (unit, Concepts.Condition.condition) result
+
+ (* TODO: fork, join *)
+end
diff --git a/lib/kernel/Lifecycle.ml b/lib/kernel/Lifecycle.ml
new file mode 100644
index 0000000..ff67ecf
--- /dev/null
+++ b/lib/kernel/Lifecycle.ml
@@ -0,0 +1,29 @@
+class type lifecycle = object
+ method reference : bool
+ method release : unit
+end
+
+class type virtual controlled_lifecycle = object
+ inherit lifecycle
+ method virtual destroy : unit
+end
+
+class null = object
+ method reference = true
+ method release = ()
+end
+
+class virtual counted = object (self)
+ val references = Atomic.make 1
+
+ method virtual destroy : unit
+
+ method reference =
+ Atomic.incr references;
+ true
+
+ method release =
+ Atomic.decr references;
+ if Atomic.get references <= 0 then
+ self#destroy
+end
diff --git a/lib/kernel/Lifecycle.mli b/lib/kernel/Lifecycle.mli
new file mode 100644
index 0000000..f110768
--- /dev/null
+++ b/lib/kernel/Lifecycle.mli
@@ -0,0 +1,12 @@
+class type lifecycle = object
+ method reference : bool
+ method release : unit
+end
+
+class type virtual controlled_lifecycle = object
+ inherit lifecycle
+ method virtual destroy : unit
+end
+
+class null : lifecycle
+class virtual counted : controlled_lifecycle
diff --git a/lib/kernel/Merkle.ml b/lib/kernel/Merkle.ml
index af703d7..ababb03 100644
--- a/lib/kernel/Merkle.ml
+++ b/lib/kernel/Merkle.ml
@@ -1,8 +1,8 @@
module type VALUE = sig
type t
- val encode : t -> Concepts.Representation.blob
- val decode : Concepts.Representation.blob -> (t, Concepts.Condition.condition) result
+ val encode : t -> Concepts.Blob.t
+ val decode : Concepts.Blob.t -> (t, Concepts.Condition.condition) result
end
module type KEY = sig
@@ -19,6 +19,7 @@ module type TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> sig
val find : S.transaction -> address -> (node option, Concepts.Condition.condition) result
val empty : node
+ val empty_under : S.transaction -> (address, Concepts.Condition.condition) result
val hash_of : node -> address
@@ -68,12 +69,12 @@ module Make : TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> struct
| Trunk { keys; _ } -> keys
let of_bencode =
- let open Concepts.Codec.Bencode in
+ let open Concepts.Encoding.Bencode in
let open Utilities.Result in
(* This is terrible *)
let decode_key t = as_string t
|> Result.map String.to_bytes
- |> Result.map Concepts.Representation.blob_of_bytes
+ |> Result.map Concepts.Blob.blob_of_bytes
|> fmap K.decode in
let decode_value t = as_string t |> Result.map Concepts.Hash.of_raw_string in
let decode_list f data = data
@@ -92,14 +93,14 @@ module Make : TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> struct
Ok (Trunk { keys; children })
| _ -> Error (Error.malformed_node ())
- let from_blob blob = Concepts.Codec.Bencode.of_blob blob
+ let from_blob blob = Concepts.Encoding.Bencode.of_blob blob
|> Utilities.Result.fmap of_bencode
let to_bencode =
- let open Concepts.Codec.Bencode in
+ let open Concepts.Encoding.Bencode in
(* Ditto. *)
let bencode_key k = K.encode k
- |> Concepts.Representation.bytes_of_blob
+ |> Concepts.Blob.bytes_of_blob
|> String.of_bytes
|> (fun s -> String s) in
let bencode_hash h = String (Concepts.Hash.to_raw_string h) in
@@ -111,7 +112,7 @@ module Make : TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> struct
Tagged ('#', Dict [("keys", List (BatFingerTree.to_list keys |> List.map bencode_key));
("children", List (BatFingerTree.to_list children |> List.map bencode_hash))])
- let to_blob node = to_bencode node |> Concepts.Codec.Bencode.to_blob
+ let to_blob node = to_bencode node |> Concepts.Encoding.Bencode.to_blob
(* TODO: we should probably cache this inside the node itself rather
than recalculating it every time. We could also allow the user to
@@ -121,7 +122,7 @@ module Make : TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> struct
let find tx addr =
let open Utilities.Result in
- let* data = S.get tx addr in
+ let* data = S.get tx (S.Hash node) in
match data with
| None -> Ok None
| Some data ->
@@ -149,9 +150,11 @@ module Make : TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> struct
let open Utilities.Result in
let data = to_blob node in
let addr = Concepts.Hash.hash_of_blob data in
- let* () = S.put tx addr data in
+ let* () = S.put tx (S.Hash addr) data in
Ok addr
+ let empty_under tx = persist tx empty
+
type op = Update of address * node | Split of address * K.t * address
let emplace i v ft =
@@ -217,7 +220,7 @@ module Make : TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> struct
BatFingerTree.iter
(fun k ->
K.encode k
- |> Concepts.Representation.bytes_of_blob
+ |> Concepts.Blob.bytes_of_blob
|> Buffer.add_bytes buffer)
ks;
Concepts.Hash.hash_of_bytes (Buffer.to_bytes buffer)
@@ -303,7 +306,7 @@ module Make : TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> struct
end
module type INTERFACE = functor (S : Abstract.Storage.STORAGE) (K : KEY) (V : VALUE) -> sig
- type address
+ type address = Concepts.Hash.hash
type node
val find : S.transaction -> address -> (node option, Concepts.Condition.condition) result
@@ -332,11 +335,11 @@ module Interface : INTERFACE = functor (S : Abstract.Storage.STORAGE) (K : KEY)
let intern tx v =
let data = V.encode v in
let addr = Concepts.Hash.hash_of_blob data in
- let* () = S.put tx addr data in
+ let* () = S.put tx (S.Hash addr) data in
Ok addr
let retrieve tx addr =
- let* data = S.get tx addr in
+ let* data = S.get tx (S.Hash addr) in
match data with
| None -> Ok None
| Some data ->
@@ -379,3 +382,11 @@ module Interface : INTERFACE = functor (S : Abstract.Storage.STORAGE) (K : KEY)
(fun _ k v -> f k v |> ignore)
() node
end
+
+module StringKey : KEY with type t = string = struct
+ type t = string
+
+ let encode s = String.to_bytes s |> Concepts.Blob.blob_of_bytes
+ let compare s1 s2 = String.compare s1 s2 |> Concepts.Ordering.of_int
+ let decode b = Concepts.Blob.bytes_of_blob b |> String.of_bytes |> Result.ok
+end
diff --git a/lib/kernel/Namespace.ml b/lib/kernel/Namespace.ml
new file mode 100644
index 0000000..7c9cd2b
--- /dev/null
+++ b/lib/kernel/Namespace.ml
@@ -0,0 +1,49 @@
+module Errors = struct
+ include Concepts.Condition
+
+ let key_already_exists key =
+ condition "key-already-exists" "The specified key already exists in the namespace"
+ ("key" |=| Concepts.Value.String key)
+
+ let no_such_key key =
+ condition "no-such-key" "The specified key does not exist in the namespace"
+ ("key" |=| Concepts.Value.String key)
+end
+
+class namespace = object (self)
+ inherit Lifecycle.null
+
+ val entries : (string, Protocols.Handle.t) BatMap.t Atomic.t =
+ Atomic.make BatMap.empty
+
+ method protocols = Protocols.[Directory.make self; Registry.make self]
+
+ method register key value =
+ Utilities.Atomic.mswap entries
+ (fun e ->
+ match BatMap.find_opt key e with
+ | None -> Ok (BatMap.add key value e)
+ | Some _ -> Error (Errors.key_already_exists key))
+ |> Result.map ignore
+
+ method unregister key =
+ Utilities.Atomic.mswap entries
+ (fun e ->
+ try
+ Ok (BatMap.remove_exn key e)
+ with Not_found ->
+ Error (Errors.no_such_key key))
+ |> Result.map ignore
+
+ method list =
+ Atomic.get entries
+ |> BatMap.keys
+ |> BatList.of_enum
+
+ method find key =
+ Atomic.get entries
+ |> BatMap.find_opt key
+ |> Utilities.Option.fmap Protocols.Handle.copy
+end
+
+let make () = new namespace
diff --git a/lib/kernel/Namespace.mli b/lib/kernel/Namespace.mli
new file mode 100644
index 0000000..3ed64a3
--- /dev/null
+++ b/lib/kernel/Namespace.mli
@@ -0,0 +1,7 @@
+class namespace : object
+ inherit Protocols.Handle.obj
+ inherit Protocols.Directory.implementation
+ inherit Protocols.Registry.implementation
+end
+
+val make : unit -> namespace
diff --git a/lib/kernel/Storage.ml b/lib/kernel/Storage.ml
new file mode 100644
index 0000000..376d839
--- /dev/null
+++ b/lib/kernel/Storage.ml
@@ -0,0 +1,22 @@
+module Make (S : Abstract.Storage.STORAGE) = struct
+ let finish tx = function
+ | Ok value ->
+ let open Utilities.Result in
+ let* () = S.commit tx in
+ Ok value
+ | Error condition ->
+ let _ = S.abort tx in
+ Error condition
+
+ let with_transaction connection body =
+ let open Utilities.Result in
+ let* tx = S.start connection in
+ body tx |> finish tx
+
+ let store_blob tx blob =
+ let open Utilities.Result in
+ let address = Concepts.Hash.hash_of_blob blob in
+ let* () = S.put tx (S.Hash address) blob in
+ Ok address
+
+end
diff --git a/lib/kernel/Storage.mli b/lib/kernel/Storage.mli
new file mode 100644
index 0000000..1148fba
--- /dev/null
+++ b/lib/kernel/Storage.mli
@@ -0,0 +1,5 @@
+module Make : functor (S : Abstract.Storage.STORAGE) -> sig
+ val finish : S.transaction -> ('a, Concepts.Condition.condition) result -> ('a, Concepts.Condition.condition) result
+ val with_transaction : S.connection -> (S.transaction -> ('a, Concepts.Condition.condition) result) -> ('a, Concepts.Condition.condition) result
+ val store_blob : S.transaction -> Concepts.Blob.t -> (Concepts.Hash.hash, Concepts.Condition.condition) result
+end