3030
3131#include " tscore/hugepages.h"
3232#include " tscore/Random.h"
33+ #include " iocore/eventsystem/Tasks.h"
34+
35+ #include < vector>
36+ #include < map>
37+ #include < atomic>
3338
3439#ifdef LOOP_CHECK_MODE
3540#define DIR_LOOP_THRESHOLD 1000
@@ -849,14 +854,51 @@ dir_lookaside_remove(const CacheKey *key, StripeSM *stripe)
849854 return ;
850855}
851856
852- // Cache Sync
853- //
857+ // Cache Dir Sync
858+
859+ static std::vector<std::unique_ptr<CacheSync>> cache_syncs;
854860
855861void
856862dir_sync_init ()
857863{
858- cacheDirSync = new CacheSync;
859- cacheDirSync->trigger = eventProcessor.schedule_in (cacheDirSync, HRTIME_SECONDS (cache_config_dir_sync_frequency));
864+ static std::atomic<bool > initialized{false };
865+ ink_release_assert (!initialized.exchange (true )); // Should only be called once
866+
867+ std::map<CacheDisk *, std::vector<int >> drive_stripe_map;
868+
869+ // Group stripes by disk
870+ for (int i = 0 ; i < gnstripes; i++) {
871+ drive_stripe_map[gstripes[i]->disk ].push_back (i);
872+ }
873+
874+ // Any negative value means "all drives" (maximum parallelism)
875+ int num_tasks = (cache_config_dir_sync_parallel_tasks < 0 ) ?
876+ drive_stripe_map.size () :
877+ std::min (drive_stripe_map.size (), static_cast <size_t >(std::max (1 , cache_config_dir_sync_parallel_tasks)));
878+
879+ cache_syncs.resize (num_tasks);
880+ for (int i = 0 ; i < num_tasks; i++) {
881+ cache_syncs[i] = std::make_unique<CacheSync>();
882+ }
883+
884+ int task_idx = 0 ;
885+
886+ for (auto &[disk, indices] : drive_stripe_map) {
887+ int target_task = task_idx % num_tasks;
888+
889+ Dbg (dbg_ctl_cache_dir_sync, " Disk %s: %zu stripe(s) assigned to task %d" , disk->path , indices.size (), target_task);
890+ for (int stripe_idx : indices) {
891+ cache_syncs[target_task]->stripe_indices .push_back (stripe_idx);
892+ gstripes[stripe_idx]->cache_sync = cache_syncs[target_task].get ();
893+ }
894+ task_idx++;
895+ }
896+
897+ for (int i = 0 ; i < num_tasks; i++) {
898+ cache_syncs[i]->current_index = 0 ;
899+ cache_syncs[i]->trigger =
900+ eventProcessor.schedule_in (cache_syncs[i].get (), HRTIME_SECONDS (cache_config_dir_sync_frequency), ET_TASK);
901+ }
860902}
861903
862904void
@@ -909,6 +951,16 @@ void
909951sync_cache_dir_on_shutdown ()
910952{
911953 Dbg (dbg_ctl_cache_dir_sync, " sync started" );
954+
955+ // Cancel any active async sync tasks first
956+ for (auto &sync : cache_syncs) {
957+ if (sync && sync->trigger ) {
958+ sync->trigger ->cancel_action ();
959+ sync->trigger = nullptr ;
960+ }
961+ }
962+ cache_syncs.clear ();
963+
912964 EThread *t = reinterpret_cast <EThread *>(0xdeadbeef );
913965 for (int i = 0 ; i < gnstripes; i++) {
914966 gstripes[i]->shutdown (t);
@@ -917,34 +969,36 @@ sync_cache_dir_on_shutdown()
917969}
918970
919971int
920- CacheSync::mainEvent (int event, Event *e )
972+ CacheSync::mainEvent (int event, Event * /* e ATS_UNUSED */ )
921973{
922974 if (trigger) {
923975 trigger->cancel_action ();
924976 trigger = nullptr ;
925977 }
926978
927979Lrestart:
928- if (stripe_index >= gnstripes) {
929- stripe_index = 0 ;
980+ if (current_index >= static_cast <int >(stripe_indices.size ())) {
981+ current_index = 0 ;
982+ #if FREE_BUF_BETWEEN_CYCLES
983+ // Free buffer between sync cycles to avoid holding large amounts of memory
984+ // ToDo: If we decide needed, we should add a RecordsConfig here.
930985 if (buf) {
931986 if (buf_huge) {
932987 ats_free_hugepage (buf, buflen);
933988 } else {
934989 ats_free (buf);
935990 }
936- buflen = 0 ;
937991 buf = nullptr ;
992+ buflen = 0 ;
938993 buf_huge = false ;
939994 }
940- Dbg (dbg_ctl_cache_dir_sync, " sync done" );
941- if (event == EVENT_INTERVAL) {
942- trigger = e->ethread ->schedule_in (this , HRTIME_SECONDS (cache_config_dir_sync_frequency));
943- } else {
944- trigger = eventProcessor.schedule_in (this , HRTIME_SECONDS (cache_config_dir_sync_frequency));
945- }
995+ #endif
996+ Dbg (dbg_ctl_cache_dir_sync, " sync cycle done" );
997+ trigger = eventProcessor.schedule_in (this , HRTIME_SECONDS (cache_config_dir_sync_frequency), ET_TASK);
946998 return EVENT_CONT;
947999 }
1000+ stripe_index = stripe_indices[current_index];
1001+ current_index++;
9481002
9491003 StripeSM *stripe = gstripes[stripe_index]; // must be named "vol" to make STAT macros work.
9501004
@@ -1059,9 +1113,7 @@ CacheSync::mainEvent(int event, Event *e)
10591113 return EVENT_CONT;
10601114 }
10611115Ldone:
1062- // done
10631116 writepos = 0 ;
1064- ++stripe_index;
10651117 goto Lrestart;
10661118}
10671119
0 commit comments