diff options
Diffstat (limited to 'src/zenserver/vfs')
| -rw-r--r-- | src/zenserver/vfs/vfsimpl.cpp | 450 | ||||
| -rw-r--r-- | src/zenserver/vfs/vfsimpl.h | 100 | ||||
| -rw-r--r-- | src/zenserver/vfs/vfsservice.cpp | 59 | ||||
| -rw-r--r-- | src/zenserver/vfs/vfsservice.h | 13 |
4 files changed, 8 insertions, 614 deletions
diff --git a/src/zenserver/vfs/vfsimpl.cpp b/src/zenserver/vfs/vfsimpl.cpp deleted file mode 100644 index d22738827..000000000 --- a/src/zenserver/vfs/vfsimpl.cpp +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "vfsimpl.h" -#include "vfsservice.h" - -#include <zencore/fmtutils.h> -#include <zencore/logging.h> -#include <zenstore/cache/structuredcachestore.h> -#include <zenvfs/projfs.h> -#include <zenvfs/vfs.h> - -#include <memory> -#include <unordered_map> - -#if ZEN_WITH_VFS - -namespace zen { - -using namespace std::literals; - -////////////////////////////////////////////////////////////////////////// - -VfsOplogDataSource::VfsOplogDataSource(std::string_view ProjectId, std::string_view OplogId, Ref<ProjectStore> InProjectStore) -: m_ProjectId(ProjectId) -, m_OplogId(OplogId) -, m_ProjectStore(std::move(InProjectStore)) -{ -} - -void -VfsOplogDataSource::ReadNamedData(std::string_view Path, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) -{ - ZEN_UNUSED(Path, Buffer, ByteOffset, ByteCount); -} - -void -VfsOplogDataSource::ReadChunkData(const Oid& ChunkId, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) -{ - IoBuffer ChunkBuffer = m_ProjectStore->GetChunk(m_ProjectId, m_OplogId, ChunkId); - if (ChunkBuffer) - { - ZEN_ASSERT(ChunkBuffer.GetSize() >= ByteOffset); - ZEN_ASSERT(ChunkBuffer.GetSize() - ByteOffset >= ByteCount); - MutableMemoryView Target(Buffer, ByteCount); - Target.CopyFrom(ChunkBuffer.GetView().Mid(ByteOffset, ByteCount)); - } -} - -void -VfsOplogDataSource::PopulateDirectory(std::string NodePath, VfsTreeNode& DirNode) -{ - // This should never be called - ZEN_UNUSED(NodePath, DirNode); -} - -////////////////////////////////////////////////////////////////////////// - -VfsCacheDataSource::VfsCacheDataSource(std::string_view NamespaceId, std::string_view BucketId, Ref<ZenCacheStore> InCacheStore) -: m_NamespaceId(NamespaceId) -, m_BucketId(BucketId) -, m_CacheStore(std::move(InCacheStore)) -{ -} - -VfsCacheDataSource::~VfsCacheDataSource() -{ -} - -void -VfsCacheDataSource::ReadNamedData(std::string_view Name, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) -{ - if (auto DotIndex = Name.find_first_of('.'); DotIndex != std::string_view::npos) - { - Name = Name.substr(0, DotIndex); - } - - IoHash HashKey = IoHash::FromHexString(Name); - - CacheRequestContext CacheContext{}; - - ZenCacheValue Value; - if (m_CacheStore->Get(CacheContext, m_NamespaceId, m_BucketId, HashKey, /* out */ Value)) - { - // TODO bounds check! - auto DataPtr = reinterpret_cast<const uint8_t*>(Value.Value.GetData()) + ByteOffset; - - memcpy(Buffer, DataPtr, ByteCount); - - return; - } -} - -void -VfsCacheDataSource::ReadChunkData(const Oid& ChunkId, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) -{ - ZEN_UNUSED(ChunkId, Buffer, ByteOffset, ByteCount); -} - -void -VfsCacheDataSource::PopulateDirectory(std::string NodePath, VfsTreeNode& DirNode) -{ - ZEN_UNUSED(NodePath, DirNode); -} - -////////////////////////////////////////////////////////////////////////// - -VfsService::Impl::Impl() -{ -} - -VfsService::Impl::~Impl() -{ - Unmount(); -} - -void -VfsService::Impl::Mount(std::string_view MountPoint) -{ - ZEN_INFO("VFS mount requested at '{}'", MountPoint); - -# if ZEN_PLATFORM_WINDOWS - if (!IsProjFsAvailable()) - { - throw std::runtime_error("Projected File System component not available"); - } -# endif - - if (!m_MountpointPath.empty()) - { - throw std::runtime_error("VFS already mounted"); - } - - m_MountpointPath = MountPoint; - - RefreshVfs(); -} - -void -VfsService::Impl::Unmount() -{ - if (m_MountpointPath.empty()) - { - return; - } - - ZEN_INFO("unmounting VFS from '{}'", m_MountpointPath); - - m_MountpointPath.clear(); - - RefreshVfs(); -} - -void -VfsService::Impl::AddService(Ref<ProjectStore>&& Ps) -{ - m_ProjectStore = std::move(Ps); - - RefreshVfs(); -} - -void -VfsService::Impl::AddService(Ref<ZenCacheStore>&& Z$) -{ - m_ZenCacheStore = std::move(Z$); - - RefreshVfs(); -} - -void -VfsService::Impl::RefreshVfs() -{ - if (m_VfsHost && m_MountpointPath.empty()) - { - m_VfsHost->RequestStop(); - m_VfsThread.join(); - m_VfsHost.reset(); - m_VfsThreadRunning.Reset(); - m_VfsDataSource = nullptr; - - return; - } - - if (!m_VfsHost && !m_MountpointPath.empty()) - { - m_VfsThread = std::thread(&VfsService::Impl::VfsThread, this); - m_VfsThreadRunning.Wait(); - - // At this stage, m_VfsHost should be initialized - - ZEN_ASSERT(m_VfsHost); - } - - if (m_ProjectStore && m_VfsHost) - { - if (!m_VfsDataSource) - { - m_VfsDataSource = new VfsServiceDataSource(this); - } - - m_VfsHost->AddMount("projects"sv, m_VfsDataSource); - } - - if (m_ZenCacheStore && m_VfsHost) - { - if (!m_VfsDataSource) - { - m_VfsDataSource = new VfsServiceDataSource(this); - } - - m_VfsHost->AddMount("ddc_cache"sv, m_VfsDataSource); - } -} - -void -VfsService::Impl::VfsThread() -{ - SetCurrentThreadName("VFS"); - - ZEN_INFO("VFS service thread now RUNNING"); - - try - { - m_VfsHost = std::make_unique<VfsHost>(m_MountpointPath); - m_VfsHost->Initialize(); - - m_VfsThreadRunning.Set(); - m_VfsHost->Run(); - } - catch (const std::exception& Ex) - { - ZEN_WARN("exception caught in VFS thread: {}", Ex.what()); - - m_VfsThreadException = std::current_exception(); - } - - if (m_VfsHost) - { - m_VfsHost->Cleanup(); - } - - ZEN_INFO("VFS service thread now EXITING"); -} - -////////////////////////////////////////////////////////////////////////// - -Ref<VfsOplogDataSource> -VfsServiceDataSource::GetOplogDataSource(std::string_view ProjectId, std::string_view OplogId) -{ - ExtendableStringBuilder<256> Key; - Key << ProjectId << "." << OplogId; - std::string StdKey{Key}; - - RwLock::ExclusiveLockScope _(m_Lock); - - if (auto It = m_OplogSourceMap.find(StdKey); It == m_OplogSourceMap.end()) - { - Ref<VfsOplogDataSource> NewSource{new VfsOplogDataSource(ProjectId, OplogId, m_VfsImpl->m_ProjectStore)}; - m_OplogSourceMap[StdKey] = NewSource; - return NewSource; - } - else - { - return It->second; - } -} - -Ref<VfsCacheDataSource> -VfsServiceDataSource::GetCacheDataSource(std::string_view NamespaceId, std::string_view BucketId) -{ - ExtendableStringBuilder<256> Key; - Key << NamespaceId << "." << BucketId; - std::string StdKey{Key}; - - RwLock::ExclusiveLockScope _(m_Lock); - - if (auto It = m_CacheSourceMap.find(StdKey); It == m_CacheSourceMap.end()) - { - Ref<VfsCacheDataSource> NewSource{new VfsCacheDataSource(NamespaceId, BucketId, m_VfsImpl->m_ZenCacheStore)}; - m_CacheSourceMap[StdKey] = NewSource; - return NewSource; - } - else - { - return It->second; - } -} - -void -VfsServiceDataSource::ReadNamedData(std::string_view Path, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) -{ - ZEN_UNUSED(Path, Buffer, ByteOffset, ByteCount); -} - -void -VfsServiceDataSource::ReadChunkData(const Oid& ChunkId, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) -{ - ZEN_UNUSED(ChunkId, Buffer, ByteOffset, ByteCount); -} - -void -VfsServiceDataSource::PopulateDirectory(std::string NodePath, VfsTreeNode& DirNode) -{ - if (NodePath == "projects"sv) - { - // Project enumeration - - m_VfsImpl->m_ProjectStore->DiscoverProjects(); - - m_VfsImpl->m_ProjectStore->IterateProjects( - [&](ProjectStore::Project& Project) { DirNode.AddVirtualNode(Project.Identifier, m_VfsImpl->m_VfsDataSource); }); - } - else if (NodePath.starts_with("projects\\"sv)) - { - std::string_view ProjectId{NodePath}; - ProjectId = ProjectId.substr(9); // Skip "projects\" - - if (std::string_view::size_type SlashOffset = ProjectId.find_first_of('\\'); SlashOffset == std::string_view::npos) - { - Ref<ProjectStore::Project> Project = m_VfsImpl->m_ProjectStore->OpenProject(ProjectId); - - if (!Project) - { - // No such project found? - - return; - } - - // Oplog enumeration - - std::vector<std::string> Oplogs = Project->ScanForOplogs(); - - for (auto& Oplog : Oplogs) - { - DirNode.AddVirtualNode(Oplog, m_VfsImpl->m_VfsDataSource); - } - } - else - { - std::string_view OplogId = ProjectId.substr(SlashOffset + 1); - ProjectId = ProjectId.substr(0, SlashOffset); - - Ref<ProjectStore::Project> Project = m_VfsImpl->m_ProjectStore->OpenProject(ProjectId); - - if (!Project) - { - // No such project found? - - return; - } - - // Oplog contents enumeration - - if (Ref<ProjectStore::Oplog> Oplog = Project->OpenOplog(OplogId, /*AllowCompact*/ false, /*VerifyPathOnDisk*/ true)) - { - Ref<VfsOplogDataSource> DataSource = GetOplogDataSource(ProjectId, OplogId); - - // Get metadata for all chunks - std::vector<ProjectStore::Oplog::ChunkInfo> ChunkInfos = Oplog->GetAllChunksInfo(Project->RootDir); - - std::unordered_map<zen::Oid, uint64_t> ChunkSizes; - - for (const auto& Ci : ChunkInfos) - { - ChunkSizes[Ci.ChunkId] = Ci.ChunkSize; - } - - auto EmitFilesForDataArray = [&](zen::CbArrayView DataArray) { - for (auto DataIter : DataArray) - { - if (zen::CbObjectView Data = DataIter.AsObjectView()) - { - std::filesystem::path FileName(Data["filename"sv].AsU8String()); - zen::Oid ChunkId = Data["id"sv].AsObjectId(); - - if (auto FindIt = ChunkSizes.find(ChunkId); FindIt != ChunkSizes.end()) - { - DirNode.AddFileNode(FileName.string(), FindIt->second /* file size */, ChunkId, DataSource); - } - else - { - ZEN_WARN("no chunk metadata found for chunk {} (file: '{}')", ChunkId, FileName); - } - } - } - }; - - Oplog->IterateOplog( - [&](CbObjectView Op) { - EmitFilesForDataArray(Op["packagedata"sv].AsArrayView()); - EmitFilesForDataArray(Op["bulkdata"sv].AsArrayView()); - }, - ProjectStore::Oplog::Paging{}); - - DirNode.AddFileNode("stats.json", 42, Oid::Zero); - } - } - } - else if (NodePath == "ddc_cache"sv) - { - // Namespace enumeration - - std::vector<std::string> Namespaces = m_VfsImpl->m_ZenCacheStore->GetNamespaces(); - - for (auto& Namespace : Namespaces) - { - DirNode.AddVirtualNode(Namespace, m_VfsImpl->m_VfsDataSource); - } - } - else if (NodePath.starts_with("ddc_cache\\"sv)) - { - std::string_view NamespaceId{NodePath}; - NamespaceId = NamespaceId.substr(10); // Skip "ddc_cache\" - - auto& Cache = m_VfsImpl->m_ZenCacheStore; - - if (std::string_view::size_type SlashOffset = NamespaceId.find_first_of('\\'); SlashOffset == std::string_view::npos) - { - // Bucket enumeration - - if (auto NsInfo = Cache->GetNamespaceInfo(NamespaceId)) - { - for (auto& BucketName : NsInfo->BucketNames) - { - DirNode.AddVirtualNode(BucketName, m_VfsImpl->m_VfsDataSource); - } - } - } - else - { - // Bucket contents enumeration - - std::string_view BucketId = NamespaceId.substr(SlashOffset + 1); - NamespaceId = NamespaceId.substr(0, SlashOffset); - - Ref<VfsCacheDataSource> DataSource = GetCacheDataSource(NamespaceId, BucketId); - - auto Enumerator = [&](const IoHash& Key, const CacheValueDetails::ValueDetails& Details) { - ExtendableStringBuilder<64> KeyString; - Key.ToHexString(KeyString); - KeyString.Append(".udd"); - DirNode.AddFileNode(KeyString, Details.Size, Oid::Zero, DataSource); - }; - - Cache->EnumerateBucketContents(NamespaceId, BucketId, Enumerator); - } - } -} - -} // namespace zen -#endif diff --git a/src/zenserver/vfs/vfsimpl.h b/src/zenserver/vfs/vfsimpl.h deleted file mode 100644 index 0dabf2c67..000000000 --- a/src/zenserver/vfs/vfsimpl.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "vfsservice.h" - -#include <zencore/logging.h> -#include <zenstore/projectstore.h> -#include <zenvfs/vfs.h> - -#if ZEN_WITH_VFS - -# include <memory> -# include <unordered_map> - -namespace zen { - -struct VfsOplogDataSource : public VfsTreeDataSource -{ - VfsOplogDataSource(std::string_view ProjectId, std::string_view OplogId, Ref<ProjectStore> InProjectStore); - - virtual void ReadNamedData(std::string_view Path, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) override; - virtual void ReadChunkData(const Oid& ChunkId, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) override; - virtual void PopulateDirectory(std::string NodePath, VfsTreeNode& DirNode) override; - -private: - std::string m_ProjectId; - std::string m_OplogId; - Ref<ProjectStore> m_ProjectStore; -}; - -struct VfsCacheDataSource : public VfsTreeDataSource -{ - VfsCacheDataSource(std::string_view NamespaceId, std::string_view BucketId, Ref<ZenCacheStore> InCacheStore); - ~VfsCacheDataSource(); - - virtual void ReadNamedData(std::string_view Path, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) override; - virtual void ReadChunkData(const Oid& ChunkId, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) override; - virtual void PopulateDirectory(std::string NodePath, VfsTreeNode& DirNode) override; - -private: - std::string m_NamespaceId; - std::string m_BucketId; - Ref<ZenCacheStore> m_CacheStore; -}; - -struct VfsServiceDataSource : public VfsTreeDataSource -{ - VfsServiceDataSource(VfsService::Impl* VfsImpl) : m_VfsImpl(VfsImpl) {} - - virtual void ReadNamedData(std::string_view Path, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) override; - virtual void ReadChunkData(const Oid& ChunkId, void* Buffer, uint64_t ByteOffset, uint64_t ByteCount) override; - virtual void PopulateDirectory(std::string NodePath, VfsTreeNode& DirNode) override; - -private: - VfsService::Impl* m_VfsImpl = nullptr; - - RwLock m_Lock; - std::unordered_map<std::string, Ref<VfsOplogDataSource>> m_OplogSourceMap; - std::unordered_map<std::string, Ref<VfsCacheDataSource>> m_CacheSourceMap; - - Ref<VfsOplogDataSource> GetOplogDataSource(std::string_view ProjectId, std::string_view OplogId); - Ref<VfsCacheDataSource> GetCacheDataSource(std::string_view NamespaceId, std::string_view BucketId); -}; - -////////////////////////////////////////////////////////////////////////// - -struct VfsService::Impl -{ - Impl(); - ~Impl(); - - void Mount(std::string_view MountPoint); - void Unmount(); - void AddService(Ref<ProjectStore>&&); - void AddService(Ref<ZenCacheStore>&&); - - inline std::string GetMountpointPath() { return m_MountpointPath; } - inline bool IsVfsRunning() const { return !!m_VfsHost.get(); } - -private: - Ref<ProjectStore> m_ProjectStore; - Ref<ZenCacheStore> m_ZenCacheStore; - Ref<VfsServiceDataSource> m_VfsDataSource; - std::string m_MountpointPath; - - std::unique_ptr<VfsHost> m_VfsHost; - std::thread m_VfsThread; - Event m_VfsThreadRunning; - std::exception_ptr m_VfsThreadException; - - void RefreshVfs(); - void VfsThread(); - - friend struct VfsServiceDataSource; -}; - -} // namespace zen - -#endif diff --git a/src/zenserver/vfs/vfsservice.cpp b/src/zenserver/vfs/vfsservice.cpp index bf761f8d1..863ec348a 100644 --- a/src/zenserver/vfs/vfsservice.cpp +++ b/src/zenserver/vfs/vfsservice.cpp @@ -1,7 +1,8 @@ // Copyright Epic Games, Inc. All Rights Reserved. #include "vfsservice.h" -#include "vfsimpl.h" + +#include <zenstore/vfsimpl.h> #include <zencore/compactbinarybuilder.h> @@ -61,10 +62,8 @@ GetContentAsCbObject(HttpServerRequest& HttpReq, CbObject& Cb) // echo {"method": "mount", "params": {"path": "d:\\VFS_ROOT"}} | curl.exe http://localhost:8558/vfs --data-binary @- // echo {"method": "unmount"} | curl.exe http://localhost:8558/vfs --data-binary @- -VfsService::VfsService(HttpStatusService& StatusService) : m_StatusService(StatusService) +VfsService::VfsService(HttpStatusService& StatusService, VfsServiceImpl* ServiceImpl) : m_StatusService(StatusService), m_Impl(ServiceImpl) { - m_Impl = new Impl; - m_Router.RegisterRoute( "info", [&](HttpRouterRequest& Request) { @@ -142,67 +141,19 @@ VfsService::VfsService(HttpStatusService& StatusService) : m_StatusService(Statu VfsService::~VfsService() { m_StatusService.UnregisterHandler("vfs", *this); - delete m_Impl; -} - -void -VfsService::Mount(std::string_view MountPoint) -{ - m_Impl->Mount(MountPoint); -} - -void -VfsService::Unmount() -{ - m_Impl->Unmount(); -} - -void -VfsService::AddService(Ref<ProjectStore>&& Ps) -{ - m_Impl->AddService(std::move(Ps)); -} - -void -VfsService::AddService(Ref<ZenCacheStore>&& Z$) -{ - m_Impl->AddService(std::move(Z$)); } #else -VfsService::VfsService(HttpStatusService& StatusService) : m_StatusService(StatusService) +VfsService::VfsService(HttpStatusService& StatusService, VfsServiceImpl* ServiceImpl) : m_StatusService(StatusService) { - ZEN_UNUSED(StatusService); + ZEN_UNUSED(ServiceImpl); } VfsService::~VfsService() { } -void -VfsService::Mount(std::string_view MountPoint) -{ - ZEN_UNUSED(MountPoint); -} - -void -VfsService::Unmount() -{ -} - -void -VfsService::AddService(Ref<ProjectStore>&& Ps) -{ - ZEN_UNUSED(Ps); -} - -void -VfsService::AddService(Ref<ZenCacheStore>&& Z$) -{ - ZEN_UNUSED(Z$); -} - #endif const char* diff --git a/src/zenserver/vfs/vfsservice.h b/src/zenserver/vfs/vfsservice.h index 0d0168e23..4e06da878 100644 --- a/src/zenserver/vfs/vfsservice.h +++ b/src/zenserver/vfs/vfsservice.h @@ -5,7 +5,6 @@ #include <zenbase/refcount.h> #include <zenhttp/httpserver.h> #include <zenhttp/httpstatus.h> -#include <zenvfs/vfs.h> #include <memory> @@ -13,6 +12,7 @@ namespace zen { class ProjectStore; class ZenCacheStore; +struct VfsServiceImpl; /** Virtual File System service @@ -28,23 +28,16 @@ class ZenCacheStore; class VfsService : public HttpService, public IHttpStatusProvider { public: - explicit VfsService(HttpStatusService& StatusService); + explicit VfsService(HttpStatusService& StatusService, VfsServiceImpl* ServiceImpl); ~VfsService(); - void Mount(std::string_view MountPoint); - void Unmount(); - - void AddService(Ref<ProjectStore>&&); - void AddService(Ref<ZenCacheStore>&&); - protected: virtual const char* BaseUri() const override; virtual void HandleRequest(HttpServerRequest& HttpServiceRequest) override; virtual void HandleStatusRequest(HttpServerRequest& Request) override; private: - struct Impl; - Impl* m_Impl = nullptr; + VfsServiceImpl* m_Impl = nullptr; HttpStatusService& m_StatusService; HttpRequestRouter m_Router; |