aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zenserver/cache/structuredcachestore.cpp8
-rw-r--r--zenstore/CAS.cpp121
-rw-r--r--zenstore/gc.cpp31
-rw-r--r--zenstore/include/zenstore/CAS.h20
-rw-r--r--zenstore/include/zenstore/gc.h21
5 files changed, 143 insertions, 58 deletions
diff --git a/zenserver/cache/structuredcachestore.cpp b/zenserver/cache/structuredcachestore.cpp
index e7b840ed8..15f7b5a7a 100644
--- a/zenserver/cache/structuredcachestore.cpp
+++ b/zenserver/cache/structuredcachestore.cpp
@@ -15,6 +15,7 @@
#include <zenstore/basicfile.h>
#include <zenstore/cas.h>
#include <zenstore/caslog.h>
+#include <zenstore/gc.h>
#include <concepts>
#include <filesystem>
@@ -1050,7 +1051,12 @@ ZenCacheDiskLayer::Scrub(ScrubContext& Ctx)
void
ZenCacheDiskLayer::GarbageCollect(GcContext& GcCtx)
{
- ZEN_UNUSED(GcCtx);
+ RwLock::SharedLockScope _(m_Lock);
+
+ for (auto& Kv : m_Buckets)
+ {
+ Kv.second.GarbageCollect(GcCtx);
+ }
}
} // namespace zen
diff --git a/zenstore/CAS.cpp b/zenstore/CAS.cpp
index a4bbfa340..a71e251e5 100644
--- a/zenstore/CAS.cpp
+++ b/zenstore/CAS.cpp
@@ -5,6 +5,9 @@
#include "compactcas.h"
#include "filecas.h"
+#include <zencore/compactbinary.h>
+#include <zencore/compactbinarybuilder.h>
+#include <zencore/compactbinaryvalidation.h>
#include <zencore/except.h>
#include <zencore/fmtutils.h>
#include <zencore/logging.h>
@@ -67,34 +70,6 @@ CasChunkSet::IterateChunks(std::function<void(const IoHash& ChunkHash)>&& Callba
//////////////////////////////////////////////////////////////////////////
-struct GcContext::GcState
-{
- CasChunkSet m_CasChunks;
- CasChunkSet m_CidChunks;
-};
-
-GcContext::GcContext() : m_State(std::make_unique<GcState>())
-{
-}
-
-GcContext::~GcContext()
-{
-}
-
-void
-GcContext::ContributeCids(std::span<const IoHash> Cids)
-{
- m_State->m_CidChunks.AddChunksToSet(Cids);
-}
-
-void
-GcContext::ContributeCas(std::span<const IoHash> Cas)
-{
- m_State->m_CasChunks.AddChunksToSet(Cas);
-}
-
-//////////////////////////////////////////////////////////////////////////
-
void
ScrubContext::ReportBadCasChunks(std::span<IoHash> BadCasChunks)
{
@@ -133,6 +108,17 @@ private:
CasContainerStrategy m_TinyStrategy;
CasContainerStrategy m_SmallStrategy;
FileCasStrategy m_LargeStrategy;
+ CbObject m_ManifestObject;
+
+ enum class StorageScheme
+ {
+ Legacy = 0,
+ WithCbManifest = 1
+ };
+
+ StorageScheme m_StorageScheme = StorageScheme::Legacy;
+
+ void UpdateManifest(bool IsNewStore);
};
CasImpl::CasImpl() : m_TinyStrategy(m_Config), m_SmallStrategy(m_Config), m_LargeStrategy(m_Config)
@@ -166,21 +152,54 @@ CasImpl::Initialize(const CasStoreConfiguration& InConfig)
ManifestPath /= ".ucas_root";
std::error_code Ec;
- BasicFile Marker;
- Marker.Open(ManifestPath.c_str(), /* IsCreate */ false, Ec);
+ BasicFile ManifestFile;
+ ManifestFile.Open(ManifestPath.c_str(), /* IsCreate */ false, Ec);
+
+ bool ManifestIsOk = false;
if (Ec)
{
- IsNewStore = true;
-
- ExtendableStringBuilder<128> manifest;
- manifest.Append("#CAS_ROOT\n");
- manifest.Append("ID=");
- zen::Oid id = zen::Oid::NewOid();
- id.ToString(manifest);
+ if (Ec == std::errc::no_such_file_or_directory)
+ {
+ IsNewStore = true;
+ }
+ }
+ else
+ {
+ IoBuffer ManifestBuffer = ManifestFile.ReadAll();
+ ManifestFile.Close();
+
+ if (ManifestBuffer.Size() > 0 && ManifestBuffer.Data<uint8_t>()[0] == '#')
+ {
+ // Old-style manifest, does not contain any useful information, so we may as well update it
+ }
+ else
+ {
+ CbObject Manifest{SharedBuffer(ManifestBuffer)};
+ CbValidateError ValidationResult = ValidateCompactBinary(ManifestBuffer, CbValidateMode::All);
+
+ if (ValidationResult == CbValidateError::None)
+ {
+ if (Manifest["id"])
+ {
+ ManifestIsOk = true;
+ }
+ }
+ else
+ {
+ ZEN_ERROR("Store manifest validation failed: {:#x}, will generate new manifest to recover", ValidationResult);
+ }
+
+ if (ManifestIsOk)
+ {
+ m_ManifestObject = std::move(Manifest);
+ }
+ }
+ }
- Marker.Open(ManifestPath.c_str(), /* IsCreate */ true);
- Marker.Write(manifest.c_str(), (DWORD)manifest.Size(), 0);
+ if (!ManifestIsOk)
+ {
+ UpdateManifest(true);
}
}
@@ -190,6 +209,30 @@ CasImpl::Initialize(const CasStoreConfiguration& InConfig)
m_SmallStrategy.Initialize("sobs", 4096, IsNewStore);
}
+void
+CasImpl::UpdateManifest(bool IsNewStore)
+{
+ if (!m_ManifestObject)
+ {
+ CbObjectWriter Cbo;
+ Cbo << "id" << zen::Oid::NewOid() << "created" << DateTime::Now();
+ m_ManifestObject = Cbo.Save();
+ }
+
+ // Write manifest to file
+
+ std::filesystem::path ManifestPath = m_Config.RootDirectory;
+ ManifestPath /= ".ucas_root";
+
+ // This will throw on failure
+
+ ZEN_TRACE("Writing new manifest to '{}'", ManifestPath);
+
+ BasicFile Marker;
+ Marker.Open(ManifestPath.c_str(), /* IsCreate */ true);
+ Marker.Write(m_ManifestObject.GetBuffer(), 0);
+}
+
CasStore::InsertResult
CasImpl::InsertChunk(IoBuffer Chunk, const IoHash& ChunkHash)
{
diff --git a/zenstore/gc.cpp b/zenstore/gc.cpp
index bfb8f015e..e7c8f3a1a 100644
--- a/zenstore/gc.cpp
+++ b/zenstore/gc.cpp
@@ -1,9 +1,40 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include <zenstore/gc.h>
+#include <zenstore/CAS.h>
namespace zen {
+//////////////////////////////////////////////////////////////////////////
+
+struct GcContext::GcState
+{
+ CasChunkSet m_CasChunks;
+ CasChunkSet m_CidChunks;
+};
+
+GcContext::GcContext() : m_State(std::make_unique<GcState>())
+{
+}
+
+GcContext::~GcContext()
+{
+}
+
+void
+GcContext::ContributeCids(std::span<const IoHash> Cids)
+{
+ m_State->m_CidChunks.AddChunksToSet(Cids);
+}
+
+void
+GcContext::ContributeCas(std::span<const IoHash> Cas)
+{
+ m_State->m_CasChunks.AddChunksToSet(Cas);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
CasGc::CasGc(CasStore& Store) : m_CasStore(Store)
{
}
diff --git a/zenstore/include/zenstore/CAS.h b/zenstore/include/zenstore/CAS.h
index 86e7e78d9..dc7e260ab 100644
--- a/zenstore/include/zenstore/CAS.h
+++ b/zenstore/include/zenstore/CAS.h
@@ -19,6 +19,8 @@
namespace zen {
+class GcContext;
+
struct CasStoreConfiguration
{
// Root directory for CAS store
@@ -50,24 +52,6 @@ private:
std::unordered_set<IoHash> m_ChunkSet;
};
-/** Garbage Collection context object
- */
-
-class GcContext
-{
-public:
- GcContext();
- ~GcContext();
-
- void ContributeCids(std::span<const IoHash> Cid);
- void ContributeCas(std::span<const IoHash> Hash);
-
-private:
- struct GcState;
-
- std::unique_ptr<GcState> m_State;
-};
-
/** Context object for data scrubbing
*
* Data scrubbing is when we traverse stored data to validate it and
diff --git a/zenstore/include/zenstore/gc.h b/zenstore/include/zenstore/gc.h
index 055843547..33a43f4d2 100644
--- a/zenstore/include/zenstore/gc.h
+++ b/zenstore/include/zenstore/gc.h
@@ -11,6 +11,27 @@ namespace zen {
class CasStore;
struct IoHash;
+/** Garbage Collection context object
+ */
+
+class GcContext
+{
+public:
+ GcContext();
+ ~GcContext();
+
+ void ContributeCids(std::span<const IoHash> Cid);
+ void ContributeCas(std::span<const IoHash> Hash);
+
+private:
+ struct GcState;
+
+ std::unique_ptr<GcState> m_State;
+};
+
+/** GC
+ */
+
class CasGc
{
public: