NOTE: unless otherwise noted,
the references below point to
specific sections and figures in the on-line
technical report available at:
http://mrg.doc.ic.ac.uk/publications/lightweight-session-programming-in-scala/paper.pdf
.
Requirements
These instructions assume an Unix-like operating system with Java 8 as default JRE/JDK. They have been tested on Ubuntu (14.04 and 15.10), Debian GNU/Linux (Sid, April 2016), and Mac OS X (10.10 and 10.11). They should also work on Windows with minor adaptations.
For some examples, and to generate the benchmark plots, you will also need Python 2.7.x and matplotlib.
Initial setup on Ubuntu (14.04 and later)
If you use Ubuntu (or recent versions of Debian GNU/Linux), this section provides detailed instructions that should be followed before compiling the sources.
-
If you are using Ubuntu 14.04,
you might first need to
enable the software repositories for Java 8. Open a terminal
and execute the following commands:
sudo add-apt-repository ppa:openjdk-r/ppa # Not needed on Ubuntu ≥ 14.10 sudo apt-get update # Not needed on Ubuntu ≥ 14.10
-
On all Ubuntu/Debian versions,
you need to ensure that Java 8 is
installed and selected as the default JRE/JDK. Thus, you should
execute the following commands:
sudo apt-get install openjdk-8-jdk # Alternatively: oracle-java8-jdk sudo update-alternatives --config java # Ensure that Java 8 is selected sudo update-alternatives --config javac # Ensure that Java 8 is selected
-
Moreover, in order to generate the benchmark plots, you might also
need to execute:
sudo apt-get install python-matplotlib
Compiling the sources
-
You will need
sbt
0.13.x: the installation instructions for various OSs are available here. -
Open a terminal, and
cd
inside thelchannels/
directory. NOTE: from now on, all commands must be launched from this position. -
Execute the following command:
This will causesbt compile
sbt
to automatically download all missing dependencies (including Scala 2.11.8) and compilelchannels
.
Examples
To launch the examples, execute:
sbt "project examples" run
You will get a prompt similar to the following:
Multiple main classes detected, select one to run: [1] lchannels.examples.calc.Local [2] lchannels.examples.calc.Queue [3] lchannels.examples.chat.demo.Local [4] lchannels.examples.game.a.Actor [5] lchannels.examples.game.b.Actor [6] lchannels.examples.game.c.Actor [7] lchannels.examples.game.demo.Local [8] lchannels.examples.game.demo.Queue [9] lchannels.examples.game.server.Actor [10] lchannels.examples.greeting.ActorClient [11] lchannels.examples.greeting.ActorServer [12] lchannels.examples.greeting.Local [13] lchannels.examples.greeting.Queue [14] lchannels.examples.greeting.SocketClient [15] lchannels.examples.greeting.StreamClient [16] lchannels.examples.http.server.Server [17] lchannels.examples.scribblegreeting.ActorClient [18] lchannels.examples.scribblegreeting.ActorServer [19] lchannels.examples.scribblegreeting.Local [20] lchannels.examples.scribblegreeting.SocketClient [21] lchannels.examples.sleepingbarber.demo.Local [22] lchannels.examples.threebuyer.alice.Actor [23] lchannels.examples.threebuyer.bob.Actor [24] lchannels.examples.threebuyer.carol.Actor [25] lchannels.examples.threebuyer.demo.Local [26] lchannels.examples.threebuyer.seller.Actor Enter number:
The prompt allows to choose among:
-
lchannels.examples.calc
: a client and server that perform simple mathematical operations. (Source) -
lchannels.examples.chat
: the "chat server with frontend" case study, described in §1, §6.1 and §B.1 of the technical report. (Source) -
lchannels.examples.greeting
: client and server implementing the "greeting protocol" of §2.1 and Example 4.2. (Source) -
lchannels.examples.scribblegreeting
: similar to the above, but based on session classes that have been automatically generated from this protocol specification, using an extended version of the Scribble tool. (Source) -
lchannels.examples.sleepingbarber
: the "sleeping barber" of Example 4.3. (Source) -
lchannels.examples.http
: HTTP server supporting the GET method. The implementation is based on session classes that have been automatically generated from this protocol specification, using an extended version of the Scribble tool. (Source) -
lchannels.examples.sleepingbarber
: the "sleeping barber" of Example 4.3. (Source) -
lchannels.examples.game
: three players connect to a game server, that creates a multiparty session allowing the players to interact directly. (Source) This example shows how type-safe multiparty sessions, and distributed multiparty delegation, can be implemented on top of the binary channel endpoints provided bylchannels
. This is based on the theoretical results presented in this technical report. Note that the protocol classes used in this example (collected in these files) are automatically generated from this protocol specification, using an extended version of the Scribble tool. -
lchannels.examples.threebuyer
: two buyers connect to a seller to purchase a book, involving a third buyer if the price is too high. (Source) This example is also based on the theoretical results presented in this technical report. The protocol classes are automatically generated from this protocol specification, using an extended version of the Scribble tool.
Running the examples
-
All examples ending
with
.Local
can be launched simply by selecting their corresponding number. They will spawn their components as separate threads (e.g., a server and one or more clients) that interact viaLocalChannel
s (§3.2). Their activity is reported via on-screen log messages. -
All examples ending
with
.Queue
can be launched simply by selecting their corresponding number. Similarly to the.Local
case above,.Queue
examples will spawn their components as separate threads; the difference is that they interact viaQueueChannel
s (§5). -
lchannels.examples.greeting.ActorClient
/.ActorServer
launch the "greeting client/server" above using actor-based channels (§5). In this case, the client and server can be launched on different JVMs, and they can still interact (thanks to Akka Remoting). Hence, you need to:-
first, launch the server by
selecting
lchannels.examples.greeting.ActorServer
from the prompt above; -
second, while the server is running, on another terminal execute again:
and from the prompt, selectsbt "project examples" run
lchannels.examples.greeting.ActorClient
.
-
first, launch the server by
selecting
-
lchannels.examples.scribblegreeting.ActorClient
/.ActorServer
: similar to the previous case. -
lchannels.examples.game.(a / b / c / server).Actor
is the 3-player game using actor-based channels. Theserver
and the three playersa
,b
,c
can be launched on different JVMs, and in this case, a distributed multiparty session delegation will occur transparently. If you want to try it, you need to:-
first, launch the
server
by selectinglchannels.examples.game.server.Actor
from the prompt above; -
then, while the server is running,
on three other terminals you should execute again:
and from the prompt, selectsbt "project examples" run
lchannels.examples.game.(a / b / c).Actor
. Note that the server creates the multiparty session and performs a (distributed) delegation: i.e., when the 3 players start interacting, the session becomes independent from the server, and when the server JVM terminates, the ongoing game is not disturbed.
-
first, launch the
-
lchannels.examples.threebuyer.(alice / bob / carol / seller).Actor
is the three-buyer example using actor-based channels. Similarly to the previous example, theseller
and the three buyersalice
,bob
,carol
can be launched on different JVMs, and in this case, a distributed multiparty session delegation will occur transparently (depending on Alice's choices). If you want to try it, you need to:-
first, launch the
seller
andcarol
, on two separate terminals, by selectinglchannels.examples.threebuyer.seller.Actor
andlchannels.examples.threebuyer.carol.Actor
from the prompt above; -
then, while both are running,
on two other terminals you should
select
lchannels.examples.game.(alice / bob).Actor
.
-
first, launch the
-
lchannels.examples.greeting.StreamClient
/.SocketClient
launch the "greeting client" above usingStreamChannel
s (§5 and §A.1 in the technical report) orSocketChannel
s (not mentioned in the technical report). TheStreamChannel
/SocketChannel
, in turn, is created by connecting to an external "greeting server", through a TCP/IP socket; for this reason, before launching this example, you need to start the "greeting server". On another terminal, execute:
When the "greeting server" is waiting for connections, you can selectpython scripts/greeting-server.py # Listens on 127.0.0.1:1337
lchannels.examples.greeting.StreamClient
/SocketClient
from the prompt above. Note that, as stated in §5 of the technical report, the "greeting server" does not need to uselchannels
, and can be written in any language (we used Python). -
lchannels.examples.scribblegreeting.SocketClient
: similar to the previous case.
Browsing the source code
The source code for all examples can be found under
examples/src/...
.
The main differences wrt. the code snippets in the technical report are the addition of log messages, and in some cases the presence of parameters that were omitted for simplicity of exposition. For instance:
-
some methods for creating instances
of
In
/Out
channels takeimplicit
parameters, such as theExecutionContext
for running Scala'sFuture.onComplete()
callbacks. As customary, such implicit parameters have been mostly omitted in the technical report (but of course, they are reported in the API documentation); -
the chat server code shown in §6.1.2 invokes
LocalChannel.factory()
to create new pairs of channels; the corresponding code in ChatServer.scala (line 200), instead, usessfactory
, which is aChatServer
parameter that can be instantiated e.g. withLocalChannel.factory
,ActorChannel.factory
, etc.: it allows to decouple the chat server implementation from the channel transport.
Benchmarks
The benchmarks (§6.2 of the technical report) can be run by executing:
./scripts/benchmark.sh
The command above launches a reduced version of the benchmarks, that should terminate pretty quickly.
If you want to replicate the measurements in §6.2 of the technical report (which take much longer and can be stressful for the Java GC) you can execute instead:
./scripts/benchmark.sh 10 2000000 # Meaning: 10 JVM invocations, ~2000000 message exchanges
In both cases above, you will obtain:
-
a
bench/
directory, with several sub-directories: each one contains the results of the benchmarks for a distinct JVM invocation; -
the cumulative benchmark results, created by aggregating the
measurements under
bench/*/
:pingpong.csv
,ring.csv
,ring-stream.csv
andchameneos.csv
. Such aggregated results have been used to generate Figure 9 in the technical report; -
one
.pdf
file for each.csv
file above, containing the plot of the benchmark results.
The source code for the benchmarks can be found under
benchmarks/src/...
.
API documentation and source code pointers
The API documentation forlchannels
is
automatically generated from source code comments, with:
sbt "project lchannels" doc
After running the command above, the documentation
can be browsed by
opening lchannels/target/scala-2.11/api/index.html
.
For reference, a (possibly outdated) copy of the documentation
is also
available online
(last update: May 3, 2016).
Here are some selected links:
-
Base classes (§3.1 in the technical report):
In
,Out
(Source) -
LocalChannel
s (§3.2 in the technical report):LocalIn
,LocalOut
(Source) -
QueueChannel
s (§5 in the technical report):QueueIn
,QueueOut
(Source) -
ActorChannel
s (§5 in the technical report):ActorIn
,ActorOut
(Source) -
StreamChannel
s (§5 in the technical report):StreamIn
,StreamOut
,StreamManager
(Source) -
SocketChannel
s (not mentioned in the technical report):SocketIn
,SocketOut
,SocketManager
(Source)
Some other features and details:
-
lchannels
-based FIFO queue (Example 4.1 in the technical report):lchannels.util.Fifo
(Source) -
Medium-parametric channel endpoints (§A.1 in the technical report):
medium.In
,medium.Out
(Source)
Miscellaneous remarks
-
You might notice that
the directory
examples/lib/
contains a file calledakka-typed-experimental_2.11-2.4.2.jar
. It is a slightly modified version of the corresponding (experimental) Akka module, automatically loaded when running thelchannels
examples. The modification consists in the following patch to the Akka 2.4.2 source code:--- a/akka-typed/src/main/scala/akka/typed/ActorRef.scala +++ b/akka-typed/src/main/scala/akka/typed/ActorRef.scala @@ -63,7 +63,7 @@ trait ScalaActorRef[-T] { this: ActorRef[T] ⇒ } object ActorRef { - private class Combined[T](val untypedRef: akka.actor.ActorRef) extends ActorRef[T] with ScalaActorRef[T] + private class Combined[T](val untypedRef: akka.actor.ActorRef) extends ActorRef[T] with ScalaActorRef[T] with Serializable implicit def toScalaActorRef[T](ref: ActorRef[T]): ScalaActorRef[T] = ref.asInstanceOf[ScalaActorRef[T]]
We applied such a patch to enable serialization of typed actor references; it will become unnecessary if/when Akka Typed will become stable.
Troubleshooting
-
If you get an error similar to:
java.lang.UnsupportedClassVersionError: ... : Unsupported major.minor version 52.0
It means that Java 8 is not your default JRE/JDK, as required.