Fix a bug where gossip loops forever while splitting messages (#7032)

* Fix a bug where gossip loops forever while splitting messages

* Get rid of while loop

* Minor clean up and rename
This commit is contained in:
Sagar Dhawan 2019-11-19 11:51:51 -08:00 committed by GitHub
parent ea656b1a3f
commit f2badf2c5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 63 additions and 17 deletions

View File

@ -913,27 +913,37 @@ impl ClusterInfo {
/// each Vec is no larger than `PROTOCOL_PAYLOAD_SIZE`
/// Note: some messages cannot be contained within that size so in the worst case this returns
/// N nested Vecs with 1 item each.
fn split_gossip_messages(mut msgs: Vec<CrdsValue>) -> Vec<Vec<CrdsValue>> {
fn split_gossip_messages(msgs: Vec<CrdsValue>) -> Vec<Vec<CrdsValue>> {
let mut messages = vec![];
while !msgs.is_empty() {
let mut payload = vec![];
let mut size = serialized_size(&payload).expect("Couldn't check size");
while let Some(msg) = msgs.pop() {
let msg_size = msg.size();
if size + msg_size > MAX_PROTOCOL_PAYLOAD_SIZE as u64 {
if msg_size < MAX_PROTOCOL_PAYLOAD_SIZE as u64 {
msgs.push(msg);
} else {
debug!(
"dropping message larger than the maximum payload size {:?}",
msg
);
let mut payload = vec![];
let base_size = serialized_size(&payload).expect("Couldn't check size");
let max_payload_size = MAX_PROTOCOL_PAYLOAD_SIZE - base_size;
let mut payload_size = 0;
for msg in msgs {
let msg_size = msg.size();
// If the message is too big to fit in this batch
if payload_size + msg_size > max_payload_size as u64 {
// See if it can fit in the next batch
if msg_size <= max_payload_size as u64 {
if !payload.is_empty() {
// Flush the current payload
messages.push(payload);
// Init the next payload
payload = vec![msg];
payload_size = msg_size;
}
break;
} else {
debug!(
"dropping message larger than the maximum payload size {:?}",
msg
);
}
size += msg_size;
payload.push(msg);
continue;
}
payload_size += msg_size;
payload.push(msg);
}
if !payload.is_empty() {
messages.push(payload);
}
messages
@ -2442,6 +2452,42 @@ mod tests {
test_split_messages(value);
}
#[test]
fn test_split_messages_packet_size() {
// Test that if a value is smaller than payload size but too large to be wrappe in a vec
// that it is still dropped
let payload: Vec<CrdsValue> = vec![];
let vec_size = serialized_size(&payload).unwrap();
let desired_size = MAX_PROTOCOL_PAYLOAD_SIZE - vec_size;
let mut value = CrdsValue::new_unsigned(CrdsData::EpochSlots(EpochSlots {
from: Pubkey::default(),
root: 0,
slots: BTreeSet::new(),
wallclock: 0,
}));
let mut i = 0;
while value.size() < desired_size {
let slots = (0..i).collect::<BTreeSet<_>>();
if slots.len() > 200 {
panic!(
"impossible to match size: last {:?} vs desired {:?}",
serialized_size(&value).unwrap(),
desired_size
);
}
value.data = CrdsData::EpochSlots(EpochSlots {
from: Pubkey::default(),
root: 0,
slots,
wallclock: 0,
});
i += 1;
}
let split = ClusterInfo::split_gossip_messages(vec![value.clone()]);
assert_eq!(split.len(), 0);
}
fn test_split_messages(value: CrdsValue) {
const NUM_VALUES: usize = 30;
let value_size = value.size();