only use a single commit in rename #3
|
@ -652,13 +652,6 @@ module Make (Pclock : Mirage_clock.PCLOCK) = struct
|
|||
let open Lwt.Infix in
|
||||
reynir marked this conversation as resolved
Outdated
|
||||
remove ?and_commit:t.committed t key >|= Result.map_error to_write_error
|
||||
|
||||
let rename t ~source ~dest =
|
||||
(* TODO(dinosaure): optimize it! It was done on the naive way. *)
|
||||
let open Lwt_result.Infix in
|
||||
get t source >>= fun contents ->
|
||||
remove t source >>= fun () ->
|
||||
set t dest contents
|
||||
|
||||
let allocate t key ?last_modified:_ size =
|
||||
let open Lwt.Infix in
|
||||
exists t key >>= function
|
||||
|
@ -709,4 +702,18 @@ module Make (Pclock : Mirage_clock.PCLOCK) = struct
|
|||
Lwt.return_ok res)
|
||||
>|= Result.map_error
|
||||
(fun err -> `Msg (Fmt.str "error pushing %a" Store.pp_error err)))
|
||||
|
||||
let rename t ~source ~dest =
|
||||
let open Lwt_result.Infix in
|
||||
let op t =
|
||||
get t source >>= fun contents ->
|
||||
remove t source >>= fun () ->
|
||||
set t dest contents
|
||||
in
|
||||
match t.committed with
|
||||
| Some _ -> op t
|
||||
| None ->
|
||||
change_and_push t op >>! function
|
||||
| Ok a -> Lwt.return a
|
||||
| Error _ as e -> Lwt.return e
|
||||
end
|
||||
reynir marked this conversation as resolved
Outdated
reynir
commented
I thought "why not unconditionally do Now I am curious if we don't have any yield points inside I thought "why not unconditionally do `change_and_push`?" and the answer is we disallow nested `change_and_push` and this is how we check if we're inside a `change_and_push`.
Now I am curious if we don't have any yield points inside `op`?
hannes
commented
Likely deserves a comment about why we check committed. I may be slow - what do you mean by "don't have any yield points inside Likely deserves a comment about why we check committed.
I may be slow - what do you mean by "don't have any yield points inside `op`"? We do have various yield points in there...
hannes
commented
added a comment in added a comment in 708cd7d
reynir
commented
So my worry was that we could have an unfortunate task interleaving where So my worry was that we could have an unfortunate task interleaving where `rename` just read `/foo` then another task (also inside `change_and_push`) sets `/foo` to something else and then the first task continues with remove & set. This was a problem before and this is an improvement.
hannes
commented
that scenario shouldn't appear anymore, since we're always in a change_and_push now. that scenario shouldn't appear anymore, since we're always in a change_and_push now.
reynir
commented
Well, it can appear if both tasks are within the
Well, it can appear if both tasks are within the `change_and_push`:
```OCaml
let* () = Store.set fs (Key.v "/foo") "value" in
Store.change_and_push fs @@ fun fs ->
Lwt.async (fun () -> Store.set fs (Key.v "/foo") "new value" |> Lwt.map ignore);
Store.rename fs ~source:(Key.v "/foo") ~dest:(Key.v "/bar")
```
|
||||
|
|
Should we keep this comment?
we can. I'm not sure what we should do with the comment, to be honest.
I opened an issue on GitHub instead: https://github.com/robur-coop/git-kv/issues/4