From c1618e86feb3c4fbeee13dcaa3995b081bc123fa Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Wed, 18 Mar 2026 14:39:06 -0600 Subject: [PATCH 1/2] Parallelize dir-sync on graceful shutdowns This will make normal ATS shutdowns come down quicker, specially on boxes with a lot of drives. This is similar to the new parallel sync options under normal operations, except this will always Parallelize as much as needed. --- src/iocore/cache/CacheDir.cc | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/iocore/cache/CacheDir.cc b/src/iocore/cache/CacheDir.cc index 413d11c6219..fec7b6d48cf 100644 --- a/src/iocore/cache/CacheDir.cc +++ b/src/iocore/cache/CacheDir.cc @@ -33,6 +33,7 @@ #include "ts/ats_probe.h" #include "iocore/eventsystem/Tasks.h" +#include #include #ifdef LOOP_CHECK_MODE @@ -958,20 +959,42 @@ Directory::entries_used() } /* - * this function flushes the cache meta data to disk when + * This function flushes the cache meta data to disk when * the cache is shutdown. Must *NOT* be used during regular - * operation. + * operation. Stripes are synced in parallel, one thread per + * physical disk. */ void sync_cache_dir_on_shutdown() { - Dbg(dbg_ctl_cache_dir_sync, "sync started"); - EThread *t = reinterpret_cast(0xdeadbeef); + Dbg(dbg_ctl_cache_dir_sync, "shutdown sync started"); + + std::unordered_map> drive_stripe_map; + for (int i = 0; i < gnstripes; i++) { - gstripes[i]->shutdown(t); + drive_stripe_map[gstripes[i]->disk].push_back(i); } - Dbg(dbg_ctl_cache_dir_sync, "sync done"); + + std::vector threads; + + threads.reserve(drive_stripe_map.size()); + for (auto &[disk, indices] : drive_stripe_map) { + Dbg(dbg_ctl_cache_dir_sync, "Disk %s: syncing %zu stripe(s)", disk->path, indices.size()); + threads.emplace_back([&indices]() { + EThread *t = reinterpret_cast(0xdeadbeef); + + for (int idx : indices) { + gstripes[idx]->shutdown(t); + } + }); + } + + for (auto &thr : threads) { + thr.join(); + } + + Dbg(dbg_ctl_cache_dir_sync, "shutdown sync done"); } int From 3cfb438b971bdd27630761faa10d7a226352f78e Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Wed, 18 Mar 2026 15:32:26 -0600 Subject: [PATCH 2/2] Address Copilot's review comments Fix lambda reference capture bug where all threads processed the last disk's stripes instead of their own; fix shared 0xdeadbeef EThread* sentinel by using a thread_local variable to give each OS thread a unique identity for MUTEX_TAKE_LOCK. --- src/iocore/cache/CacheDir.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/iocore/cache/CacheDir.cc b/src/iocore/cache/CacheDir.cc index fec7b6d48cf..efdd155cfd6 100644 --- a/src/iocore/cache/CacheDir.cc +++ b/src/iocore/cache/CacheDir.cc @@ -981,10 +981,13 @@ sync_cache_dir_on_shutdown() threads.reserve(drive_stripe_map.size()); for (auto &[disk, indices] : drive_stripe_map) { Dbg(dbg_ctl_cache_dir_sync, "Disk %s: syncing %zu stripe(s)", disk->path, indices.size()); - threads.emplace_back([&indices]() { - EThread *t = reinterpret_cast(0xdeadbeef); + auto stripe_indices = indices; + threads.emplace_back([stripe_indices]() { + // Use a thread_local variable to give each OS thread a unique EThread* sentinel instead of 0xdeadbeef. + thread_local char thread_sentinel; + EThread *t = reinterpret_cast(&thread_sentinel); - for (int idx : indices) { + for (int idx : stripe_indices) { gstripes[idx]->shutdown(t); } });