aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/zen/cmds/admin_cmd.cpp17
-rw-r--r--src/zen/cmds/admin_cmd.h2
-rw-r--r--src/zenserver/admin/admin.cpp16
-rw-r--r--src/zenserver/cache/cachedisklayer.cpp29
-rw-r--r--src/zenserver/config.cpp19
-rw-r--r--src/zenserver/config.h2
-rw-r--r--src/zenserver/projectstore/projectstore.cpp18
-rw-r--r--src/zenserver/zenserver.cpp4
-rw-r--r--src/zenstore/compactcas.cpp20
-rw-r--r--src/zenstore/filecas.cpp2
-rw-r--r--src/zenstore/gc.cpp356
-rw-r--r--src/zenstore/include/zenstore/gc.h10
12 files changed, 332 insertions, 163 deletions
diff --git a/src/zen/cmds/admin_cmd.cpp b/src/zen/cmds/admin_cmd.cpp
index b041aa46e..5786ae6c5 100644
--- a/src/zen/cmds/admin_cmd.cpp
+++ b/src/zen/cmds/admin_cmd.cpp
@@ -99,6 +99,15 @@ GcCommand::GcCommand()
.add_option("", "", "usegcv1", "Force use of GC version 1", cxxopts::value(m_ForceUseGCV1)->default_value("false"), "<usegcv2>");
m_Options
.add_option("", "", "usegcv2", "Force use of GC version 2", cxxopts::value(m_ForceUseGCV2)->default_value("false"), "<usegcv2>");
+ m_Options.add_option("",
+ "",
+ "compactblockthreshold",
+ "How much of a compact block should be used to skip compacting the block. 0 - compact only empty eligible blocks, "
+ "100 - compact all non-full eligible blocks.",
+ cxxopts::value(m_CompactBlockThreshold)->default_value("60"),
+ "<compactblockthreshold>");
+ m_Options
+ .add_option("", "", "verbose", "Enable verbose logging for GC", cxxopts::value(m_Verbose)->default_value("false"), "<verbose>");
}
GcCommand::~GcCommand()
@@ -155,6 +164,14 @@ GcCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
Params.Add({"forceusegcv2", "true"});
}
+ if (m_CompactBlockThreshold)
+ {
+ Params.Add({"compactblockthreshold", fmt::format("{}", m_CompactBlockThreshold)});
+ }
+ if (m_Verbose)
+ {
+ Params.Add({"verbose", "true"});
+ }
cpr::Session Session;
Session.SetHeader(cpr::Header{{"Accept", "application/json"}});
diff --git a/src/zen/cmds/admin_cmd.h b/src/zen/cmds/admin_cmd.h
index 1938ad1fa..084c2f654 100644
--- a/src/zen/cmds/admin_cmd.h
+++ b/src/zen/cmds/admin_cmd.h
@@ -45,6 +45,8 @@ private:
uint64_t m_DiskSizeSoftLimit{0};
bool m_ForceUseGCV1{false};
bool m_ForceUseGCV2{false};
+ uint32_t m_CompactBlockThreshold = 90;
+ bool m_Verbose{false};
};
class GcStatusCommand : public StorageCommand
diff --git a/src/zenserver/admin/admin.cpp b/src/zenserver/admin/admin.cpp
index 0b302c36e..f1d9f8d7c 100644
--- a/src/zenserver/admin/admin.cpp
+++ b/src/zenserver/admin/admin.cpp
@@ -219,6 +219,9 @@ HttpAdminService::HttpAdminService(GcScheduler& Scheduler,
Response << "DiskSizeSoftLimit" << NiceBytes(State.Config.DiskSizeSoftLimit);
Response << "MinimumFreeDiskSpaceToAllowWrites" << NiceBytes(State.Config.MinimumFreeDiskSpaceToAllowWrites);
Response << "LightweightInterval" << ToTimeSpan(State.Config.LightweightInterval);
+ Response << "UseGCVersion" << ((State.Config.UseGCVersion == GcVersion::kV1) ? "1" : "2");
+ Response << "CompactBlockUsageThresholdPercent" << State.Config.CompactBlockUsageThresholdPercent;
+ Response << "Verbose" << State.Config.Verbose;
}
Response.EndObject();
Response << "AreDiskWritesBlocked" << State.AreDiskWritesBlocked;
@@ -326,6 +329,19 @@ HttpAdminService::HttpAdminService(GcScheduler& Scheduler,
GcParams.ForceGCVersion = GcVersion::kV2;
}
+ if (auto Param = Params.GetValue("compactblockthreshold"); Param.empty() == false)
+ {
+ if (auto Value = ParseInt<uint32_t>(Param))
+ {
+ GcParams.CompactBlockUsageThresholdPercent = Value.value();
+ }
+ }
+
+ if (auto Param = Params.GetValue("verbose"); Param.empty() == false)
+ {
+ GcParams.Verbose = Param == "true"sv;
+ }
+
const bool Started = m_GcScheduler.TriggerGc(GcParams);
CbObjectWriter Response;
diff --git a/src/zenserver/cache/cachedisklayer.cpp b/src/zenserver/cache/cachedisklayer.cpp
index 32ef420d1..2be32e372 100644
--- a/src/zenserver/cache/cachedisklayer.cpp
+++ b/src/zenserver/cache/cachedisklayer.cpp
@@ -2502,7 +2502,10 @@ public:
if (Ctx.Settings.IsDeleteMode)
{
- ZEN_DEBUG("GCV2: cachebucket [COMPACT] '{}': compacting {} blocks", m_Bucket.m_BucketDir, BlocksToCompact.size());
+ if (Ctx.Settings.Verbose)
+ {
+ ZEN_INFO("GCV2: cachebucket [COMPACT] '{}': compacting {} blocks", m_Bucket.m_BucketDir, BlocksToCompact.size());
+ }
m_Bucket.m_BlockStore.CompactBlocks(
BlockCompactState,
@@ -2539,9 +2542,12 @@ public:
}
else
{
- ZEN_DEBUG("GCV2: cachebucket [COMPACT] '{}': skipped compacting of {} eligible blocks",
- m_Bucket.m_BucketDir,
- BlocksToCompact.size());
+ if (Ctx.Settings.Verbose)
+ {
+ ZEN_INFO("GCV2: cachebucket [COMPACT] '{}': skipped compacting of {} eligible blocks",
+ m_Bucket.m_BucketDir,
+ BlocksToCompact.size());
+ }
}
}
}
@@ -2712,9 +2718,22 @@ public:
}
}
- virtual void RemoveUsedReferencesFromSet(GcCtx&, HashSet& IoCids) override
+ virtual void RemoveUsedReferencesFromSet(GcCtx& Ctx, HashSet& IoCids) override
{
ZEN_ASSERT(m_IndexLock);
+ size_t InitialCount = IoCids.size();
+ Stopwatch Timer;
+ const auto _ = MakeGuard([&] {
+ if (!Ctx.Settings.Verbose)
+ {
+ return;
+ }
+ ZEN_INFO("GCV2: cachebucket [FILTER REFERENCES] '{}': filtered out {} used references out of {} in {}",
+ m_CacheBucket.m_BucketDir,
+ InitialCount - IoCids.size(),
+ InitialCount,
+ NiceTimeSpanMs(Timer.GetElapsedTimeMs()));
+ });
for (const IoHash& ReferenceHash : m_CacheBucket.m_ReferenceHashes)
{
diff --git a/src/zenserver/config.cpp b/src/zenserver/config.cpp
index e33c6ff70..3640abfaf 100644
--- a/src/zenserver/config.cpp
+++ b/src/zenserver/config.cpp
@@ -887,6 +887,10 @@ ParseConfigFile(const std::filesystem::path& Path,
LuaOptions.AddOption("gc.lightweightntervalseconds"sv,
ServerOptions.GcConfig.LightweightIntervalSeconds,
"gc-lightweight-interval-seconds"sv);
+ LuaOptions.AddOption("gc.compactblockthreshold"sv,
+ ServerOptions.GcConfig.CompactBlockUsageThresholdPercent,
+ "gc-compactblock-threshold"sv);
+ LuaOptions.AddOption("gc.verbose"sv, ServerOptions.GcConfig.Verbose, "gc-verbose"sv);
////// gc
LuaOptions.AddOption("gc.cache.maxdurationseconds"sv, ServerOptions.GcConfig.Cache.MaxDurationSeconds, "gc-cache-duration-seconds"sv);
@@ -1317,6 +1321,21 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
cxxopts::value<uint64_t>(ServerOptions.GcConfig.DiskSizeSoftLimit)->default_value("0"),
"");
+ options.add_option("gc",
+ "",
+ "gc-compactblock-threshold",
+ "Garbage collection - how much of a compact block should be used to skip compacting the block. 0 - compact only "
+ "empty eligible blocks, 100 - compact all non-full eligible blocks.",
+ cxxopts::value<uint32_t>(ServerOptions.GcConfig.CompactBlockUsageThresholdPercent)->default_value("60"),
+ "");
+
+ options.add_option("gc",
+ "",
+ "gc-verbose",
+ "Enable verbose logging for GC.",
+ cxxopts::value<bool>(ServerOptions.GcConfig.Verbose)->default_value("false"),
+ "");
+
options.add_option("objectstore",
"",
"objectstore-enabled",
diff --git a/src/zenserver/config.h b/src/zenserver/config.h
index 406fb0b70..c7f6e1e2a 100644
--- a/src/zenserver/config.h
+++ b/src/zenserver/config.h
@@ -72,6 +72,8 @@ struct ZenGcConfig
int32_t LightweightIntervalSeconds = 0;
uint64_t MinimumFreeDiskSpaceToAllowWrites = 1ul << 28;
bool UseGCV2 = false;
+ uint32_t CompactBlockUsageThresholdPercent = 90;
+ bool Verbose = false;
};
struct ZenOpenIdProviderConfig
diff --git a/src/zenserver/projectstore/projectstore.cpp b/src/zenserver/projectstore/projectstore.cpp
index 617104ddc..21aa6b44a 100644
--- a/src/zenserver/projectstore/projectstore.cpp
+++ b/src/zenserver/projectstore/projectstore.cpp
@@ -3341,8 +3341,24 @@ public:
}
}
- virtual void RemoveUsedReferencesFromSet(GcCtx&, HashSet& IoCids) override
+ virtual void RemoveUsedReferencesFromSet(GcCtx& Ctx, HashSet& IoCids) override
{
+ ZEN_ASSERT(m_OplogLock);
+
+ size_t InitialCount = IoCids.size();
+ Stopwatch Timer;
+ const auto _ = MakeGuard([&] {
+ if (!Ctx.Settings.Verbose)
+ {
+ return;
+ }
+ ZEN_INFO("GCV2: projectstore [FILTER REFERENCES] '{}': filtered out {} used references out of {} in {}",
+ m_Oplog.m_BasePath,
+ InitialCount - IoCids.size(),
+ InitialCount,
+ NiceTimeSpanMs(Timer.GetElapsedTimeMs()));
+ });
+
for (const IoHash& ReferenceHash : m_References)
{
IoCids.erase(ReferenceHash);
diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp
index e6724e40a..a50ff1b53 100644
--- a/src/zenserver/zenserver.cpp
+++ b/src/zenserver/zenserver.cpp
@@ -288,7 +288,9 @@ ZenServer::Initialize(const ZenServerOptions& ServerOptions, ZenServerState::Zen
.DiskSizeSoftLimit = ServerOptions.GcConfig.DiskSizeSoftLimit,
.MinimumFreeDiskSpaceToAllowWrites = ServerOptions.GcConfig.MinimumFreeDiskSpaceToAllowWrites,
.LightweightInterval = std::chrono::seconds(ServerOptions.GcConfig.LightweightIntervalSeconds),
- .UseGCVersion = ServerOptions.GcConfig.UseGCV2 ? GcVersion::kV2 : GcVersion::kV1};
+ .UseGCVersion = ServerOptions.GcConfig.UseGCV2 ? GcVersion::kV2 : GcVersion::kV1,
+ .CompactBlockUsageThresholdPercent = ServerOptions.GcConfig.CompactBlockUsageThresholdPercent,
+ .Verbose = ServerOptions.GcConfig.Verbose};
m_GcScheduler.Initialize(GcConfig);
// Create and register admin interface last to make sure all is properly initialized
diff --git a/src/zenstore/compactcas.cpp b/src/zenstore/compactcas.cpp
index 7b8e930b3..1d608be8d 100644
--- a/src/zenstore/compactcas.cpp
+++ b/src/zenstore/compactcas.cpp
@@ -621,9 +621,12 @@ public:
if (Ctx.Settings.IsDeleteMode)
{
- ZEN_DEBUG("GCV2: compactcas [COMPACT] '{}': compacting {} blocks",
- m_CasContainerStrategy.m_RootDirectory / m_CasContainerStrategy.m_ContainerBaseName,
- BlocksToCompact.size());
+ if (Ctx.Settings.Verbose)
+ {
+ ZEN_INFO("GCV2: compactcas [COMPACT] '{}': compacting {} blocks",
+ m_CasContainerStrategy.m_RootDirectory / m_CasContainerStrategy.m_ContainerBaseName,
+ BlocksToCompact.size());
+ }
m_CasContainerStrategy.m_BlockStore.CompactBlocks(
BlockCompactState,
@@ -660,9 +663,12 @@ public:
}
else
{
- ZEN_DEBUG("GCV2: compactcas [COMPACT] '{}': skipped compacting of {} eligible blocks",
- m_CasContainerStrategy.m_RootDirectory / m_CasContainerStrategy.m_ContainerBaseName,
- BlocksToCompact.size());
+ if (Ctx.Settings.Verbose)
+ {
+ ZEN_INFO("GCV2: compactcas [COMPACT] '{}': skipped compacting of {} eligible blocks",
+ m_CasContainerStrategy.m_RootDirectory / m_CasContainerStrategy.m_ContainerBaseName,
+ BlocksToCompact.size());
+ }
}
}
}
@@ -763,7 +769,7 @@ CasContainerStrategy::CreateReferencePruner(GcCtx& Ctx, GcReferenceStoreStats&)
{
return;
}
- ZEN_INFO("GCV2: compactcas [CREATE PRUNERS] '{}' in {}",
+ ZEN_INFO("GCV2: compactcas [CREATE PRUNER] '{}' in {}",
m_RootDirectory / m_ContainerBaseName,
NiceTimeSpanMs(Timer.GetElapsedTimeMs()));
});
diff --git a/src/zenstore/filecas.cpp b/src/zenstore/filecas.cpp
index 6e432bc9d..2623e157d 100644
--- a/src/zenstore/filecas.cpp
+++ b/src/zenstore/filecas.cpp
@@ -1512,7 +1512,7 @@ FileCasStrategy::CreateReferencePruner(GcCtx& Ctx, GcReferenceStoreStats&)
{
return;
}
- ZEN_INFO("GCV2: filecas [CREATE PRUNERS] '{}' in {}", m_RootDirectory, NiceTimeSpanMs(Timer.GetElapsedTimeMs()));
+ ZEN_INFO("GCV2: filecas [CREATE PRUNER] '{}' in {}", m_RootDirectory, NiceTimeSpanMs(Timer.GetElapsedTimeMs()));
});
std::vector<IoHash> CidsToCheck;
{
diff --git a/src/zenstore/gc.cpp b/src/zenstore/gc.cpp
index b78b23350..64958cdea 100644
--- a/src/zenstore/gc.cpp
+++ b/src/zenstore/gc.cpp
@@ -620,27 +620,34 @@ GcManager::CollectGarbage(const GcSettings& Settings)
if (!m_GcReferencers.empty())
{
Latch WorkLeft(1);
- // First remove any cache keys that may own references
- SCOPED_TIMER(Result.RemoveExpiredDataMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- for (size_t Index = 0; Index < m_GcReferencers.size(); Index++)
{
- GcReferencer* Owner = m_GcReferencers[Index];
- std::pair<std::string, GcReferencerStats>& Stats = Result.ReferencerStats[Index];
- WorkLeft.AddCount(1);
- ThreadPool.ScheduleWork([&Ctx, &WorkLeft, Owner, &Stats, &StoreCompactorsLock, &StoreCompactors]() {
- auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
- Stats.first = Owner->GetGcName(Ctx);
- SCOPED_TIMER(Stats.second.RemoveExpiredDataStats.ElapsedMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- std::unique_ptr<GcStoreCompactor> StoreCompactor(Owner->RemoveExpiredData(Ctx, Stats.second.RemoveExpiredDataStats));
- if (StoreCompactor)
- {
- RwLock::ExclusiveLockScope __(StoreCompactorsLock);
- StoreCompactors.insert_or_assign(std::move(StoreCompactor), &Stats.second.CompactStoreStats);
- }
+ // First remove any cache keys that may own references
+ SCOPED_TIMER(Result.RemoveExpiredDataMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()); if (Ctx.Settings.Verbose) {
+ ZEN_INFO("GCV2: Removed epxired data for {} referenceners in {}",
+ m_GcReferencers.size(),
+ NiceTimeSpanMs(Result.RemoveExpiredDataMS.count()));
});
+ for (size_t Index = 0; Index < m_GcReferencers.size(); Index++)
+ {
+ GcReferencer* Owner = m_GcReferencers[Index];
+ std::pair<std::string, GcReferencerStats>& Stats = Result.ReferencerStats[Index];
+ WorkLeft.AddCount(1);
+ ThreadPool.ScheduleWork([&Ctx, &WorkLeft, Owner, &Stats, &StoreCompactorsLock, &StoreCompactors]() {
+ auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
+ Stats.first = Owner->GetGcName(Ctx);
+ SCOPED_TIMER(Stats.second.RemoveExpiredDataStats.ElapsedMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
+ std::unique_ptr<GcStoreCompactor> StoreCompactor(
+ Owner->RemoveExpiredData(Ctx, Stats.second.RemoveExpiredDataStats));
+ if (StoreCompactor)
+ {
+ RwLock::ExclusiveLockScope __(StoreCompactorsLock);
+ StoreCompactors.insert_or_assign(std::move(StoreCompactor), &Stats.second.CompactStoreStats);
+ }
+ });
+ }
+ WorkLeft.CountDown();
+ WorkLeft.Wait();
}
- WorkLeft.CountDown();
- WorkLeft.Wait();
}
if (!Ctx.Settings.SkipCidDelete)
@@ -654,31 +661,42 @@ GcManager::CollectGarbage(const GcSettings& Settings)
ReferencePruners.reserve(m_GcReferenceStores.size());
Latch WorkLeft(1);
RwLock ReferencePrunersLock;
- // CreateReferencePruner is usually not very heavy but big data sets change that
- SCOPED_TIMER(Result.CreateReferencePrunersMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- for (size_t Index = 0; Index < m_GcReferenceStores.size(); Index++)
{
- GcReferenceStore* ReferenceStore = m_GcReferenceStores[Index];
- std::pair<std::string, GcReferenceStoreStats>& Stats = Result.ReferenceStoreStats[Index];
- WorkLeft.AddCount(1);
- ThreadPool.ScheduleWork([&Ctx, ReferenceStore, &Stats, Index, &WorkLeft, &ReferencePrunersLock, &ReferencePruners]() {
- auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
- Stats.first = ReferenceStore->GetGcName(Ctx);
- std::unique_ptr<GcReferencePruner> ReferencePruner;
- {
- SCOPED_TIMER(Stats.second.CreateReferencePrunersMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- // The ReferenceStore will pick a list of CId entries to check, returning a collector
- ReferencePruner = std::unique_ptr<GcReferencePruner>(ReferenceStore->CreateReferencePruner(Ctx, Stats.second));
- }
- if (ReferencePruner)
- {
- RwLock::ExclusiveLockScope __(ReferencePrunersLock);
- ReferencePruners.insert_or_assign(Index, std::move(ReferencePruner));
- }
- });
+ // CreateReferencePruner is usually not very heavy but big data sets change that
+ SCOPED_TIMER(Result.CreateReferencePrunersMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs());
+ if (Ctx.Settings.Verbose) {
+ ZEN_INFO("GCV2: Created {} reference pruners using {} referencer stores in {}",
+ ReferencePruners.size(),
+ m_GcReferenceStores.size(),
+ NiceTimeSpanMs(Result.CreateReferencePrunersMS.count()));
+ });
+ for (size_t Index = 0; Index < m_GcReferenceStores.size(); Index++)
+ {
+ GcReferenceStore* ReferenceStore = m_GcReferenceStores[Index];
+ std::pair<std::string, GcReferenceStoreStats>& Stats = Result.ReferenceStoreStats[Index];
+ WorkLeft.AddCount(1);
+ ThreadPool.ScheduleWork(
+ [&Ctx, ReferenceStore, &Stats, Index, &WorkLeft, &ReferencePrunersLock, &ReferencePruners]() {
+ auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
+ Stats.first = ReferenceStore->GetGcName(Ctx);
+ std::unique_ptr<GcReferencePruner> ReferencePruner;
+ {
+ SCOPED_TIMER(Stats.second.CreateReferencePrunersMS =
+ std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
+ // The ReferenceStore will pick a list of CId entries to check, returning a collector
+ ReferencePruner =
+ std::unique_ptr<GcReferencePruner>(ReferenceStore->CreateReferencePruner(Ctx, Stats.second));
+ }
+ if (ReferencePruner)
+ {
+ RwLock::ExclusiveLockScope __(ReferencePrunersLock);
+ ReferencePruners.insert_or_assign(Index, std::move(ReferencePruner));
+ }
+ });
+ }
+ WorkLeft.CountDown();
+ WorkLeft.Wait();
}
- WorkLeft.CountDown();
- WorkLeft.Wait();
}
if (!ReferencePruners.empty())
@@ -690,47 +708,57 @@ GcManager::CollectGarbage(const GcSettings& Settings)
ReferenceCheckers.reserve(m_GcReferencers.size());
Latch WorkLeft(1);
RwLock ReferenceCheckersLock;
- SCOPED_TIMER(Result.CreateReferenceCheckersMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- // Lock all reference owners from changing the reference data and get access to check for referenced data
- for (size_t Index = 0; Index < m_GcReferencers.size(); Index++)
{
- GcReferencer* Referencer = m_GcReferencers[Index];
- std::pair<std::string, GcReferencerStats>& Stats = Result.ReferencerStats[Index];
- WorkLeft.AddCount(1);
- ThreadPool.ScheduleWork([&Ctx, &WorkLeft, Referencer, Index, &Stats, &ReferenceCheckersLock, &ReferenceCheckers]() {
- auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
- // The Referencer will create a reference checker that guarrantees that the references do not change as long as
- // it lives
- std::vector<GcReferenceChecker*> Checkers;
- {
- SCOPED_TIMER(Stats.second.CreateReferenceCheckersMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- Checkers = Referencer->CreateReferenceCheckers(Ctx);
- }
- try
- {
- if (!Checkers.empty())
- {
- RwLock::ExclusiveLockScope __(ReferenceCheckersLock);
- for (auto& Checker : Checkers)
+ SCOPED_TIMER(Result.CreateReferenceCheckersMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs());
+ if (Ctx.Settings.Verbose) {
+ ZEN_INFO("GCV2: Created {} reference checkers using {} referencers in {}",
+ ReferenceCheckers.size(),
+ m_GcReferencers.size(),
+ NiceTimeSpanMs(Result.CreateReferenceCheckersMS.count()));
+ });
+ // Lock all reference owners from changing the reference data and get access to check for referenced data
+ for (size_t Index = 0; Index < m_GcReferencers.size(); Index++)
+ {
+ GcReferencer* Referencer = m_GcReferencers[Index];
+ std::pair<std::string, GcReferencerStats>& Stats = Result.ReferencerStats[Index];
+ WorkLeft.AddCount(1);
+ ThreadPool.ScheduleWork(
+ [&Ctx, &WorkLeft, Referencer, Index, &Stats, &ReferenceCheckersLock, &ReferenceCheckers]() {
+ auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
+ // The Referencer will create a reference checker that guarrantees that the references do not change as
+ // long as it lives
+ std::vector<GcReferenceChecker*> Checkers;
+ {
+ SCOPED_TIMER(Stats.second.CreateReferenceCheckersMS =
+ std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
+ Checkers = Referencer->CreateReferenceCheckers(Ctx);
+ }
+ try
{
- ReferenceCheckers.insert_or_assign(std::unique_ptr<GcReferenceChecker>(Checker), Index);
- Checker = nullptr;
+ if (!Checkers.empty())
+ {
+ RwLock::ExclusiveLockScope __(ReferenceCheckersLock);
+ for (auto& Checker : Checkers)
+ {
+ ReferenceCheckers.insert_or_assign(std::unique_ptr<GcReferenceChecker>(Checker), Index);
+ Checker = nullptr;
+ }
+ }
}
- }
- }
- catch (std::exception&)
- {
- while (!Checkers.empty())
- {
- delete Checkers.back();
- Checkers.pop_back();
- }
- throw;
- }
- });
+ catch (std::exception&)
+ {
+ while (!Checkers.empty())
+ {
+ delete Checkers.back();
+ Checkers.pop_back();
+ }
+ throw;
+ }
+ });
+ }
+ WorkLeft.CountDown();
+ WorkLeft.Wait();
}
- WorkLeft.CountDown();
- WorkLeft.Wait();
}
ZEN_INFO("GCV2: Locking state for {} reference checkers", ReferenceCheckers.size());
@@ -744,21 +772,28 @@ GcManager::CollectGarbage(const GcSettings& Settings)
// we delete the ReferenceCheckers
Latch WorkLeft(1);
- SCOPED_TIMER(Result.LockStateMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- for (auto& It : ReferenceCheckers)
{
- GcReferenceChecker* Checker = It.first.get();
- size_t Index = It.second;
- std::pair<std::string, GcReferencerStats>& Stats = Result.ReferencerStats[Index];
- WorkLeft.AddCount(1);
- ThreadPool.ScheduleWork([&Ctx, Checker, Index, &Stats, &WorkLeft]() {
- auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
- SCOPED_TIMER(Stats.second.LockStateMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- Checker->LockState(Ctx);
- });
+ SCOPED_TIMER(Result.LockStateMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs());
+ if (Ctx.Settings.Verbose) {
+ ZEN_INFO("GCV2: Locked state using {} reference checkers in {}",
+ ReferenceCheckers.size(),
+ NiceTimeSpanMs(Result.LockStateMS.count()));
+ });
+ for (auto& It : ReferenceCheckers)
+ {
+ GcReferenceChecker* Checker = It.first.get();
+ size_t Index = It.second;
+ std::pair<std::string, GcReferencerStats>& Stats = Result.ReferencerStats[Index];
+ WorkLeft.AddCount(1);
+ ThreadPool.ScheduleWork([&Ctx, Checker, Index, &Stats, &WorkLeft]() {
+ auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
+ SCOPED_TIMER(Stats.second.LockStateMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
+ Checker->LockState(Ctx);
+ });
+ }
+ WorkLeft.CountDown();
+ WorkLeft.Wait();
}
- WorkLeft.CountDown();
- WorkLeft.Wait();
}
ZEN_INFO("GCV2: Removing unreferenced data for {} reference pruners", ReferencePruners.size());
@@ -783,34 +818,43 @@ GcManager::CollectGarbage(const GcSettings& Settings)
Latch WorkLeft(1);
- SCOPED_TIMER(Result.RemoveUnreferencedDataMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- for (auto& It : ReferencePruners)
{
- GcReferencePruner* Pruner = It.second.get();
- size_t Index = It.first;
- GcReferenceStoreStats& Stats = Result.ReferenceStoreStats[Index].second;
- WorkLeft.AddCount(1);
- ThreadPool.ScheduleWork(
- [&Ctx, Pruner, &Stats, &WorkLeft, &GetUnusedReferences, &StoreCompactorsLock, &StoreCompactors]() {
- auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
- // Go through all the ReferenceCheckers to see if the list of Cids the collector selected are referenced
- // or not.
- std::unique_ptr<GcStoreCompactor> StoreCompactor;
- {
- SCOPED_TIMER(Stats.RemoveUnreferencedDataStats.ElapsedMS =
- std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- StoreCompactor = std::unique_ptr<GcStoreCompactor>(
- Pruner->RemoveUnreferencedData(Ctx, Stats.RemoveUnreferencedDataStats, GetUnusedReferences));
- }
- if (StoreCompactor)
- {
- RwLock::ExclusiveLockScope __(StoreCompactorsLock);
- StoreCompactors.insert_or_assign(std::move(StoreCompactor), &Stats.CompactStoreStats);
- }
- });
+ SCOPED_TIMER(Result.RemoveUnreferencedDataMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs());
+ if (Ctx.Settings.Verbose) {
+ ZEN_INFO("GCV2: Removed unused data using {} pruners in {}",
+ ReferencePruners.size(),
+ NiceTimeSpanMs(Result.RemoveUnreferencedDataMS.count()));
+ });
+ for (auto& It : ReferencePruners)
+ {
+ GcReferencePruner* Pruner = It.second.get();
+ size_t Index = It.first;
+ GcReferenceStoreStats& Stats = Result.ReferenceStoreStats[Index].second;
+ WorkLeft.AddCount(1);
+ ThreadPool.ScheduleWork(
+ [&Ctx, Pruner, &Stats, &WorkLeft, &GetUnusedReferences, &StoreCompactorsLock, &StoreCompactors]() {
+ auto _ = MakeGuard([&WorkLeft]() { WorkLeft.CountDown(); });
+ // Go through all the ReferenceCheckers to see if the list of Cids the collector selected are
+ // referenced or not.
+ std::unique_ptr<GcStoreCompactor> StoreCompactor;
+ {
+ SCOPED_TIMER(Stats.RemoveUnreferencedDataStats.ElapsedMS =
+ std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
+ StoreCompactor = std::unique_ptr<GcStoreCompactor>(
+ Pruner->RemoveUnreferencedData(Ctx,
+ Stats.RemoveUnreferencedDataStats,
+ GetUnusedReferences));
+ }
+ if (StoreCompactor)
+ {
+ RwLock::ExclusiveLockScope __(StoreCompactorsLock);
+ StoreCompactors.insert_or_assign(std::move(StoreCompactor), &Stats.CompactStoreStats);
+ }
+ });
+ }
+ WorkLeft.CountDown();
+ WorkLeft.Wait();
}
- WorkLeft.CountDown();
- WorkLeft.Wait();
}
// Let the GcReferencers add new data, we will only change on-disk data at this point, adding new data is allowed
ReferenceCheckers.clear();
@@ -819,7 +863,7 @@ GcManager::CollectGarbage(const GcSettings& Settings)
}
}
- ZEN_INFO("GCV2: Compacting reference stores for {} store compactors", StoreCompactors.size());
+ ZEN_INFO("GCV2: Compacting using {} store compactors", StoreCompactors.size());
if (!StoreCompactors.empty())
{
auto ClaimDiskReserve = [&]() -> uint64_t {
@@ -836,15 +880,19 @@ GcManager::CollectGarbage(const GcSettings& Settings)
};
// Remove the stuff we deemed unreferenced from disk - may be heavy operation
// Don't do in parallel, we don't want to steal CPU/Disk from regular operation
- SCOPED_TIMER(Result.CompactStoresMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- for (auto& It : StoreCompactors)
{
- GcStoreCompactor* Compactor = It.first.get();
- GcCompactStoreStats& Stats = *It.second;
+ SCOPED_TIMER(Result.CompactStoresMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()); if (Ctx.Settings.Verbose) {
+ ZEN_INFO("GCV2: Compacted {} stores in {}", StoreCompactors.size(), NiceTimeSpanMs(Result.CompactStoresMS.count()));
+ });
+ for (auto& It : StoreCompactors)
{
- // Go through all the ReferenceCheckers to see if the list of Cids the collector selected are referenced or not.
- SCOPED_TIMER(Stats.ElapsedMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
- Compactor->CompactStore(Ctx, Stats, ClaimDiskReserve);
+ GcStoreCompactor* Compactor = It.first.get();
+ GcCompactStoreStats& Stats = *It.second;
+ {
+ // Go through all the ReferenceCheckers to see if the list of Cids the collector selected are referenced or not.
+ SCOPED_TIMER(Stats.ElapsedMS = std::chrono::milliseconds(Timer.GetElapsedTimeMs()););
+ Compactor->CompactStore(Ctx, Stats, ClaimDiskReserve);
+ }
}
}
StoreCompactors.clear();
@@ -1445,18 +1493,20 @@ GcScheduler::SchedulerThread()
try
{
- bool DoGc = m_Config.Enabled;
- bool DoScrubbing = false;
- std::chrono::seconds ScrubTimeslice = std::chrono::seconds::max();
- bool DoDelete = true;
- bool CollectSmallObjects = m_Config.CollectSmallObjects;
- std::chrono::seconds GcInterval = m_Config.Interval;
- std::chrono::seconds LightweightGcInterval = m_Config.LightweightInterval;
- std::chrono::seconds MaxCacheDuration = m_Config.MaxCacheDuration;
- std::chrono::seconds MaxProjectStoreDuration = m_Config.MaxProjectStoreDuration;
- uint64_t DiskSizeSoftLimit = m_Config.DiskSizeSoftLimit;
- bool SkipCid = false;
- GcVersion UseGCVersion = m_Config.UseGCVersion;
+ bool DoGc = m_Config.Enabled;
+ bool DoScrubbing = false;
+ std::chrono::seconds ScrubTimeslice = std::chrono::seconds::max();
+ bool DoDelete = true;
+ bool CollectSmallObjects = m_Config.CollectSmallObjects;
+ std::chrono::seconds GcInterval = m_Config.Interval;
+ std::chrono::seconds LightweightGcInterval = m_Config.LightweightInterval;
+ std::chrono::seconds MaxCacheDuration = m_Config.MaxCacheDuration;
+ std::chrono::seconds MaxProjectStoreDuration = m_Config.MaxProjectStoreDuration;
+ uint64_t DiskSizeSoftLimit = m_Config.DiskSizeSoftLimit;
+ bool SkipCid = false;
+ GcVersion UseGCVersion = m_Config.UseGCVersion;
+ uint32_t CompactBlockUsageThresholdPercent = m_Config.CompactBlockUsageThresholdPercent;
+ bool Verbose = m_Config.Verbose;
bool DiskSpaceGCTriggered = false;
bool TimeBasedGCTriggered = false;
@@ -1491,7 +1541,10 @@ GcScheduler::SchedulerThread()
DoDelete = false;
}
UseGCVersion = TriggerParams.ForceGCVersion.value_or(UseGCVersion);
- DoGc = true;
+ CompactBlockUsageThresholdPercent =
+ TriggerParams.CompactBlockUsageThresholdPercent.value_or(CompactBlockUsageThresholdPercent);
+ Verbose = TriggerParams.Verbose.value_or(Verbose);
+ DoGc = true;
}
if (m_TriggerScrubParams)
@@ -1696,7 +1749,14 @@ GcScheduler::SchedulerThread()
}
}
- CollectGarbage(CacheExpireTime, ProjectStoreExpireTime, DoDelete, CollectSmallObjects, SkipCid, UseGCVersion);
+ CollectGarbage(CacheExpireTime,
+ ProjectStoreExpireTime,
+ DoDelete,
+ CollectSmallObjects,
+ SkipCid,
+ UseGCVersion,
+ CompactBlockUsageThresholdPercent,
+ Verbose);
uint32_t RunningState = static_cast<uint32_t>(GcSchedulerStatus::kRunning);
if (!m_Status.compare_exchange_strong(RunningState, static_cast<uint32_t>(GcSchedulerStatus::kIdle)))
@@ -1778,7 +1838,9 @@ GcScheduler::CollectGarbage(const GcClock::TimePoint& CacheExpireTime,
bool Delete,
bool CollectSmallObjects,
bool SkipCid,
- GcVersion UseGCVersion)
+ GcVersion UseGCVersion,
+ uint32_t CompactBlockUsageThresholdPercent,
+ bool Verbose)
{
ZEN_TRACE_CPU("GcScheduler::CollectGarbage");
@@ -1841,12 +1903,14 @@ GcScheduler::CollectGarbage(const GcClock::TimePoint& CacheExpireTime,
break;
case GcVersion::kV2:
{
- const GcSettings Settings = {.CacheExpireTime = CacheExpireTime,
- .ProjectStoreExpireTime = ProjectStoreExpireTime,
- .CollectSmallObjects = CollectSmallObjects,
- .IsDeleteMode = Delete,
- .SkipCidDelete = SkipCid,
- .DiskReservePath = m_Config.RootDirectory / "reserve.gc"};
+ const GcSettings Settings = {.CacheExpireTime = CacheExpireTime,
+ .ProjectStoreExpireTime = ProjectStoreExpireTime,
+ .CollectSmallObjects = CollectSmallObjects,
+ .IsDeleteMode = Delete,
+ .SkipCidDelete = SkipCid,
+ .Verbose = Verbose,
+ .CompactBlockUsageThresholdPercent = CompactBlockUsageThresholdPercent,
+ .DiskReservePath = m_Config.RootDirectory / "reserve.gc"};
GcClock::TimePoint GcStartTime = GcClock::Now();
GcResult Result = m_GcManager.CollectGarbage(Settings);
diff --git a/src/zenstore/include/zenstore/gc.h b/src/zenstore/include/zenstore/gc.h
index 4cd01bc2c..f50af8006 100644
--- a/src/zenstore/include/zenstore/gc.h
+++ b/src/zenstore/include/zenstore/gc.h
@@ -397,7 +397,9 @@ struct GcSchedulerConfig
uint64_t DiskSizeSoftLimit = 0;
uint64_t MinimumFreeDiskSpaceToAllowWrites = 1ul << 28;
std::chrono::seconds LightweightInterval{};
- GcVersion UseGCVersion = GcVersion::kV1;
+ GcVersion UseGCVersion = GcVersion::kV1;
+ uint32_t CompactBlockUsageThresholdPercent = 90;
+ bool Verbose = false;
};
struct GcSchedulerState
@@ -469,6 +471,8 @@ public:
bool SkipCid = false;
bool SkipDelete = false;
std::optional<GcVersion> ForceGCVersion;
+ std::optional<uint32_t> CompactBlockUsageThresholdPercent;
+ std::optional<bool> Verbose;
};
bool TriggerGc(const TriggerGcParams& Params);
@@ -488,7 +492,9 @@ private:
bool Delete,
bool CollectSmallObjects,
bool SkipCid,
- GcVersion UseGCVersion);
+ GcVersion UseGCVersion,
+ uint32_t CompactBlockUsageThresholdPercent,
+ bool Verbose);
void ScrubStorage(bool DoDelete, std::chrono::seconds TimeSlice);
LoggerRef Log() { return m_Log; }
virtual bool AreDiskWritesAllowed() const override { return !m_AreDiskWritesBlocked.load(); }