@@ -538,6 +538,97 @@ TEST(DurableTransactionLog, CompactPreservesRollbackDecisions) {
538538 EXPECT_EQ (after[0 ].participants [2 ], " b3" );
539539}
540540
541+ // =====================================================================
542+ // Auto-compaction: DistributedTransactionManager fires compact() after
543+ // N successful completions when set_auto_compact_threshold(N) is used.
544+ // =====================================================================
545+
546+ TEST (DurableTxnLogAutoCompactTest, AutoCompactFiresAtThreshold) {
547+ TempLogPath tmp;
548+ DurableTransactionLog log;
549+ ASSERT_TRUE (log.open (tmp.path ));
550+
551+ MockDistributedExecutor mock;
552+ DistributedTransactionManager mgr (mock);
553+ mgr.set_durable_log (&log);
554+ mgr.set_auto_compact_threshold (3 ); // compact after 3 completions
555+
556+ for (int i = 0 ; i < 3 ; ++i) {
557+ ASSERT_TRUE (mgr.begin ());
558+ ASSERT_TRUE (mgr.enlist_backend (" b1" ));
559+ ASSERT_TRUE (mgr.commit ());
560+ }
561+
562+ // After 3 completions, compaction should have fired.
563+ // Verify: in-doubt set is empty (all 3 txns are COMPLETE).
564+ auto in_doubt = DurableTransactionLog::scan_in_doubt (tmp.path );
565+ EXPECT_TRUE (in_doubt.empty ());
566+
567+ struct stat st;
568+ ASSERT_EQ (::stat (tmp.path .c_str (), &st), 0 );
569+ // Compaction leaves only in-doubt entries (none here), so file should be small
570+ EXPECT_LT (st.st_size , 1024 );
571+ }
572+
573+ TEST (DurableTxnLogAutoCompactTest, ThresholdZeroDisablesAutoCompact) {
574+ TempLogPath tmp;
575+ DurableTransactionLog log;
576+ ASSERT_TRUE (log.open (tmp.path ));
577+
578+ MockDistributedExecutor mock;
579+ DistributedTransactionManager mgr (mock);
580+ mgr.set_durable_log (&log);
581+ // Threshold = 0 (default) means auto-compact is disabled.
582+
583+ for (int i = 0 ; i < 5 ; ++i) {
584+ ASSERT_TRUE (mgr.begin ());
585+ ASSERT_TRUE (mgr.enlist_backend (" b1" ));
586+ ASSERT_TRUE (mgr.commit ());
587+ }
588+
589+ // Without compaction, 5 txns x 2 records (DECISION + COMPLETE) each
590+ // should be in the file.
591+ struct stat st;
592+ ASSERT_EQ (::stat (tmp.path .c_str (), &st), 0 );
593+ EXPECT_GT (st.st_size , 100 );
594+ }
595+
596+ TEST (DurableTxnLogAutoCompactTest, CounterResetsAfterCompact) {
597+ TempLogPath tmp;
598+ DurableTransactionLog log;
599+ ASSERT_TRUE (log.open (tmp.path ));
600+
601+ MockDistributedExecutor mock;
602+ DistributedTransactionManager mgr (mock);
603+ mgr.set_durable_log (&log);
604+ mgr.set_auto_compact_threshold (2 );
605+
606+ // First 2 commits -> compact fires
607+ for (int i = 0 ; i < 2 ; ++i) {
608+ ASSERT_TRUE (mgr.begin ());
609+ ASSERT_TRUE (mgr.enlist_backend (" b1" ));
610+ ASSERT_TRUE (mgr.commit ());
611+ }
612+
613+ // 3rd commit: counter has reset, so no compact fires yet
614+ ASSERT_TRUE (mgr.begin ());
615+ ASSERT_TRUE (mgr.enlist_backend (" b1" ));
616+ ASSERT_TRUE (mgr.commit ());
617+
618+ struct stat st1;
619+ ASSERT_EQ (::stat (tmp.path .c_str (), &st1), 0 );
620+ off_t size_after_3 = st1.st_size ;
621+
622+ // 4th commit -> counter hits 2 again, compact fires
623+ ASSERT_TRUE (mgr.begin ());
624+ ASSERT_TRUE (mgr.enlist_backend (" b1" ));
625+ ASSERT_TRUE (mgr.commit ());
626+
627+ struct stat st2;
628+ ASSERT_EQ (::stat (tmp.path .c_str (), &st2), 0 );
629+ EXPECT_LE (st2.st_size , size_after_3);
630+ }
631+
541632// =====================================================================
542633// DistributedTransactionManager integration with the WAL
543634// =====================================================================
0 commit comments