@@ -396,7 +396,7 @@ impl StoreDriver for FastSlowStore {
396396 return self . slow_store . update ( key, reader, size_info) . await ;
397397 }
398398
399- let ( mut fast_tx, fast_rx) = make_buf_channel_pair ( ) ;
399+ let ( fast_tx, fast_rx) = make_buf_channel_pair ( ) ;
400400 let ( mut slow_tx, slow_rx) = make_buf_channel_pair ( ) ;
401401
402402 let key_debug = format ! ( "{key:?}" ) ;
@@ -408,16 +408,17 @@ impl StoreDriver for FastSlowStore {
408408 let mut bytes_sent: u64 = 0 ;
409409
410410 let data_stream_fut = async move {
411+ let mut fast_tx = Some ( fast_tx) ;
411412 loop {
412413 let buffer = reader
413414 . recv ( )
414415 . await
415416 . err_tip ( || "Failed to read buffer in fastslow store" ) ?;
416417 if buffer. is_empty ( ) {
417418 // EOF received.
418- fast_tx . send_eof ( ) . err_tip (
419- || "Failed to write eof to fast store in fast_slow store update" ,
420- ) ? ;
419+ if let Some ( mut ftx ) = fast_tx . take ( ) {
420+ drop ( ftx . send_eof ( ) ) ;
421+ }
421422 slow_tx
422423 . send_eof ( )
423424 . err_tip ( || "Failed to write eof to writer in fast_slow store update" ) ?;
@@ -429,34 +430,43 @@ impl StoreDriver for FastSlowStore {
429430 }
430431
431432 let chunk_len = buffer. len ( ) ;
432- let send_start = std:: time:: Instant :: now ( ) ;
433- let ( fast_result, slow_result) =
434- join ! ( fast_tx. send( buffer. clone( ) ) , slow_tx. send( buffer) ) ;
435- let send_elapsed = send_start. elapsed ( ) ;
436- if send_elapsed. as_secs ( ) >= 5 {
437- warn ! (
438- chunk_len,
439- send_elapsed_ms = send_elapsed. as_millis( ) ,
440- total_bytes = bytes_sent,
441- "FastSlowStore::update: channel send stalled (>5s). A downstream store may be hanging" ,
442- ) ;
443- }
444- bytes_sent += u64:: try_from ( chunk_len) . unwrap_or ( u64:: MAX ) ;
445- fast_result
446- . map_err ( |e| {
433+ if let Some ( ref mut ftx) = fast_tx {
434+ let send_start = std:: time:: Instant :: now ( ) ;
435+ let ( fast_result, slow_result) =
436+ join ! ( ftx. send( buffer. clone( ) ) , slow_tx. send( buffer) ) ;
437+ let send_elapsed = send_start. elapsed ( ) ;
438+ if send_elapsed. as_secs ( ) >= 5 {
439+ warn ! (
440+ chunk_len,
441+ send_elapsed_ms = send_elapsed. as_millis( ) ,
442+ total_bytes = bytes_sent,
443+ "FastSlowStore::update: channel send stalled (>5s). A downstream store may be hanging" ,
444+ ) ;
445+ }
446+ if fast_result. is_err ( ) {
447+ warn ! (
448+ total_bytes = bytes_sent,
449+ "FastSlowStore::update: fast store channel failed, continuing with slow store only" ,
450+ ) ;
451+ fast_tx = None ;
452+ }
453+ slow_result. map_err ( |e| {
447454 make_err ! (
448455 Code :: Internal ,
449- "Failed to send message to fast_store in fast_slow_store {:?}" ,
456+ "Failed to send message to slow_store in fast_slow store {:?}" ,
450457 e
451458 )
452- } )
453- . merge ( slow_result. map_err ( |e| {
459+ } ) ?;
460+ } else {
461+ slow_tx. send ( buffer) . await . map_err ( |e| {
454462 make_err ! (
455463 Code :: Internal ,
456464 "Failed to send message to slow_store in fast_slow store {:?}" ,
457465 e
458466 )
459- } ) ) ?;
467+ } ) ?;
468+ }
469+ bytes_sent += u64:: try_from ( chunk_len) . unwrap_or ( u64:: MAX ) ;
460470 }
461471 } ;
462472
@@ -483,7 +493,15 @@ impl StoreDriver for FastSlowStore {
483493 "FastSlowStore::update: completed successfully" ,
484494 ) ;
485495 }
486- data_stream_res. merge ( fast_res) . merge ( slow_res) ?;
496+ // Slow store success is required; fast store failure is tolerated since it's a cache.
497+ data_stream_res. merge ( slow_res) ?;
498+ if let Err ( err) = fast_res {
499+ warn ! (
500+ ?err,
501+ key = %key_debug,
502+ "FastSlowStore::update: fast store failed during upload; data stored in slow store" ,
503+ ) ;
504+ }
487505 Ok ( ( ) )
488506 }
489507
@@ -591,16 +609,23 @@ impl StoreDriver for FastSlowStore {
591609 // TODO(palfrey) Investigate if we should maybe ignore errors here instead of
592610 // forwarding them up.
593611 if self . fast_store . has ( key. borrow ( ) ) . await ?. is_some ( ) {
594- self . metrics
595- . fast_store_hit_count
596- . fetch_add ( 1 , Ordering :: Acquire ) ;
597- self . fast_store
598- . get_part ( key, writer. borrow_mut ( ) , offset, length)
599- . await ?;
600- self . metrics
601- . fast_store_downloaded_bytes
602- . fetch_add ( writer. get_bytes_written ( ) , Ordering :: Acquire ) ;
603- return Ok ( ( ) ) ;
612+ match self
613+ . fast_store
614+ . get_part ( key. borrow ( ) , writer. borrow_mut ( ) , offset, length)
615+ . await
616+ {
617+ Ok ( ( ) ) => {
618+ self . metrics
619+ . fast_store_hit_count
620+ . fetch_add ( 1 , Ordering :: Acquire ) ;
621+ self . metrics
622+ . fast_store_downloaded_bytes
623+ . fetch_add ( writer. get_bytes_written ( ) , Ordering :: Acquire ) ;
624+ return Ok ( ( ) ) ;
625+ }
626+ Err ( err) if err. code == Code :: NotFound => { }
627+ Err ( err) => return Err ( err) ,
628+ }
604629 }
605630
606631 // If the fast store is noop or read only or update only then bypass it.
0 commit comments