@@ -18,7 +18,9 @@ use std::sync::{Arc, Mutex};
1818
1919use async_trait:: async_trait;
2020use bytes:: Bytes ;
21- use nativelink_config:: stores:: { FastSlowSpec , MemorySpec , NoopSpec , StoreDirection , StoreSpec } ;
21+ use nativelink_config:: stores:: {
22+ EvictionPolicy , FastSlowSpec , MemorySpec , NoopSpec , StoreDirection , StoreSpec ,
23+ } ;
2224use nativelink_error:: { Code , Error , ResultExt , make_err} ;
2325use nativelink_macro:: nativelink_test;
2426use nativelink_metric:: MetricsComponent ;
@@ -32,6 +34,7 @@ use nativelink_util::store_trait::{RemoveItemCallback, Store, StoreDriver, Store
3234use pretty_assertions:: assert_eq;
3335use rand:: rngs:: SmallRng ;
3436use rand:: { Rng , SeedableRng } ;
37+ use tracing:: debug;
3538
3639const MEGABYTE_SZ : usize = 1024 * 1024 ;
3740
@@ -570,3 +573,97 @@ async fn fast_readonly_only_not_updated_on_get() -> Result<(), Error> {
570573 ) ;
571574 Ok ( ( ) )
572575}
576+
577+ #[ ignore]
578+ #[ nativelink_test]
579+ async fn slow_store_safe_eviction ( ) -> Result < ( ) , Error > {
580+ let fast_store_spec = MemorySpec {
581+ eviction_policy : Some ( EvictionPolicy {
582+ max_bytes : 100 ,
583+ ..Default :: default ( )
584+ } ) ,
585+ } ;
586+ let slow_store_spec = MemorySpec {
587+ eviction_policy : Some ( EvictionPolicy {
588+ max_bytes : 101 ,
589+ ..Default :: default ( )
590+ } ) ,
591+ } ;
592+ let fast_store = Store :: new ( MemoryStore :: new ( & fast_store_spec) ) ;
593+ let slow_store = Store :: new ( MemoryStore :: new ( & slow_store_spec) ) ;
594+ let fast_slow_store = Store :: new ( FastSlowStore :: new (
595+ & FastSlowSpec {
596+ fast : StoreSpec :: Memory ( fast_store_spec) ,
597+ slow : StoreSpec :: Memory ( slow_store_spec) ,
598+ fast_direction : StoreDirection :: default ( ) ,
599+ slow_direction : StoreDirection :: default ( ) ,
600+ } ,
601+ fast_store. clone ( ) ,
602+ slow_store. clone ( ) ,
603+ ) ) ;
604+
605+ let data1 = make_random_data ( 100 ) ;
606+ let digest1 = DigestInfo :: try_new ( VALID_HASH , data1. len ( ) ) . unwrap ( ) ;
607+
608+ let data2 = make_random_data ( 10 ) ;
609+ let digest2 = DigestInfo :: try_new ( VALID_HASH , data2. len ( ) ) . unwrap ( ) ;
610+
611+ assert_eq ! (
612+ fast_slow_store
613+ . has( digest1)
614+ . await
615+ . merge( fast_slow_store. has( digest2) . await ) ,
616+ Ok ( None ) ,
617+ "Expected data to not exist in store"
618+ ) ;
619+
620+ debug ! ( "Uploading first data..." ) ;
621+ fast_slow_store
622+ . update_oneshot ( digest1, data1. clone ( ) . into ( ) )
623+ . await ?;
624+
625+ debug ! ( "Uploading second data..." ) ;
626+ fast_slow_store
627+ . update_oneshot ( digest2, data2. clone ( ) . into ( ) )
628+ . await ?;
629+
630+ debug ! ( "Both uploads complete" ) ;
631+
632+ assert_eq ! (
633+ fast_slow_store. has( digest1) . await ,
634+ Ok ( Some ( 100 ) ) ,
635+ "Expected first data to not exist in store, because eviction"
636+ ) ;
637+
638+ let ( tx, mut rx) = make_buf_channel_pair ( ) ;
639+
640+ assert_eq ! (
641+ fast_slow_store. get( digest1, tx) . await ,
642+ Ok ( ( ) ) ,
643+ "Expected first data to not exist in store, because eviction"
644+ ) ;
645+
646+ rx. recv ( ) . await . unwrap ( ) ;
647+ assert_eq ! ( rx. get_bytes_received( ) , 100 ) ;
648+
649+ assert_eq ! (
650+ fast_slow_store. has( digest2) . await ,
651+ Ok ( Some ( 10 ) ) ,
652+ "Expected first data to not exist in store, because eviction"
653+ ) ;
654+
655+ let ( tx, mut rx) = make_buf_channel_pair ( ) ;
656+
657+ assert_eq ! (
658+ fast_slow_store. get( digest2, tx) . await ,
659+ Ok ( ( ) ) ,
660+ "Expected second data to not exist in store, because eviction"
661+ ) ;
662+
663+ rx. recv ( ) . await . unwrap ( ) ;
664+ assert_eq ! ( rx. get_bytes_received( ) , 10 ) ;
665+
666+ assert ! ( false ) ;
667+
668+ Ok ( ( ) )
669+ }
0 commit comments