aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2024-09-03 20:33:34 +0200
committerGitHub Enterprise <[email protected]>2024-09-03 20:33:34 +0200
commit9a48f6b32f525bbaf8053a4873f663b3e5f820a7 (patch)
tree63638ec7a38331846715fdb2efe6ef61958f48fb /src
parentoplog index snapshots (#140) (diff)
downloadzen-9a48f6b32f525bbaf8053a4873f663b3e5f820a7.tar.xz
zen-9a48f6b32f525bbaf8053a4873f663b3e5f820a7.zip
delay oplog read (#141)
- Improvement: Don't keep all oplogs open after GC, close them when references are fetched unless they are open by client
Diffstat (limited to 'src')
-rw-r--r--src/zenserver/projectstore/projectstore.cpp336
-rw-r--r--src/zenserver/projectstore/projectstore.h22
2 files changed, 213 insertions, 145 deletions
diff --git a/src/zenserver/projectstore/projectstore.cpp b/src/zenserver/projectstore/projectstore.cpp
index 1952adcd3..c1905228c 100644
--- a/src/zenserver/projectstore/projectstore.cpp
+++ b/src/zenserver/projectstore/projectstore.cpp
@@ -1143,33 +1143,15 @@ ProjectStore::Oplog::Read()
ZEN_TRACE_CPU("Oplog::Read");
ZEN_LOG_SCOPE("Oplog::Read '{}'", m_OplogId);
- std::filesystem::path StateFilePath = m_BasePath / "oplog.zcb"sv;
- if (std::filesystem::is_regular_file(StateFilePath))
+ std::optional<CbObject> Config = ReadStateFile(m_BasePath, [this]() { return Log(); });
+ if (Config.has_value())
{
- ZEN_INFO("oplog '{}/{}': config read from '{}'", m_OuterProject->Identifier, m_OplogId, StateFilePath);
-
- BasicFile Blob;
- Blob.Open(StateFilePath, BasicFile::Mode::kRead);
-
- IoBuffer Obj = Blob.ReadAll();
- CbValidateError ValidationError = ValidateCompactBinary(MemoryView(Obj.Data(), Obj.Size()), CbValidateMode::All);
-
- if (ValidationError != CbValidateError::None)
+ if (Config.value().GetSize() == 0)
{
- ZEN_ERROR("validation error {} hit for '{}'", int(ValidationError), StateFilePath);
+ // Invalid config file
return;
}
-
- CbObject Cfg = LoadCompactBinaryObject(Obj);
-
- m_MarkerPath = Cfg["gcpath"sv].AsU8String();
- }
- else
- {
- ZEN_INFO("oplog '{}/{}': config read not found at '{}', assuming legacy store",
- m_OuterProject->Identifier,
- m_OplogId,
- StateFilePath);
+ m_MarkerPath = Config.value()["gcpath"sv].AsU8String();
}
if (!m_MetaValid)
@@ -1283,6 +1265,35 @@ ProjectStore::Oplog::Reset()
return true;
}
+std::optional<CbObject>
+ProjectStore::Oplog::ReadStateFile(const std::filesystem::path& BasePath, std::function<LoggerRef()>&& Log)
+{
+ ZEN_TRACE_CPU("Oplog::ReadStateFile");
+ using namespace std::literals;
+
+ std::filesystem::path StateFilePath = BasePath / "oplog.zcb"sv;
+ if (std::filesystem::is_regular_file(StateFilePath))
+ {
+ // ZEN_INFO("oplog '{}/{}': config read from '{}'", m_OuterProject->Identifier, m_OplogId, StateFilePath);
+
+ BasicFile Blob;
+ Blob.Open(StateFilePath, BasicFile::Mode::kRead);
+
+ IoBuffer Obj = Blob.ReadAll();
+ CbValidateError ValidationError = ValidateCompactBinary(MemoryView(Obj.Data(), Obj.Size()), CbValidateMode::All);
+
+ if (ValidationError != CbValidateError::None)
+ {
+ ZEN_ERROR("validation error {} hit for oplog config at '{}'", int(ValidationError), StateFilePath);
+ return CbObject();
+ }
+
+ return LoadCompactBinaryObject(Obj);
+ }
+ ZEN_INFO("config for oplog not found at '{}'. Assuming legacy store", StateFilePath);
+ return {};
+}
+
void
ProjectStore::Oplog::WriteIndexSnapshot()
{
@@ -3052,7 +3063,7 @@ ProjectStore::Project::ScrubStorage(ScrubContext& Ctx)
void
ProjectStore::Project::GatherReferences(GcContext& GcCtx)
{
- ZEN_TRACE_CPU("Store::Project::GatherReferences");
+ ZEN_TRACE_CPU("Project::GatherReferences");
Stopwatch Timer;
const auto Guard = MakeGuard([&] {
@@ -3263,6 +3274,28 @@ ProjectStore::Project::IsOplogTouchedSince(const GcClock::TimePoint TouchTime, s
return false;
}
+bool
+ProjectStore::Project::IsExpired(const GcClock::TimePoint ExpireTime, std::string_view OplogId) const
+{
+ using namespace std::literals;
+
+ {
+ RwLock::SharedLockScope Lock(m_ProjectLock);
+ auto OplogIt = m_Oplogs.find(std::string(OplogId));
+
+ if (OplogIt != m_Oplogs.end())
+ {
+ Lock.ReleaseNow();
+ return IsExpired(ExpireTime, *OplogIt->second.get());
+ }
+ }
+
+ std::filesystem::path OplogBasePath = BasePathForOplog(OplogId);
+ std::optional<CbObject> OplogConfig = Oplog::ReadStateFile(OplogBasePath, [this]() { return Log(); });
+ std::filesystem::path MarkerPath = OplogConfig.has_value() ? OplogConfig.value()["gcpath"sv].AsU8String() : std::u8string();
+ return IsExpired(std::string(OplogId), MarkerPath, ExpireTime);
+}
+
void
ProjectStore::Project::TouchProject()
{
@@ -4955,16 +4988,14 @@ ProjectStore::GetGcName(GcCtx&)
class ProjectStoreGcStoreCompactor : public GcStoreCompactor
{
public:
- ProjectStoreGcStoreCompactor(ProjectStore& ProjectStore,
- const std::filesystem::path& BasePath,
- std::vector<std::filesystem::path>&& OplogPathsToRemove,
- std::vector<std::filesystem::path>&& ProjectPathsToRemove,
- std::vector<std::pair<std::string, std::string>>&& OplogsToCompact)
+ ProjectStoreGcStoreCompactor(ProjectStore& ProjectStore,
+ const std::filesystem::path& BasePath,
+ std::vector<std::filesystem::path>&& OplogPathsToRemove,
+ std::vector<std::filesystem::path>&& ProjectPathsToRemove)
: m_ProjectStore(ProjectStore)
, m_BasePath(BasePath)
, m_OplogPathsToRemove(std::move(OplogPathsToRemove))
, m_ProjectPathsToRemove(std::move(ProjectPathsToRemove))
- , m_OplogsToCompact(std::move(OplogsToCompact))
{
}
@@ -4984,6 +5015,7 @@ public:
NiceTimeSpanMs(Timer.GetElapsedTimeMs()));
});
+ size_t CompactOplogCount = 0;
if (Ctx.Settings.IsDeleteMode)
{
for (const std::filesystem::path& OplogPath : m_OplogPathsToRemove)
@@ -5020,23 +5052,29 @@ public:
}
}
}
- else
- {
- ZEN_DEBUG("GCV2: projectstore [COMPACT] '{}': Skipped deleting and compacting of {} oplogs and {} projects",
- m_BasePath,
- m_OplogPathsToRemove.size(),
- m_ProjectPathsToRemove.size());
- }
+ for (auto ProjectIt : m_ProjectStore.m_Projects)
{
- for (auto It : m_OplogsToCompact)
+ Ref<ProjectStore::Project> Project = ProjectIt.second;
+ std::vector<std::string> OplogsToCompact = Project->GetOplogsToCompact();
+ CompactOplogCount += OplogsToCompact.size();
+ for (const std::string& OplogId : OplogsToCompact)
{
- const std::string& ProjectId = It.first;
- const std::string& OplogId = It.second;
- Ref<ProjectStore::Project> Project = m_ProjectStore.OpenProject(ProjectId);
- if (Project)
+ ProjectStore::Oplog* OpLog = nullptr;
{
- ProjectStore::Oplog* OpLog = Project->OpenOplog(OplogId, /*AllowCompact*/ false);
+ RwLock::SharedLockScope __(Project->m_ProjectLock);
+ if (auto OpIt = Project->m_Oplogs.find(OplogId); OpIt != Project->m_Oplogs.end())
+ {
+ OpLog = OpIt->second.get();
+ }
+ else
+ {
+ std::filesystem::path OplogBasePath = Project->BasePathForOplog(OplogId);
+ OpLog =
+ new ProjectStore::Oplog(OplogId, Project.Get(), Project->m_CidStore, OplogBasePath, std::filesystem::path{});
+ OpLog->Read();
+ }
+
if (OpLog)
{
const uint64_t PreSize = OpLog->TotalSize();
@@ -5051,23 +5089,35 @@ public:
Stats.RemovedDisk += FreedSize;
}
+
+ if (auto OpIt = Project->m_Oplogs.find(OplogId); OpIt == Project->m_Oplogs.end())
+ {
+ delete OpLog;
+ }
}
}
}
+ if (!Ctx.Settings.IsDeleteMode)
+ {
+ ZEN_DEBUG("GCV2: projectstore [COMPACT] '{}': Skipped deleting of {} oplogs and {} projects, skipped compacting {} oplogs",
+ m_BasePath,
+ m_OplogPathsToRemove.size(),
+ m_ProjectPathsToRemove.size(),
+ CompactOplogCount);
+ }
+
m_ProjectPathsToRemove.clear();
m_OplogPathsToRemove.clear();
- m_OplogsToCompact.clear();
}
virtual std::string GetGcName(GcCtx&) override { return fmt::format("projectstore: '{}'", m_BasePath.string()); }
private:
- ProjectStore& m_ProjectStore;
- std::filesystem::path m_BasePath;
- std::vector<std::filesystem::path> m_OplogPathsToRemove;
- std::vector<std::filesystem::path> m_ProjectPathsToRemove;
- std::vector<std::pair<std::string, std::string>> m_OplogsToCompact;
+ ProjectStore& m_ProjectStore;
+ std::filesystem::path m_BasePath;
+ std::vector<std::filesystem::path> m_OplogPathsToRemove;
+ std::vector<std::filesystem::path> m_ProjectPathsToRemove;
};
GcStoreCompactor*
@@ -5111,21 +5161,6 @@ ProjectStore::RemoveExpiredData(GcCtx& Ctx, GcStats& Stats)
}
}
- for (const Ref<Project>& Project : Projects)
- {
- std::vector<std::string> OpLogs = Project->ScanForOplogs();
- for (const std::string& OpLogId : OpLogs)
- {
- Project->OpenOplog(OpLogId, /*AllowCompact*/ false);
- if (Ctx.IsCancelledFlag)
- {
- return nullptr;
- }
- }
- }
-
- std::vector<std::pair<std::string, std::string>> OplogsToCompact;
-
size_t ExpiredOplogCount = 0;
for (const Ref<Project>& Project : Projects)
{
@@ -5135,28 +5170,17 @@ ProjectStore::RemoveExpiredData(GcCtx& Ctx, GcStats& Stats)
}
std::vector<std::string> ExpiredOplogs;
+
+ std::vector<std::string> OpLogs = Project->ScanForOplogs();
+ for (const std::string& OplogId : OpLogs)
{
- Project->IterateOplogs(
- [&Ctx, &Stats, &Project, &ExpiredOplogs, &OplogsToCompact](const RwLock::SharedLockScope&, ProjectStore::Oplog& Oplog) {
- Stats.CheckedCount++;
- if (Project->IsExpired(Ctx.Settings.ProjectStoreExpireTime, Oplog))
- {
- ExpiredOplogs.push_back(Oplog.OplogId());
- }
- else
- {
- GcClock::TimePoint CompactExpireTime = GcClock::Now() - std::chrono::minutes(30);
- if (!Project->IsOplogTouchedSince(CompactExpireTime, Oplog.OplogId()))
- {
- const uint32_t CompactUnusedThreshold = 25;
- if (Oplog.GetUnusedSpacePercent() >= CompactUnusedThreshold)
- {
- OplogsToCompact.push_back(std::make_pair(Project->Identifier, Oplog.OplogId()));
- }
- }
- }
- });
+ Stats.CheckedCount++;
+ if (Project->IsExpired(Ctx.Settings.ProjectStoreExpireTime, OplogId))
+ {
+ ExpiredOplogs.push_back(OplogId);
+ }
}
+
std::filesystem::path ProjectPath = BasePathForProject(Project->Identifier);
ExpiredOplogCount += ExpiredOplogs.size();
if (Ctx.Settings.IsDeleteMode)
@@ -5177,13 +5201,6 @@ ProjectStore::RemoveExpiredData(GcCtx& Ctx, GcStats& Stats)
}
}
- if (ExpiredProjects.empty() && ExpiredOplogCount == 0 && OplogsToCompact.empty())
- {
- ZEN_DEBUG("GCV2: projectstore [REMOVE EXPIRED] '{}': no expired projects, expired oplogs or oplogs to compact found",
- m_ProjectBasePath);
- return nullptr;
- }
-
if (Ctx.Settings.IsDeleteMode)
{
for (const Ref<Project>& Project : ExpiredProjects)
@@ -5222,15 +5239,7 @@ ProjectStore::RemoveExpiredData(GcCtx& Ctx, GcStats& Stats)
size_t ExpiredProjectCount = ExpiredProjects.size();
Stats.FoundCount += ExpiredOplogCount + ExpiredProjectCount;
- if (!OplogPathsToRemove.empty() || !ProjectPathsToRemove.empty() || !OplogsToCompact.empty())
- {
- return new ProjectStoreGcStoreCompactor(*this,
- m_ProjectBasePath,
- std::move(OplogPathsToRemove),
- std::move(ProjectPathsToRemove),
- std::move(OplogsToCompact));
- }
- return nullptr;
+ return new ProjectStoreGcStoreCompactor(*this, m_ProjectBasePath, std::move(OplogPathsToRemove), std::move(ProjectPathsToRemove));
}
class ProjectStoreReferenceChecker : public GcReferenceChecker
@@ -5362,7 +5371,7 @@ public:
ProjectStoreOplogReferenceChecker(ProjectStore& InProjectStore, Ref<ProjectStore::Project> InProject, std::string_view InOplog)
: m_ProjectStore(InProjectStore)
, m_Project(InProject)
- , m_OplogName(InOplog)
+ , m_OplogId(InOplog)
{
m_Project->EnableUpdateCapture();
}
@@ -5372,10 +5381,15 @@ public:
try
{
m_Project->DisableUpdateCapture();
- if (m_OplogCaptureEnabled)
+
+ RwLock::SharedLockScope _(m_Project->m_ProjectLock);
+ if (auto It = m_Project->m_Oplogs.find(m_OplogId); It != m_Project->m_Oplogs.end())
{
- ZEN_ASSERT(m_Oplog);
- m_Oplog->DisableUpdateCapture();
+ ProjectStore::Oplog* Oplog = It->second.get();
+ if (Oplog == m_OplogWithUpdateCapture)
+ {
+ Oplog->DisableUpdateCapture();
+ }
}
}
catch (const std::exception& Ex)
@@ -5384,7 +5398,7 @@ public:
}
}
- virtual std::string GetGcName(GcCtx&) override { return fmt::format("oplog: '{}/{}'", m_Project->Identifier, m_OplogName); }
+ virtual std::string GetGcName(GcCtx&) override { return fmt::format("oplog: '{}/{}'", m_Project->Identifier, m_OplogId); }
virtual void PreCache(GcCtx& Ctx) override
{
@@ -5396,40 +5410,59 @@ public:
{
return;
}
- if (m_Oplog)
- {
- ZEN_INFO("GCV2: projectstore [PRECACHE] '{}': precached {} references in {} from {}/{}",
- m_Oplog->m_BasePath,
- m_References.size(),
- NiceTimeSpanMs(Timer.GetElapsedTimeMs()),
- m_Project->Identifier,
- m_Oplog->OplogId());
- }
+ ZEN_INFO("GCV2: projectstore [PRECACHE] '{}': precached {} references in {} from {}/{}",
+ m_OplogBasePath,
+ m_References.size(),
+ NiceTimeSpanMs(Timer.GetElapsedTimeMs()),
+ m_Project->Identifier,
+ m_OplogId);
});
- if (auto It = m_Project->m_Oplogs.find(m_OplogName); It != m_Project->m_Oplogs.end())
+ ProjectStore::Oplog* Oplog = nullptr;
+ auto __ = MakeGuard([this, Oplog]() {
+ if (Oplog != nullptr && m_OplogWithUpdateCapture == nullptr)
+ {
+ delete Oplog;
+ }
+ });
+ m_OplogBasePath = m_Project->BasePathForOplog(m_OplogId);
+
+ RwLock::SharedLockScope ___(m_Project->m_ProjectLock);
+ if (auto It = m_Project->m_Oplogs.find(m_OplogId); It != m_Project->m_Oplogs.end())
+ {
+ It->second->EnableUpdateCapture();
+ Oplog = It->second.get();
+ m_OplogWithUpdateCapture = Oplog;
+ }
+ else if (ProjectStore::Oplog::ExistsAt(m_OplogBasePath))
+ {
+ Oplog = new ProjectStore::Oplog(m_OplogId, m_Project.Get(), m_Project->m_CidStore, m_OplogBasePath, std::filesystem::path{});
+ Oplog->Read();
+ }
+
+ RwLock::SharedLockScope ____(Oplog->m_OplogLock);
+ if (Ctx.IsCancelledFlag)
{
- m_Oplog = It->second.get();
- m_Oplog->EnableUpdateCapture();
- m_OplogCaptureEnabled = true;
+ return;
+ }
- RwLock::SharedLockScope __(m_Oplog->m_OplogLock);
- if (Ctx.IsCancelledFlag)
+ GcClock::TimePoint CompactExpireTime = GcClock::Now() - std::chrono::minutes(30);
+ if (!m_Project->IsOplogTouchedSince(CompactExpireTime, m_OplogId))
+ {
+ const uint32_t CompactUnusedThreshold = 25;
+ if (Oplog->GetUnusedSpacePercent() >= CompactUnusedThreshold)
{
- return;
+ m_Project->AddOplogToCompact(m_OplogId);
}
-
- m_Oplog->GetAttachmentsLocked(m_References, m_ProjectStore.m_Config.StoreAttachmentMetaData);
}
+
+ Oplog->GetAttachmentsLocked(m_References, m_ProjectStore.m_Config.StoreAttachmentMetaData);
+ m_OplogAccessTime = m_Project->LastOplogAccessTime(m_OplogId);
}
virtual void UpdateLockedState(GcCtx& Ctx) override
{
ZEN_TRACE_CPU("Store::Oplog::UpdateLockedState");
- if (!m_Oplog)
- {
- return;
- }
Stopwatch Timer;
const auto _ = MakeGuard([&] {
@@ -5438,28 +5471,37 @@ public:
return;
}
ZEN_INFO("GCV2: projectstore [LOCKSTATE] '{}': found {} references in {} from {}/{}",
- m_Oplog->m_BasePath,
+ m_OplogBasePath,
m_References.size(),
NiceTimeSpanMs(Timer.GetElapsedTimeMs()),
m_Project->Identifier,
- m_Oplog->OplogId());
+ m_OplogId);
});
- m_Oplog->IterateCapturedLSNs([&](const CbObjectView& UpdateOp) -> bool {
- UpdateOp.IterateAttachments([&](CbFieldView Visitor) { m_References.emplace_back(Visitor.AsAttachment()); });
- return true;
- });
- std::vector<IoHash> AddedAttachments = m_Oplog->GetCapturedAttachments();
- m_References.insert(m_References.end(), AddedAttachments.begin(), AddedAttachments.end());
+ if (auto It = m_Project->m_Oplogs.find(m_OplogId); It != m_Project->m_Oplogs.end())
+ {
+ ProjectStore::Oplog* Oplog = It->second.get();
+ Oplog->IterateCapturedLSNs([&](const CbObjectView& UpdateOp) -> bool {
+ UpdateOp.IterateAttachments([&](CbFieldView Visitor) { m_References.emplace_back(Visitor.AsAttachment()); });
+ return true;
+ });
+ std::vector<IoHash> AddedAttachments = Oplog->GetCapturedAttachments();
+ m_References.insert(m_References.end(), AddedAttachments.begin(), AddedAttachments.end());
+ }
+ else if (m_Project->LastOplogAccessTime(m_OplogId) > m_OplogAccessTime && ProjectStore::Oplog::ExistsAt(m_OplogBasePath))
+ {
+ ProjectStore::Oplog* Oplog =
+ new ProjectStore::Oplog(m_OplogId, m_Project.Get(), m_Project->m_CidStore, m_OplogBasePath, std::filesystem::path{});
+ Oplog->Read();
+ RwLock::SharedLockScope __(Oplog->m_OplogLock);
+ Oplog->GetAttachmentsLocked(m_References, m_ProjectStore.m_Config.StoreAttachmentMetaData);
+ delete Oplog;
+ }
}
virtual void RemoveUsedReferencesFromSet(GcCtx& Ctx, HashSet& IoCids) override
{
ZEN_TRACE_CPU("Store::Oplog::RemoveUsedReferencesFromSet");
- if (!m_Oplog)
- {
- return;
- }
size_t InitialCount = IoCids.size();
Stopwatch Timer;
@@ -5468,11 +5510,13 @@ public:
{
return;
}
- ZEN_INFO("GCV2: projectstore [FILTER REFERENCES] '{}': filtered out {} used references out of {} in {}",
- m_Oplog->m_BasePath,
+ ZEN_INFO("GCV2: projectstore [FILTER REFERENCES] '{}': filtered out {} used references out of {} in {} from {}/{}",
+ m_OplogBasePath,
InitialCount - IoCids.size(),
InitialCount,
- NiceTimeSpanMs(Timer.GetElapsedTimeMs()));
+ NiceTimeSpanMs(Timer.GetElapsedTimeMs()),
+ m_Project->Identifier,
+ m_OplogId);
});
for (const IoHash& ReferenceHash : m_References)
@@ -5488,10 +5532,11 @@ public:
}
ProjectStore& m_ProjectStore;
Ref<ProjectStore::Project> m_Project;
- std::string m_OplogName;
- ProjectStore::Oplog* m_Oplog = nullptr;
+ std::string m_OplogId;
+ std::filesystem::path m_OplogBasePath;
+ ProjectStore::Oplog* m_OplogWithUpdateCapture = nullptr;
std::vector<IoHash> m_References;
- bool m_OplogCaptureEnabled = false;
+ GcClock::TimePoint m_OplogAccessTime;
};
std::vector<GcReferenceChecker*>
@@ -5559,6 +5604,7 @@ ProjectStore::CreateReferenceCheckers(GcCtx& Ctx)
std::vector<RwLock::SharedLockScope>
ProjectStore::LockState(GcCtx&)
{
+ ZEN_TRACE_CPU("Store::LockState");
std::vector<RwLock::SharedLockScope> Locks;
Locks.emplace_back(RwLock::SharedLockScope(m_ProjectsLock));
for (auto& ProjectIt : m_Projects)
diff --git a/src/zenserver/projectstore/projectstore.h b/src/zenserver/projectstore/projectstore.h
index 55a3b7dee..7d969874d 100644
--- a/src/zenserver/projectstore/projectstore.h
+++ b/src/zenserver/projectstore/projectstore.h
@@ -172,6 +172,8 @@ public:
Project* GetOuterProject() const { return m_OuterProject; }
void CompactIfUnusedExceeds(bool DryRun, uint32_t CompactUnusedThreshold, std::string_view LogPrefix);
+ static std::optional<CbObject> ReadStateFile(const std::filesystem::path& BasePath, std::function<LoggerRef()>&& Log);
+
private:
struct FileMapEntry
{
@@ -276,6 +278,7 @@ public:
std::vector<std::string> ScanForOplogs() const;
bool IsExpired(const GcClock::TimePoint ExpireTime) const;
bool IsExpired(const GcClock::TimePoint ExpireTime, const ProjectStore::Oplog& Oplog) const;
+ bool IsExpired(const GcClock::TimePoint ExpireTime, std::string_view OplogId) const;
bool IsOplogTouchedSince(const GcClock::TimePoint TouchTime, std::string_view Oplog) const;
void TouchProject();
void TouchOplog(std::string_view Oplog);
@@ -301,6 +304,21 @@ public:
std::vector<RwLock::SharedLockScope> GetGcReferencerLocks();
+ void AddOplogToCompact(std::string_view OplogId)
+ {
+ m_OplogsToCompactLock.WithExclusiveLock([&]() { m_OplogsToCompact.insert(std::string(OplogId)); });
+ }
+ std::vector<std::string> GetOplogsToCompact()
+ {
+ std::vector<std::string> Result;
+ m_OplogsToCompactLock.WithExclusiveLock([&]() {
+ Result.reserve(m_OplogsToCompact.size());
+ Result.insert(Result.end(), m_OplogsToCompact.begin(), m_OplogsToCompact.end());
+ m_OplogsToCompact.clear();
+ });
+ return Result;
+ }
+
private:
ProjectStore* m_ProjectStore;
CidStore& m_CidStore;
@@ -314,6 +332,9 @@ public:
uint32_t m_UpdateCaptureRefCounter = 0;
std::unique_ptr<std::vector<std::string>> m_CapturedOplogs;
+ RwLock m_OplogsToCompactLock;
+ std::unordered_set<std::string> m_OplogsToCompact;
+
std::filesystem::path BasePathForOplog(std::string_view OplogId) const;
bool IsExpired(const std::string& EntryName, const std::filesystem::path& MarkerPath, const GcClock::TimePoint ExpireTime) const;
void WriteAccessTimes();
@@ -321,6 +342,7 @@ public:
friend class ProjectStoreOplogReferenceChecker;
friend class ProjectStoreReferenceChecker;
+ friend class ProjectStoreGcStoreCompactor;
};
// Oplog* OpenProjectOplog(std::string_view ProjectId, std::string_view OplogId);