@@ -8693,4 +8693,85 @@ TEST(RecyclerTest, recycle_tablet_with_delete_file_failure) {
86938693 EXPECT_EQ (it->size (), 0 ) << " All recycle rowset keys should be deleted" ;
86948694 }
86958695}
8696+
8697+ TEST (RecyclerTest, enable_recycler_default_true) {
8698+ EXPECT_TRUE (config::enable_recycler);
8699+ }
8700+
8701+ TEST (RecyclerTest, enable_recycler_skip_instance_scanner) {
8702+ auto txn_kv = std::make_shared<MemTxnKv>();
8703+ ASSERT_EQ (txn_kv->init (), 0 );
8704+
8705+ bool old_val = config::enable_recycler;
8706+ config::enable_recycler = false ;
8707+ DORIS_CLOUD_DEFER {
8708+ config::enable_recycler = old_val;
8709+ };
8710+
8711+ int64_t old_recycle_interval = config::recycle_interval_seconds;
8712+ config::recycle_interval_seconds = 0 ;
8713+ DORIS_CLOUD_DEFER {
8714+ config::recycle_interval_seconds = old_recycle_interval;
8715+ };
8716+
8717+ int64_t old_sleep = config::recycler_sleep_before_scheduling_seconds;
8718+ config::recycler_sleep_before_scheduling_seconds = 0 ;
8719+ DORIS_CLOUD_DEFER {
8720+ config::recycler_sleep_before_scheduling_seconds = old_sleep;
8721+ };
8722+
8723+ Recycler recycler (txn_kv);
8724+ std::thread t ([&]() { recycler.instance_scanner_callback (); });
8725+
8726+ // Let the callback complete one iteration:
8727+ // sleep(0) -> check enable_recycler (false, skip) -> wait_for(0, timeout)
8728+ std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
8729+
8730+ recycler.stopped_ = true ;
8731+ recycler.notifier_ .notify_all ();
8732+ t.join ();
8733+
8734+ EXPECT_TRUE (recycler.pending_instance_queue_ .empty ());
8735+ }
8736+
8737+ TEST (RecyclerTest, enable_recycler_skip_recycle_callback) {
8738+ auto txn_kv = std::make_shared<MemTxnKv>();
8739+ ASSERT_EQ (txn_kv->init (), 0 );
8740+
8741+ bool old_val = config::enable_recycler;
8742+ config::enable_recycler = false ;
8743+ DORIS_CLOUD_DEFER {
8744+ config::enable_recycler = old_val;
8745+ };
8746+
8747+ Recycler recycler (txn_kv);
8748+
8749+ InstanceInfoPB instance;
8750+ instance.set_instance_id (" test_instance" );
8751+ recycler.pending_instance_queue_ .push_back (instance);
8752+ recycler.pending_instance_set_ .insert (" test_instance" );
8753+
8754+ std::thread t ([&]() { recycler.recycle_callback (); });
8755+
8756+ // Wait until the callback has popped the instance from the queue.
8757+ // Can not wait on pending_instance_cond_ here because the callback does
8758+ // not notify after popping, which may cause a deadlock: both the main
8759+ // thread and the callback end up waiting on the same CV with different
8760+ // predicates and no one will wake them up.
8761+ while (true ) {
8762+ {
8763+ std::lock_guard lock (recycler.mtx_ );
8764+ if (recycler.pending_instance_queue_ .empty ()) break ;
8765+ }
8766+ std::this_thread::yield ();
8767+ }
8768+
8769+ recycler.stopped_ = true ;
8770+ recycler.pending_instance_cond_ .notify_all ();
8771+ t.join ();
8772+
8773+ EXPECT_TRUE (recycler.pending_instance_queue_ .empty ());
8774+ EXPECT_TRUE (recycler.pending_instance_set_ .empty ());
8775+ EXPECT_TRUE (recycler.recycling_instance_map_ .empty ());
8776+ }
86968777} // namespace doris::cloud
0 commit comments