ray/java
Yujie Liu 3b5e700fd7 [JavaWorker] Java code lint check and binding to CI (#2225)
* add java code lint check and fix the java code lint error

* add java doc lint check and fix the java doc lint error

* add java code and doc lint to the CI
2018-06-09 16:26:54 -07:00
..
api [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
common [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
example [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
hook [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
runtime-common [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
runtime-dev [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
runtime-native [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
test [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
build.sh [JavaWorker] Enable java worker support (#2094) 2018-05-26 14:38:50 -07:00
checkstyle-suppressions.xml [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
checkstyle.xml [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
cleanup.sh [JavaWorker] Enable java worker support (#2094) 2018-05-26 14:38:50 -07:00
logfilter.sh [JavaWorker] Enable java worker support (#2094) 2018-05-26 14:38:50 -07:00
pom.xml [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
ray.config.ini [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00
README.rst [JavaWorker] Enable java worker support (#2094) 2018-05-26 14:38:50 -07:00
test.sh [JavaWorker] Java code lint check and binding to CI (#2225) 2018-06-09 16:26:54 -07:00

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This directory contains the java worker, with the following components.

-  java/api: Ray API definition
-  java/common: utilities
-  java/hook: binary rewrite of the Java byte-code for remote execution
-  java/runtime-common: common implementation of the runtime in worker
-  java/runtime-dev: a pure-java mock implementation of the runtime for
   fast development
-  java/runtime-native: a native implementation of the runtime
-  java/test: various tests
-  src/local\_scheduler/lib/java: JNI client library for local scheduler
-  src/plasma/lib/java: JNI client library for plasma storage

Build and test
==============

::

    # build native components
    ../build.sh -l java

    # build java worker
    mvn clean install -Dmaven.test.skip

    # test
    export RAY_CONFIG=ray.config.ini
    mvn test

Quick start
===========

Starting Ray
------------

.. code:: java

    Ray.init();

Read and write remote objects
-----------------------------

Each remote object is considered a ``RayObject<T>`` where ``T`` is the
type for this object. You can use ``Ray.put`` and ``RayObject<T>.get``
to write and read the objects.

.. code:: java

    Integer x = 1;
    RayObject<Integer> obj = Ray.put(x);
    Integer x1 = obj.get();
    assert (x.equals(x1));

Remote functions
----------------

Here is an ordinary java code piece for composing
``hello world example``.

.. code:: java

    public class ExampleClass {
        public static void main(String[] args) {
            String str1 = add("hello", "world");
            String str = add(str1, "example");
            System.out.println(str);
        }
        public static String add(String a, String b) {
            return a + " " + b;
        }
    }

We use ``@RayRemote`` to indicate that a function is remote, and use
``Ray.call`` to invoke it. The result from the latter is a
``RayObject<R>`` where ``R`` is the return type of the target function.
The following shows the changed example with ``add`` annotated, and
correspondent calls executed on remote machines.

.. code:: java

    public class ExampleClass {
        public static void main(String[] args) {
            Ray.init();
            RayObject<String> objStr1 = Ray.call(ExampleClass::add, "hello", "world");
            RayObject<String> objStr2 = Ray.call(ExampleClass::add, objStr1, "example");
            String str = objStr2.get();
            System.out.println(str);
        }

        @RayRemote
        public static String add(String a, String b) {
            return a + " " + b;
        }
    }

Ray Java API
============

Basic API
---------

``Ray.init()``
~~~~~~~~~~~~~~

Ray.init should be invoked before any other Ray functions to initialize
the runtime.

``@RayRemote``
~~~~~~~~~~~~~~

The annotation of ``@RayRemote`` can be used to decorate static java
method or class. The former indicates that a target function is a remote
function, which is valid with the follow requirements. \* it must be a
public static method \* parameters and return value must not be the
primitive type of java such as int, double, but could use the wrapper
class like Integer,Double \* the return value of the method must always
be the same with the same input

When the annotation is used for classes, the classes are considered
actors(a mechanism to share state among many remote functions). The
member functions can be invoked using ``Ray.call``. The requirements for
an actor class are as follows. \* it must have an constructor without
any parameter \* if it is an inner class, it must be public static \* it
must not have a member field or method decorated using
``public static``, as the semantic is undefined with multiple instances
of this same class on different machines \* an actor method must be
decorated using ``public`` but no ``static``, and the other requirements
are the same as above.

``Ray.call``
~~~~~~~~~~~~

.. code:: java

    RayObject<R> call(Func func, ...);

``func`` is the target method, continued with appropriate parameters.
There are some requirements here:

-  the return type of ``func`` must be ``R``
-  currently at most 6 parameters of ``func`` are allowed
-  each parameter must be of type ``T`` of the correspondent ``func``'s
   parameter, or be the lifted ``RayObject<T>`` to indicate a result
   from another ray call

The returned object is labled as ``RayObject<R>`` and its value will be
put into memory of the machine where the function call is executed.

``Ray.put``
~~~~~~~~~~~

You can also invoke ``Ray.put`` to explicitly place an object into local
memory.

.. code:: java

    public static <T> RayObject<T> put(T object);
    public static <T, TM> RayObject<T> put(T obj, TM metadata);

``RayObject<T>.get/getMeta``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code:: java

    public class RayObject<T> {
        public T get() throws TaskExecutionException;
        public <M> M getMeta() throws TaskExecutionException;
    }

This method blocks current thread until requested data gets ready and is
fetched (if needed) from remote memory to local.

``Ray.wait``
~~~~~~~~~~~~

Calling ``Ray.wait`` will block current thread and wait for specified
ray calls. It returns when at least ``numReturns`` calls are completed,
or the ``timeout`` expires. See multi-value support for ``RayList``.

.. code:: java

    public static WaitResult<T> wait(RayList<T> waitfor, int numReturns, int timeout);
    public static WaitResult<T> wait(RayList<T> waitfor, int numReturns);
    public static WaitResult<T> wait(RayList<T> waitfor);

Multi-value API
---------------

Multi-value Types
~~~~~~~~~~~~~~~~~

Java worker supports multiple ``RayObject``\ s in a single data
structure as a return value or a ray call parameter, through the
following container types.

``MultipleReturnsX<R0, R1, ...>``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

There are multiple heterogeneous values, with their types as ``R0``,
``R1``,... respectively. Note currently this container type is only
supported as the return type of a ray call, therefore you can not use it
as the type of an input parameter.

``RayList<T>``
''''''''''''''

A list of ``RayObject<T>``, inherited from ``List<T>`` in Java. It can
be used as the type for both return value and parameters.

``RayMap<L, T>``
''''''''''''''''

A map of ``RayObject<T>`` with each indexed using a label with type
``L``, inherited from ``Map<L, T>``. It can be used as the type for both
return value and parameters.

Enable multiple heterogeneous return values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Java worker support at most four multiple heterogeneous return values,
and in order to let the runtime know the number of return values we
supply the method of ``Ray.call_X`` as follows.

.. code:: java

    RayObjects2<R0, R1> call_2(Func func, ...);
    RayObjects3<R0, R1, R2> call_3(Func func, ...);
    RayObjects4<R0, R1, R2, R3> call_4(Func func, ...);

Note ``func`` must match the following requirements.

-  It must hava the return value of ``MultipleReturnsX``, and must be
   invoked using correspondent ``Ray.call_X``

Here is an example.

.. code:: java

    public class MultiRExample {
        public static void main(String[] args) {
            Ray.init();
            RayObjects2<Integer, String> refs = Ray.call_2(MultiRExample::sayMultiRet);
            Integer obj1 = refs.r0().get();
            String obj2 = refs.r1().get();
            Assert.assertTrue(obj1.equals(123));
            Assert.assertTrue(obj2.equals("123"));
        }

        @RayRemote
        public static MultipleReturns2<Integer, String> sayMultiRet() {
            return new MultipleReturns2<Integer, String>(123, "123");
        }
    }

Return with ``RayList``
~~~~~~~~~~~~~~~~~~~~~~~

We use ``Ray.call_n`` to do so, which is similar to ``Ray.call`` except
an additional parameter ``returnCount`` which tells the number of return
``RayObject<R>`` in ``RayList<R>``. This is because Ray core engines
needs to know it before the method is really called.

.. code:: java

    RayList<R> call_n(Func func, Integer returnCount, ...);

Here is an example.

.. code:: java

    public class ListRExample {
        public static void main(String[] args) {
            Ray.init();
            RayList<Integer> ns = Ray.call_n(ListRExample::sayList, 10, 10);
            for (int i = 0; i < 10; i++) {
                RayObject<Integer> obj = ns.Get(i);
                Assert.assertTrue(i == obj.get());
            }
        }

        @RayRemote
        public static List<Integer> sayList(Integer count) {
            ArrayList<Integer> rets = new ArrayList<>();
            for (int i = 0; i < count; i++)
                rets.add(i);
            return rets;
        }
    }

Return with ``RayMap``
~~~~~~~~~~~~~~~~~~~~~~

This is similar to ``RayList`` case, except that now each return
``RayObject<R>`` in ``RayMap<L,R>`` has a given label when
``Ray.call_n`` is made.

.. code:: java

    RayMap<L, R> call_n(Func func, Collection<L> returnLabels, ...);

Here is an example.

.. code:: java

    public class MapRExample {
        public static void main(String[] args) {
            Ray.init();
            RayMap<Integer, String> ns = Ray.call_n(MapRExample::sayMap,
                    Arrays.asList(1, 2, 4, 3), "n_futures_");
            for (Entry<Integer, RayObject<String>> ne : ns.EntrySet()) {
                Integer key = ne.getKey();
                RayObject<String> obj = ne.getValue();
                Assert.assertTrue(obj.get().equals("n_futures_" + key));
            }
        }

        @RayRemote(externalIO = true)
        public static Map<Integer, String> sayMap(Collection<Integer> ids,
                                                String prefix) {
            Map<Integer, String> ret = new HashMap<>();
            for (int id : ids) {
                ret.put(id, prefix + id);
            }
            return ret;
        }
    }

Enable ``RayList`` and ``RayMap`` as parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code:: java

    public class ListTExample {
        public static void main(String[] args) {
            Ray.init();
            RayList<Integer> ints = new RayList<>();
            ints.add(Ray.put(new Integer(1)));
            ints.add(Ray.put(new Integer(1)));
            ints.add(Ray.put(new Integer(1)));
            RayObject<Integer> obj = Ray.call(ListTExample::sayReadRayList
                                            (List<Integer>)ints);
            Assert.assertTrue(obj.get().equals(3));
        }

        @RayRemote
        public static int sayReadRayList(List<Integer> ints) {
            int sum = 0;
            for (Integer i : ints) {
                sum += i;
            }
            return sum;
        }
    }

Actor Support
-------------

Create Actors
~~~~~~~~~~~~~

A regular class annotated with ``@RayRemote`` is an actor class.

.. code:: java

    @RayRemote
    public class Adder {
      public Adder() {
        sum = 0;
      }

      public Integer add(Integer n) {
        return sum += n;
      }

      private Integer sum;
    }

Whenever you call ``Ray.create()`` method, an actor will be created, and
you get a local ``RayActor`` of that actor as the return value.

.. code:: java

    RayActor<Adder> adder = Ray.create(Adder.class);

Call Actor Methods
~~~~~~~~~~~~~~~~~~

The same ``Ray.call`` or its extended versions (e.g., ``Ray.call_n``) is
applied, except that the first argument becomes ``RayActor``.

.. code:: java

    RayObject<R> Ray.call(Func func, RayActor<Adder> actor, ...);
    RayObject<Integer> result1 = Ray.call(Adder::add, adder, 1);
    RayObject<Integer> result2 = Ray.call(Adder::add, adder, 10);
    result2.get(); // 11