Skip to content

Commit 5583a5d

Browse files
authored
Fix bug in buf_channel::consume() where exact size doesn't receive eof (#858)
In the event the receiver is receiving the exact size of data, but the writer sends all the data, but not an eof then the writer decides not to send the eof the receiver will consider it "good". This issue has been fixed by this PR.
1 parent b2b83df commit 5583a5d

File tree

3 files changed

+34
-14
lines changed

3 files changed

+34
-14
lines changed

nativelink-store/tests/filesystem_store_test.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ mod filesystem_store_tests {
228228

229229
const HASH1: &str = "0123456789abcdef000000000000000000010000000000000123456789abcdef";
230230
const HASH2: &str = "0123456789abcdef000000000000000000020000000000000123456789abcdef";
231-
const VALUE1: &str = "1234";
232-
const VALUE2: &str = "4321";
231+
const VALUE1: &str = "0123456789";
232+
const VALUE2: &str = "9876543210";
233233

234234
#[tokio::test]
235235
async fn valid_results_after_shutdown_test() -> Result<(), Error> {
@@ -814,8 +814,9 @@ mod filesystem_store_tests {
814814

815815
#[tokio::test]
816816
async fn eviction_on_insert_calls_unref_once() -> Result<(), Error> {
817+
const SMALL_VALUE: &str = "01";
817818
const BIG_VALUE: &str = "0123";
818-
let small_digest = DigestInfo::try_new(HASH1, VALUE1.len())?;
819+
let small_digest = DigestInfo::try_new(HASH1, SMALL_VALUE.len())?;
819820
let big_digest = DigestInfo::try_new(HASH1, BIG_VALUE.len())?;
820821

821822
static UNREFED_DIGESTS: Lazy<Mutex<Vec<DigestInfo>>> = Lazy::new(|| Mutex::new(Vec::new()));
@@ -851,7 +852,7 @@ mod filesystem_store_tests {
851852
// Insert data into store.
852853
store
853854
.as_ref()
854-
.update_oneshot(small_digest, VALUE1.into())
855+
.update_oneshot(small_digest, SMALL_VALUE.into())
855856
.await?;
856857
store
857858
.as_ref()

nativelink-util/src/buf_channel.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ impl DropCloserReadHalf {
218218
if !self.eof_sent.load(Ordering::Acquire) {
219219
return Err(make_err!(
220220
Code::Internal,
221-
"EOF received before sending EOF; sender was probably dropped"
221+
"Sender dropped before sending EOF"
222222
));
223223
}
224224
self.maybe_populate_recent_data(&ZERO_DATA);
@@ -323,14 +323,13 @@ impl DropCloserReadHalf {
323323
if chunk.len() > size {
324324
let remaining = chunk.split_off(size);
325325
self.queued_data.push_front(Ok(remaining));
326-
}
327-
if chunk.len() == size {
326+
// No need to read EOF if we are a partial chunk.
328327
return Ok(chunk);
329328
}
330-
// If we are a partial chunk and our next chunk is EOF, we are done.
329+
// Try to read our EOF to ensure our sender did not error out.
331330
match self.peek().await {
332331
Ok(peeked_chunk) => {
333-
if peeked_chunk.is_empty() {
332+
if peeked_chunk.is_empty() || chunk.len() == size {
334333
return Ok(chunk);
335334
}
336335
}

nativelink-util/tests/buf_channel_test.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use std::task::Poll;
16+
1517
use bytes::{Bytes, BytesMut};
18+
use futures::poll;
1619
use nativelink_error::{make_err, Code, Error, ResultExt};
1720
use nativelink_util::buf_channel::make_buf_channel_pair;
1821
use tokio::try_join;
@@ -67,7 +70,7 @@ mod buf_channel_tests {
6770
}
6871

6972
#[tokio::test]
70-
async fn consume_test() -> Result<(), Error> {
73+
async fn consume_all_test() -> Result<(), Error> {
7174
let (mut tx, mut rx) = make_buf_channel_pair();
7275
let tx_fut = async move {
7376
tx.send(DATA1.into()).await?;
@@ -91,7 +94,7 @@ mod buf_channel_tests {
9194
/// Test to ensure data is optimized so that the exact same pointer is received
9295
/// when calling `collect_all_with_size_hint` when a copy is not needed.
9396
#[tokio::test]
94-
async fn consume_is_optimized_test() -> Result<(), Error> {
97+
async fn consume_all_is_optimized_test() -> Result<(), Error> {
9598
let (mut tx, mut rx) = make_buf_channel_pair();
9699
let sent_data = Bytes::from(DATA1);
97100
let send_data_ptr = sent_data.as_ptr();
@@ -112,7 +115,7 @@ mod buf_channel_tests {
112115
}
113116

114117
#[tokio::test]
115-
async fn take_test() -> Result<(), Error> {
118+
async fn consume_some_test() -> Result<(), Error> {
116119
let (mut tx, mut rx) = make_buf_channel_pair();
117120
let tx_fut = async move {
118121
tx.send(DATA1.into()).await?;
@@ -139,7 +142,7 @@ mod buf_channel_tests {
139142
/// we don't need to concat the data together and instead return a view to
140143
/// the original data instead of making a copy.
141144
#[tokio::test]
142-
async fn take_optimized_test() -> Result<(), Error> {
145+
async fn consume_some_optimized_test() -> Result<(), Error> {
143146
let (mut tx, mut rx) = make_buf_channel_pair();
144147
let first_chunk = Bytes::from(DATA1);
145148
let first_chunk_ptr = first_chunk.as_ptr();
@@ -159,6 +162,23 @@ mod buf_channel_tests {
159162
Ok(())
160163
}
161164

165+
#[tokio::test]
166+
async fn consume_some_reads_eof() -> Result<(), Error> {
167+
let (mut tx, mut rx) = make_buf_channel_pair();
168+
tx.send(DATA1.into()).await?;
169+
170+
let consume_fut = rx.consume(Some(DATA1.len()));
171+
tokio::pin!(consume_fut);
172+
assert_eq!(
173+
poll!(&mut consume_fut),
174+
Poll::Pending,
175+
"Consume should not have completed yet"
176+
);
177+
tx.send_eof()?;
178+
assert_eq!(consume_fut.await?, Bytes::from(DATA1));
179+
Ok(())
180+
}
181+
162182
#[tokio::test]
163183
async fn simple_stream_test() -> Result<(), Error> {
164184
use futures::StreamExt;
@@ -245,7 +265,7 @@ mod buf_channel_tests {
245265
rx.recv().await,
246266
Err(make_err!(
247267
Code::Internal,
248-
"EOF received before sending EOF; sender was probably dropped"
268+
"Sender dropped before sending EOF"
249269
))
250270
);
251271
Result::<(), Error>::Ok(())

0 commit comments

Comments
 (0)