Skip to content

Commit

Permalink
Merge pull request #15 from lsd-ucsc/target-specific-info
Browse files Browse the repository at this point in the history
Allow the Transport to have a different kind of information for the target ChoreographyLocation
  • Loading branch information
ihaveint authored Sep 20, 2023
2 parents f992cf0 + 07f5021 commit 5bf932a
Show file tree
Hide file tree
Showing 13 changed files with 300 additions and 160 deletions.
10 changes: 5 additions & 5 deletions chorus_book/src/guide-input-and-output.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ let choreo = DemoChoreography {
input: "World".to_string(),
};

let projector = Projector::new(Alice, transport);
let projector = Projector::new(Alice, alice_transport);
projector.epp_and_run(choreo);
```

Expand Down Expand Up @@ -93,7 +93,7 @@ To run the sample choreography above at Alice, we use the `local` method to cons
# });
# }
# }
let projector_for_alice = Projector::new(Alice, transport);
let projector_for_alice = Projector::new(Alice, alice_transport);
// Because the target of the projector is Alice, the located value is available at Alice.
let string_at_alice: Located<String, Alice> = projector_for_alice.local("Hello, World!".to_string());
// Instantiate the choreography with the located value
Expand All @@ -120,7 +120,7 @@ For Bob, we use the `remote` method to construct the located value.
# });
# }
# }
let projector_for_bob = Projector::new(Bob, transport);
let projector_for_bob = Projector::new(Bob, bob_transport);
// Construct a remote located value at Alice. The actual value is not required.
let string_at_alice = projector_for_bob.remote(Alice);
// Instantiate the choreography with the located value
Expand Down Expand Up @@ -161,7 +161,7 @@ impl Choreography<String> for DemoChoreography {
# }
# }
let choreo = DemoChoreography;
let projector = Projector::new(Alice, transport);
let projector = Projector::new(Alice, alice_transport);
let output = projector.epp_and_run(choreo);
assert_eq!(output, "Hello, World!".to_string());
```
Expand All @@ -183,7 +183,7 @@ impl Choreography<Located<String, Alice>> for DemoChoreography {
}
}

let projector = Projector::new(Alice, transport);
let projector = Projector::new(Alice, alice_transport);
let output = projector.epp_and_run(DemoChoreography);
let string_at_alice = projector.unwrap(output);
assert_eq!(string_at_alice, "Hello, World!".to_string());
Expand Down
16 changes: 10 additions & 6 deletions chorus_book/src/guide-projector.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ To create a `Projector`, you need to provide the target location and the transpo

```rust
# extern crate chorus_lib;
# use chorus_lib::transport::local::LocalTransport;
# use std::sync::Arc;
# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel};
# use chorus_lib::core::{ChoreographyLocation, Projector};
# use chorus_lib::{LocationSet};
# let transport = LocalTransport::<LocationSet!(Alice, Bob)>::new();
# let transport_channel = Arc::new(LocalTransportChannel::<LocationSet!(Alice, Bob)>::new());
# let alice_transport = LocalTransport::new(Alice, Arc::clone(&transport_channel));
# #[derive(ChoreographyLocation)]
# struct Alice;
# #[derive(ChoreographyLocation)]
# struct Bob;
#

let projector = Projector::new(Alice, transport);
let projector = Projector::new(Alice, alice_transport);
```

Notice that the `Projector` is parameterized by its target location type. You will need one projector for each location to execute choreography.
Expand All @@ -29,10 +31,12 @@ To execute a choreography, you need to call the `epp_and_run` method on the `Pro

```rust
# extern crate chorus_lib;
# use chorus_lib::transport::local::LocalTransport;
# use std::sync::Arc;
# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel};
# use chorus_lib::core::{ChoreographyLocation, Projector, Choreography, ChoreoOp};
# use chorus_lib::{LocationSet};
# let transport = LocalTransport::<LocationSet!(Alice, Bob)>::new();
# let transport_channel = Arc::new(LocalTransportChannel::<LocationSet!(Alice, Bob)>::new());
# let alice_transport = LocalTransport::new(Alice, Arc::clone(&transport_channel));
# #[derive(ChoreographyLocation)]
# struct Alice;
# #[derive(ChoreographyLocation)]
Expand All @@ -45,7 +49,7 @@ To execute a choreography, you need to call the `epp_and_run` method on the `Pro
# }
#

# let projector = Projector::new(Alice, transport);
# let projector = Projector::new(Alice, alice_transport);
projector.epp_and_run(HelloWorldChoreography);
```

Expand Down
69 changes: 48 additions & 21 deletions chorus_book/src/guide-transport.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,47 @@ ChoRus provides two built-in transports: `local` and `http`.

### The Local Transport

The `local` transport is used to execute choreographies on the same machine on different threads. This is useful for testing and prototyping.
The `local` transport is used to execute choreographies on the same machine on different threads. This is useful for testing and prototyping. Each `local` transport is defined over `LocalTransportChannel`, which contains the set of `ChoreographyLocation` that the `local` transport operates on. You can build a `LocalTransportChannel` by importing the `LocalTransportChannel` stsruct from the `chorus_lib` crate.

To use the `local` transport, import the `LocalTransport` struct from the `chorus_lib` crate.
```rust
# extern crate chorus_lib;
# use std::sync::Arc;
# use chorus_lib::core::{ChoreographyLocation};
# use chorus_lib::{LocationSet};
# #[derive(ChoreographyLocation)]
# struct Alice;
# #[derive(ChoreographyLocation)]
# struct Bob;
use chorus_lib::transport::local::LocalTransportChannel;

let transport_channel = Arc::new(LocalTransportChannel::<LocationSet!(Alice, Bob)>::new());
```

To use the `local` transport, first import the `LocalTransport` struct from the `chorus_lib` crate.

```rust
# extern crate chorus_lib;
use chorus_lib::transport::local::LocalTransport;
# use std::sync::Arc;
# use chorus_lib::core::{ChoreographyLocation};
# use chorus_lib::{LocationSet};
# #[derive(ChoreographyLocation)]
# struct Alice;
# let transport_channel = Arc::new(LocalTransportChannel::<LocationSet!(Alice)>::new());
use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel};

let alice_transport = LocalTransport::new(Alice, Arc::clone(&transport_channel));
```

You can construct a `LocalTransport` instance by passing a slice of locations to the `from` method.
Then build the transport by using the `LocalTransport::new` associated function, which takes a target location (explained in the [Projector section](./guide-projector.md)) and the `LocalTransportChannel`.

You can construct a `LocalTransport` instance by passing a target location(lained in the [Projector section](./guide-projector.md)) and a `std::sync::Arc` of `LocalTransportChannel` to the `new` method.

Because of the nature of the `Local` transport, you must use the same `LocalTransport` instance for all locations. You can `clone` the `LocalTransport` instance and pass it to the threads.
Because of the nature of the `Local` transport, you must make a `std::sync::Arc` from the `LocalTransportChannel`, by using the `std::sync::Arc::clone(&local_transport)`.

```rust
# extern crate chorus_lib;
# use chorus_lib::transport::local::LocalTransport;
# use std::sync::Arc;
# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel};
# use std::thread;
# use chorus_lib::core::{ChoreographyLocation, ChoreoOp, Choreography, Projector};
# use chorus_lib::{LocationSet};
Expand All @@ -37,21 +62,19 @@ Because of the nature of the `Local` transport, you must use the same `LocalTran
# fn run(self, op: &impl ChoreoOp<Self::L>) {
# }
# }


let transport_channel = Arc::new(LocalTransportChannel::<LocationSet!(Alice, Bob)>::new());
let mut handles: Vec<thread::JoinHandle<()>> = Vec::new();
let transport = LocalTransport::<LocationSet!(Alice, Bob)>::new();
{
// create a clone for Alice
let transport = transport.clone();
// create a transport for Alice
let transport = LocalTransport::new(Alice, Arc::clone(&transport_channel));
handles.push(thread::spawn(move || {
let p = Projector::new(Alice, transport);
p.epp_and_run(HelloWorldChoreography);
}));
}
{
// create another for Bob
let transport = transport.clone();
let transport = LocalTransport::new(Bob, Arc::clone(&transport_channel));
handles.push(thread::spawn(move || {
let p = Projector::new(Bob, transport);
p.epp_and_run(HelloWorldChoreography);
Expand All @@ -63,24 +86,26 @@ let transport = LocalTransport::<LocationSet!(Alice, Bob)>::new();

The `http` transport is used to execute choreographies on different machines. This is useful for executing choreographies in a distributed system.

To use the `http` transport, import the `HttpTransport` struct and the `http_config` macro from the `chorus_lib` crate.
To use the `http` transport, import the `HttpTransport` struct and the `transport_config` macro from the `chorus_lib` crate.

```rust
# extern crate chorus_lib;
use chorus_lib::transport::http::HttpTransport;
use chorus_lib::http_config;
use chorus_lib::transport_config;
```

The `new` constructor takes the name of the projection target and "configuration" of type `HttpConfig`. To build the `HttpConfig`, you should use the macro `http_config` and give it a comma separatedlist of key: values where each key is a `ChoreographyLocation` and each value is a tuple of (host_name, port). You can think of configuration as a map from locations to the hostname and port of the location.
The new constructor takes a "configuration" of type TransportConfig. To build the TransportConfig, you should use the macro transport_config and give it a key => value, followed by a comma (if you have more than one key/value), and a comma-separated list of key: values where the key => value is the target ChoreographyLocation and the value is the required information for the target, and each following key: value is a ChoreographyLocation and the required information for it (`(host_name, port)` in this case). For HttpTransport You can think of TransportConfig as a map from locations to the hostname and port of the location. But for a generic Transport, it can contain any kind of information.

```rust
{{#include ./header.txt}}
# use chorus_lib::transport::http::{HttpTransport};
# use chorus_lib::http_config;
# use std::collections::HashMap;
# use chorus_lib::transport_config;
let config = transport_config!(
Alice => ("0.0.0.0".to_string(), 9010),
Bob: ("localhost".to_string(), 9011)
);

let config = http_config!(Alice: ("localhost", 8080), Bob: ("localhost", 8081));
let transport = HttpTransport::new(Alice, &config);
let transport = HttpTransport::new(&config);
```

In the above example, the transport will start the HTTP server on port 8080 on localhost. If Alice needs to send a message to Bob, it will use `http://localhost:8081` as the destination.
Expand All @@ -96,7 +121,8 @@ Note that when calling `epp_and_run` on a `Projector`, you will get a compile er

```rust, compile_fail
# extern crate chorus_lib;
# use chorus_lib::transport::local::LocalTransport;
# use std::sync::Arc;
# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel};
# use chorus_lib::core::{ChoreographyLocation, Projector, Choreography, ChoreoOp};
# use chorus_lib::{LocationSet};
Expand All @@ -111,7 +137,8 @@ impl Choreography for HelloWorldChoreography {
}
}
let transport = LocalTransport::<LocationSet!(Alice)>::new();
let transport_channel = Arc::new(LocalTransportChannel::<LocationSet!(Alice)>::new());
let transport = LocalTransport::new(Alice, Arc::clone(&transport_channel));
let projector = Projector::new(Alice, transport);
projector.epp_and_run(HelloWorldChoreography);
```
8 changes: 6 additions & 2 deletions chorus_book/src/header.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# extern crate chorus_lib;
# use std::sync::Arc;
# use chorus_lib::core::{ChoreoOp, Choreography, ChoreographyLocation, Projector, Located, Superposition, Runner};
# use chorus_lib::transport::local::LocalTransport;
# use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel};
# use chorus_lib::{LocationSet};
# #[derive(ChoreographyLocation)]
# struct Alice;
# #[derive(ChoreographyLocation)]
# struct Bob;
# #[derive(ChoreographyLocation)]
# struct Carol;
# let transport = LocalTransport::<LocationSet!(Alice, Bob, Carol)>::new();
# let transport_channel = Arc::new(LocalTransportChannel::<LocationSet!(Alice, Bob, Carol)>::new());
# let alice_transport = LocalTransport::new(Alice, Arc::clone(&transport_channel));
# let bob_transport = LocalTransport::new(Bob, Arc::clone(&transport_channel));
# let carol_transport = LocalTransport::new(Carol, Arc::clone(&transport_channel));
13 changes: 9 additions & 4 deletions chorus_lib/examples/bookseller.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
extern crate chorus_lib;

use std::io;
use std::sync::Arc;
use std::thread;

use chrono::NaiveDate;

use chorus_lib::core::{ChoreoOp, Choreography, ChoreographyLocation, Projector};
use chorus_lib::transport::local::LocalTransport;
use chorus_lib::transport::local::{LocalTransport, LocalTransportChannel};
use chorus_lib::LocationSet;

fn get_book(title: &str) -> Option<(i32, NaiveDate)> {
Expand Down Expand Up @@ -73,9 +74,13 @@ impl Choreography for BooksellerChoreography {
}

fn main() {
let transport = LocalTransport::<LocationSet!(Seller, Buyer)>::new();
let seller_projector = Projector::new(Seller, transport.clone());
let buyer_projector = Projector::new(Buyer, transport.clone());
let transport_channel = Arc::new(LocalTransportChannel::<LocationSet!(Seller, Buyer)>::new());

let transport_seller = LocalTransport::new(Seller, Arc::clone(&transport_channel));
let transport_buyer = LocalTransport::new(Buyer, Arc::clone(&transport_channel));

let seller_projector = Projector::new(Seller, transport_seller);
let buyer_projector = Projector::new(Buyer, transport_buyer);

let mut handles: Vec<thread::JoinHandle<()>> = Vec::new();
handles.push(thread::spawn(move || {
Expand Down
36 changes: 24 additions & 12 deletions chorus_lib/examples/bookseller2.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
extern crate chorus_lib;

use std::collections::HashMap;
use std::sync::Arc;
use std::thread;
use std::{collections::HashMap, sync::Arc};

use chorus_lib::LocationSet;
use chorus_lib::{
core::{ChoreoOp, Choreography, ChoreographyLocation, Located, Projector},
transport::local::LocalTransport,
transport::local::{LocalTransport, LocalTransportChannel},
};
use chrono::NaiveDate;

Expand Down Expand Up @@ -142,16 +143,16 @@ fn main() {
i
};

let transport = LocalTransport::<LocationSet!(Seller, Buyer1, Buyer2)>::new();
let seller_projector = Arc::new(Projector::new(Seller, transport.clone()));
let buyer1_projector = Arc::new(Projector::new(Buyer1, transport.clone()));
let buyer2_projector = Arc::new(Projector::new(Buyer2, transport.clone()));
let transport_channel =
Arc::new(LocalTransportChannel::<LocationSet!(Seller, Buyer1, Buyer2)>::new());

println!("Tries to buy HoTT with one buyer");
type OneBuyerBooksellerChoreography = BooksellerChoreography<OneBuyerDecider>;
let mut handles = Vec::new();
{
let seller_projector = seller_projector.clone();
let transport = LocalTransport::new(Seller, Arc::clone(&transport_channel));
let seller_projector = Projector::new(Seller, transport);

let inventory = inventory.clone();
handles.push(thread::spawn(move || {
seller_projector.epp_and_run(OneBuyerBooksellerChoreography {
Expand All @@ -162,7 +163,9 @@ fn main() {
}));
}
{
let buyer1_projector = buyer1_projector.clone();
let transport = LocalTransport::new(Buyer1, Arc::clone(&transport_channel));
let buyer1_projector = Projector::new(Buyer1, transport);

handles.push(thread::spawn(move || {
let result = buyer1_projector.epp_and_run(OneBuyerBooksellerChoreography {
_marker: std::marker::PhantomData,
Expand All @@ -176,7 +179,9 @@ fn main() {
}));
}
{
let buyer2_projector = buyer2_projector.clone();
let transport = LocalTransport::new(Buyer2, Arc::clone(&transport_channel));
let buyer2_projector = Projector::new(Buyer2, transport);

handles.push(thread::spawn(move || {
buyer2_projector.epp_and_run(OneBuyerBooksellerChoreography {
_marker: std::marker::PhantomData,
Expand All @@ -193,7 +198,9 @@ fn main() {
type TwoBuyerBooksellerChoreography = BooksellerChoreography<TwoBuyerDecider>;
let mut handles = Vec::new();
{
let seller_projector = seller_projector.clone();
let transport = LocalTransport::new(Seller, Arc::clone(&transport_channel));
let seller_projector = Projector::new(Seller, transport);

let inventory = inventory.clone();
handles.push(thread::spawn(move || {
seller_projector.epp_and_run(TwoBuyerBooksellerChoreography {
Expand All @@ -204,7 +211,9 @@ fn main() {
}));
}
{
let buyer1_projector = buyer1_projector.clone();
let transport = LocalTransport::new(Buyer1, Arc::clone(&transport_channel));
let buyer1_projector = Projector::new(Buyer1, transport);

handles.push(thread::spawn(move || {
let result = buyer1_projector.epp_and_run(TwoBuyerBooksellerChoreography {
_marker: std::marker::PhantomData,
Expand All @@ -218,7 +227,10 @@ fn main() {
}));
}
{
let buyer2_projector = buyer2_projector.clone();
let transport = LocalTransport::new(Buyer2, Arc::clone(&transport_channel));

let buyer2_projector = Projector::new(Buyer2, transport);

handles.push(thread::spawn(move || {
buyer2_projector.epp_and_run(TwoBuyerBooksellerChoreography {
_marker: std::marker::PhantomData,
Expand Down
Loading

0 comments on commit 5bf932a

Please sign in to comment.