// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include #include #include "monitoring/httpstats.h" #include "monitoring/httpstatus.h" #include namespace spdlog { class logger; } namespace zen { class CasStore; class CidStore; class CbObjectView; class ScrubContext; class UpstreamCache; class ZenCacheStore; enum class CachePolicy : uint32_t; /** * Structured cache service. Imposes constraints on keys, supports blobs and * structured values * * Keys are structured as: * * {BucketId}/{KeyHash} * * Where BucketId is a lower-case alphanumeric string, and KeyHash is a 40-character * hexadecimal sequence. The hash value may be derived in any number of ways, it's * up to the application to pick an approach. * * Values may be structured or unstructured. Structured values are encoded using Unreal * Engine's compact binary encoding (see CbObject) * * Additionally, attachments may be addressed as: * * {BucketId}/{KeyHash}/{PayloadHash} * * Where the two initial components are the same as for the main endpoint * * The storage strategy is as follows: * * - Structured values are stored in a dedicated backing store per bucket * - Unstructured values and attachments are stored in the CAS pool * */ class HttpStructuredCacheService : public HttpService, public IHttpStatsProvider, public IHttpStatusProvider { public: HttpStructuredCacheService(ZenCacheStore& InCacheStore, CidStore& InCidStore, HttpStatsService& StatsService, HttpStatusService& StatusService, std::unique_ptr UpstreamCache); ~HttpStructuredCacheService(); virtual const char* BaseUri() const override; virtual void HandleRequest(zen::HttpServerRequest& Request) override; void Flush(); void Scrub(ScrubContext& Ctx); private: struct CacheRef { std::string BucketSegment; IoHash HashKey; IoHash PayloadId; }; struct CacheStats { std::atomic_uint64_t HitCount{}; std::atomic_uint64_t UpstreamHitCount{}; std::atomic_uint64_t MissCount{}; }; [[nodiscard]] bool ValidateKeyUri(zen::HttpServerRequest& Request, CacheRef& OutRef); void HandleCacheRecordRequest(zen::HttpServerRequest& Request, const CacheRef& Ref, CachePolicy Policy); void HandleGetCacheRecord(zen::HttpServerRequest& Request, const CacheRef& Ref, CachePolicy Policy); void HandlePutCacheRecord(zen::HttpServerRequest& Request, const CacheRef& Ref, CachePolicy Policy); void HandleCachePayloadRequest(zen::HttpServerRequest& Request, const CacheRef& Ref, CachePolicy Policy); void HandleGetCachePayload(zen::HttpServerRequest& Request, const CacheRef& Ref, CachePolicy Policy); void HandlePutCachePayload(zen::HttpServerRequest& Request, const CacheRef& Ref, CachePolicy Policy); void HandleRpcRequest(zen::HttpServerRequest& Request); void HandleRpcGetCacheRecords(zen::HttpServerRequest& Request, CbObjectView BatchRequest); void HandleRpcGetCachePayloads(zen::HttpServerRequest& Request, CbObjectView BatchRequest); void HandleCacheBucketRequest(zen::HttpServerRequest& Request, std::string_view Bucket); virtual void HandleStatsRequest(zen::HttpServerRequest& Request) override; virtual void HandleStatusRequest(zen::HttpServerRequest& Request) override; spdlog::logger& Log() { return m_Log; } spdlog::logger& m_Log; ZenCacheStore& m_CacheStore; HttpStatsService& m_StatsService; HttpStatusService& m_StatusService; CidStore& m_CidStore; std::unique_ptr m_UpstreamCache; uint64_t m_LastScrubTime = 0; metrics::OperationTiming m_HttpRequests; metrics::OperationTiming m_UpstreamGetRequestTiming; CacheStats m_CacheStats; }; } // namespace zen