// Copyright Epic Games, Inc. All Rights Reserved. #include #include "compactcas.h" #include "filecas.h" #include #include #include #include #include #include #include #include #include #include #include #include struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" when using /permissive- #include ////////////////////////////////////////////////////////////////////////// namespace zen { /** * Slightly less naive CAS store */ class CasImpl : public CasStore { public: CasImpl(); virtual ~CasImpl(); virtual void Initialize(const CasStoreConfiguration& InConfig) override; virtual CasStore::InsertResult InsertChunk(IoBuffer Chunk, const IoHash& ChunkHash) override; virtual IoBuffer FindChunk(const IoHash& ChunkHash) override; virtual void FilterChunks(CasChunkSet& InOutChunks) override; virtual void Flush() override; private: void PickDefaultDirectory(); CasContainerStrategy m_TinyStrategy; CasContainerStrategy m_SmallStrategy; FileCasStrategy m_LargeStrategy; }; CasImpl::CasImpl() : m_TinyStrategy(m_Config, m_Stats), m_SmallStrategy(m_Config, m_Stats), m_LargeStrategy(m_Config, m_Stats) { } CasImpl::~CasImpl() { } void CasImpl::Initialize(const CasStoreConfiguration& InConfig) { m_Config = InConfig; ZEN_INFO("initializing CAS pool at {}", m_Config.RootDirectory); // Ensure root directory exists - create if it doesn't exist already std::filesystem::create_directories(m_Config.RootDirectory); // Open or create manifest bool IsNewStore = false; { std::filesystem::path ManifestPath = m_Config.RootDirectory; ManifestPath /= ".ucas_root"; CAtlFile marker; HRESULT hRes = marker.Create(ManifestPath.c_str(), GENERIC_READ, 0, OPEN_EXISTING); if (FAILED(hRes)) { IsNewStore = true; ExtendableStringBuilder<128> manifest; manifest.Append("#CAS_ROOT\n"); // TODO: should write something meaningful here manifest.Append("ID="); zen::Oid id = zen::Oid::NewOid(); id.ToString(manifest); hRes = marker.Create(ManifestPath.c_str(), GENERIC_WRITE, 0, CREATE_ALWAYS); if (SUCCEEDED(hRes)) marker.Write(manifest.c_str(), (DWORD)manifest.Size()); } } // Initialize payload storage m_TinyStrategy.Initialize("tobs", 16, IsNewStore); m_SmallStrategy.Initialize("sobs", 4096, IsNewStore); } CasStore::InsertResult CasImpl::InsertChunk(IoBuffer Chunk, const IoHash& ChunkHash) { const uint64_t ChunkSize = Chunk.Size(); if (ChunkSize < m_Config.TinyValueThreshold) { ZEN_ASSERT(ChunkSize); return m_TinyStrategy.InsertChunk(Chunk, ChunkHash); } else if (ChunkSize < m_Config.HugeValueThreshold) { return m_SmallStrategy.InsertChunk(Chunk, ChunkHash); } return m_LargeStrategy.InsertChunk(Chunk, ChunkHash); } IoBuffer CasImpl::FindChunk(const IoHash& ChunkHash) { if (IoBuffer Found = m_SmallStrategy.FindChunk(ChunkHash)) { return Found; } if (IoBuffer Found = m_TinyStrategy.FindChunk(ChunkHash)) { return Found; } if (IoBuffer Found = m_LargeStrategy.FindChunk(ChunkHash)) { return Found; } // Not found return IoBuffer{}; } void CasImpl::FilterChunks(CasChunkSet& InOutChunks) { m_SmallStrategy.FilterChunks(InOutChunks); m_TinyStrategy.FilterChunks(InOutChunks); m_LargeStrategy.FilterChunks(InOutChunks); } void CasImpl::Flush() { m_SmallStrategy.Flush(); m_TinyStrategy.Flush(); m_LargeStrategy.Flush(); } ////////////////////////////////////////////////////////////////////////// CasStore* CreateCasStore() { return new CasImpl(); } ////////////////////////////////////////////////////////////////////////// // // Testing related code follows... // void CAS_forcelink() { } TEST_CASE("CasStore") { zen::CasStoreConfiguration config; config.RootDirectory = "c:\\temp\\test"; std::unique_ptr store{CreateCasStore()}; store->Initialize(config); } } // namespace zen