Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental Eio-port #113

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft

Conversation

patricoferris
Copy link
Contributor

This is a very experimental PR/branch that starts trying to port OBuilder to Eio. As part of some other work I wanted to start tackling ocaml-multicore/eio#126 so I was looking for a good candidate that made heavy use of subprocesses and redirections!

This branch is currently building with this branch of Eio: https://github.com/patricoferris/eioio/tree/processes

The trickiest part at the moment seems to be how to handle cancellation correctly. I was thinking of maybe just having a global switch that's passes in via Build.build that everything uses to spawn fibers etc. and that can be the switch that is cancelled if the user does -- any thoughts on this @talex5 ?

lib/build_log.ml Outdated
Comment on lines 41 to 45
try
match Flow.read ch (Cstruct.sub buf 0 max_chunk_size) with
| 0 -> Promise.resolve set_th (Ok ())
| n -> dst (Cstruct.to_string buf ~off:0 ~len:n); aux ()
with End_of_file -> Promise.resolve set_th (Ok ())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
try
match Flow.read ch (Cstruct.sub buf 0 max_chunk_size) with
| 0 -> Promise.resolve set_th (Ok ())
| n -> dst (Cstruct.to_string buf ~off:0 ~len:n); aux ()
with End_of_file -> Promise.resolve set_th (Ok ())
match Flow.read ch (Cstruct.sub buf 0 max_chunk_size) with
| 0 -> Promise.resolve set_th (Ok ())
| n -> dst (Cstruct.to_string buf ~off:0 ~len:n); aux ()
| exception End_of_file -> Promise.resolve set_th (Ok ())

Copy link
Contributor

@talex5 talex5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for experimenting with this! I skimmed it and added a few comments.

The trickiest part at the moment seems to be how to handle cancellation correctly. I was thinking of maybe just having a global switch that's passes in via Build.build that everything uses to spawn fibers etc. and that can be the switch that is cancelled if the user does -- any thoughts on this @talex5 ?

Ideally, we just remove almost everything to do with cancellation. If the user wants to cancel a build they can just cancel the fiber running it and let Eio's cancellation system sort it out.

let purge path =
Sys.readdir path |> Array.to_list |> Lwt_list.iter_s (fun item ->
let purge t path =
Sys.readdir path |> Array.to_list |> Fiber.iter (fun item ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: the direct translation of Lwt_list.iter_s is List.iter.

(libraries lwt lwt.unix fmt fmt.cli fmt.tty tar-unix obuilder cmdliner logs.fmt logs.cli))
(libraries eio_main fmt fmt.cli fmt.tty tar-unix obuilder cmdliner logs.fmt logs.cli))

(vendored_dirs lwt_eio.0.2 eioio tar.2.0.1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's called eio now. You might want to rename your fork.

let args = "btrfs" :: args in
let args = if sudo && not running_as_root then "sudo" :: args else args in
Os.exec ~stdout:`Dev_null args
Switch.run @@ fun sw ->
Os.exec ~sw ~process:t.process args
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Os.exec shouldn't take a switch, because when it returns the process has already finished.

let check_kernel_version () =
Os.pread ["uname"; "-r"] >>= fun kver ->
let check_kernel_version process =
let kver = Switch.run @@ fun sw -> Os.pread ~sw ~process ["uname"; "-r"] in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't have a switch here either.

lib/build.ml Outdated
)
>>= fun mounts ->
let mounts =
Fiber.map (fun { Obuilder_spec.Cache.id; target; buildkit_options = _ } ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a direct translation:

Suggested change
Fiber.map (fun { Obuilder_spec.Cache.id; target; buildkit_options = _ } ->
List.map (fun { Obuilder_spec.Cache.id; target; buildkit_options = _ } ->

(** [empty] is a read-only log with no content. *)

val of_saved : string -> t Lwt.t
val of_saved : Eio.Dir.t -> string -> t
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val of_saved : Eio.Dir.t -> string -> t
val of_saved : Eio.Path.t -> t

log : Build_log.t Lwt.t;
result : (([`Loaded | `Saved] * S.id), [`Cancelled | `Msg of string]) Lwt_result.t;
set_cancelled : unit Promise.u; (* Resolve this to cancel (when [users = 0]). *)
log : (Build_log.t, exn) result Promise.t;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
log : (Build_log.t, exn) result Promise.t;
log : Build_log.t Promise.or_exn;

lib/os.ml Outdated
let r, w = Lwt_unix.pipe_in ~cloexec:true () in
let w = { raw = w; needs_close = true } in
Lwt.finalize
let with_pipe_from_child ~sw fn =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let with_pipe_from_child ~sw fn =
let with_pipe_from_child fn =
Switch.run @@ fun sw ->

lib/s.ml Outdated
@@ -65,13 +65,16 @@ module type SANDBOX = sig
type t

val run :
cancelled:unit Lwt.t ->
?stdin:Os.unix_fd ->
sw:Eio__core.Switch.t ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't need a switch here. Everything will be finished when run returns.

sw:Eio__core.Switch.t ->
dir:#Eio.Dir.t ->
process:Eio.Process.t ->
cancelled:unit Eio.Promise.t ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can probably remove this and use Eio's built-in cancellation.

@MisterDA
Copy link
Contributor

MisterDA commented Jan 9, 2023

Are there any blockers apart from applying the suggestions from the code review and rebasing? I'd definitely enjoy debugging with backtraces (hoping that the switch to OCaml 5 and Eio would provide them).

@talex5
Copy link
Contributor

talex5 commented Jan 13, 2023

Are there any blockers apart from applying the suggestions from the code review and rebasing? I'd definitely enjoy debugging with backtraces (hoping that the switch to OCaml 5 and Eio would provide them).

However, you might not enjoy that it will no longer work on Windows :-( See ocaml-multicore/eio#125 for remaining issues if you want to help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants