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

Protobuf [WIP] #12

Merged
merged 15 commits into from
Jun 20, 2018
Merged

Protobuf [WIP] #12

merged 15 commits into from
Jun 20, 2018

Conversation

dinosaure
Copy link
Member

No description provided.

@dinosaure
Copy link
Member Author

Depend on #10 currently ... Just see share my work.

@samoht
Copy link
Member

samoht commented Jun 8, 2018

Some compilation errors:

#=== ERROR while installing lambda.~unknown ===================================#
# opam-version         1.2.2 (aa258ecc06d3aea5a67f442a4ffd23f2a457180b)
# os                   linux
# command              jbuilder build -p lambda -j 4
# path                 /home/opam/.opam/4.06.0/build/lambda.~unknown
# compiler             4.06.0
# exit-code            1
# env-file             /home/opam/.opam/4.06.0/build/lambda.~unknown/lambda-7857-ffb3fd.env
# stdout-file          /home/opam/.opam/4.06.0/build/lambda.~unknown/lambda-7857-ffb3fd.out
# stderr-file          /home/opam/.opam/4.06.0/build/lambda.~unknown/lambda-7857-ffb3fd.err
### stderr ###
# File "src/jbuild", line 4, characters 16-31:
# Error: Library "lambda_protobuf" not found.
# Hint: try: jbuilder external-lib-deps --missing -p lambda @install
#       menhir src/parser.{ml,mli}
# Note: the nonterminal symbol list (from parser.mly) is renamed parser_list.

lambda.opam Outdated
@@ -9,6 +9,7 @@ bug-reports: "https://github.com/samoht/mirage-lambda/issues"
build: [ "jbuilder" "build" "-p" name "-j" jobs ]
depends: [
"jbuilder" {build}
"lambda-protobuf"
Copy link
Member

Choose a reason for hiding this comment

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

why do you need this in the opam file?

Copy link
Member

Choose a reason for hiding this comment

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

and if you do need it, don't forget to pin it in .travis.yml too!

required string name = 1;
repeated Type arguments = 2;
required Type return = 3;
required int32 smartptr = 4;
Copy link
Contributor

Choose a reason for hiding this comment

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

What value should the Haskell side provide for the smartptr field? Maybe this field should not be serialized, but resolved by the Mirage server based on the name field?

Copy link
Member Author

Choose a reason for hiding this comment

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

The idea behind smartptr is to bind (on the MirageOS/OCaml side) an int64 with functions/primitives. Then, when we deserialize, we try to find this identifier in an internal map of the unikernel. So, currently the identifier is an int64 to be close to the idea of how to share a function between two processes. However, we can choose another identifier (like a string if you want).

On the haskell side, you just need to have a Map int64 ([value] -> value) (or, if you prefer a string, a Map String ([value] -> value).

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, so the smartptr is just the index into the array of primitives? E.g. here it would be index 4 for Block.read? The name field is ignored in that case? I feel a mapping from strings to primitives might be easier to maintain.

Copy link
Member Author

Choose a reason for hiding this comment

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

Exactly, so I will change the key to be a string 👍

message Int64 { }
message Bool { }
message String { }
message Lwt { }
Copy link
Contributor

Choose a reason for hiding this comment

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

How to handle values of Lwt type? E.g. some block operations have lwt return types. Is the value serialization not implemented, yet, or am I overlooking something?

Copy link
Member Author

Choose a reason for hiding this comment

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

You need to use Apply and Lwt (like Apply (Int, Lwt)). This about a limitation of the OCaml type-system (and the higher kind polymorphism). We can provide a sugar about that if you want.

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, thanks. Just to verify, would the following be a correct encoding of the program

λ (output_block : page_aligned_buffer).
  Block.read 42 output_block

(using the definitions from here)

lam {
  typ { abstract { witness: "Cstruct.t" } }
  var: "output_block"
  expr {
    app {
      a {
        app {
          a {
            prm {
              value {
                name: "Block.read"
                arguments { int64 { } }
                arguments { list { value { abstract { witness: "Cstruct.t" } } } }
                return {
                  apply {
                    a {
                      result { a { unit { } } b { abstract { witness: "Block.error" } } }
                    }
                    b { lwt { } }
                  }
                }
                smartptr: 4
              }
            }
          }
          b { val { value { int64 { value: 42 } } } }
        }
      }
      b { var { var: 0 } }
    }
  }
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Exactly 👍 , as I said, we can provide a sugar and translate lwt { something } to apply { a { something } b { lwt { } } internally if it's better for you.

@@ -0,0 +1,195 @@
message Type {
Copy link
Contributor

Choose a reason for hiding this comment

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

protoc complains about a missing line syntax = "proto2";.

Copy link
Member Author

Choose a reason for hiding this comment

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

Noted.

@aherrmann
Copy link
Contributor

Thanks for the updates.

I have another question:
Block.get_info returns a value of type lwt info.
How can I access the fields in the info record?

There are two parts to this.
First, how can I get through the lwt? Is there a bind and return in lambda?
Second, how can I access record fields? Judging by this comment this seems to be not implemented, yet?

@samoht
Copy link
Member

samoht commented Jun 19, 2018

As bind and return are polymorphic, at the moment we need to define them as primitives and expose monorphic types. This is really annoying and I am not sure how to solve that yet (I will have a go at it tomorrow). For the record fields, I have a branch that I will try to resurect. Meanwhile, you can define primitives to read the fields, eg. something like:

  let info = Type.abstract "Mirage_block.info" in
  let primitives = [
    primitive "read_write" [info] Type.bool (fun x -> x.Mirage_block.read_write);
   ...
  ] in

@samoht
Copy link
Member

samoht commented Jun 20, 2018

I've rebased on top of master -- my plan is to fix the CI and then merge the PR. We can improve it (use first-class bind/return + syntax for records) in subsequent PRs.

@aherrmann
Copy link
Contributor

aherrmann commented Jun 20, 2018

We can improve it (use first-class bind/return + syntax for records) in subsequent PRs.

Sounds good, defining dedicated primitives is a viable work-around for a start.

I tried compiling the code on revision 5c5fcad.
I'm getting compilation errors with the following Dockerfile:

FROM ocaml/opam:alpine-3.6_ocaml-4.06.0
USER opam
RUN opam remote add dev git://github.com/mirage/mirage-dev \
 && opam depext -i mirage
# The opam repo shipped with the docker image does not contain crowbar
RUN opam repo add opam https://opam.ocaml.org \
 && opam install crowbar higher menhir lwt ocaml-protoc ppx_deriving

COPY mirage-lambda mirage-lambda
RUN sudo chown -R opam mirage-lambda \
 && sudo chmod -R +w mirage-lambda
WORKDIR mirage-lambda
# Get opam installed tools into $PATH
RUN source ~/.profile \
 && make

This is the compilation output with the error message at the end:

Step 8/8 : RUN source ~/.profile  && make
 ---> Running in 2e339291e0a4
jbuilder build --dev
ocaml-protoc proto/lambda_pb.{ml,mli},proto/lambda_types.{ml,mli}
Generating ./lambda_types.mli
Generating ./lambda_types.ml
Generating ./lambda_pb.mli
Generating ./lambda_pb.ml
      ocamlc proto/lambda_protobuf__.{cmi,cmo,cmt}
    ocamllex src/lexer.ml
      ocamlc src/lambda__.{cmi,cmo,cmt}
    ocamldep proto/lambda_protobuf.dependsi.ocamldep-output
    ocamldep proto/lambda_protobuf.depends.ocamldep-output
    ocamlopt proto/lambda_protobuf__.{cmx,o}
    ocamlopt src/lambda__.{cmx,o}
      menhir src/parser.{ml,mli}
Note: the nonterminal symbol list (from src/parser.mly) is renamed src_parser_list.
    ocamlopt .ppx/ppx_deriving.eq+ppx_deriving.show+ppx_deriving.ord/ppx.exe
         ppx src/eq.pp.ml
         ppx src/lambda.pp.ml
         ppx src/fuzzer.pp.ml
         ppx src/parsetree.pp.ml
         ppx src/primitive.pp.ml
         ppx src/lambda.pp.mli
         ppx src/parsetree.pp.mli
         ppx src/t.pp.ml
         ppx src/typedtree.pp.ml
         ppx src/primitive.pp.mli
         ppx src/typedtree.pp.mli
         ppx src/parser.pp.mli
         ppx src/lexer.pp.ml
    ocamldep src/lambda.dependsi.ocamldep-output
         ppx src/parser.pp.ml
    ocamldep src/lambda.depends.ocamldep-output
      ocamlc src/lambda__Eq.{cmi,cmo,cmt}
    ocamlopt src/lambda__Eq.{cmx,o}
      ocamlc src/lambda__T.{cmi,cmo,cmt}
      ocamlc src/lambda__Parsetree.{cmi,cmti}
      ocamlc src/lambda__Parser.{cmi,cmti}
      ocamlc src/lambda__Typedtree.{cmi,cmti}
    ocamlopt src/lambda__T.{cmx,o}
      ocamlc src/lambda__Lexer.{cmi,cmo,cmt}
      ocamlc src/lambda__Primitive.{cmi,cmti}
      ocamlc src/lambda__Typedtree.{cmo,cmt} (exit 2)
(cd _build/default && /home/opam/.opam/4.06.0/bin/ocamlc.opt -w @a-4-29-40-41-42-44-45-48-58-59-60-40 -strict-sequence -strict-formats -short-paths -keep-locs -g -bin-annot -I /home/opam/.opam/4.06.0/lib/afl-persistent -I /home/opam/.opam/4.06.0/lib/bytes -I /home/opam/.opam/4.06.0/lib/cmdliner -I /home/opam/.opam/4.06.0/lib/crowbar -I /home/opam/.opam/4.06.0/lib/fmt -I /home/opam/.opam/4.06.0/lib/higher -I /home/opam/.opam/4.06.0/lib/logs -I /home/opam/.opam/4.06.0/lib/lwt -I /home/opam/.opam/4.06.0/lib/ocaml -I /home/opam/.opam/4.06.0/lib/ocplib-endian -I /home/opam/.opam/4.06.0/lib/ppx_deriving -I /home/opam/.opam/4.06.0/lib/result -I /home/opam/.opam/4.06.0/lib/uchar -no-alias-deps -I src -open Lambda__ -o src/lambda__Typedtree.cmo -c -impl src/typedtree.pp.ml)
File "src/typedtree.ml", line 275, characters 6-115:
Error: This expression has type unit but an expression was expected of type v
      ocamlc src/lambda__Parsetree.{cmo,cmt} (exit 2)
(cd _build/default && /home/opam/.opam/4.06.0/bin/ocamlc.opt -w @a-4-29-40-41-42-44-45-48-58-59-60-40 -strict-sequence -strict-formats -short-paths -keep-locs -g -bin-annot -I /home/opam/.opam/4.06.0/lib/afl-persistent -I /home/opam/.opam/4.06.0/lib/bytes -I /home/opam/.opam/4.06.0/lib/cmdliner -I /home/opam/.opam/4.06.0/lib/crowbar -I /home/opam/.opam/4.06.0/lib/fmt -I /home/opam/.opam/4.06.0/lib/higher -I /home/opam/.opam/4.06.0/lib/logs -I /home/opam/.opam/4.06.0/lib/lwt -I /home/opam/.opam/4.06.0/lib/ocaml -I /home/opam/.opam/4.06.0/lib/ocplib-endian -I /home/opam/.opam/4.06.0/lib/ppx_deriving -I /home/opam/.opam/4.06.0/lib/result -I /home/opam/.opam/4.06.0/lib/uchar -no-alias-deps -I src -open Lambda__ -o src/lambda__Parsetree.cmo -c -impl src/parsetree.pp.ml)
File "src/parsetree.ml", line 159, characters 4-70:
Error: This expression has type unit but an expression was expected of type
         string
      ocamlc src/lambda__Fuzzer.{cmi,cmo,cmt} (exit 2)
(cd _build/default && /home/opam/.opam/4.06.0/bin/ocamlc.opt -w @a-4-29-40-41-42-44-45-48-58-59-60-40 -strict-sequence -strict-formats -short-paths -keep-locs -g -bin-annot -I /home/opam/.opam/4.06.0/lib/afl-persistent -I /home/opam/.opam/4.06.0/lib/bytes -I /home/opam/.opam/4.06.0/lib/cmdliner -I /home/opam/.opam/4.06.0/lib/crowbar -I /home/opam/.opam/4.06.0/lib/fmt -I /home/opam/.opam/4.06.0/lib/higher -I /home/opam/.opam/4.06.0/lib/logs -I /home/opam/.opam/4.06.0/lib/lwt -I /home/opam/.opam/4.06.0/lib/ocaml -I /home/opam/.opam/4.06.0/lib/ocplib-endian -I /home/opam/.opam/4.06.0/lib/ppx_deriving -I /home/opam/.opam/4.06.0/lib/result -I /home/opam/.opam/4.06.0/lib/uchar -no-alias-deps -I src -open Lambda__ -o src/lambda__Fuzzer.cmo -c -impl src/fuzzer.pp.ml)
File "src/fuzzer.ml", line 39, characters 14-100:
Error: This expression has type unit but an expression was expected of type
         a Fmt.t = Format.formatter -> a -> unit
    ocamlopt src/lambda__Parsetree.{cmx,o} (exit 2)
(cd _build/default && /home/opam/.opam/4.06.0/bin/ocamlopt.opt -w @a-4-29-40-41-42-44-45-48-58-59-60-40 -strict-sequence -strict-formats -short-paths -keep-locs -g -I /home/opam/.opam/4.06.0/lib/afl-persistent -I /home/opam/.opam/4.06.0/lib/bytes -I /home/opam/.opam/4.06.0/lib/cmdliner -I /home/opam/.opam/4.06.0/lib/crowbar -I /home/opam/.opam/4.06.0/lib/fmt -I /home/opam/.opam/4.06.0/lib/higher -I /home/opam/.opam/4.06.0/lib/logs -I /home/opam/.opam/4.06.0/lib/lwt -I /home/opam/.opam/4.06.0/lib/ocaml -I /home/opam/.opam/4.06.0/lib/ocplib-endian -I /home/opam/.opam/4.06.0/lib/ppx_deriving -I /home/opam/.opam/4.06.0/lib/result -I /home/opam/.opam/4.06.0/lib/uchar -no-alias-deps -I src -open Lambda__ -o src/lambda__Parsetree.cmx -c -impl src/parsetree.pp.ml)
File "src/parsetree.ml", line 159, characters 4-70:
Error: This expression has type unit but an expression was expected of type
         string
make: *** [Makefile:4: all] Error 1

@samoht
Copy link
Member

samoht commented Jun 20, 2018

This error is very strange. I've just pushed a Dockerfile (and pushed samoht/mirage-lambda on Dockerhub) where I managed to compile the project properly. I guess it would be more useful for you if we could start a small unikernel listening on a port so you could test the client side.

@aherrmann
Copy link
Contributor

I guess it would be more useful for you if we could start a small unikernel listening on a port so you could test the client side.

Yes, that would be great! You can find a description of the wire-protocol I have in mind here. The corresponding protobufs definition is here. Let me know if there's something that you think should be changed.

@samoht
Copy link
Member

samoht commented Jun 20, 2018

@aherrmann the protocol looks great to me! Do you mind adding a copy in that repo too (with the description + request.proto)?

@samoht samoht merged commit 1f10738 into mirage:master Jun 20, 2018
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.

3 participants