Previous: Transactions make errors survivable, Up: Tutorial [Contents]
“Machines grow faster and memories grow larger. But the speed of light is constant and New York is not getting any closer to Tokyo.”
— Mark S. Miller, Robust Composition: Towards a Unified Approach to Access Control and Concurrency Control
Promise pipelining provides two different features at once:
Consider the following car factory, which makes cars carrying the company name of the factory:
;; Create a "car factory", which makes cars branded with ;; company-name. (define (^car-factory bcom company-name) ;; The constructor for cars we will create. (define (^car bcom model color) (methods ; methods for the ^car ((drive) ; drive the car (format #f "*Vroom vroom!* You drive your ~a ~a ~a!" color company-name model)))) ;; methods for the ^car-factory instance (methods ; methods for the ^car-factory ((make-car model color) ; create a car (spawn ^car model color))))
Here is an instance of this car factory, which we will call
fork-motors
, which we will spawn on a-vat
:
scheme> ,enter a-vat goblins[1]> (define fork-motors (spawn ^car-factory "Fork"))
Since asynchronous message passing with <-
works across
machines, it does not matter whether interacitons with
fork-motors
are local or via objects communicating over the
network. We will treat fork-motors
as living on machine A, and
so the following interactions will happen with invocations originating
from machine B.
Let’s send a message to fork-motors
invoking the
'make-car
method, receiving back a promise for the car which
will be made, which we shall name car-vow
(-vow
being
the conventional suffix given for promises in Goblins):
goblins[1]> ,q scheme> ,enter-vat b-vat ;; Interaction on machine B, communicating with fork-motors on A goblins[1]> (define car-vow (<- fork-motors 'make-car "Explorist" "blue"))
So we have a promise to a future car reference, but not the reference itself. We would like to drive the car as soon as it rolls off the lot of the factory, which of course involves sending a message to the car.
Without promise pipelining, making use of the tools we have already shown (and following the pattern most other distributed programming systems use), we would end up with something like:
;; Interaction on machine B, communicating with A goblins[1]> (on car-vow ; B->A: first resolve the car-vow (lambda (our-car) ; A->B: car-vow resolved as our-car (on (<- our-car 'drive) ; B->A: now we can message our-car (lambda (val) ; A->B: result of that message (format #f "Heard: ~a\n" val)))))
With promise pipelining, we can simply message the promise of the car
directly. The first benefit can be observed from code compactness, in
that we do not need to do an on
of car-vow
to later
message our-car
, we can simply message car-vow
directly:
;; Interaction on machine B, communicating with A goblins[1]> (on (<- car-vow 'drive) ; B->A: send message to future car (lambda (val) ; A->B: result of that message (format #t "Heard: ~a\n" val)))
While clearly a considerable programming convenience, the other advantage of promise pipelining is a reduction of round-trips, whether between our event-loop vats or across machines on the network.
This can be understood by looking at the comments to the right of the two above code interactions. The message flow in the first case looks like:
B => A => B => A => B
The message flow in the second case looks like:
B => A => B
In other words, machine B can say to machine A: “Make me a car, and as soon as that car is ready, I want to drive it!”
With this in mind, the promise behind Mark Miller’s quote at the beginning of this section is clear.1 If two objects are on opposite ends of the planet, round trips are unavoidably expensive. Promise pipelining both allows us to make plans as programmers and allows for Goblins to optimize carrying out those steps as bulk operations over the network.
Like so many examples in this document, the designs of promise pipelining and the explanation of its value come from the E programming language, the many contributors to its design, and Mark S. Miller’s extraordinary work documenting that work and its history. If you find this section interesting, both the the Promise Pipelining page from erights.org and sections 2.5 and 16.2 of Mark Miller’s dissertation.
Previous: Transactions make errors survivable, Up: Tutorial [Contents]