diff options
Diffstat (limited to 'lib/kernel/BranchManager.ml')
| -rw-r--r-- | lib/kernel/BranchManager.ml | 63 |
1 files changed, 63 insertions, 0 deletions
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 |
