113.33.01

core

core_kernel

113.33.00

async

Keep up to date with interface changes in Async_kernel, Async_extra and
Async_unix.

async_extended

I haven't thought very hard about what happens if the subprocess dies after
successful handshake and/or the implications of the Writer's monitor being the
monitor in effect when with_close is called. I think heartbeats will kill the
connection before this becomes an issue.

It's causing problems for the open-source release on platforms that don't have
Posix_clock.gettime:

  https://github.com/janestreet/async_extended/issues/1

Seems that a module with Deprecated in the name and no uses should just be binned.

async_extra

The resulting functions are analogous to Pipe.iter_without_pushback and
Pipe.iter.

async_kernel

This required fixing a few places where the new Let_syntax in scope
shadowed Command.Param.Let_syntax.

Wrapping the unhandle exception with Error.create will serialize this exception
and prevent us to have good error reporting in Js_of_ocaml.

Time_source still uses the Async scheduler for running jobs that
fire -- the new power comes from the user being able to advance time
distinctly from the wall clock.

And, for non-wall-clock time sources, don't show the Job.ts in
events, because they are uninformative pool pointers.

Context: implementation of Eager_deferred in the works that essentially wants to
redefine map, bind, etc, in the following way:

  let map t ~f =
    if Deferred.is_determined t
    then return (f (Deferred.value_exn t))
    else Deferred.map t ~f
  ;;

async_parallel

This is needed when using Async_parallel_deprecated in a daemonized processes, such as
the in-development jenga server.

Without this option, Calling Process.run ~prog:"jenga" ~args:"server";"start"` ` from
build-manager is problematic because the resulting deferred never becomes determined.

async_rpc_kernel

Summary

The aborted Deferred.t that got passed to Pipe_rpc implementations is
gone. The situations where it would have been determined now close the reading
end of the user-supplied pipe instead.

Details

Previously, when an RPC dispatcher decided to abort a query, the RPC
implementation would get its aborted Deferred.t filled in, but would remain
free to write some final elements to the pipe.

This is a little bit more flexible than the new interface, but it's also
problematic in that the implementer could easily just not pay attention to
aborted. (They're not obligated to pay attention to when the pipe is closed,
either, but at least they can't keep writing to it.) We don't think the extra
flexibility was used at all.

In the future, we may also simplify the client side to remove the abort
function on the dispatch side (at least when not using dispatch_iter). For the
time being it remains, but closing the received pipe is the preferred way of
aborting the query.

There are a couple of known ways this might have changed behavior from before.
Both of these appear not to cause problems in the jane repo.

Here's an example of what a new error looks like:

((rpc_error
  (Uncaught_exn
   ((location "server-side blocking rpc computation")
    (exn
     (Invalid_argument
      "Float.iround_up_exn: argument (100000000000000000000.000000) is too large"))
    (backtrace
      "Raised at file \"pervasives.ml\", line 31, characters 25-45\
     \nCalled from file \"result.ml\", line 43, characters 17-22\
     \nCalled from file \"monad.ml\", line 17, characters 20-28\
     \n"))))
 (connection_description ("Client connected via TCP" (localhost 3333)))
 (rpc_tag foo) (rpc_version 1))

async_smtp

async_ssl

async_unix

This changes the behavior the sexp function. I've gone through the entire
tree rewriting sexp to create_s, attempting to follow these guidelines:

Please do not switch from Sexp.save* to Writer.save_sexp* in this
feature -- this feature is just for the deprecation. You can do the
switch in a subfeature or later feature.

A note aboute Core_extended.Sexp
----------------------------------

This feature causes surprising behavior in Core_extended.Sexp, where
opening Async.Std undoes any previous open of Core_extended.Std:

   open Core.Std
   open Core_extended.Std

   type t = int Sexp.Comprehension.t `@@deriving sexp`

   open Async.Std

   type u = int Sexp.Comprehension.t `@@deriving sexp`

The type t is fine but u fails to compile because at that point
the module Sexp has no submodule Comprehension.

But we already have the same problem with module Unix if you open
Async.Std after Core_extended.Std, so I left the Sexp module as is.

bignum

core

This feature improves the interface of Command.Param.one_of by
saving the caller from passing the flag names separately.

Exports Time_ns.Span.Option.unchecked_value and
.Ofday.Option.unchecked_value!

As a result, clarified slightly the role of Time_ns.Ofday, like
Time.Ofday, as 24h wall-clock times, not linear time offsets, which
latter would have to be up to 25h for DST.

core_extended

core_kernel

We did identify the set of functions to document:

  Time_ns.Span.((+), (-), scale_int, scale_int63, create, of_parts)
  Time_ns.(add, sub, diff, abs_diff, next_multiple)

Added Core_int63.(add_with_overflow_exn, abs_with_overflow_exn, neg_with_overflow_exn)
in the course of abandoned work on overflow detection in Time_ns. These may
be useful. mul_with_overflow_exn was abandoned because
1. it's a lot of work to review
2. there's a better approach: Go to the C level and check the high word of
the product from the IMUL instruction, which is both simpler and faster.

Float.sign currently maps -1e-8 and nan to Zero. Some users don't
expect this. This feature addresses that via the following changes:

Previously, the error message was something like:

("Timing_wheel.Priority_queue got invalid key"
 (key ...) (timing_wheel ...))

Now, it will be like:

("Timing_wheel cannot schedule alarm before start of current interval"
 (at ...) (now_interval_num_start ...))

The old message was confusing because key is less understandable
than at, and because it didn't make clear that this is a usage
error, as opposed to a Timing_wheel bug.

Implementing this efficiently required adding a field to timing wheel:

mutable now_interval_num_start : Time_ns.t

so that the check done by add is fast.

Since Map and Set already have Make_using_comparator functors,
there's no particular reason for Comparable not to have one.

More concretely, this will be useful when (if) we add stable
containers to core: we can add a stable version of Comparable.Make,
then pass the resulting comparator into the unstable functor to get
equal types.

Also changed type of overhead parameters to Percent.t

This is so that code like this will compile:

include T
include Comparable.Make_using_comparator (T)

Removed fields from Timing_wheel_ns.t that are now constants:

; min_time         : Time_ns.t
; max_time         : Time_ns.t
; min_interval_num : Interval_num.t

The f used to return 'a2 option, and it was unclear whether None
meant do nothing or remove. (It meant do nothing.)

Testing
-------
Added an inline test for boundary cases. Presently it returns the
identical values to caml_int_compare, though probably it should only
be held to same sign results.

incremental

This is configurable via the argument to
Incremental.Make_with_config, which now takes:

  val bind_lhs_change_should_invalidate_rhs : bool

So, one can now build an Incremental without invalidation using:

  Incremental.Make_with_config (struct
    include Incremental.Config.Default ()
    let bind_lhs_change_should_invalidate_rhs = false
  end) ()

Implementation
--------------
The implementation is simple:
When a bind rhs changes, instead of invalidate_nodes_created_on_rhs,
we rescope_nodes_created_on_rhs, which moves the nodes up to
the bind's parent.

Testing
-------
Turned the unit tests into a functor parameterized on
bind_lhs_change_should_invalidate_rhs, and run them with both true
and false. Modified tests where necessary to skip tests of
invalidity when bind_lhs_change_should_invalidate_rhs = false.

Added a unit test of bind_lhs_change_should_invalidate_rhs = true
that makes sure a node created on a bind rhs whose lhs subsequently
changes continues to stabilize correctly.

jenga

In jenga/server, builds will run on a daemonized server; the build trace is displayed on
any clients which are watching. Api.printf and Api.printf_verbose allow messages
from the jenga/root.ml.

The command line flag -verbose will be a client flag, not a server flag, allowing the
choice of verbosity to be selected per-client. It therefore won't make sense to allow
jenga/root.ml to ask if verbose is true, so we remove verbose from the jenga Api.

Instead jenga/root/ml can use printf_verbose for messages which are to be displayed
only by a client that is watching with -verbose.

Old jenga:

  *** jenga: ERROR: (summary) a/.DEFAULT: External command failed
        - build a stdout
        + bash -e -u -o pipefail -c false
        - exit a stdout, 3ms, exited with code 1
  *** jenga: ERROR: (summary) a/foo.ml.d: External command failed
        - build a stdout
        + .../ocamldep.opt -modules -impl foo.ml
        foo.ml:
        File "foo.ml", line 2, characters 0-0:
        Error: Syntax error
        - exit a stdout, 4ms, exited with code 2

New jenga:

  *** jenga: ERROR: (summary) a/.DEFAULT: External command failed
        - build a .DEFAULT
        + bash -e -u -o pipefail -c false
        - exit a .DEFAULT, 5ms, exited with code 1
  *** jenga: ERROR: (summary) a/foo.ml.d: External command failed
        - build a rule of foo.ml.d
        + .../ocamldep.opt -modules -impl foo.ml
        foo.ml:
        File "foo.ml", line 2, characters 0-0:
        Error: Syntax error
        - exit a rule of foo.ml.d, 6ms, exited with code 2

we are in a situation where, jenga before this feature would consider the command is still
running. This makes for some annoying debug, because which command started the stray
process is hard to tell, the stdout and stderr of the initial process are not visible
anywhere (they are in jenga's memory), etc.
Also jenga appears stuck.

So instead, we expect the stdout/stderr to close shortly after the initial process dies,
and if not, we close stdout/stderr ourselves and consider that the command failed.

To test, I put this in a jbuild:
(alias
((name DEFAULT)
(deps ())
(action "(echo false >&2; sleep 4) & ")))

and JENGA_OPTIONS='((fd_close_timeout 2s))' jenga -P complained:

  *** jenga: ERROR: (summary) lib/sexplib/src/.DEFAULT: External command failed
        - build lib/sexplib/src stdout
        + bash -e -u -o pipefail -c '(echo false >&2; sleep 4) & '
        false
        - exit lib/sexplib/src stdout, 2.004s, stdout or stderr wasn't closed 2s after process exited (due to a stray process perhaps?)

Also I had hydra do a full tree build (both in jane-continuous-release and jane-release)
and they both succeeded.

This controlled Config.delay_for_dev which inserted a delay of N seconds before running
any job in Job.run. I have heard this described as the most pointless command line flag
of all time!

Reason to fix now: Another feature jane/jenga/api.printf removes Api.verbose which
exposes Config.verbose to jenga/root.ml. Following both features, we can remove the
Run.For_user hackery.

Without this fix, we may get nan as the value of a Time.t which breaks an invariant of
the Time module. This may result in a crash in Time.to_ofday.

  ("unhandled exception"
   ((monitor.ml.Error_
     ((exn "Option.value_exn None")
      (backtrace
       ("Raised by primitive operation at file \"option.ml\", line 59, characters 4-21"
        "Called from file \"zone.ml\", line 751, characters 8-104"
        "Called from file \"zone.ml\", line 761, characters 10-48"
        "Called from file \"time0.ml\", line 275, characters 31-54"
        "Called from file \"finish_time_estimator.ml\", line 38, characters 14-54"
        "Called from file \"message.ml\", line 384, characters 30-66"
        "Called from file \"list.ml\", line 73, characters 12-15"
        "Called from file \"list.ml\", line 73, characters 12-15"
        "Called from file \"message.ml\", line 158, characters 2-42"
        "Called from file \"deferred0.ml\", line 65, characters 64-69"
        "Called from file \"job_queue.ml\", line 160, characters 6-47" ""))
      (monitor
       (((name try_with) (here ()) (id 4) (has_seen_error true)
         (is_detached true))))))
    ((pid 17688) (thread_id 4

There changes have no semantic effects; it's just code movement.

  1. Extract Message.Job_summary as a top level module.
  2. Extract Build.Run_reason as a top level module.
  3. Create all Effort.Counter instances in Progress.

Additionally, this feature lets the user see what jenga is currently working on by doing jenga diagnostics dump-tenacious-graph.

Along the way, fixed jenga monitor to exit non-zero when it can't discover jengaroot.

This feature is necessary to support env-var discovery in build-manager via RPC, rather
than the current hack of parsing the output from jenga.

Environment variable manipulation is exposed on the command line with:

  jenga env get NAME
  jenga env set NAME VALUE
  jenga env unset NAME
  jenga env print

The Api supports access to either the current value of a variable, or to a dependency
which responds dynamically to changes made by setenv.

  Var.peek   : 'a Var.t -> 'a
  Dep.getenv : 'a Var.t -> 'a Dep.t

Removed app/jenga/lib/rpc_intf.mli - just unhelpful code duplication of the
descriptions in rpc_intf.ml.

  1. Attribute an error to the head target ONLY.

  2. Additional targets are treated as dependants of the head_target, and so (if
    demanded) are regarded as having failure' noterror' status.

  3. Always use head-target in the "-build" line message, instead of whatever target
    happens (non deterministically) to get demanded first.

  4. Allow user control over the which target is regarded as the head_target, by taking
    the first target listed as the head_target.

Allow the user to demand a `build' of (just) the jengaroot.

ocaml_plugin

1) Improve documentation, add readme to include more info about what is being
checked exactly.

2) Avoid the switch -code-style _ for application that have made a choice of
code style statically. Having the swtich available at runtime is just
confusing, since only 1 style is going to work anyway.

ppx_bench

ppx_expect

Changes to the implementation of ppx_expect (including some refactoring):

More generally, try to preserve the formatting a bit more when
correcting from empty or single to multi-line.

ppx_fields_conv

ppx_inline_test

ppx_optcomp

ppx_sexp_conv

rpc_parallel

Summary

The aborted Deferred.t that got passed to Pipe_rpc implementations is
gone. The situations where it would have been determined now close the reading
end of the user-supplied pipe instead.

Details

Previously, when an RPC dispatcher decided to abort a query, the RPC
implementation would get its aborted Deferred.t filled in, but would remain
free to write some final elements to the pipe.

This is a little bit more flexible than the new interface, but it's also
problematic in that the implementer could easily just not pay attention to
aborted. (They're not obligated to pay attention to when the pipe is closed,
either, but at least they can't keep writing to it.) We don't think the extra
flexibility was used at all.

In the future, we may also simplify the client side to remove the abort
function on the dispatch side (at least when not using dispatch_iter). For the
time being it remains, but closing the received pipe is the preferred way of
aborting the query.

There are a couple of known ways this might have changed behavior from before.
Both of these appear not to cause problems in the jane repo.

What Rpc_parallel used to do for you:
------------------------------------

What it now does:
-----------------

This also allowed for running the worker initialization code before we daemonize.

Namely:
1) Toplevel hashtables are initialized with size 1 to reduce overhead due to linking with Rpc_parallel
2) The master rpc server is only started upon the first call to spawn

Also, move all the example code off of the managed module

1) Take serve out of the Connection module. It shouldn't be in there because it does nothing with the Connection.t type
2) Remove some unnecessary functions defined on Connection.t's. E.g. no longer expose close_reason because all the exception handling will be done with the registered exn handlers.
3) Move Rpc_settings module
4) Separate global_state into as_worker and as_master
5) Some cleanup with how we are managing worker ids
6) create a record type for Init_connection_state_rpc.query

sexplib

Previously chars >= 127 are escaped or not depending on:

  1. other character in the string
  2. the system
  3. environment variable settings

(2) and (3) are because String.escaped from the stdlib uses the C
function isprint which is locale and OS dependent.

This can cause invalid UTF-8 sequence to be printed by sexplib, which
is annoying:

https://github.com/janestreet/sexplib/issues/18

Starting with this release, sexplib:

  1. copies the String.escaped function of OCaml 4.03 which escapes
    all non-ascii characters
  2. make sure we escape the string when it contains characters >= 127

from silently succeeding.

Also, now we no longer read an included file multiple times.
This lets even crazy stuff like this to work:

$ echo 'hi ' | sexp resolve <(echo '((:include /dev/stdin) (:include /dev/stdin))')