-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pad shreds on retrieval from blockstore only when needed #17204
Closed
Closed
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
004db7e
Only zero-pad data shreds when necessary
3259dfa
Remove resizing from Shred::new_from_serialized()
fafc686
Remove nonce from shred payload before deserialization
3844a03
Remove all-shred-same-length requirement from deshred()
d8b6061
Make serve_repair tests pass
ca41625
Add bench that more clearly shows difference for resize
d52173c
Add comment about payload truncation
389e5af
Rename function
d5cf747
Condense repeated shred logic and move back into shred module
44c0b36
Make cargo fmt happy
ea67c1d
Add functions to remove repeated resizes
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -247,6 +247,13 @@ impl Shred { | |
packet.meta.size = len; | ||
} | ||
|
||
pub fn copy_from_packet(packet: &Packet) -> Result<Self> { | ||
let mut serialized_shred = vec![0; SHRED_PAYLOAD_SIZE]; | ||
// TODO: assert packet.data.len() >= SHRED_PAYLOAD_SIZE / == PACKET_DATA_SIZE ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thoughts on this assertion? We had something like this in window service; we could move it here to avoid repeated lines for all the callers of this. |
||
serialized_shred.copy_from_slice(&packet.data[..SHRED_PAYLOAD_SIZE]); | ||
Shred::new_from_serialized_shred(serialized_shred) | ||
} | ||
|
||
pub fn new_from_data( | ||
slot: Slot, | ||
index: u32, | ||
|
@@ -314,16 +321,65 @@ impl Shred { | |
} | ||
} | ||
|
||
pub fn new_from_serialized_shred(mut payload: Vec<u8>) -> Result<Self> { | ||
/// De-serializes a shred into its' headers and payload | ||
pub fn new_from_serialized_shred(payload: Vec<u8>) -> Result<Self> { | ||
// A shred can be deserialized in several cases; payload length will vary for these: | ||
// payload.len() <= SHRED_PAYLOAD_SIZE when payload is retrieved from the blockstore | ||
// payload.len() == SHRED_PAYLOAD_SIZE when a new shred is created | ||
// payload.len() == PACKET_DATA_SIZE when payload comes from a packet (window serivce) | ||
// The below assertion requires that packets be shortened before calling | ||
assert!(payload.len() <= SHRED_PAYLOAD_SIZE); | ||
|
||
let mut start = 0; | ||
let common_header: ShredCommonHeader = | ||
Self::deserialize_obj(&mut start, SIZE_OF_COMMON_SHRED_HEADER, &payload)?; | ||
|
||
let slot = common_header.slot; | ||
// Shreds should be padded out to SHRED_PAYLOAD_SIZE | ||
// so that erasure generation/recovery works correctly | ||
// But only the data_header.size is stored in blockstore. | ||
|
||
let shred = if common_header.shred_type == ShredType(CODING_SHRED) { | ||
let coding_header: CodingShredHeader = | ||
Self::deserialize_obj(&mut start, SIZE_OF_CODING_SHRED_HEADER, &payload)?; | ||
Self { | ||
common_header, | ||
data_header: DataShredHeader::default(), | ||
coding_header, | ||
payload, | ||
} | ||
} else if common_header.shred_type == ShredType(DATA_SHRED) { | ||
let data_header: DataShredHeader = | ||
Self::deserialize_obj(&mut start, SIZE_OF_DATA_SHRED_HEADER, &payload)?; | ||
if u64::from(data_header.parent_offset) > common_header.slot { | ||
return Err(ShredError::InvalidParentOffset { | ||
slot, | ||
parent_offset: data_header.parent_offset, | ||
}); | ||
} | ||
Self { | ||
common_header, | ||
data_header, | ||
coding_header: CodingShredHeader::default(), | ||
payload, | ||
} | ||
} else { | ||
return Err(ShredError::InvalidShredType); | ||
}; | ||
|
||
Ok(shred) | ||
} | ||
|
||
pub fn new_from_serialized_shred_pad_out(mut payload: Vec<u8>) -> Result<Self> { | ||
// A shred can be deserialized in several cases; payload length will vary for these: | ||
// payload.len() <= SHRED_PAYLOAD_SIZE when payload is retrieved from the blockstore | ||
// payload.len() == SHRED_PAYLOAD_SIZE when a new shred is created | ||
// payload.len() == PACKET_DATA_SIZE when payload comes from a packet (window serivce) | ||
|
||
// Pad out the shred | ||
payload.resize(SHRED_PAYLOAD_SIZE, 0); | ||
|
||
let mut start = 0; | ||
let common_header: ShredCommonHeader = | ||
Self::deserialize_obj(&mut start, SIZE_OF_COMMON_SHRED_HEADER, &payload)?; | ||
let slot = common_header.slot; | ||
|
||
let shred = if common_header.shred_type == ShredType(CODING_SHRED) { | ||
let coding_header: CodingShredHeader = | ||
Self::deserialize_obj(&mut start, SIZE_OF_CODING_SHRED_HEADER, &payload)?; | ||
|
@@ -933,7 +989,6 @@ impl Shredder { | |
pub fn deshred(shreds: &[Shred]) -> std::result::Result<Vec<u8>, reed_solomon_erasure::Error> { | ||
use reed_solomon_erasure::Error::TooFewDataShards; | ||
const SHRED_DATA_OFFSET: usize = SIZE_OF_COMMON_SHRED_HEADER + SIZE_OF_DATA_SHRED_HEADER; | ||
Self::verify_consistent_shred_payload_sizes(&"deshred()", shreds)?; | ||
let index = shreds.first().ok_or(TooFewDataShards)?.index(); | ||
let aligned = shreds.iter().zip(index..).all(|(s, i)| s.index() == i); | ||
let data_complete = { | ||
|
@@ -1876,7 +1931,7 @@ pub mod tests { | |
let shred = Shred::new_from_data(10, 0, 1000, Some(&[1, 2, 3]), false, false, 0, 1, 0); | ||
let mut packet = Packet::default(); | ||
shred.copy_to_packet(&mut packet); | ||
let shred_res = Shred::new_from_serialized_shred(packet.data.to_vec()); | ||
let shred_res = Shred::copy_from_packet(&packet); | ||
assert_matches!( | ||
shred_res, | ||
Err(ShredError::InvalidParentOffset { | ||
|
@@ -1940,4 +1995,13 @@ pub mod tests { | |
assert_eq!(None, get_shred_slot_index_type(&packet, &mut stats)); | ||
assert_eq!(1, stats.bad_shred_type); | ||
} | ||
|
||
#[test] | ||
fn test_shred_copy_to_from_packet() { | ||
let shred = Shred::new_from_data(1, 3, 0, None, true, true, 0, 0, 0); | ||
let mut packet = Packet::default(); | ||
shred.copy_to_packet(&mut packet); | ||
let copied_shred = Shred::copy_from_packet(&packet).unwrap(); | ||
assert_eq!(shred, copied_shred); | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason to break this out into a separate function was because of
get_cf()
's implementation:Note the
db_vec.to_vec()
; this clones db_vec into a new vector. If we do the resize later, then a second allocation & memcpy will occur with Vector::resize(); doing this here shaves that off.