diff options
| author | Dan Engelbrecht <[email protected]> | 2023-05-16 12:23:42 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-05-16 12:23:42 +0200 |
| commit | a4ff07d68eeae66c008bfac28cb87c94a92cf257 (patch) | |
| tree | 630940f228c35d29fac31ced2ba7f9fd16fca1c8 | |
| parent | Added CHANGELOG.md descriptions for recent changes (diff) | |
| download | zen-a4ff07d68eeae66c008bfac28cb87c94a92cf257.tar.xz zen-a4ff07d68eeae66c008bfac28cb87c94a92cf257.zip | |
Add `--gc-projectstore-duration-seconds` option (#281)
* Add `--gc-projectstore-duration-seconds` option
* Cleanup lua gc options parsing
* Remove dead configuration values
* changelog
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | src/zenserver/admin/admin.cpp | 8 | ||||
| -rw-r--r-- | src/zenserver/cache/structuredcachestore.cpp | 18 | ||||
| -rw-r--r-- | src/zenserver/config.cpp | 22 | ||||
| -rw-r--r-- | src/zenserver/config.h | 32 | ||||
| -rw-r--r-- | src/zenserver/projectstore/projectstore.cpp | 24 | ||||
| -rw-r--r-- | src/zenserver/zenserver.cpp | 5 | ||||
| -rw-r--r-- | src/zenstore/compactcas.cpp | 29 | ||||
| -rw-r--r-- | src/zenstore/filecas.cpp | 4 | ||||
| -rw-r--r-- | src/zenstore/gc.cpp | 77 | ||||
| -rw-r--r-- | src/zenstore/include/zenstore/gc.h | 18 |
11 files changed, 141 insertions, 97 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 25885462b..8dabdaee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ## +- Feature: zenserver: Add command line option `--gc-projectstore-duration-seconds` to control GC life time of project store data - Bugfix: Improve error handling when processing requests in http asio - Bugfix: Error out if `test` is passed to zenserver in release builds (tests are only compiled in for debug) - Improvement: Added logging when bad chunks are detected in `BlockStore` diff --git a/src/zenserver/admin/admin.cpp b/src/zenserver/admin/admin.cpp index 3a93c9aec..c37622cb6 100644 --- a/src/zenserver/admin/admin.cpp +++ b/src/zenserver/admin/admin.cpp @@ -54,6 +54,14 @@ HttpAdminService::HttpAdminService(GcScheduler& Scheduler) : m_GcScheduler(Sched } } + if (auto Param = Params.GetValue("maxprojectstoreduration"); Param.empty() == false) + { + if (auto Value = ParseInt<uint64_t>(Param)) + { + GcParams.MaxProjectStoreDuration = std::chrono::seconds(Value.value()); + } + } + if (auto Param = Params.GetValue("disksizesoftlimit"); Param.empty() == false) { if (auto Value = ParseInt<uint64_t>(Param)) diff --git a/src/zenserver/cache/structuredcachestore.cpp b/src/zenserver/cache/structuredcachestore.cpp index d56b3cfe2..3a6e5cbc3 100644 --- a/src/zenserver/cache/structuredcachestore.cpp +++ b/src/zenserver/cache/structuredcachestore.cpp @@ -1006,7 +1006,7 @@ ZenCacheDiskLayer::CacheBucket::OpenLog(const bool IsNew) { LogEntryCount = ReadLog(LogPath, m_LogFlushPosition); } - else + else if (fs::is_regular_file(LogPath)) { ZEN_WARN("removing invalid cas log at '{}'", LogPath); std::filesystem::remove(LogPath); @@ -1512,7 +1512,7 @@ ZenCacheDiskLayer::CacheBucket::GatherReferences(GcContext& GcCtx) NiceLatencyNs(ReadBlockLongestTimeUs)); }); - const GcClock::TimePoint ExpireTime = GcCtx.ExpireTime(); + const GcClock::TimePoint ExpireTime = GcCtx.CacheExpireTime(); const GcClock::Tick ExpireTicks = ExpireTime.time_since_epoch().count(); @@ -2976,7 +2976,7 @@ TEST_CASE("z$.gc") GcClock::Duration MaxDuration, std::span<const IoHash> Cids, std::vector<IoHash>& OutKeep) { - GcContext GcCtx(Time - MaxDuration); + GcContext GcCtx(Time - MaxDuration, Time - MaxDuration); Gc.CollectGarbage(GcCtx); OutKeep.clear(); GcCtx.FilterCids(Cids, [&OutKeep](const IoHash& Hash) { OutKeep.push_back(Hash); }); @@ -3055,7 +3055,7 @@ TEST_CASE("z$.gc") } { - GcContext GcCtx(CurrentTime - std::chrono::hours(46)); + GcContext GcCtx(CurrentTime - std::chrono::hours(46), CurrentTime - std::chrono::hours(46)); Gc.CollectGarbage(GcCtx); @@ -3069,7 +3069,7 @@ TEST_CASE("z$.gc") // Move forward in time and collect again { - GcContext GcCtx(CurrentTime + std::chrono::minutes(2)); + GcContext GcCtx(CurrentTime + std::chrono::minutes(2), CurrentTime + std::chrono::minutes(2)); Gc.CollectGarbage(GcCtx); for (const auto& Key : Keys) @@ -3099,7 +3099,7 @@ TEST_CASE("z$.gc") } { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(2)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(2), GcClock::Now() - std::chrono::hours(2)); GcCtx.CollectSmallObjects(true); Gc.CollectGarbage(GcCtx); @@ -3114,7 +3114,7 @@ TEST_CASE("z$.gc") // Move forward in time and collect again { - GcContext GcCtx(GcClock::Now() + std::chrono::minutes(2)); + GcContext GcCtx(GcClock::Now() + std::chrono::minutes(2), GcClock::Now() + std::chrono::minutes(2)); GcCtx.CollectSmallObjects(true); Zcs.Flush(); @@ -3303,7 +3303,7 @@ TEST_CASE("z$.threadedinsert") // * doctest::skip(true)) C++; } - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); GcCtx.AddRetainedCids(KeepHashes); Zcs.CollectGarbage(GcCtx); @@ -3351,7 +3351,7 @@ TEST_CASE("z$.threadedinsert") // * doctest::skip(true)) C++; } - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); GcCtx.AddRetainedCids(KeepHashes); Zcs.CollectGarbage(GcCtx); diff --git a/src/zenserver/config.cpp b/src/zenserver/config.cpp index 5b635b89d..0e7aac079 100644 --- a/src/zenserver/config.cpp +++ b/src/zenserver/config.cpp @@ -506,6 +506,13 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions) options.add_option("gc", "", + "gc-projectstore-duration-seconds", + "Max duration in seconds before project store entries get evicted. Default set to 1209600 (2 weeks)", + cxxopts::value<int32_t>(ServerOptions.GcConfig.ProjectStore.MaxDurationSeconds)->default_value("1209600"), + ""); + + options.add_option("gc", + "", "disk-reserve-size", "Size of gc disk reserve in bytes. Default set to 268435456 (256 Mb). Set to zero to disable.", cxxopts::value<uint64_t>(ServerOptions.GcConfig.DiskReserveSize)->default_value("268435456"), @@ -522,14 +529,14 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions) "", "gc-low-diskspace-threshold", "Minimum free space on disk to allow writes to disk. Default set to 268435456 (256 Mb). Set to zero to disable.", - cxxopts::value<uint64_t>(ServerOptions.GcConfig.Cache.MinimumFreeDiskSpaceToAllowWrites)->default_value("268435456"), + cxxopts::value<uint64_t>(ServerOptions.GcConfig.MinimumFreeDiskSpaceToAllowWrites)->default_value("268435456"), ""); options.add_option("gc", "", "gc-disksize-softlimit", "Garbage collection disk usage soft limit. Default set to 0 (Off).", - cxxopts::value<uint64_t>(ServerOptions.GcConfig.Cache.DiskSizeSoftLimit)->default_value("0"), + cxxopts::value<uint64_t>(ServerOptions.GcConfig.DiskSizeSoftLimit)->default_value("0"), ""); options.add_option("objectstore", @@ -878,21 +885,16 @@ ParseConfigFile(const std::filesystem::path& Path, ZenServerOptions& ServerOptio ServerOptions.GcConfig.MonitorIntervalSeconds = GcConfig.value().get_or("monitorintervalseconds", 30); ServerOptions.GcConfig.IntervalSeconds = GcConfig.value().get_or("intervalseconds", 0); ServerOptions.GcConfig.DiskReserveSize = GcConfig.value().get_or("diskreservesize", uint64_t(1u << 28)); + ServerOptions.GcConfig.DiskSizeSoftLimit = GcConfig.value().get_or("disksizesoftlimit", 0); ServerOptions.GcConfig.MinimumFreeDiskSpaceToAllowWrites = GcConfig.value().get_or("lowdiskspacethreshold", 0); if (sol::optional<sol::table> CacheGcConfig = GcConfig.value()["cache"]) { ServerOptions.GcConfig.Cache.MaxDurationSeconds = CacheGcConfig.value().get_or("maxdurationseconds", int32_t(0)); - ServerOptions.GcConfig.Cache.DiskSizeLimit = CacheGcConfig.value().get_or("disksizelimit", ~uint64_t(0)); - ServerOptions.GcConfig.Cache.MemorySizeLimit = CacheGcConfig.value().get_or("memorysizelimit", ~uint64_t(0)); - ServerOptions.GcConfig.Cache.DiskSizeSoftLimit = CacheGcConfig.value().get_or("disksizesoftlimit", 0); } - - if (sol::optional<sol::table> CasGcConfig = GcConfig.value()["cas"]) + if (sol::optional<sol::table> CacheGcConfig = GcConfig.value()["projectstore"]) { - ServerOptions.GcConfig.Cas.LargeStrategySizeLimit = CasGcConfig.value().get_or("largestrategysizelimit", ~uint64_t(0)); - ServerOptions.GcConfig.Cas.SmallStrategySizeLimit = CasGcConfig.value().get_or("smallstrategysizelimit", ~uint64_t(0)); - ServerOptions.GcConfig.Cas.TinyStrategySizeLimit = CasGcConfig.value().get_or("tinystrategysizelimit", ~uint64_t(0)); + ServerOptions.GcConfig.ProjectStore.MaxDurationSeconds = CacheGcConfig.value().get_or("maxdurationseconds", int32_t(0)); } } diff --git a/src/zenserver/config.h b/src/zenserver/config.h index caf4adce7..4f63e2644 100644 --- a/src/zenserver/config.h +++ b/src/zenserver/config.h @@ -69,32 +69,26 @@ struct ZenUpstreamCacheConfig struct ZenCacheEvictionPolicy { - uint64_t DiskSizeLimit = ~uint64_t(0); - uint64_t MemorySizeLimit = 1024 * 1024 * 1024; - int32_t MaxDurationSeconds = 24 * 60 * 60; - uint64_t DiskSizeSoftLimit = 0; - uint64_t MinimumFreeDiskSpaceToAllowWrites = 256u * 1024u * 1024u; - bool Enabled = true; + int32_t MaxDurationSeconds = 24 * 60 * 60; }; -struct ZenCasEvictionPolicy +struct ZenProjectStoreEvictionPolicy { - uint64_t LargeStrategySizeLimit = ~uint64_t(0); - uint64_t SmallStrategySizeLimit = ~uint64_t(0); - uint64_t TinyStrategySizeLimit = ~uint64_t(0); - bool Enabled = true; + int32_t MaxDurationSeconds = 7 * 24 * 60 * 60; }; struct ZenGcConfig { - ZenCasEvictionPolicy Cas; - ZenCacheEvictionPolicy Cache; - int32_t MonitorIntervalSeconds = 30; - int32_t IntervalSeconds = 0; - bool CollectSmallObjects = true; - bool Enabled = true; - uint64_t DiskReserveSize = 1ul << 28; - uint64_t MinimumFreeDiskSpaceToAllowWrites = 1ul << 28; + // ZenCasEvictionPolicy Cas; + ZenCacheEvictionPolicy Cache; + ZenProjectStoreEvictionPolicy ProjectStore; + int32_t MonitorIntervalSeconds = 30; + int32_t IntervalSeconds = 0; + bool CollectSmallObjects = true; + bool Enabled = true; + uint64_t DiskReserveSize = 1ul << 28; + uint64_t DiskSizeSoftLimit = 0; + uint64_t MinimumFreeDiskSpaceToAllowWrites = 1ul << 28; }; struct ZenOpenIdProviderConfig diff --git a/src/zenserver/projectstore/projectstore.cpp b/src/zenserver/projectstore/projectstore.cpp index 03c1e8927..0beb207ae 100644 --- a/src/zenserver/projectstore/projectstore.cpp +++ b/src/zenserver/projectstore/projectstore.cpp @@ -1581,7 +1581,7 @@ ProjectStore::Project::GatherReferences(GcContext& GcCtx) } IterateOplogs([&](Oplog& Ops) { - if (!IsExpired(GcCtx.ExpireTime(), Ops)) + if (!IsExpired(GcCtx.ProjectStoreExpireTime(), Ops)) { Ops.GatherReferences(GcCtx); } @@ -1804,7 +1804,7 @@ ProjectStore::GatherReferences(GcContext& GcCtx) for (auto& Kv : m_Projects) { - if (Kv.second->IsExpired(GcCtx.ExpireTime())) + if (Kv.second->IsExpired(GcCtx.ProjectStoreExpireTime())) { ExpiredProjectCount++; continue; @@ -1842,7 +1842,7 @@ ProjectStore::CollectGarbage(GcContext& GcCtx) RwLock::SharedLockScope _(m_ProjectsLock); for (auto& Kv : m_Projects) { - if (Kv.second->IsExpired(GcCtx.ExpireTime())) + if (Kv.second->IsExpired(GcCtx.ProjectStoreExpireTime())) { ExpiredProjects.push_back(Kv.second); ExpiredProjectCount++; @@ -1865,7 +1865,7 @@ ProjectStore::CollectGarbage(GcContext& GcCtx) { RwLock::ExclusiveLockScope _(m_ProjectsLock); Project->IterateOplogs([&GcCtx, &Project, &ExpiredOplogs](ProjectStore::Oplog& Oplog) { - if (Project->IsExpired(GcCtx.ExpireTime(), Oplog)) + if (Project->IsExpired(GcCtx.ProjectStoreExpireTime(), Oplog)) { ExpiredOplogs.push_back(Oplog.OplogId()); } @@ -1893,7 +1893,7 @@ ProjectStore::CollectGarbage(GcContext& GcCtx) std::string ProjectId; { RwLock::ExclusiveLockScope _(m_ProjectsLock); - if (!Project->IsExpired(GcCtx.ExpireTime())) + if (!Project->IsExpired(GcCtx.ProjectStoreExpireTime())) { ZEN_DEBUG("ProjectStore::CollectGarbage skipped garbage collect of project '{}'. Project no longer expired.", ProjectId); continue; @@ -4173,7 +4173,7 @@ TEST_CASE("project.store.gc") } { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); ProjectStore.GatherReferences(GcCtx); size_t RefCount = 0; GcCtx.IterateCids([&RefCount](const IoHash&) { RefCount++; }); @@ -4184,7 +4184,7 @@ TEST_CASE("project.store.gc") } { - GcContext GcCtx(GcClock::Now() + std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() + std::chrono::hours(24), GcClock::Now() + std::chrono::hours(24)); ProjectStore.GatherReferences(GcCtx); size_t RefCount = 0; GcCtx.IterateCids([&RefCount](const IoHash&) { RefCount++; }); @@ -4197,7 +4197,7 @@ TEST_CASE("project.store.gc") std::filesystem::remove(Project1FilePath); { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); ProjectStore.GatherReferences(GcCtx); size_t RefCount = 0; GcCtx.IterateCids([&RefCount](const IoHash&) { RefCount++; }); @@ -4208,7 +4208,7 @@ TEST_CASE("project.store.gc") } { - GcContext GcCtx(GcClock::Now() + std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() + std::chrono::hours(24), GcClock::Now() + std::chrono::hours(24)); ProjectStore.GatherReferences(GcCtx); size_t RefCount = 0; GcCtx.IterateCids([&RefCount](const IoHash&) { RefCount++; }); @@ -4220,7 +4220,7 @@ TEST_CASE("project.store.gc") std::filesystem::remove(Project2OplogPath); { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); ProjectStore.GatherReferences(GcCtx); size_t RefCount = 0; GcCtx.IterateCids([&RefCount](const IoHash&) { RefCount++; }); @@ -4231,7 +4231,7 @@ TEST_CASE("project.store.gc") } { - GcContext GcCtx(GcClock::Now() + std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() + std::chrono::hours(24), GcClock::Now() + std::chrono::hours(24)); ProjectStore.GatherReferences(GcCtx); size_t RefCount = 0; GcCtx.IterateCids([&RefCount](const IoHash&) { RefCount++; }); @@ -4243,7 +4243,7 @@ TEST_CASE("project.store.gc") std::filesystem::remove(Project2FilePath); { - GcContext GcCtx(GcClock::Now() + std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() + std::chrono::hours(24), GcClock::Now() + std::chrono::hours(24)); ProjectStore.GatherReferences(GcCtx); size_t RefCount = 0; GcCtx.IterateCids([&RefCount](const IoHash&) { RefCount++; }); diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index b97cbbc26..789b6f4a6 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -409,11 +409,12 @@ public: .MonitorInterval = std::chrono::seconds(ServerOptions.GcConfig.MonitorIntervalSeconds), .Interval = std::chrono::seconds(ServerOptions.GcConfig.IntervalSeconds), .MaxCacheDuration = std::chrono::seconds(ServerOptions.GcConfig.Cache.MaxDurationSeconds), + .MaxProjectStoreDuration = std::chrono::seconds(ServerOptions.GcConfig.ProjectStore.MaxDurationSeconds), .CollectSmallObjects = ServerOptions.GcConfig.CollectSmallObjects, .Enabled = ServerOptions.GcConfig.Enabled, .DiskReserveSize = ServerOptions.GcConfig.DiskReserveSize, - .DiskSizeSoftLimit = ServerOptions.GcConfig.Cache.DiskSizeSoftLimit, - .MinimumFreeDiskSpaceToAllowWrites = ServerOptions.GcConfig.Cache.MinimumFreeDiskSpaceToAllowWrites}; + .DiskSizeSoftLimit = ServerOptions.GcConfig.DiskSizeSoftLimit, + .MinimumFreeDiskSpaceToAllowWrites = ServerOptions.GcConfig.MinimumFreeDiskSpaceToAllowWrites}; m_GcScheduler.Initialize(GcConfig); return EffectiveBasePort; diff --git a/src/zenstore/compactcas.cpp b/src/zenstore/compactcas.cpp index e4c2c2ecf..0f6f011e1 100644 --- a/src/zenstore/compactcas.cpp +++ b/src/zenstore/compactcas.cpp @@ -645,6 +645,13 @@ CasContainerStrategy::ReadIndexFile(const std::filesystem::path& IndexPath, uint uint64_t CasContainerStrategy::ReadLog(const std::filesystem::path& LogPath, uint64_t SkipEntryCount) { + if (!TCasLogFile<CasDiskIndexEntry>::IsValid(LogPath)) + { + ZEN_WARN("removing invalid cas log at '{}'", LogPath); + std::filesystem::remove(LogPath); + return 0; + } + size_t LogEntryCount = 0; Stopwatch Timer; const auto _ = MakeGuard([&] { @@ -972,7 +979,7 @@ TEST_CASE("compactcas.gc.basic") CHECK(InsertResult.New); Cas.Flush(); - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); Cas.CollectGarbage(GcCtx); @@ -1002,7 +1009,7 @@ TEST_CASE("compactcas.gc.removefile") CasContainerStrategy Cas(Gc); Cas.Initialize(TempDir.Path(), "cb", 65536, 1 << 4, false); - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); Cas.CollectGarbage(GcCtx); @@ -1057,7 +1064,7 @@ TEST_CASE("compactcas.gc.compact") // Keep first and last { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; @@ -1092,7 +1099,7 @@ TEST_CASE("compactcas.gc.compact") // Keep last { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; KeepChunks.push_back(ChunkHashes[8]); @@ -1124,7 +1131,7 @@ TEST_CASE("compactcas.gc.compact") // Keep mixed { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; KeepChunks.push_back(ChunkHashes[1]); @@ -1159,7 +1166,7 @@ TEST_CASE("compactcas.gc.compact") // Keep multiple at end { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; KeepChunks.push_back(ChunkHashes[6]); @@ -1194,7 +1201,7 @@ TEST_CASE("compactcas.gc.compact") // Keep every other { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; KeepChunks.push_back(ChunkHashes[0]); @@ -1273,7 +1280,7 @@ TEST_CASE("compactcas.gc.deleteblockonopen") // GC every other block { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; for (size_t i = 0; i < 20; i += 2) @@ -1340,7 +1347,7 @@ TEST_CASE("compactcas.gc.handleopeniobuffer") Cas.Flush(); // GC everything - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); Cas.CollectGarbage(GcCtx); @@ -1496,7 +1503,7 @@ TEST_CASE("compactcas.threadedinsert") C++; } - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); GcCtx.AddRetainedCids(KeepHashes); Cas.CollectGarbage(GcCtx); @@ -1537,7 +1544,7 @@ TEST_CASE("compactcas.threadedinsert") C++; } - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); GcCtx.AddRetainedCids(KeepHashes); Cas.CollectGarbage(GcCtx); diff --git a/src/zenstore/filecas.cpp b/src/zenstore/filecas.cpp index 2b64bd202..88b847c51 100644 --- a/src/zenstore/filecas.cpp +++ b/src/zenstore/filecas.cpp @@ -1417,7 +1417,7 @@ TEST_CASE("cas.file.gc") { InsertChunks(); - GcContext Ctx(GcClock::Now() - std::chrono::hours(24)); + GcContext Ctx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); FileCas.CollectGarbage(Ctx); for (const IoHash& Key : Keys) @@ -1433,7 +1433,7 @@ TEST_CASE("cas.file.gc") { InsertChunks(); - GcContext Ctx(GcClock::Now() - std::chrono::hours(24)); + GcContext Ctx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); for (const IoHash& Key : Keys) { diff --git a/src/zenstore/gc.cpp b/src/zenstore/gc.cpp index a7c757877..2d7e0e02f 100644 --- a/src/zenstore/gc.cpp +++ b/src/zenstore/gc.cpp @@ -189,16 +189,19 @@ struct GcContext::GcState CacheKeyContexts m_ExpiredCacheKeys; HashKeySet m_RetainedCids; HashKeySet m_DeletedCids; - GcClock::TimePoint m_ExpireTime; + GcClock::TimePoint m_CacheExpireTime; + GcClock::TimePoint m_ProjectStoreExpireTime; bool m_DeletionMode = true; bool m_CollectSmallObjects = false; std::filesystem::path DiskReservePath; }; -GcContext::GcContext(const GcClock::TimePoint& ExpireTime) : m_State(std::make_unique<GcState>()) +GcContext::GcContext(const GcClock::TimePoint& CacheExpireTime, const GcClock::TimePoint& ProjectStoreExpireTime) +: m_State(std::make_unique<GcState>()) { - m_State->m_ExpireTime = ExpireTime; + m_State->m_CacheExpireTime = CacheExpireTime; + m_State->m_ProjectStoreExpireTime = ProjectStoreExpireTime; } GcContext::~GcContext() @@ -278,9 +281,15 @@ GcContext::CollectSmallObjects(bool NewState) } GcClock::TimePoint -GcContext::ExpireTime() const +GcContext::CacheExpireTime() const { - return m_State->m_ExpireTime; + return m_State->m_CacheExpireTime; +} + +GcClock::TimePoint +GcContext::ProjectStoreExpireTime() const +{ + return m_State->m_ProjectStoreExpireTime; } void @@ -710,11 +719,12 @@ GcScheduler::SchedulerThread() continue; } - bool Delete = true; - bool CollectSmallObjects = m_Config.CollectSmallObjects; - std::chrono::seconds MaxCacheDuration = m_Config.MaxCacheDuration; - uint64_t DiskSizeSoftLimit = m_Config.DiskSizeSoftLimit; - GcClock::TimePoint Now = GcClock::Now(); + bool Delete = true; + bool CollectSmallObjects = m_Config.CollectSmallObjects; + std::chrono::seconds MaxCacheDuration = m_Config.MaxCacheDuration; + std::chrono::seconds MaxProjectStoreDuration = m_Config.MaxProjectStoreDuration; + uint64_t DiskSizeSoftLimit = m_Config.DiskSizeSoftLimit; + GcClock::TimePoint Now = GcClock::Now(); if (m_TriggerGcParams) { const auto TriggerParams = m_TriggerGcParams.value(); @@ -725,13 +735,20 @@ GcScheduler::SchedulerThread() { MaxCacheDuration = TriggerParams.MaxCacheDuration; } + if (TriggerParams.MaxProjectStoreDuration != std::chrono::seconds::max()) + { + MaxProjectStoreDuration = TriggerParams.MaxProjectStoreDuration; + } if (TriggerParams.DiskSizeSoftLimit != 0) { DiskSizeSoftLimit = TriggerParams.DiskSizeSoftLimit; } } - GcClock::TimePoint ExpireTime = MaxCacheDuration == GcClock::Duration::max() ? GcClock::TimePoint::min() : Now - MaxCacheDuration; + GcClock::TimePoint CacheExpireTime = + MaxCacheDuration == GcClock::Duration::max() ? GcClock::TimePoint::min() : Now - MaxCacheDuration; + GcClock::TimePoint ProjectStoreExpireTime = + MaxProjectStoreDuration == GcClock::Duration::max() ? GcClock::TimePoint::min() : Now - MaxProjectStoreDuration; const GcStorageSize TotalSize = m_GcManager.TotalStorageSize(); @@ -786,9 +803,13 @@ GcScheduler::SchedulerThread() std::unique_lock Lock(m_GcMutex); GcClock::Tick AgeTick = m_DiskUsageWindow.FindTimepointThatRemoves(GcDiskSpaceGoal, Now.time_since_epoch().count()); GcClock::TimePoint SizeBasedExpireTime = GcClock::TimePointFromTick(AgeTick); - if (SizeBasedExpireTime > ExpireTime) + if (SizeBasedExpireTime > CacheExpireTime) + { + CacheExpireTime = SizeBasedExpireTime; + } + if (SizeBasedExpireTime > ProjectStoreExpireTime) { - ExpireTime = SizeBasedExpireTime; + ProjectStoreExpireTime = SizeBasedExpireTime; } } @@ -832,7 +853,7 @@ GcScheduler::SchedulerThread() } } - CollectGarbage(ExpireTime, Delete, CollectSmallObjects); + CollectGarbage(CacheExpireTime, ProjectStoreExpireTime, Delete, CollectSmallObjects); uint32_t RunningState = static_cast<uint32_t>(GcSchedulerStatus::kRunning); if (!m_Status.compare_exchange_strong(RunningState, static_cast<uint32_t>(GcSchedulerStatus::kIdle))) @@ -859,17 +880,20 @@ GcScheduler::NextGcTime(GcClock::TimePoint CurrentTime) } void -GcScheduler::CollectGarbage(const GcClock::TimePoint& ExpireTime, bool Delete, bool CollectSmallObjects) +GcScheduler::CollectGarbage(const GcClock::TimePoint& CacheExpireTime, + const GcClock::TimePoint& ProjectStoreExpireTime, + bool Delete, + bool CollectSmallObjects) { - GcContext GcCtx(ExpireTime); + GcContext GcCtx(CacheExpireTime, ProjectStoreExpireTime); GcCtx.SetDeletionMode(Delete); GcCtx.CollectSmallObjects(CollectSmallObjects); - // GcCtx.MaxCacheDuration(MaxCacheDuration); GcCtx.DiskReservePath(m_Config.RootDirectory / "reserve.gc"); - ZEN_INFO("garbage collection STARTING, small objects gc {}, cutoff time {}", + ZEN_INFO("garbage collection STARTING, small objects gc {}, cache cutoff time {}, project store cutoff time {}", GcCtx.CollectSmallObjects() ? "ENABLED"sv : "DISABLED"sv, - ExpireTime); + CacheExpireTime, + ProjectStoreExpireTime); { Stopwatch Timer; const auto __ = MakeGuard([&] { ZEN_INFO("garbage collection DONE in {}", NiceTimeSpanMs(Timer.GetElapsedTimeMs())); }); @@ -878,9 +902,10 @@ GcScheduler::CollectGarbage(const GcClock::TimePoint& ExpireTime, bool Delete, b if (Delete) { - m_LastGcExpireTime = ExpireTime; + GcClock::TimePoint KeepRangeStart = Min(CacheExpireTime, ProjectStoreExpireTime); + m_LastGcExpireTime = KeepRangeStart; std::unique_lock Lock(m_GcMutex); - m_DiskUsageWindow.KeepRange(ExpireTime.time_since_epoch().count(), GcClock::Duration::max().count()); + m_DiskUsageWindow.KeepRange(KeepRangeStart.time_since_epoch().count(), GcClock::Duration::max().count()); } m_LastGcTime = GcClock::Now(); @@ -953,7 +978,7 @@ TEST_CASE("gc.basic") const auto InsertResult = CidStore.AddChunk(CompressedChunk.GetCompressed().Flatten().AsIoBuffer(), CompressedChunk.DecodeRawHash()); CHECK(InsertResult.New); - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); CidStore.Flush(); @@ -1012,7 +1037,7 @@ TEST_CASE("gc.full") // Keep first and last { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; @@ -1047,7 +1072,7 @@ TEST_CASE("gc.full") // Keep last { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; KeepChunks.push_back(ChunkHashes[8]); @@ -1079,7 +1104,7 @@ TEST_CASE("gc.full") // Keep mixed { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; KeepChunks.push_back(ChunkHashes[1]); @@ -1114,7 +1139,7 @@ TEST_CASE("gc.full") // Keep multiple at end { - GcContext GcCtx(GcClock::Now() - std::chrono::hours(24)); + GcContext GcCtx(GcClock::Now() - std::chrono::hours(24), GcClock::Now() - std::chrono::hours(24)); GcCtx.CollectSmallObjects(true); std::vector<IoHash> KeepChunks; KeepChunks.push_back(ChunkHashes[6]); diff --git a/src/zenstore/include/zenstore/gc.h b/src/zenstore/include/zenstore/gc.h index 4c709b8a2..881936d0f 100644 --- a/src/zenstore/include/zenstore/gc.h +++ b/src/zenstore/include/zenstore/gc.h @@ -48,7 +48,7 @@ public: class GcContext { public: - GcContext(const GcClock::TimePoint& ExpireTime); + GcContext(const GcClock::TimePoint& CacheExpireTime, const GcClock::TimePoint& ProjectStoreExpireTime); ~GcContext(); void AddRetainedCids(std::span<const IoHash> Cid); @@ -70,7 +70,8 @@ public: bool CollectSmallObjects() const; void CollectSmallObjects(bool NewState); - GcClock::TimePoint ExpireTime() const; + GcClock::TimePoint CacheExpireTime() const; + GcClock::TimePoint ProjectStoreExpireTime() const; void DiskReservePath(const std::filesystem::path& Path); uint64_t ClaimGCReserve(); @@ -174,6 +175,7 @@ struct GcSchedulerConfig std::chrono::seconds MonitorInterval{30}; std::chrono::seconds Interval{}; std::chrono::seconds MaxCacheDuration{86400}; + std::chrono::seconds MaxProjectStoreDuration{604800}; bool CollectSmallObjects = true; bool Enabled = true; uint64_t DiskReserveSize = 1ul << 28; @@ -216,16 +218,20 @@ public: struct TriggerGcParams { - bool CollectSmallObjects = false; - std::chrono::seconds MaxCacheDuration = std::chrono::seconds::max(); - uint64_t DiskSizeSoftLimit = 0; + bool CollectSmallObjects = false; + std::chrono::seconds MaxCacheDuration = std::chrono::seconds::max(); + std::chrono::seconds MaxProjectStoreDuration = std::chrono::seconds::max(); + uint64_t DiskSizeSoftLimit = 0; }; bool TriggerGc(const TriggerGcParams& Params); private: void SchedulerThread(); - void CollectGarbage(const GcClock::TimePoint& ExpireTime, bool Delete, bool CollectSmallObjects); + void CollectGarbage(const GcClock::TimePoint& CacheExpireTime, + const GcClock::TimePoint& ProjectStoreExpireTime, + bool Delete, + bool CollectSmallObjects); GcClock::TimePoint NextGcTime(GcClock::TimePoint CurrentTime); spdlog::logger& Log() { return m_Log; } virtual bool AreDiskWritesAllowed() const override { return !m_AreDiskWritesBlocked.load(); } |