Skip to content

Commit ab0d4e6

Browse files
GCS do not upload zero (#1995)
We take pains not to attempt to fetch the zero byte digest from the GCS store, so we should avoid uploading it too. The stdout is usually zero bytes and uploading loads of them causes a lot of 429 errors. Add a check for the zero byte digest and error if it's not zero bytes.
1 parent b050976 commit ab0d4e6

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

nativelink-store/src/gcs_store.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,15 @@ where
228228
mut reader: DropCloserReadHalf,
229229
upload_size: UploadSizeInfo,
230230
) -> Result<(), Error> {
231+
if is_zero_digest(digest.borrow()) {
232+
return reader.recv().await.and_then(|should_be_empty| {
233+
should_be_empty
234+
.is_empty()
235+
.then_some(())
236+
.ok_or_else(|| make_err!(Code::Internal, "Zero byte hash not empty"))
237+
});
238+
}
239+
231240
let object_path = self.make_object_path(&digest);
232241

233242
reader.set_max_recent_data_size(

nativelink-store/tests/gcs_store_test.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use mock_instant::thread_local::MockClock;
2121
use nativelink_config::stores::{CommonObjectSpec, ExperimentalGcsSpec};
2222
use nativelink_error::{Code, Error, make_err};
2323
use nativelink_macro::nativelink_test;
24+
use nativelink_store::cas_utils::ZERO_BYTE_DIGESTS;
2425
use nativelink_store::gcs_client::client::GcsOperations;
2526
use nativelink_store::gcs_client::mocks::{MockGcsOperations, MockRequest};
2627
use nativelink_store::gcs_client::types::{DEFAULT_CONTENT_TYPE, ObjectPath};
@@ -230,6 +231,83 @@ async fn simple_update() -> Result<(), Error> {
230231
Ok(())
231232
}
232233

234+
#[nativelink_test]
235+
async fn update_zero_length() -> Result<(), Error> {
236+
// Create mock GCS operations
237+
let mock_ops = Arc::new(MockGcsOperations::new());
238+
let store = create_test_store(mock_ops.clone()).await?;
239+
240+
let digest = ZERO_BYTE_DIGESTS[0];
241+
let store_key: StoreKey = to_store_key(digest);
242+
let (mut tx, rx) = make_buf_channel_pair();
243+
244+
// Start update operation
245+
let store_clone = store.clone();
246+
let update_fut = nativelink_util::spawn!("update_task", async move {
247+
store_clone
248+
.update(store_key, rx, UploadSizeInfo::ExactSize(0))
249+
.await
250+
});
251+
252+
tx.send_eof()?;
253+
update_fut.await??;
254+
255+
// Verify the mock operations were called correctly
256+
let requests = mock_ops.get_requests().await;
257+
let write_requests = requests.iter().filter_map(|req| {
258+
if let MockRequest::Write {
259+
object_path,
260+
content_len,
261+
} = req
262+
{
263+
Some((object_path, content_len))
264+
} else {
265+
None
266+
}
267+
});
268+
269+
assert_eq!(write_requests.count(), 0, "Expected no write request");
270+
271+
Ok(())
272+
}
273+
274+
#[nativelink_test]
275+
async fn update_zero_digest_with_data() -> Result<(), Error> {
276+
const DATA_SIZE: usize = 50;
277+
278+
// Create mock GCS operations
279+
let mock_ops = Arc::new(MockGcsOperations::new());
280+
let store = create_test_store(mock_ops.clone()).await?;
281+
282+
// Create test data
283+
let mut send_data = BytesMut::new();
284+
for i in 0..DATA_SIZE {
285+
send_data.put_u8(u8::try_from((i % 93) + 33).unwrap());
286+
}
287+
let send_data = send_data.freeze();
288+
289+
let digest = ZERO_BYTE_DIGESTS[0];
290+
let store_key: StoreKey = to_store_key(digest);
291+
let (mut tx, rx) = make_buf_channel_pair();
292+
293+
// Start update operation
294+
let store_clone = store.clone();
295+
let update_fut = nativelink_util::spawn!("update_task", async move {
296+
store_clone
297+
.update(store_key, rx, UploadSizeInfo::ExactSize(DATA_SIZE as u64))
298+
.await
299+
});
300+
301+
tx.send(send_data).await?;
302+
tx.send_eof()?;
303+
assert!(
304+
update_fut.await?.is_err(),
305+
"No error for zero byte digest with data"
306+
);
307+
308+
Ok(())
309+
}
310+
233311
#[nativelink_test]
234312
async fn get_part_test() -> Result<(), Error> {
235313
// Create mock GCS operations

0 commit comments

Comments
 (0)