Skip to content

Commit ec1bb14

Browse files
committed
Make the logging less verbose
1 parent 8afb8ee commit ec1bb14

File tree

6 files changed

+151
-136
lines changed

6 files changed

+151
-136
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# [tag:gitignore] Keep this in sync with [ref:excluded_input_paths].
2+
.data
23
/artifacts/
34
/target/

src/acceptor.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub struct PrepareResponse {
4141

4242
// Logic for the "prepare" endpoint
4343
fn prepare(request: &PrepareRequest, state: &mut State) -> PrepareResponse {
44-
info!(
44+
debug!(
4545
"Received prepare request:\n{}",
4646
serde_yaml::to_string(request).unwrap(), // Serialization is safe.
4747
);
@@ -78,7 +78,7 @@ pub struct AcceptResponse {
7878

7979
// Logic for the "accept" endpoint
8080
fn accept(request: &AcceptRequest, state: &mut State) -> AcceptResponse {
81-
info!(
81+
debug!(
8282
"Received accept request:\n{}",
8383
serde_yaml::to_string(request).unwrap(), // Serialization is safe.
8484
);
@@ -113,8 +113,8 @@ pub struct ChooseResponse;
113113

114114
// Logic for the "choose" endpoint
115115
fn choose(request: &ChooseRequest, state: &mut State) -> ChooseResponse {
116-
info!("Received notification that consensus was achieved.");
117116
if state.chosen_value.is_none() {
117+
info!("Consensus was achieved.");
118118
println!("{}", request.value);
119119
io::stdout().flush().unwrap_or(());
120120
state.chosen_value = Some(request.value.clone());

src/main.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
mod acceptor;
44
mod config;
55
mod proposer;
6+
mod rpc;
67
mod state;
78

89
#[macro_use]
@@ -228,7 +229,7 @@ async fn settings() -> io::Result<Settings> {
228229
);
229230

230231
// Determine the data file path [tag:data_file_path_has_parent].
231-
let data_file_path = Path::join(data_dir_path, format!("{}:{}", ip, port));
232+
let data_file_path = Path::join(data_dir_path, format!("{}-{}", ip, port));
232233

233234
// Return the settings.
234235
Ok(Settings {
@@ -279,22 +280,26 @@ async fn main() {
279280
}
280281
}
281282

282-
// Run the acceptor and the proposer, if applicable.
283+
// Run the acceptor and the proposer, if applicable. Also, broadcasr any chosen value from the
284+
// persisted state.
283285
if let Err(error) = try_join!(
284286
acceptor::acceptor(state.clone(), &settings.data_file_path, settings.address),
285287
async {
286-
if let Some(value) = &settings.proposal {
287-
propose(
288-
state,
289-
&settings.data_file_path,
290-
&settings.nodes,
291-
settings.node_index,
292-
value,
293-
)
294-
.await
295-
} else {
296-
Ok(())
288+
// If there's a value to propose and no chosen value in the persisted state, propose the
289+
// value.
290+
if state.read().await.chosen_value.is_none() {
291+
if let Some(value) = &settings.proposal {
292+
propose(
293+
state.clone(),
294+
&settings.data_file_path,
295+
&settings.nodes,
296+
settings.node_index,
297+
value,
298+
)
299+
.await?;
300+
}
297301
}
302+
Ok(())
298303
},
299304
) {
300305
error!("{}", error);

src/proposer.rs

+27-120
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,33 @@ use {
44
AcceptRequest, AcceptResponse, ChooseRequest, ChooseResponse, PrepareRequest,
55
PrepareResponse, ACCEPT_ENDPOINT, CHOOSE_ENDPOINT, PREPARE_ENDPOINT,
66
},
7+
rpc::{broadcast_all, broadcast_quorum},
78
state::{ProposalNumber, State},
89
},
9-
futures::{stream::FuturesUnordered, StreamExt},
10-
hyper::{client::HttpConnector, Body, Client, Method, Request},
10+
hyper::Client,
1111
rand::{thread_rng, Rng},
12-
serde::{de::DeserializeOwned, Serialize},
13-
std::{cmp::min, io, net::SocketAddr, path::Path, sync::Arc, time::Duration},
12+
std::{io, net::SocketAddr, path::Path, sync::Arc, time::Duration},
1413
tokio::{sync::RwLock, time::sleep},
1514
};
1615

1716
// Duration constants
18-
const EXPONENTIAL_BACKOFF_MIN: Duration = Duration::from_millis(100);
19-
const EXPONENTIAL_BACKOFF_MAX: Duration = Duration::from_secs(2);
20-
const EXPONENTIAL_BACKOFF_MULTIPLIER: u32 = 2;
2117
const RESTART_DELAY_MIN: Duration = Duration::from_millis(0);
2218
const RESTART_DELAY_MAX: Duration = Duration::from_millis(100);
2319

20+
// Generate a new proposal number.
21+
fn generate_proposal_number(
22+
nodes: &[SocketAddr],
23+
node_index: usize,
24+
state: &mut State,
25+
) -> ProposalNumber {
26+
let proposal_number = ProposalNumber {
27+
round: state.next_round,
28+
proposer_address: nodes[node_index],
29+
};
30+
state.next_round += 1;
31+
proposal_number
32+
}
33+
2434
// Propose a value to the cluster.
2535
pub async fn propose(
2636
state: Arc<RwLock<State>>,
@@ -31,6 +41,9 @@ pub async fn propose(
3141
) -> Result<(), io::Error> {
3242
// Retry until the protocol succeeds.
3343
loop {
44+
// Create an HTTP client.
45+
let client = Client::new();
46+
3447
// Generate a new proposal number.
3548
let proposal_number = {
3649
// The `unwrap` is safe since it can only fail if a panic already happened.
@@ -40,11 +53,8 @@ pub async fn propose(
4053
proposal_number
4154
};
4255

43-
// Create an HTTP client.
44-
let client = Client::new();
45-
4656
// Send a prepare message to all the nodes.
47-
info!(
57+
debug!(
4858
"Preparing value `{}` with proposal number:\n{}",
4959
original_value,
5060
// Serialization is safe.
@@ -65,19 +75,19 @@ pub async fn propose(
6575
.max_by_key(|accepted_proposal| accepted_proposal.0)
6676
{
6777
// There was an accepted proposal. Use that.
68-
info!(
78+
debug!(
6979
"Discovered existing value from cluster: {}",
7080
accepted_proposal.1,
7181
);
7282
accepted_proposal.1
7383
} else {
7484
// Propose the given value.
75-
info!("Quorum replied with no existing value.");
85+
debug!("Quorum replied with no existing value.");
7686
original_value.to_owned()
7787
};
7888

7989
// Send an accept message to all the nodes.
80-
info!(
90+
debug!(
8191
"Requesting acceptance of value `{}` with proposal number:\n{}",
8292
new_value,
8393
// The `unwrap` is safe because serialization should never fail.
@@ -110,127 +120,24 @@ pub async fn propose(
110120
}
111121
if value_chosen {
112122
// The protocol succeeded. Notify all the nodes and return.
113-
info!("Consensus achieved. Notifying all the nodes.");
123+
debug!("Consensus achieved. Notifying all the nodes.");
114124
broadcast_all::<ChooseResponse>(
115125
&client,
116126
nodes,
117127
CHOOSE_ENDPOINT,
118128
&ChooseRequest { value: new_value },
119129
)
120130
.await;
121-
info!("All nodes notified.");
131+
info!("Proposer finished.");
122132
return Ok(());
123133
}
124134

125135
// The protocol failed. Sleep for a random duration before starting over.
126-
info!("Failed to reach consensus. Starting over.");
136+
debug!("Failed to reach consensus. Starting over.");
127137
sleep(thread_rng().gen_range(RESTART_DELAY_MIN..RESTART_DELAY_MAX)).await;
128138
}
129139
}
130140

131-
// Generate a new proposal number.
132-
fn generate_proposal_number(
133-
nodes: &[SocketAddr],
134-
node_index: usize,
135-
state: &mut State,
136-
) -> ProposalNumber {
137-
let proposal_number = ProposalNumber {
138-
round: state.next_round,
139-
proposer_address: nodes[node_index],
140-
};
141-
state.next_round += 1;
142-
proposal_number
143-
}
144-
145-
// Send a request without retries.
146-
async fn try_to_send<T: DeserializeOwned>(
147-
client: &Client<HttpConnector, Body>,
148-
node: SocketAddr,
149-
endpoint: &str,
150-
payload: &impl Serialize,
151-
) -> Result<T, hyper::Error> {
152-
Ok(bincode::deserialize(
153-
&hyper::body::to_bytes(
154-
client
155-
.request(
156-
Request::builder()
157-
.method(Method::POST)
158-
.uri(format!("http://{}{}", node, endpoint))
159-
// The `unwrap` is safe because serialization should never fail.
160-
.body(Body::from(bincode::serialize(&payload).unwrap()))
161-
.unwrap(), // Safe since we constructed a well-formed request
162-
)
163-
.await?
164-
.into_body(),
165-
)
166-
.await?,
167-
)
168-
.unwrap()) // Safe under non-Byzantine conditions
169-
}
170-
171-
// Send a request, retrying with exponential backoff until it succeeds.
172-
async fn send<T: DeserializeOwned>(
173-
client: &Client<HttpConnector, Body>,
174-
node: SocketAddr,
175-
endpoint: &str,
176-
payload: &impl Serialize,
177-
) -> T {
178-
// The delay between requests
179-
let mut delay = EXPONENTIAL_BACKOFF_MIN;
180-
181-
// Retry until the request succeeds.
182-
loop {
183-
// Send the request.
184-
match try_to_send(client, node, endpoint, payload).await {
185-
Ok(response) => {
186-
return response;
187-
}
188-
Err(error) => {
189-
// Log the error.
190-
error!("Received error: {}", error);
191-
}
192-
}
193-
194-
// Sleep before retrying.
195-
sleep(delay).await;
196-
delay = min(
197-
delay * EXPONENTIAL_BACKOFF_MULTIPLIER,
198-
EXPONENTIAL_BACKOFF_MAX,
199-
);
200-
}
201-
}
202-
203-
// Send a request to all nodes. Return once a majority of responses come in.
204-
async fn broadcast_quorum<T: DeserializeOwned>(
205-
client: &Client<HttpConnector, Body>,
206-
nodes: &[SocketAddr],
207-
endpoint: &str,
208-
payload: &impl Serialize,
209-
) -> Vec<T> {
210-
nodes
211-
.iter()
212-
.map(|node| send(client, *node, endpoint, payload))
213-
.collect::<FuturesUnordered<_>>()
214-
.take(nodes.len() / 2 + 1)
215-
.collect()
216-
.await
217-
}
218-
219-
// Send a request to all nodes. Return once all responses come in.
220-
async fn broadcast_all<T: DeserializeOwned>(
221-
client: &Client<HttpConnector, Body>,
222-
nodes: &[SocketAddr],
223-
endpoint: &str,
224-
payload: &impl Serialize,
225-
) -> Vec<T> {
226-
nodes
227-
.iter()
228-
.map(|node| send(client, *node, endpoint, payload))
229-
.collect::<FuturesUnordered<_>>()
230-
.collect()
231-
.await
232-
}
233-
234141
#[cfg(test)]
235142
mod tests {
236143
use {

0 commit comments

Comments
 (0)