Add protocol request for requesting the highest blob in a slot (#2759)
This commit is contained in:
@@ -157,6 +157,7 @@ enum Protocol {
|
|||||||
/// Window protocol messages
|
/// Window protocol messages
|
||||||
/// TODO: move this message to a different module
|
/// TODO: move this message to a different module
|
||||||
RequestWindowIndex(NodeInfo, u64, u64),
|
RequestWindowIndex(NodeInfo, u64, u64),
|
||||||
|
RequestHighestWindowIndex(NodeInfo, u64, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClusterInfo {
|
impl ClusterInfo {
|
||||||
@@ -712,10 +713,22 @@ impl ClusterInfo {
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn window_highest_index_request_bytes(
|
||||||
|
&self,
|
||||||
|
slot_height: u64,
|
||||||
|
blob_index: u64,
|
||||||
|
) -> Result<Vec<u8>> {
|
||||||
|
let req =
|
||||||
|
Protocol::RequestHighestWindowIndex(self.my_data().clone(), slot_height, blob_index);
|
||||||
|
let out = serialize(&req)?;
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn window_index_request(
|
pub fn window_index_request(
|
||||||
&self,
|
&self,
|
||||||
slot_height: u64,
|
slot_height: u64,
|
||||||
blob_index: u64,
|
blob_index: u64,
|
||||||
|
get_highest: bool,
|
||||||
) -> Result<(SocketAddr, Vec<u8>)> {
|
) -> Result<(SocketAddr, Vec<u8>)> {
|
||||||
// find a peer that appears to be accepting replication, as indicated
|
// find a peer that appears to be accepting replication, as indicated
|
||||||
// by a valid tvu port location
|
// by a valid tvu port location
|
||||||
@@ -725,7 +738,13 @@ impl ClusterInfo {
|
|||||||
}
|
}
|
||||||
let n = thread_rng().gen::<usize>() % valid.len();
|
let n = thread_rng().gen::<usize>() % valid.len();
|
||||||
let addr = valid[n].gossip; // send the request to the peer's gossip port
|
let addr = valid[n].gossip; // send the request to the peer's gossip port
|
||||||
let out = self.window_index_request_bytes(slot_height, blob_index)?;
|
let out = {
|
||||||
|
if get_highest {
|
||||||
|
self.window_highest_index_request_bytes(slot_height, blob_index)?
|
||||||
|
} else {
|
||||||
|
self.window_index_request_bytes(slot_height, blob_index)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
submit(
|
submit(
|
||||||
influxdb::Point::new("cluster-info")
|
influxdb::Point::new("cluster-info")
|
||||||
@@ -735,6 +754,7 @@ impl ClusterInfo {
|
|||||||
|
|
||||||
Ok((addr, out))
|
Ok((addr, out))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_pull_requests(&mut self) -> Vec<(SocketAddr, Protocol)> {
|
fn new_pull_requests(&mut self) -> Vec<(SocketAddr, Protocol)> {
|
||||||
let now = timestamp();
|
let now = timestamp();
|
||||||
let pulls: Vec<_> = self.gossip.new_pull_request(now).ok().into_iter().collect();
|
let pulls: Vec<_> = self.gossip.new_pull_request(now).ok().into_iter().collect();
|
||||||
@@ -854,9 +874,6 @@ impl ClusterInfo {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: To support repairing multiple slots, broadcast needs to reset
|
|
||||||
// blob index for every slot, and window requests should be by slot + index.
|
|
||||||
// Issue: https://github.com/solana-labs/solana/issues/2440
|
|
||||||
fn run_window_request(
|
fn run_window_request(
|
||||||
from: &NodeInfo,
|
from: &NodeInfo,
|
||||||
from_addr: &SocketAddr,
|
from_addr: &SocketAddr,
|
||||||
@@ -889,6 +906,32 @@ impl ClusterInfo {
|
|||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_highest_window_request(
|
||||||
|
from_addr: &SocketAddr,
|
||||||
|
blocktree: Option<&Arc<Blocktree>>,
|
||||||
|
slot_height: u64,
|
||||||
|
highest_index: u64,
|
||||||
|
) -> Vec<SharedBlob> {
|
||||||
|
if let Some(blocktree) = blocktree {
|
||||||
|
// Try to find the requested index in one of the slots
|
||||||
|
let meta = blocktree.meta(slot_height);
|
||||||
|
|
||||||
|
if let Ok(Some(meta)) = meta {
|
||||||
|
if meta.received > highest_index {
|
||||||
|
// meta.received must be at least 1 by this point
|
||||||
|
let blob = blocktree.get_data_blob(slot_height, meta.received - 1);
|
||||||
|
|
||||||
|
if let Ok(Some(mut blob)) = blob {
|
||||||
|
blob.meta.set_addr(from_addr);
|
||||||
|
return vec![Arc::new(RwLock::new(blob))];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
//TODO we should first coalesce all the requests
|
//TODO we should first coalesce all the requests
|
||||||
fn handle_blob(
|
fn handle_blob(
|
||||||
obj: &Arc<RwLock<Self>>,
|
obj: &Arc<RwLock<Self>>,
|
||||||
@@ -1012,6 +1055,7 @@ impl ClusterInfo {
|
|||||||
slot_height: u64,
|
slot_height: u64,
|
||||||
blob_index: u64,
|
blob_index: u64,
|
||||||
from_addr: &SocketAddr,
|
from_addr: &SocketAddr,
|
||||||
|
is_get_highest: bool,
|
||||||
) -> Vec<SharedBlob> {
|
) -> Vec<SharedBlob> {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
@@ -1039,14 +1083,20 @@ impl ClusterInfo {
|
|||||||
slot_height,
|
slot_height,
|
||||||
blob_index,
|
blob_index,
|
||||||
);
|
);
|
||||||
let res = Self::run_window_request(
|
let res = {
|
||||||
&from,
|
if is_get_highest {
|
||||||
&from_addr,
|
Self::run_highest_window_request(&from_addr, blocktree, slot_height, blob_index)
|
||||||
blocktree,
|
} else {
|
||||||
&my_info,
|
Self::run_window_request(
|
||||||
slot_height,
|
&from,
|
||||||
blob_index,
|
&from_addr,
|
||||||
);
|
blocktree,
|
||||||
|
&my_info,
|
||||||
|
slot_height,
|
||||||
|
blob_index,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
report_time_spent(
|
report_time_spent(
|
||||||
"RequestWindowIndex",
|
"RequestWindowIndex",
|
||||||
&now.elapsed(),
|
&now.elapsed(),
|
||||||
@@ -1054,6 +1104,7 @@ impl ClusterInfo {
|
|||||||
);
|
);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_protocol(
|
fn handle_protocol(
|
||||||
me: &Arc<RwLock<Self>>,
|
me: &Arc<RwLock<Self>>,
|
||||||
from_addr: &SocketAddr,
|
from_addr: &SocketAddr,
|
||||||
@@ -1120,6 +1171,18 @@ impl ClusterInfo {
|
|||||||
slot_height,
|
slot_height,
|
||||||
blob_index,
|
blob_index,
|
||||||
from_addr,
|
from_addr,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Protocol::RequestHighestWindowIndex(from, slot_height, highest_index) => {
|
||||||
|
Self::handle_request_window_index(
|
||||||
|
me,
|
||||||
|
&from,
|
||||||
|
blocktree,
|
||||||
|
slot_height,
|
||||||
|
highest_index,
|
||||||
|
from_addr,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1368,7 +1431,7 @@ mod tests {
|
|||||||
fn window_index_request() {
|
fn window_index_request() {
|
||||||
let me = NodeInfo::new_localhost(Keypair::new().pubkey(), timestamp());
|
let me = NodeInfo::new_localhost(Keypair::new().pubkey(), timestamp());
|
||||||
let mut cluster_info = ClusterInfo::new(me);
|
let mut cluster_info = ClusterInfo::new(me);
|
||||||
let rv = cluster_info.window_index_request(0, 0);
|
let rv = cluster_info.window_index_request(0, 0, false);
|
||||||
assert_matches!(rv, Err(Error::ClusterInfoError(ClusterInfoError::NoPeers)));
|
assert_matches!(rv, Err(Error::ClusterInfoError(ClusterInfoError::NoPeers)));
|
||||||
|
|
||||||
let gossip_addr = socketaddr!([127, 0, 0, 1], 1234);
|
let gossip_addr = socketaddr!([127, 0, 0, 1], 1234);
|
||||||
@@ -1383,7 +1446,7 @@ mod tests {
|
|||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
cluster_info.insert_info(nxt.clone());
|
cluster_info.insert_info(nxt.clone());
|
||||||
let rv = cluster_info.window_index_request(0, 0).unwrap();
|
let rv = cluster_info.window_index_request(0, 0, false).unwrap();
|
||||||
assert_eq!(nxt.gossip, gossip_addr);
|
assert_eq!(nxt.gossip, gossip_addr);
|
||||||
assert_eq!(rv.0, nxt.gossip);
|
assert_eq!(rv.0, nxt.gossip);
|
||||||
|
|
||||||
@@ -1403,7 +1466,7 @@ mod tests {
|
|||||||
let mut two = false;
|
let mut two = false;
|
||||||
while !one || !two {
|
while !one || !two {
|
||||||
//this randomly picks an option, so eventually it should pick both
|
//this randomly picks an option, so eventually it should pick both
|
||||||
let rv = cluster_info.window_index_request(0, 0).unwrap();
|
let rv = cluster_info.window_index_request(0, 0, false).unwrap();
|
||||||
if rv.0 == gossip_addr {
|
if rv.0 == gossip_addr {
|
||||||
one = true;
|
one = true;
|
||||||
}
|
}
|
||||||
@@ -1472,6 +1535,54 @@ mod tests {
|
|||||||
Blocktree::destroy(&ledger_path).expect("Expected successful database destruction");
|
Blocktree::destroy(&ledger_path).expect("Expected successful database destruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// test run_window_requestwindow requests respond with the right blob, and do not overrun
|
||||||
|
#[test]
|
||||||
|
fn run_highest_window_request() {
|
||||||
|
solana_logger::setup();
|
||||||
|
let ledger_path = get_tmp_ledger_path("run_highest_window_request");
|
||||||
|
{
|
||||||
|
let blocktree = Arc::new(Blocktree::open(&ledger_path).unwrap());
|
||||||
|
let rv =
|
||||||
|
ClusterInfo::run_highest_window_request(&socketaddr_any!(), Some(&blocktree), 0, 0);
|
||||||
|
assert!(rv.is_empty());
|
||||||
|
|
||||||
|
let data_size = 1;
|
||||||
|
let max_index = 5;
|
||||||
|
let blobs: Vec<_> = (0..max_index)
|
||||||
|
.map(|i| {
|
||||||
|
let mut blob = Blob::default();
|
||||||
|
blob.set_size(data_size);
|
||||||
|
blob.set_index(i);
|
||||||
|
blob.set_slot(2);
|
||||||
|
blob.meta.size = data_size + BLOB_HEADER_SIZE;
|
||||||
|
blob
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
blocktree
|
||||||
|
.write_blobs(&blobs)
|
||||||
|
.expect("Expect successful ledger write");
|
||||||
|
|
||||||
|
let rv =
|
||||||
|
ClusterInfo::run_highest_window_request(&socketaddr_any!(), Some(&blocktree), 2, 1);
|
||||||
|
assert!(!rv.is_empty());
|
||||||
|
let v = rv[0].clone();
|
||||||
|
assert_eq!(v.read().unwrap().index(), max_index - 1);
|
||||||
|
assert_eq!(v.read().unwrap().slot(), 2);
|
||||||
|
assert_eq!(v.read().unwrap().meta.size, BLOB_HEADER_SIZE + data_size);
|
||||||
|
|
||||||
|
let rv = ClusterInfo::run_highest_window_request(
|
||||||
|
&socketaddr_any!(),
|
||||||
|
Some(&blocktree),
|
||||||
|
2,
|
||||||
|
max_index,
|
||||||
|
);
|
||||||
|
assert!(rv.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
Blocktree::destroy(&ledger_path).expect("Expected successful database destruction");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_leader() {
|
fn test_default_leader() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
@@ -59,7 +59,7 @@ impl RepairService {
|
|||||||
cluster_info
|
cluster_info
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.window_index_request(slot_height, blob_index)
|
.window_index_request(slot_height, blob_index, false)
|
||||||
.map(|result| (result, slot_height, blob_index))
|
.map(|result| (result, slot_height, blob_index))
|
||||||
.ok()
|
.ok()
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user