diff options
| author | Stefan Boberg <[email protected]> | 2021-10-05 22:25:53 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-10-05 22:25:53 +0200 |
| commit | 20ac7384f8ca558f1fb933eda846604792240ea0 (patch) | |
| tree | e5c95b422b847af50b77807af916e389fcaf83aa /zenserver | |
| parent | stats: Mean returns zero when the count is zero (diff) | |
| download | zen-20ac7384f8ca558f1fb933eda846604792240ea0.tar.xz zen-20ac7384f8ca558f1fb933eda846604792240ea0.zip | |
Merged from upstream
Diffstat (limited to 'zenserver')
| -rw-r--r-- | zenserver/cache/structuredcache.cpp | 25 | ||||
| -rw-r--r-- | zenserver/cache/structuredcache.h | 22 | ||||
| -rw-r--r-- | zenserver/cache/structuredcachestore.cpp | 194 | ||||
| -rw-r--r-- | zenserver/cache/structuredcachestore.h | 31 | ||||
| -rw-r--r-- | zenserver/monitoring/httpstats.cpp | 50 | ||||
| -rw-r--r-- | zenserver/monitoring/httpstats.h | 37 | ||||
| -rw-r--r-- | zenserver/monitoring/httpstatus.cpp | 50 | ||||
| -rw-r--r-- | zenserver/monitoring/httpstatus.h | 37 | ||||
| -rw-r--r-- | zenserver/upstream/upstreamcache.cpp | 68 | ||||
| -rw-r--r-- | zenserver/upstream/zen.cpp | 6 | ||||
| -rw-r--r-- | zenserver/upstream/zen.h | 5 | ||||
| -rw-r--r-- | zenserver/xmake.lua | 15 | ||||
| -rw-r--r-- | zenserver/zenserver.cpp | 283 | ||||
| -rw-r--r-- | zenserver/zenserver.vcxproj | 7 | ||||
| -rw-r--r-- | zenserver/zenserver.vcxproj.filters | 7 |
15 files changed, 587 insertions, 250 deletions
diff --git a/zenserver/cache/structuredcache.cpp b/zenserver/cache/structuredcache.cpp index d6174caf6..27bb1c5cd 100644 --- a/zenserver/cache/structuredcache.cpp +++ b/zenserver/cache/structuredcache.cpp @@ -12,6 +12,7 @@ #include <zenhttp/httpserver.h> #include <zenstore/CAS.h> +#include "monitoring/httpstats.h" #include "structuredcache.h" #include "structuredcachestore.h" #include "upstream/jupiter.h" @@ -149,13 +150,19 @@ ParseCachePolicy(const HttpServerRequest::QueryParams& QueryParams) HttpStructuredCacheService::HttpStructuredCacheService(ZenCacheStore& InCacheStore, CasStore& InStore, CidStore& InCidStore, + HttpStatsService& StatsService, + HttpStatusService& StatusService, std::unique_ptr<UpstreamCache> UpstreamCache) : m_Log(logging::Get("cache")) , m_CacheStore(InCacheStore) +, m_StatsService(StatsService) +, m_StatusService(StatusService) , m_CasStore(InStore) , m_CidStore(InCidStore) , m_UpstreamCache(std::move(UpstreamCache)) { + StatsService.RegisterHandler("z$", *this); + StatusService.RegisterHandler("z$", *this); } HttpStructuredCacheService::~HttpStructuredCacheService() @@ -200,13 +207,6 @@ HttpStructuredCacheService::HandleRequest(HttpServerRequest& Request) { std::string_view Key = Request.RelativeUri(); - if (Key.empty() || Key == "stats.json") - { - $.Cancel(); - - return HandleStatusRequest(Request); - } - if (std::all_of(begin(Key), end(Key), [](const char c) { return std::isalnum(c); })) { // Bucket reference @@ -870,10 +870,9 @@ HttpStructuredCacheService::ValidateKeyUri(HttpServerRequest& Request, CacheRef& } void -HttpStructuredCacheService::HandleStatusRequest(zen::HttpServerRequest& Request) +HttpStructuredCacheService::HandleStatsRequest(zen::HttpServerRequest& Request) { CbObjectWriter Cbo; - Cbo << "ok" << true; EmitSnapshot("requests", m_HttpRequests, Cbo); @@ -899,4 +898,12 @@ HttpStructuredCacheService::HandleStatusRequest(zen::HttpServerRequest& Request) Request.WriteResponse(HttpResponseCode::OK, Cbo.Save()); } +void +HttpStructuredCacheService::HandleStatusRequest(zen::HttpServerRequest& Request) +{ + CbObjectWriter Cbo; + Cbo << "ok" << true; + Request.WriteResponse(HttpResponseCode::OK, Cbo.Save()); +} + } // namespace zen diff --git a/zenserver/cache/structuredcache.h b/zenserver/cache/structuredcache.h index a360878bd..703e24ed3 100644 --- a/zenserver/cache/structuredcache.h +++ b/zenserver/cache/structuredcache.h @@ -5,6 +5,9 @@ #include <zencore/stats.h> #include <zenhttp/httpserver.h> +#include "monitoring/httpstats.h" +#include "monitoring/httpstatus.h" + #include <memory> namespace spdlog { @@ -47,12 +50,14 @@ enum class CachePolicy : uint8_t; * */ -class HttpStructuredCacheService : public zen::HttpService +class HttpStructuredCacheService : public HttpService, public IHttpStatsProvider, public IHttpStatusProvider { public: HttpStructuredCacheService(ZenCacheStore& InCacheStore, - zen::CasStore& InCasStore, - zen::CidStore& InCidStore, + CasStore& InCasStore, + CidStore& InCidStore, + HttpStatsService& StatsService, + HttpStatusService& StatusService, std::unique_ptr<UpstreamCache> UpstreamCache); ~HttpStructuredCacheService(); @@ -86,13 +91,16 @@ private: void HandleGetCachePayload(zen::HttpServerRequest& Request, const CacheRef& Ref, CachePolicy Policy); void HandlePutCachePayload(zen::HttpServerRequest& Request, const CacheRef& Ref, CachePolicy Policy); void HandleCacheBucketRequest(zen::HttpServerRequest& Request, std::string_view Bucket); - void HandleStatusRequest(zen::HttpServerRequest& Request); + virtual void HandleStatsRequest(zen::HttpServerRequest& Request) override; + virtual void HandleStatusRequest(zen::HttpServerRequest& Request) override; spdlog::logger& Log() { return m_Log; } spdlog::logger& m_Log; - zen::ZenCacheStore& m_CacheStore; - zen::CasStore& m_CasStore; - zen::CidStore& m_CidStore; + ZenCacheStore& m_CacheStore; + HttpStatsService& m_StatsService; + HttpStatusService& m_StatusService; + CasStore& m_CasStore; + CidStore& m_CidStore; std::unique_ptr<UpstreamCache> m_UpstreamCache; uint64_t m_LastScrubTime = 0; metrics::OperationTiming m_HttpRequests; diff --git a/zenserver/cache/structuredcachestore.cpp b/zenserver/cache/structuredcachestore.cpp index b97f0830f..83a21f87a 100644 --- a/zenserver/cache/structuredcachestore.cpp +++ b/zenserver/cache/structuredcachestore.cpp @@ -32,6 +32,8 @@ ZenCacheStore::ZenCacheStore(CasStore& Cas, const std::filesystem::path& RootDir { ZEN_INFO("initializing structured cache at '{}'", RootDir); CreateDirectories(RootDir); + + m_DiskLayer.DiscoverBuckets(); } ZenCacheStore::~ZenCacheStore() @@ -149,6 +151,10 @@ ZenCacheMemoryLayer::Get(std::string_view InBucket, const IoHash& HashKey, ZenCa _.ReleaseNow(); + // There's a race here. Since the lock is released early to allow + // inserts, the bucket delete path could end up deleting the + // underlying data structure + return Bucket->Get(HashKey, OutValue); } @@ -210,11 +216,13 @@ ZenCacheMemoryLayer::GarbageCollect(GcContext& GcCtx) void ZenCacheMemoryLayer::CacheBucket::Scrub(ScrubContext& Ctx) { + RwLock::SharedLockScope _(m_bucketLock); + std::vector<IoHash> BadHashes; for (auto& Kv : m_cacheMap) { - if (Kv.first != IoHash::HashBuffer(Kv.second)) + if (Kv.first != IoHash::HashBuffer(Kv.second.Payload)) { BadHashes.push_back(Kv.first); } @@ -222,10 +230,16 @@ ZenCacheMemoryLayer::CacheBucket::Scrub(ScrubContext& Ctx) if (!BadHashes.empty()) { - Ctx.ReportBadChunks(BadHashes); + Ctx.ReportBadCasChunks(BadHashes); } } +void +ZenCacheMemoryLayer::CacheBucket::GarbageCollect(GcContext& GcCtx) +{ + ZEN_UNUSED(GcCtx); +} + bool ZenCacheMemoryLayer::CacheBucket::Get(const IoHash& HashKey, ZenCacheValue& OutValue) { @@ -237,18 +251,26 @@ ZenCacheMemoryLayer::CacheBucket::Get(const IoHash& HashKey, ZenCacheValue& OutV } else { - OutValue.Value = bucketIt->second; + BucketValue& Value = bucketIt.value(); + OutValue.Value = Value.Payload; + Value.LastAccess = GetCurrentTimeStamp(); return true; } } +uint64_t +ZenCacheMemoryLayer::CacheBucket::GetCurrentTimeStamp() +{ + return GetLofreqTimerValue(); +} + void ZenCacheMemoryLayer::CacheBucket::Put(const IoHash& HashKey, const ZenCacheValue& Value) { RwLock::ExclusiveLockScope _(m_bucketLock); - m_cacheMap[HashKey] = Value.Value; + m_cacheMap.insert_or_assign(HashKey, BucketValue{.LastAccess = GetCurrentTimeStamp(), .Payload = Value.Value}); } ////////////////////////////////////////////////////////////////////////// @@ -258,11 +280,17 @@ ZenCacheMemoryLayer::CacheBucket::Put(const IoHash& HashKey, const ZenCacheValue struct DiskLocation { - uint64_t OffsetAndFlags; - uint32_t Size; - uint32_t IndexDataSize; + inline DiskLocation() = default; + + inline DiskLocation(uint64_t Offset, uint64_t ValueSize, uint32_t IndexSize, uint64_t Flags) + : OffsetAndFlags(CombineOffsetAndFlags(Offset, Flags)) + , LowerSize(ValueSize & 0xFFFFffff) + , IndexDataSize(IndexSize) + { + } - static const uint64_t kOffsetMask = 0x00FF'ffFF'ffFF'ffFFull; + static const uint64_t kOffsetMask = 0x0000'ffFF'ffFF'ffFFull; + static const uint64_t kSizeMask = 0x00FF'0000'0000'0000ull; static const uint64_t kFlagsMask = 0xff00'0000'0000'0000ull; static const uint64_t kStandaloneFile = 0x8000'0000'0000'0000ull; static const uint64_t kStructured = 0x4000'0000'0000'0000ull; @@ -270,6 +298,7 @@ struct DiskLocation static uint64_t CombineOffsetAndFlags(uint64_t Offset, uint64_t Flags) { return Offset | Flags; } inline uint64_t Offset() const { return OffsetAndFlags & kOffsetMask; } + inline uint64_t Size() const { return LowerSize; } inline uint64_t IsFlagSet(uint64_t Flag) const { return OffsetAndFlags & Flag; } inline ZenContentType GetContentType() const { @@ -282,6 +311,11 @@ struct DiskLocation return ContentType; } + +private: + uint64_t OffsetAndFlags = 0; + uint32_t LowerSize = 0; + uint32_t IndexDataSize = 0; }; struct DiskIndexEntry @@ -299,7 +333,7 @@ struct ZenCacheDiskLayer::CacheBucket CacheBucket(CasStore& Cas); ~CacheBucket(); - void OpenOrCreate(std::filesystem::path BucketDir); + void OpenOrCreate(std::filesystem::path BucketDir, bool AllowCreate = true); static bool Delete(std::filesystem::path BucketDir); bool Get(const IoHash& HashKey, ZenCacheValue& OutValue); @@ -309,13 +343,13 @@ struct ZenCacheDiskLayer::CacheBucket void Scrub(ScrubContext& Ctx); void GarbageCollect(GcContext& GcCtx); - inline bool IsOk() const { return m_Ok; } + inline bool IsOk() const { return m_IsOk; } private: CasStore& m_CasStore; std::filesystem::path m_BucketDir; Oid m_BucketId; - bool m_Ok = false; + bool m_IsOk = false; uint64_t m_LargeObjectThreshold = 64 * 1024; // These files are used to manage storage of small objects for this bucket @@ -355,7 +389,7 @@ ZenCacheDiskLayer::CacheBucket::Delete(std::filesystem::path BucketDir) } void -ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir) +ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir, bool AllowCreate) { CreateDirectories(BucketDir); @@ -382,17 +416,23 @@ ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir) { ManifestFile.Read(&m_BucketId, sizeof(Oid), 0); - m_Ok = true; + m_IsOk = true; } - if (!m_Ok) + if (!m_IsOk) { ManifestFile.Close(); } } - if (!m_Ok) + if (!m_IsOk) { + if (AllowCreate == false) + { + // Invalid bucket + return; + } + // No manifest file found, this is a new bucket ManifestFile.Open(ManifestPath, /* IsCreate */ true, Ec); @@ -424,13 +464,13 @@ ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir) m_SlogFile.Replay([&](const DiskIndexEntry& Record) { m_Index[Record.Key] = Record.Location; - MaxFileOffset = std::max<uint64_t>(MaxFileOffset, Record.Location.Offset() + Record.Location.Size); + MaxFileOffset = std::max<uint64_t>(MaxFileOffset, Record.Location.Offset() + Record.Location.Size()); }); m_WriteCursor = (MaxFileOffset + 15) & ~15; } - m_Ok = true; + m_IsOk = true; } void @@ -453,7 +493,7 @@ ZenCacheDiskLayer::CacheBucket::GetInlineCacheValue(const DiskLocation& Loc, Zen { if (!Loc.IsFlagSet(DiskLocation::kStandaloneFile)) { - OutValue.Value = IoBufferBuilder::MakeFromFileHandle(m_SobsFile.Handle(), Loc.Offset(), Loc.Size); + OutValue.Value = IoBufferBuilder::MakeFromFileHandle(m_SobsFile.Handle(), Loc.Offset(), Loc.Size()); OutValue.Value.SetContentType(Loc.GetContentType()); return true; @@ -482,7 +522,7 @@ ZenCacheDiskLayer::CacheBucket::GetStandaloneCacheValue(const IoHash& HashKey, Z bool ZenCacheDiskLayer::CacheBucket::Get(const IoHash& HashKey, ZenCacheValue& OutValue) { - if (!m_Ok) + if (!m_IsOk) { return false; } @@ -509,7 +549,7 @@ ZenCacheDiskLayer::CacheBucket::Get(const IoHash& HashKey, ZenCacheValue& OutVal void ZenCacheDiskLayer::CacheBucket::Put(const IoHash& HashKey, const ZenCacheValue& Value) { - if (!m_Ok) + if (!m_IsOk) { return; } @@ -531,10 +571,9 @@ ZenCacheDiskLayer::CacheBucket::Put(const IoHash& HashKey, const ZenCacheValue& RwLock::ExclusiveLockScope _(m_IndexLock); - DiskLocation Loc{.OffsetAndFlags = DiskLocation::CombineOffsetAndFlags(m_WriteCursor, EntryFlags), - .Size = gsl::narrow<uint32_t>(Value.Value.Size())}; + DiskLocation Loc(m_WriteCursor, Value.Value.Size(), 0, EntryFlags); - m_WriteCursor = RoundUp(m_WriteCursor + Loc.Size, 16); + m_WriteCursor = RoundUp(m_WriteCursor + Loc.Size(), 16); if (auto it = m_Index.find(HashKey); it == m_Index.end()) { @@ -544,11 +583,13 @@ ZenCacheDiskLayer::CacheBucket::Put(const IoHash& HashKey, const ZenCacheValue& else { // TODO: should check if write is idempotent and bail out if it is? + // this would requiring comparing contents on disk unless we add a + // content hash to the index entry it.value() = Loc; } m_SlogFile.Append({.Key = HashKey, .Location = Loc}); - m_SobsFile.Write(Value.Value.Data(), Loc.Size, Loc.Offset()); + m_SobsFile.Write(Value.Value.Data(), Loc.Size(), Loc.Offset()); } } @@ -572,55 +613,45 @@ ZenCacheDiskLayer::CacheBucket::Flush() void ZenCacheDiskLayer::CacheBucket::Scrub(ScrubContext& Ctx) { - std::vector<DiskIndexEntry> StandaloneFiles; - - std::vector<IoHash> BadChunks; - std::vector<IoBuffer> BadStandaloneChunks; + std::atomic<uint64_t> ScrubbedChunks{0}, ScrubbedBytes{0}; { RwLock::SharedLockScope _(m_IndexLock); for (auto& Kv : m_Index) { - const IoHash& Hash = Kv.first; - const DiskLocation& Loc = Kv.second; + const IoHash& HashKey = Kv.first; + const DiskLocation& Loc = Kv.second; ZenCacheValue Value; - if (!GetInlineCacheValue(Loc, Value)) + if (GetInlineCacheValue(Loc, Value)) { - ZEN_ASSERT(Loc.IsFlagSet(DiskLocation::kStandaloneFile)); - StandaloneFiles.push_back({.Key = Hash, .Location = Loc}); + // Validate contents } else { - if (GetStandaloneCacheValue(Hash, Value, Loc)) + if (Loc.IsFlagSet(DiskLocation::kStandaloneFile)) { - // Hash contents - - const IoHash ComputedHash = HashBuffer(Value.Value); - - if (ComputedHash != Hash) + if (GetStandaloneCacheValue(HashKey, Value, Loc)) { - BadChunks.push_back(Hash); + // Note: we cannot currently validate contents since we don't + // have a content hash! + } + else + { + // Value not found } - } - else - { - // Non-existent } } } } - if (Ctx.RunRecovery()) - { - // Clean out bad chunks - } + Ctx.ReportScrubbed(ScrubbedChunks, ScrubbedBytes); - if (!BadChunks.empty()) + if (Ctx.RunRecovery()) { - Ctx.ReportBadChunks(BadChunks); + // Clean out bad data } } @@ -681,7 +712,7 @@ ZenCacheDiskLayer::CacheBucket::PutLargeObject(const IoHash& HashKey, const ZenC RwLock::ExclusiveLockScope _(m_IndexLock); - DiskLocation Loc{.OffsetAndFlags = DiskLocation::CombineOffsetAndFlags(0, EntryFlags), .Size = 0}; + DiskLocation Loc(/* Offset */ 0, Value.Value.Size(), 0, EntryFlags); if (auto it = m_Index.find(HashKey); it == m_Index.end()) { @@ -739,7 +770,7 @@ ZenCacheDiskLayer::Get(std::string_view InBucket, const IoHash& HashKey, ZenCach std::filesystem::path BucketPath = m_RootDir; BucketPath /= std::string(InBucket); - Bucket->OpenOrCreate(BucketPath.c_str()); + Bucket->OpenOrCreate(BucketPath); } } @@ -782,7 +813,7 @@ ZenCacheDiskLayer::Put(std::string_view InBucket, const IoHash& HashKey, const Z std::filesystem::path bucketPath = m_RootDir; bucketPath /= std::string(InBucket); - Bucket->OpenOrCreate(bucketPath.c_str()); + Bucket->OpenOrCreate(bucketPath); } } @@ -794,6 +825,63 @@ ZenCacheDiskLayer::Put(std::string_view InBucket, const IoHash& HashKey, const Z } } +void +ZenCacheDiskLayer::DiscoverBuckets() +{ + FileSystemTraversal Traversal; + struct Visitor : public FileSystemTraversal::TreeVisitor + { + virtual void VisitFile([[maybe_unused]] const std::filesystem::path& Parent, + [[maybe_unused]] const path_view& File, + [[maybe_unused]] uint64_t FileSize) override + { + } + + virtual bool VisitDirectory([[maybe_unused]] const std::filesystem::path& Parent, const path_view& DirectoryName) override + { + Dirs.push_back(std::wstring(DirectoryName)); + return false; + } + + std::vector<std::wstring> Dirs; + } Visit; + + Traversal.TraverseFileSystem(m_RootDir, Visit); + + // Initialize buckets + + RwLock::ExclusiveLockScope _(m_Lock); + + for (const std::wstring& BucketName : Visit.Dirs) + { + // New bucket needs to be created + + std::string BucketName8 = WideToUtf8(BucketName); + + if (auto It = m_Buckets.find(BucketName8); It != m_Buckets.end()) + { + } + else + { + auto InsertResult = m_Buckets.try_emplace(BucketName8, m_CasStore); + + std::filesystem::path BucketPath = m_RootDir; + BucketPath /= BucketName8; + + CacheBucket& Bucket = InsertResult.first->second; + + Bucket.OpenOrCreate(BucketPath, /* AllowCreate */ false); + + if (!Bucket.IsOk()) + { + ZEN_WARN("Found directory '{}' in our base directory '{}' but it is not a valid bucket", BucketName8, m_RootDir); + + m_Buckets.erase(InsertResult.first); + } + } + } +} + bool ZenCacheDiskLayer::DropBucket(std::string_view InBucket) { diff --git a/zenserver/cache/structuredcachestore.h b/zenserver/cache/structuredcachestore.h index 011f13323..4753af627 100644 --- a/zenserver/cache/structuredcachestore.h +++ b/zenserver/cache/structuredcachestore.h @@ -46,6 +46,11 @@ struct ZenCacheValue CbObject IndexData; }; +/** In-memory cache storage + + Intended for small values which are frequently accessed + + */ class ZenCacheMemoryLayer { public: @@ -58,19 +63,39 @@ public: void Scrub(ScrubContext& Ctx); void GarbageCollect(GcContext& GcCtx); + struct Configuration + { + uint64_t TargetFootprintBytes = 16 * 1024 * 1024; + uint64_t ScavengeThreshold = 4 * 1024 * 1024; + }; + + const Configuration& GetConfiguration() const { return m_Configuration; } + void SetConfiguration(const Configuration& NewConfig) { m_Configuration = NewConfig; } + private: struct CacheBucket { - RwLock m_bucketLock; - tsl::robin_map<IoHash, IoBuffer> m_cacheMap; + struct BucketValue + { + uint64_t LastAccess = 0; + IoBuffer Payload; + }; + + RwLock m_bucketLock; + tsl::robin_map<IoHash, BucketValue> m_cacheMap; bool Get(const IoHash& HashKey, ZenCacheValue& OutValue); void Put(const IoHash& HashKey, const ZenCacheValue& Value); void Scrub(ScrubContext& Ctx); + void GarbageCollect(GcContext& GcCtx); + + private: + uint64_t GetCurrentTimeStamp(); }; RwLock m_Lock; std::unordered_map<std::string, CacheBucket> m_Buckets; + Configuration m_Configuration; }; class ZenCacheDiskLayer @@ -86,6 +111,8 @@ public: void Scrub(ScrubContext& Ctx); void GarbageCollect(GcContext& GcCtx); + void DiscoverBuckets(); + private: /** A cache bucket manages a single directory containing metadata and data for that bucket diff --git a/zenserver/monitoring/httpstats.cpp b/zenserver/monitoring/httpstats.cpp new file mode 100644 index 000000000..de04294d0 --- /dev/null +++ b/zenserver/monitoring/httpstats.cpp @@ -0,0 +1,50 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "httpstats.h" + +namespace zen { + +HttpStatsService::HttpStatsService() : m_Log(logging::Get("stats")) +{ +} + +HttpStatsService::~HttpStatsService() +{ +} + +const char* +HttpStatsService::BaseUri() const +{ + return "/stats/"; +} + +void +HttpStatsService::RegisterHandler(std::string_view Id, IHttpStatsProvider& Provider) +{ + RwLock::ExclusiveLockScope _(m_Lock); + m_Providers.insert_or_assign(std::string(Id), &Provider); +} + +void +HttpStatsService::HandleRequest(HttpServerRequest& Request) +{ + using namespace std::literals; + + std::string_view Key = Request.RelativeUri(); + + switch (Request.RequestVerb()) + { + case HttpVerb::kHead: + case HttpVerb::kGet: + if (auto It = m_Providers.find(std::string{Key}); It != end(m_Providers)) + { + return It->second->HandleStatsRequest(Request); + } + + [[fallthrough]]; + default: + return; + } +} + +} // namespace zen diff --git a/zenserver/monitoring/httpstats.h b/zenserver/monitoring/httpstats.h new file mode 100644 index 000000000..1c3c79dd0 --- /dev/null +++ b/zenserver/monitoring/httpstats.h @@ -0,0 +1,37 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include <zencore/logging.h> +#include <zenhttp/httpserver.h> + +#include <map> + +namespace zen { + +struct IHttpStatsProvider +{ + virtual void HandleStatsRequest(HttpServerRequest& Request) = 0; +}; + +class HttpStatsService : public HttpService +{ +public: + HttpStatsService(); + ~HttpStatsService(); + + virtual const char* BaseUri() const override; + virtual void HandleRequest(HttpServerRequest& Request) override; + void RegisterHandler(std::string_view Id, IHttpStatsProvider& Provider); + +private: + spdlog::logger& m_Log; + HttpRequestRouter m_Router; + + inline spdlog::logger& Log() { return m_Log; } + + RwLock m_Lock; + std::map<std::string, IHttpStatsProvider*> m_Providers; +}; + +} // namespace zen
\ No newline at end of file diff --git a/zenserver/monitoring/httpstatus.cpp b/zenserver/monitoring/httpstatus.cpp new file mode 100644 index 000000000..e12662b1c --- /dev/null +++ b/zenserver/monitoring/httpstatus.cpp @@ -0,0 +1,50 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "httpstatus.h" + +namespace zen { + +HttpStatusService::HttpStatusService() : m_Log(logging::Get("status")) +{ +} + +HttpStatusService::~HttpStatusService() +{ +} + +const char* +HttpStatusService::BaseUri() const +{ + return "/status/"; +} + +void +HttpStatusService::RegisterHandler(std::string_view Id, IHttpStatusProvider& Provider) +{ + RwLock::ExclusiveLockScope _(m_Lock); + m_Providers.insert_or_assign(std::string(Id), &Provider); +} + +void +HttpStatusService::HandleRequest(HttpServerRequest& Request) +{ + using namespace std::literals; + + std::string_view Key = Request.RelativeUri(); + + switch (Request.RequestVerb()) + { + case HttpVerb::kHead: + case HttpVerb::kGet: + if (auto It = m_Providers.find(std::string{Key}); It != end(m_Providers)) + { + return It->second->HandleStatusRequest(Request); + } + + [[fallthrough]]; + default: + return; + } +} + +} // namespace zen diff --git a/zenserver/monitoring/httpstatus.h b/zenserver/monitoring/httpstatus.h new file mode 100644 index 000000000..8f069f760 --- /dev/null +++ b/zenserver/monitoring/httpstatus.h @@ -0,0 +1,37 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include <zencore/logging.h> +#include <zenhttp/httpserver.h> + +#include <map> + +namespace zen { + +struct IHttpStatusProvider +{ + virtual void HandleStatusRequest(HttpServerRequest& Request) = 0; +}; + +class HttpStatusService : public HttpService +{ +public: + HttpStatusService(); + ~HttpStatusService(); + + virtual const char* BaseUri() const override; + virtual void HandleRequest(HttpServerRequest& Request) override; + void RegisterHandler(std::string_view Id, IHttpStatusProvider& Provider); + +private: + spdlog::logger& m_Log; + HttpRequestRouter m_Router; + + RwLock m_Lock; + std::map<std::string, IHttpStatusProvider*> m_Providers; + + inline spdlog::logger& Log() { return m_Log; } +}; + +} // namespace zen
\ No newline at end of file diff --git a/zenserver/upstream/upstreamcache.cpp b/zenserver/upstream/upstreamcache.cpp index a183e7ebf..ba5991b3f 100644 --- a/zenserver/upstream/upstreamcache.cpp +++ b/zenserver/upstream/upstreamcache.cpp @@ -8,6 +8,7 @@ #include <zencore/compactbinarybuilder.h> #include <zencore/compactbinarypackage.h> #include <zencore/compactbinaryvalidation.h> +#include <zencore/blockingqueue.h> #include <zencore/fmtutils.h> #include <zencore/stats.h> #include <zencore/stream.h> @@ -23,7 +24,6 @@ #include <algorithm> #include <atomic> -#include <deque> #include <thread> #include <unordered_map> @@ -33,70 +33,6 @@ using namespace std::literals; namespace detail { - template<typename T> - class BlockingQueue - { - public: - BlockingQueue() = default; - - ~BlockingQueue() { CompleteAdding(); } - - void Enqueue(T&& Item) - { - { - std::lock_guard Lock(m_Lock); - m_Queue.emplace_back(std::move(Item)); - m_Size++; - } - - m_NewItemSignal.notify_one(); - } - - bool WaitAndDequeue(T& Item) - { - if (m_CompleteAdding.load()) - { - return false; - } - - std::unique_lock Lock(m_Lock); - m_NewItemSignal.wait(Lock, [this]() { return !m_Queue.empty() || m_CompleteAdding.load(); }); - - if (!m_Queue.empty()) - { - Item = std::move(m_Queue.front()); - m_Queue.pop_front(); - m_Size--; - - return true; - } - - return false; - } - - void CompleteAdding() - { - if (!m_CompleteAdding.load()) - { - m_CompleteAdding.store(true); - m_NewItemSignal.notify_all(); - } - } - - std::size_t Size() const - { - std::unique_lock Lock(m_Lock); - return m_Queue.size(); - } - - private: - mutable std::mutex m_Lock; - std::condition_variable m_NewItemSignal; - std::deque<T> m_Queue; - std::atomic_bool m_CompleteAdding{false}; - std::atomic_uint32_t m_Size; - }; - class JupiterUpstreamEndpoint final : public UpstreamEndpoint { public: @@ -1029,7 +965,7 @@ private: spdlog::logger& Log() { return m_Log; } - using UpstreamQueue = detail::BlockingQueue<UpstreamCacheRecord>; + using UpstreamQueue = BlockingQueue<UpstreamCacheRecord>; struct RunState { diff --git a/zenserver/upstream/zen.cpp b/zenserver/upstream/zen.cpp index c988a6b0b..6141fd397 100644 --- a/zenserver/upstream/zen.cpp +++ b/zenserver/upstream/zen.cpp @@ -328,7 +328,9 @@ namespace detail { ////////////////////////////////////////////////////////////////////////// -ZenStructuredCacheClient::ZenStructuredCacheClient(std::string_view ServiceUrl) : m_ServiceUrl(ServiceUrl) +ZenStructuredCacheClient::ZenStructuredCacheClient(std::string_view ServiceUrl) +: m_Log(logging::Get(std::string_view("zenclient"))) +, m_ServiceUrl(ServiceUrl) { } @@ -369,7 +371,7 @@ ZenStructuredCacheClient::FreeSessionState(detail::ZenCacheSessionState* State) using namespace std::literals; ZenStructuredCacheSession::ZenStructuredCacheSession(ZenStructuredCacheClient& OuterClient) -: m_Log(logging::Get("zenclient"sv)) +: m_Log(OuterClient.Log()) , m_Client(OuterClient) { m_SessionState = m_Client.AllocSessionState(); diff --git a/zenserver/upstream/zen.h b/zenserver/upstream/zen.h index 158be668a..12e46bd8d 100644 --- a/zenserver/upstream/zen.h +++ b/zenserver/upstream/zen.h @@ -138,8 +138,11 @@ public: std::string_view ServiceUrl() const { return m_ServiceUrl; } + inline spdlog::logger& Log() { return m_Log; } + private: - std::string m_ServiceUrl; + spdlog::logger& m_Log; + std::string m_ServiceUrl; RwLock m_SessionStateLock; std::list<detail::ZenCacheSessionState*> m_SessionStateCache; diff --git a/zenserver/xmake.lua b/zenserver/xmake.lua index 7a6981fcd..fb1ba651d 100644 --- a/zenserver/xmake.lua +++ b/zenserver/xmake.lua @@ -32,3 +32,18 @@ target("zenserver") add_packages( "vcpkg::cxxopts", "vcpkg::mimalloc") + + on_load(function(target) + local commit, err = os.iorun("git log -1 --format=\"%h-%cI\"") + if commit ~= nil then + commit = commit:gsub("%s+", "") + commit = commit:gsub("\n", "") + if is_mode("release") then + commit = "rel-" .. commit + else + commit = "dbg-" .. commit + end + target:add("defines","BUILD_VERSION=\"" .. commit .. "\"") + print("build version " .. commit) + end + end) diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp index f9b4d5677..18c59636d 100644 --- a/zenserver/zenserver.cpp +++ b/zenserver/zenserver.cpp @@ -1,5 +1,6 @@ // Copyright Epic Games, Inc. All Rights Reserved. +#include <zencore/compactbinarybuilder.h> #include <zencore/filesystem.h> #include <zencore/fmtutils.h> #include <zencore/iobuffer.h> @@ -31,6 +32,10 @@ #include <set> #include <unordered_map> +#if !defined(BUILD_VERSION) +# define BUILD_VERSION ("dev-build") +#endif + ////////////////////////////////////////////////////////////////////////// // We don't have any doctest code in this file but this is needed to bring // in some shared code into the executable @@ -83,6 +88,8 @@ #include "diag/diagsvcs.h" #include "experimental/frontend.h" #include "experimental/usnjournal.h" +#include "monitoring/httpstats.h" +#include "monitoring/httpstatus.h" #include "projectstore.h" #include "testing/httptest.h" #include "testing/launch.h" @@ -96,17 +103,16 @@ namespace zen { -class ZenServer -{ - ZenServerState::ZenServerEntry* m_ServerEntry = nullptr; +using namespace std::literals; +class ZenServer : public IHttpStatusProvider +{ public: void Initialize(ZenServiceConfig& ServiceConfig, int BasePort, int ParentPid, ZenServerState::ZenServerEntry* ServerEntry) { - m_ServerEntry = ServerEntry; using namespace fmt::literals; - ZEN_INFO(ZEN_APP_NAME " initializing"); + m_ServerEntry = ServerEntry; m_DebugOptionForcedCrash = ServiceConfig.ShouldCrash; if (ParentPid) @@ -140,6 +146,15 @@ public: // Ok so now we're configured, let's kick things off + m_Http = zen::CreateHttpServer(); + m_Http->Initialize(BasePort); + m_Http->RegisterService(m_HealthService); + m_Http->RegisterService(m_StatsService); + m_Http->RegisterService(m_StatusService); + m_StatusService.RegisterHandler("status", *this); + + // Initialize storage and services + ZEN_INFO("initializing storage"); zen::CasStoreConfiguration Config; @@ -167,95 +182,7 @@ public: if (ServiceConfig.StructuredCacheEnabled) { - using namespace std::literals; - auto ValueOrDefault = [](std::string_view Value, std::string_view Default) { return Value.empty() ? Default : Value; }; - - ZEN_INFO("instantiating structured cache service"); - m_CacheStore = std::make_unique<ZenCacheStore>(*m_CasStore, m_DataRoot / "cache"); - - std::unique_ptr<zen::UpstreamCache> UpstreamCache; - if (ServiceConfig.UpstreamCacheConfig.CachePolicy != UpstreamCachePolicy::Disabled) - { - const ZenUpstreamCacheConfig& UpstreamConfig = ServiceConfig.UpstreamCacheConfig; - - zen::UpstreamCacheOptions UpstreamOptions; - UpstreamOptions.ReadUpstream = - (uint8_t(ServiceConfig.UpstreamCacheConfig.CachePolicy) & uint8_t(UpstreamCachePolicy::Read)) != 0; - UpstreamOptions.WriteUpstream = - (uint8_t(ServiceConfig.UpstreamCacheConfig.CachePolicy) & uint8_t(UpstreamCachePolicy::Write)) != 0; - - if (UpstreamConfig.UpstreamThreadCount < 32) - { - UpstreamOptions.ThreadCount = static_cast<uint32_t>(UpstreamConfig.UpstreamThreadCount); - } - - UpstreamOptions.StatsEnabled = UpstreamConfig.StatsEnabled; - - UpstreamCache = zen::MakeUpstreamCache(UpstreamOptions, *m_CacheStore, *m_CidStore); - - if (!UpstreamConfig.ZenConfig.Urls.empty()) - { - std::unique_ptr<zen::UpstreamEndpoint> ZenEndpoint = zen::MakeZenUpstreamEndpoint(UpstreamConfig.ZenConfig.Urls); - UpstreamCache->RegisterEndpoint(std::move(ZenEndpoint)); - } - - { - zen::CloudCacheClientOptions Options; - if (UpstreamConfig.JupiterConfig.UseProductionSettings) - { - Options = zen::CloudCacheClientOptions{ - .ServiceUrl = "https://jupiter.devtools.epicgames.com"sv, - .DdcNamespace = "ue.ddc"sv, - .BlobStoreNamespace = "ue.ddc"sv, - .OAuthProvider = "https://epicgames.okta.com/oauth2/auso645ojjWVdRI3d0x7/v1/token"sv, - .OAuthClientId = "0oao91lrhqPiAlaGD0x7"sv, - .OAuthSecret = "-GBWjjenhCgOwhxL5yBKNJECVIoDPH0MK4RDuN7d"sv, - .UseLegacyDdc = false}; - } - else if (UpstreamConfig.JupiterConfig.UseDevelopmentSettings) - { - Options = zen::CloudCacheClientOptions{ - .ServiceUrl = "https://jupiter.devtools-dev.epicgames.com"sv, - .DdcNamespace = "ue4.ddc"sv, - .BlobStoreNamespace = "test.ddc"sv, - .OAuthProvider = "https://epicgames.okta.com/oauth2/auso645ojjWVdRI3d0x7/v1/token"sv, - .OAuthClientId = "0oao91lrhqPiAlaGD0x7"sv, - .OAuthSecret = "-GBWjjenhCgOwhxL5yBKNJECVIoDPH0MK4RDuN7d"sv, - .UseLegacyDdc = false}; - } - - Options.ServiceUrl = ValueOrDefault(UpstreamConfig.JupiterConfig.Url, Options.ServiceUrl); - Options.DdcNamespace = ValueOrDefault(UpstreamConfig.JupiterConfig.DdcNamespace, Options.DdcNamespace); - Options.BlobStoreNamespace = ValueOrDefault(UpstreamConfig.JupiterConfig.Namespace, Options.BlobStoreNamespace); - Options.OAuthProvider = ValueOrDefault(UpstreamConfig.JupiterConfig.OAuthProvider, Options.OAuthProvider); - Options.OAuthClientId = ValueOrDefault(UpstreamConfig.JupiterConfig.OAuthClientId, Options.OAuthClientId); - Options.OAuthSecret = ValueOrDefault(UpstreamConfig.JupiterConfig.OAuthClientSecret, Options.OAuthSecret); - Options.UseLegacyDdc |= UpstreamConfig.JupiterConfig.UseLegacyDdc; - - if (!Options.ServiceUrl.empty()) - { - std::unique_ptr<zen::UpstreamEndpoint> JupiterEndpoint = zen::MakeJupiterUpstreamEndpoint(Options); - UpstreamCache->RegisterEndpoint(std::move(JupiterEndpoint)); - } - } - - if (UpstreamCache->Initialize()) - { - ZEN_INFO("upstream cache active ({})", - UpstreamOptions.ReadUpstream && UpstreamOptions.WriteUpstream ? "READ|WRITE" - : UpstreamOptions.ReadUpstream ? "READONLY" - : UpstreamOptions.WriteUpstream ? "WRITEONLY" - : "DISABLED"); - } - else - { - UpstreamCache.reset(); - ZEN_INFO("NOT using upstream cache"); - } - } - - m_StructuredCacheService.reset( - new zen::HttpStructuredCacheService(*m_CacheStore, *m_CasStore, *m_CidStore, std::move(UpstreamCache))); + InitializeStructuredCache(ServiceConfig); } else { @@ -273,13 +200,8 @@ public: } #endif - m_Http = zen::CreateHttpServer(); - m_Http->Initialize(BasePort); - m_Http->RegisterService(m_HealthService); - m_Http->RegisterService(m_TestService); // NOTE: this is intentionally not limited to test mode as it's useful for diagnostics m_Http->RegisterService(m_TestingService); - m_Http->RegisterService(m_AdminService); if (m_HttpProjectService) @@ -305,12 +227,15 @@ public: } m_FrontendService = std::make_unique<HttpFrontendService>(m_ContentRoot); + if (m_FrontendService) { m_Http->RegisterService(*m_FrontendService); } } + void InitializeStructuredCache(ZenServiceConfig& ServiceConfig); + #if ZEN_ENABLE_MESH void StartMesh(int BasePort) { @@ -351,8 +276,12 @@ public: const bool IsInteractiveMode = zen::IsInteractiveSession() && !m_TestMode; + m_CurrentState = kRunning; + m_Http->Run(IsInteractiveMode); + m_CurrentState = kShuttingDown; + ZEN_INFO(ZEN_APP_NAME " exiting"); m_IoContext.stop(); @@ -425,6 +354,7 @@ public: void Scrub() { + Stopwatch Timer; ZEN_INFO("Storage validation STARTING"); ScrubContext Ctx; @@ -433,7 +363,13 @@ public: m_ProjectStore->Scrub(Ctx); m_StructuredCacheService->Scrub(Ctx); - ZEN_INFO("Storage validation DONE"); + const uint64_t ElapsedTimeMs = Timer.GetElapsedTimeMs(); + + ZEN_INFO("Storage validation DONE in {}, ({} in {} chunks - {})", + NiceTimeSpanMs(ElapsedTimeMs), + NiceBytes(Ctx.ScrubbedBytes()), + Ctx.ScrubbedChunks(), + NiceByteRate(Ctx.ScrubbedBytes(), ElapsedTimeMs)); } void Flush() @@ -451,18 +387,51 @@ public: m_ProjectStore->Flush(); } + virtual void HandleStatusRequest(HttpServerRequest& Request) override + { + CbObjectWriter Cbo; + Cbo << "ok" << true; + Cbo << "state" << ToString(m_CurrentState); + Request.WriteResponse(HttpResponseCode::OK, Cbo.Save()); + } + private: - bool m_IsDedicatedMode = false; - bool m_TestMode = false; - std::filesystem::path m_DataRoot; - std::filesystem::path m_ContentRoot; - std::jthread m_IoRunner; - asio::io_context m_IoContext; - asio::steady_timer m_PidCheckTimer{m_IoContext}; - zen::ProcessMonitor m_ProcessMonitor; - zen::NamedMutex m_ServerMutex; + ZenServerState::ZenServerEntry* m_ServerEntry = nullptr; + bool m_IsDedicatedMode = false; + bool m_TestMode = false; + std::filesystem::path m_DataRoot; + std::filesystem::path m_ContentRoot; + std::jthread m_IoRunner; + asio::io_context m_IoContext; + asio::steady_timer m_PidCheckTimer{m_IoContext}; + zen::ProcessMonitor m_ProcessMonitor; + zen::NamedMutex m_ServerMutex; + + enum ServerState + { + kInitializing, + kRunning, + kShuttingDown + } m_CurrentState = kInitializing; + + std::string_view ToString(ServerState Value) + { + switch (Value) + { + case kInitializing: + return "initializing"sv; + case kRunning: + return "running"sv; + case kShuttingDown: + return "shutdown"sv; + default: + return "unknown"sv; + } + } zen::Ref<zen::HttpServer> m_Http; + zen::HttpStatusService m_StatusService; + zen::HttpStatsService m_StatsService; std::unique_ptr<zen::CasStore> m_CasStore{zen::CreateCasStore()}; std::unique_ptr<zen::CidStore> m_CidStore; std::unique_ptr<zen::ZenCacheStore> m_CacheStore; @@ -485,6 +454,100 @@ private: bool m_DebugOptionForcedCrash = false; }; +void +ZenServer::InitializeStructuredCache(ZenServiceConfig& ServiceConfig) +{ + using namespace std::literals; + auto ValueOrDefault = [](std::string_view Value, std::string_view Default) { return Value.empty() ? Default : Value; }; + + ZEN_INFO("instantiating structured cache service"); + m_CacheStore = std::make_unique<ZenCacheStore>(*m_CasStore, m_DataRoot / "cache"); + + std::unique_ptr<zen::UpstreamCache> UpstreamCache; + if (ServiceConfig.UpstreamCacheConfig.CachePolicy != UpstreamCachePolicy::Disabled) + { + const ZenUpstreamCacheConfig& UpstreamConfig = ServiceConfig.UpstreamCacheConfig; + + zen::UpstreamCacheOptions UpstreamOptions; + UpstreamOptions.ReadUpstream = (uint8_t(ServiceConfig.UpstreamCacheConfig.CachePolicy) & uint8_t(UpstreamCachePolicy::Read)) != 0; + UpstreamOptions.WriteUpstream = (uint8_t(ServiceConfig.UpstreamCacheConfig.CachePolicy) & uint8_t(UpstreamCachePolicy::Write)) != 0; + + if (UpstreamConfig.UpstreamThreadCount < 32) + { + UpstreamOptions.ThreadCount = static_cast<uint32_t>(UpstreamConfig.UpstreamThreadCount); + } + + UpstreamOptions.StatsEnabled = UpstreamConfig.StatsEnabled; + + UpstreamCache = zen::MakeUpstreamCache(UpstreamOptions, *m_CacheStore, *m_CidStore); + + if (!UpstreamConfig.ZenConfig.Urls.empty()) + { + std::unique_ptr<zen::UpstreamEndpoint> ZenEndpoint = zen::MakeZenUpstreamEndpoint(UpstreamConfig.ZenConfig.Urls); + UpstreamCache->RegisterEndpoint(std::move(ZenEndpoint)); + } + + { + zen::CloudCacheClientOptions Options; + if (UpstreamConfig.JupiterConfig.UseProductionSettings) + { + Options = zen::CloudCacheClientOptions{.ServiceUrl = "https://jupiter.devtools.epicgames.com"sv, + .DdcNamespace = "ue.ddc"sv, + .BlobStoreNamespace = "ue.ddc"sv, + .OAuthProvider = "https://epicgames.okta.com/oauth2/auso645ojjWVdRI3d0x7/v1/token"sv, + .OAuthClientId = "0oao91lrhqPiAlaGD0x7"sv, + .OAuthSecret = "-GBWjjenhCgOwhxL5yBKNJECVIoDPH0MK4RDuN7d"sv, + .UseLegacyDdc = false}; + } + else if (UpstreamConfig.JupiterConfig.UseDevelopmentSettings) + { + Options = zen::CloudCacheClientOptions{.ServiceUrl = "https://jupiter.devtools-dev.epicgames.com"sv, + .DdcNamespace = "ue4.ddc"sv, + .BlobStoreNamespace = "test.ddc"sv, + .OAuthProvider = "https://epicgames.okta.com/oauth2/auso645ojjWVdRI3d0x7/v1/token"sv, + .OAuthClientId = "0oao91lrhqPiAlaGD0x7"sv, + .OAuthSecret = "-GBWjjenhCgOwhxL5yBKNJECVIoDPH0MK4RDuN7d"sv, + .UseLegacyDdc = false}; + } + + Options.ServiceUrl = ValueOrDefault(UpstreamConfig.JupiterConfig.Url, Options.ServiceUrl); + Options.DdcNamespace = ValueOrDefault(UpstreamConfig.JupiterConfig.DdcNamespace, Options.DdcNamespace); + Options.BlobStoreNamespace = ValueOrDefault(UpstreamConfig.JupiterConfig.Namespace, Options.BlobStoreNamespace); + Options.OAuthProvider = ValueOrDefault(UpstreamConfig.JupiterConfig.OAuthProvider, Options.OAuthProvider); + Options.OAuthClientId = ValueOrDefault(UpstreamConfig.JupiterConfig.OAuthClientId, Options.OAuthClientId); + Options.OAuthSecret = ValueOrDefault(UpstreamConfig.JupiterConfig.OAuthClientSecret, Options.OAuthSecret); + Options.UseLegacyDdc |= UpstreamConfig.JupiterConfig.UseLegacyDdc; + + if (!Options.ServiceUrl.empty()) + { + std::unique_ptr<zen::UpstreamEndpoint> JupiterEndpoint = zen::MakeJupiterUpstreamEndpoint(Options); + UpstreamCache->RegisterEndpoint(std::move(JupiterEndpoint)); + } + } + + if (UpstreamCache->Initialize()) + { + ZEN_INFO("upstream cache active ({})", + UpstreamOptions.ReadUpstream && UpstreamOptions.WriteUpstream ? "READ|WRITE" + : UpstreamOptions.ReadUpstream ? "READONLY" + : UpstreamOptions.WriteUpstream ? "WRITEONLY" + : "DISABLED"); + } + else + { + UpstreamCache.reset(); + ZEN_INFO("NOT using upstream cache"); + } + } + + m_StructuredCacheService.reset(new zen::HttpStructuredCacheService(*m_CacheStore, + *m_CasStore, + *m_CidStore, + m_StatsService, + m_StatusService, + std::move(UpstreamCache))); +} + } // namespace zen class ZenWindowsService : public WindowsService @@ -532,7 +595,7 @@ ZenWindowsService::Run() ParseServiceConfig(GlobalOptions.DataDir, /* out */ ServiceConfig); - ZEN_INFO("zen cache server starting on port {}", GlobalOptions.BasePort); + ZEN_INFO(ZEN_APP_NAME " - starting on port {}, build '{}'", GlobalOptions.BasePort, BUILD_VERSION); ZenServerState ServerState; ServerState.Initialize(); diff --git a/zenserver/zenserver.vcxproj b/zenserver/zenserver.vcxproj index 335786fbf..7fad477a1 100644 --- a/zenserver/zenserver.vcxproj +++ b/zenserver/zenserver.vcxproj @@ -108,8 +108,12 @@ <ClInclude Include="cache\structuredcachestore.h" /> <ClInclude Include="compute\apply.h" /> <ClInclude Include="config.h" /> + <ClInclude Include="diag\formatters.h" /> <ClInclude Include="diag\logging.h" /> <ClInclude Include="experimental\frontend.h" /> + <ClInclude Include="experimental\vfs.h" /> + <ClInclude Include="monitoring\httpstats.h" /> + <ClInclude Include="monitoring\httpstatus.h" /> <ClInclude Include="resource.h" /> <ClInclude Include="sos\sos.h" /> <ClInclude Include="testing\httptest.h" /> @@ -134,6 +138,9 @@ <ClCompile Include="config.cpp" /> <ClCompile Include="diag\logging.cpp" /> <ClCompile Include="experimental\frontend.cpp" /> + <ClCompile Include="experimental\vfs.cpp" /> + <ClCompile Include="monitoring\httpstats.cpp" /> + <ClCompile Include="monitoring\httpstatus.cpp" /> <ClCompile Include="projectstore.cpp" /> <ClCompile Include="cache\cacheagent.cpp" /> <ClCompile Include="sos\sos.cpp" /> diff --git a/zenserver/zenserver.vcxproj.filters b/zenserver/zenserver.vcxproj.filters index 1c5b17fee..04e639a33 100644 --- a/zenserver/zenserver.vcxproj.filters +++ b/zenserver/zenserver.vcxproj.filters @@ -41,6 +41,10 @@ <ClInclude Include="experimental\frontend.h"> <Filter>experimental</Filter> </ClInclude> + <ClInclude Include="diag\formatters.h" /> + <ClInclude Include="experimental\vfs.h" /> + <ClInclude Include="monitoring\httpstats.h" /> + <ClInclude Include="monitoring\httpstatus.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="zenserver.cpp" /> @@ -77,6 +81,9 @@ <ClCompile Include="experimental\frontend.cpp"> <Filter>experimental</Filter> </ClCompile> + <ClCompile Include="experimental\vfs.cpp" /> + <ClCompile Include="monitoring\httpstats.cpp" /> + <ClCompile Include="monitoring\httpstatus.cpp" /> </ItemGroup> <ItemGroup> <Filter Include="cache"> |