aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/cache/httpstructuredcache.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-10-06 22:33:00 +0200
committerStefan Boberg <[email protected]>2025-10-06 22:33:00 +0200
commit1383dbdc563d90c170ab30ba622ee44e2e37e723 (patch)
tree59777db60000fe2ab2334f05776fb9ded4ca41fb /src/zenserver/cache/httpstructuredcache.cpp
parentMerge branch 'main' into sb/rpc-analysis (diff)
parent5.7.6 (diff)
downloadzen-1383dbdc563d90c170ab30ba622ee44e2e37e723.tar.xz
zen-1383dbdc563d90c170ab30ba622ee44e2e37e723.zip
Merge remote-tracking branch 'origin/main' into sb/rpc-analysis
Diffstat (limited to 'src/zenserver/cache/httpstructuredcache.cpp')
-rw-r--r--src/zenserver/cache/httpstructuredcache.cpp894
1 files changed, 426 insertions, 468 deletions
diff --git a/src/zenserver/cache/httpstructuredcache.cpp b/src/zenserver/cache/httpstructuredcache.cpp
index c62b5325e..dd5bf05cb 100644
--- a/src/zenserver/cache/httpstructuredcache.cpp
+++ b/src/zenserver/cache/httpstructuredcache.cpp
@@ -5,11 +5,14 @@
#include <zencore/compactbinary.h>
#include <zencore/compactbinarybuilder.h>
#include <zencore/compactbinarypackage.h>
+#include <zencore/compactbinaryutil.h>
#include <zencore/compactbinaryvalidation.h>
#include <zencore/compress.h>
#include <zencore/enumflags.h>
#include <zencore/fmtutils.h>
#include <zencore/logging.h>
+#include <zencore/memory/llm.h>
+#include <zencore/parallelwork.h>
#include <zencore/scopeguard.h>
#include <zencore/stream.h>
#include <zencore/timer.h>
@@ -17,14 +20,14 @@
#include <zencore/workthreadpool.h>
#include <zenhttp/httpserver.h>
#include <zenhttp/httpstats.h>
+#include <zenhttp/packageformat.h>
+#include <zenremotestore/jupiter/jupiterclient.h>
+#include <zenstore/cache/cache.h>
#include <zenstore/cache/structuredcachestore.h>
#include <zenstore/gc.h>
-#include <zenutil/cache/cache.h>
-#include <zenutil/cache/cacherequests.h>
-#include <zenutil/cache/rpcrecording.h>
-#include <zenutil/packageformat.h>
+#include <zenutil/rpcrecording.h>
+#include <zenutil/workerpools.h>
-#include "upstream/jupiter.h"
#include "upstream/upstreamcache.h"
#include "upstream/zen.h"
#include "zenstore/cidstore.h"
@@ -36,16 +39,20 @@
#include <queue>
#include <thread>
-#include <cpr/cpr.h>
#include <gsl/gsl-lite.hpp>
-#if ZEN_WITH_TESTS
-# include <zencore/testing.h>
-# include <zencore/testutils.h>
-#endif
-
namespace zen {
+const FLLMTag&
+GetCacheHttpTag()
+{
+ static FLLMTag CacheHttpTag("http", FLLMTag("cache"));
+
+ return CacheHttpTag;
+}
+
+extern const FLLMTag& GetCacheRpcTag();
+
using namespace std::literals;
//////////////////////////////////////////////////////////////////////////
@@ -63,184 +70,6 @@ namespace {
static constinit std::string_view HttpZCacheUtilStopRecording = "exec$/stop-recording"sv;
static constinit std::string_view HttpZCacheUtilReplayRecording = "exec$/replay-recording"sv;
static constinit std::string_view HttpZCacheDetailsPrefix = "details$"sv;
-
- constinit AsciiSet ValidNamespaceNameCharactersSet{"abcdefghijklmnopqrstuvwxyz0123456789-_.ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
- constinit AsciiSet ValidBucketNameCharactersSet{"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
-
- std::optional<std::string> GetValidNamespaceName(std::string_view Name)
- {
- if (Name.empty())
- {
- ZEN_WARN("Namespace is invalid, empty namespace is not allowed");
- return {};
- }
-
- if (Name.length() > 64)
- {
- ZEN_WARN("Namespace '{}' is invalid, length exceeds 64 characters", Name);
- return {};
- }
-
- if (!AsciiSet::HasOnly(Name, ValidNamespaceNameCharactersSet))
- {
- ZEN_WARN("Namespace '{}' is invalid, invalid characters detected", Name);
- return {};
- }
-
- return ToLower(Name);
- }
-
- std::optional<std::string> GetValidBucketName(std::string_view Name)
- {
- if (Name.empty())
- {
- ZEN_WARN("Bucket name is invalid, empty bucket name is not allowed");
- return {};
- }
-
- if (!AsciiSet::HasOnly(Name, ValidBucketNameCharactersSet))
- {
- ZEN_WARN("Bucket name '{}' is invalid, invalid characters detected", Name);
- return {};
- }
-
- return ToLower(Name);
- }
-
- std::optional<IoHash> GetValidIoHash(std::string_view Hash)
- {
- if (Hash.length() != IoHash::StringLength)
- {
- return {};
- }
-
- IoHash KeyHash;
- if (!ParseHexBytes(Hash.data(), Hash.size(), KeyHash.Hash))
- {
- return {};
- }
- return KeyHash;
- }
-
- struct HttpRequestData
- {
- std::optional<std::string> Namespace;
- std::optional<std::string> Bucket;
- std::optional<IoHash> HashKey;
- std::optional<IoHash> ValueContentId;
- };
-
- bool HttpRequestParseRelativeUri(std::string_view Key, HttpRequestData& Data)
- {
- std::vector<std::string_view> Tokens;
- uint32_t TokenCount = ForEachStrTok(Key, '/', [&](const std::string_view& Token) {
- Tokens.push_back(Token);
- return true;
- });
-
- switch (TokenCount)
- {
- case 0:
- return true;
- case 1:
- Data.Namespace = GetValidNamespaceName(Tokens[0]);
- return Data.Namespace.has_value();
- case 2:
- {
- std::optional<IoHash> PossibleHashKey = GetValidIoHash(Tokens[1]);
- if (PossibleHashKey.has_value())
- {
- // Legacy bucket/key request
- Data.Bucket = GetValidBucketName(Tokens[0]);
- if (!Data.Bucket.has_value())
- {
- return false;
- }
- Data.HashKey = PossibleHashKey;
- Data.Namespace = ZenCacheStore::DefaultNamespace;
- return true;
- }
- Data.Namespace = GetValidNamespaceName(Tokens[0]);
- if (!Data.Namespace.has_value())
- {
- return false;
- }
- Data.Bucket = GetValidBucketName(Tokens[1]);
- if (!Data.Bucket.has_value())
- {
- return false;
- }
- return true;
- }
- case 3:
- {
- std::optional<IoHash> PossibleHashKey = GetValidIoHash(Tokens[1]);
- if (PossibleHashKey.has_value())
- {
- // Legacy bucket/key/valueid request
- Data.Bucket = GetValidBucketName(Tokens[0]);
- if (!Data.Bucket.has_value())
- {
- return false;
- }
- Data.HashKey = PossibleHashKey;
- Data.ValueContentId = GetValidIoHash(Tokens[2]);
- if (!Data.ValueContentId.has_value())
- {
- return false;
- }
- Data.Namespace = ZenCacheStore::DefaultNamespace;
- return true;
- }
- Data.Namespace = GetValidNamespaceName(Tokens[0]);
- if (!Data.Namespace.has_value())
- {
- return false;
- }
- Data.Bucket = GetValidBucketName(Tokens[1]);
- if (!Data.Bucket.has_value())
- {
- return false;
- }
- Data.HashKey = GetValidIoHash(Tokens[2]);
- if (!Data.HashKey)
- {
- return false;
- }
- return true;
- }
- case 4:
- {
- Data.Namespace = GetValidNamespaceName(Tokens[0]);
- if (!Data.Namespace.has_value())
- {
- return false;
- }
-
- Data.Bucket = GetValidBucketName(Tokens[1]);
- if (!Data.Bucket.has_value())
- {
- return false;
- }
-
- Data.HashKey = GetValidIoHash(Tokens[2]);
- if (!Data.HashKey.has_value())
- {
- return false;
- }
-
- Data.ValueContentId = GetValidIoHash(Tokens[3]);
- if (!Data.ValueContentId.has_value())
- {
- return false;
- }
- return true;
- }
- default:
- return false;
- }
- }
-
} // namespace
//////////////////////////////////////////////////////////////////////////
@@ -250,7 +79,8 @@ HttpStructuredCacheService::HttpStructuredCacheService(ZenCacheStore& InCach
HttpStatsService& StatsService,
HttpStatusService& StatusService,
UpstreamCache& UpstreamCache,
- const DiskWriteBlocker* InDiskWriteBlocker)
+ const DiskWriteBlocker* InDiskWriteBlocker,
+ OpenProcessCache& InOpenProcessCache)
: m_Log(logging::Get("cache"))
, m_CacheStore(InCacheStore)
, m_StatsService(StatsService)
@@ -258,6 +88,7 @@ HttpStructuredCacheService::HttpStructuredCacheService(ZenCacheStore& InCach
, m_CidStore(InCidStore)
, m_UpstreamCache(UpstreamCache)
, m_DiskWriteBlocker(InDiskWriteBlocker)
+, m_OpenProcessCache(InOpenProcessCache)
, m_RpcHandler(m_Log, m_CacheStats, UpstreamCache, InCacheStore, InCidStore, InDiskWriteBlocker)
{
m_StatsService.RegisterHandler("z$", *this);
@@ -290,24 +121,6 @@ HttpStructuredCacheService::Flush()
}
void
-HttpStructuredCacheService::ScrubStorage(ScrubContext& Ctx)
-{
- if (m_LastScrubTime == Ctx.ScrubTimestamp())
- {
- return;
- }
-
- ZenCacheStore::Info Info = m_CacheStore.GetInfo();
-
- ZEN_INFO("scrubbing '{}'", Info.BasePath);
-
- m_LastScrubTime = Ctx.ScrubTimestamp();
-
- m_CidStore.ScrubStorage(Ctx);
- m_CacheStore.ScrubStorage(Ctx);
-}
-
-void
HttpStructuredCacheService::HandleDetailsRequest(HttpServerRequest& Request)
{
std::string_view Key = Request.RelativeUri();
@@ -538,18 +351,38 @@ HttpStructuredCacheService::HandleRequest(HttpServerRequest& Request)
{
ZEN_TRACE_CPU("z$::Http::HandleRequest");
+ ZEN_MEMSCOPE(GetCacheHttpTag());
+
metrics::OperationTiming::Scope $(m_HttpRequests);
- std::string_view Key = Request.RelativeUri();
- if (Key == HttpZCacheRPCPrefix)
+ const std::string_view Key = Request.RelativeUri();
+
+ std::string_view UriNamespace;
+
+ if (Key.ends_with(HttpZCacheRPCPrefix))
{
- return HandleRpcRequest(Request);
+ const size_t RpcOffset = Key.length() - HttpZCacheRPCPrefix.length();
+
+ if (RpcOffset)
+ {
+ std::string_view KeyPrefix = Key.substr(0, RpcOffset);
+
+ if (KeyPrefix.back() == '/')
+ {
+ KeyPrefix.remove_suffix(1);
+
+ UriNamespace = KeyPrefix;
+ }
+ }
+
+ return HandleRpcRequest(Request, UriNamespace);
}
if (Key == HttpZCacheUtilStartRecording)
{
- HttpServerRequest::QueryParams Params = Request.GetQueryParams();
- std::string RecordPath = cpr::util::urlDecode(std::string(Params.GetValue("path")));
+ HttpServerRequest::QueryParams Params = Request.GetQueryParams();
+
+ std::string RecordPath = UrlDecode(Params.GetValue("path"));
{
RwLock::ExclusiveLockScope _(m_RequestRecordingLock);
@@ -586,9 +419,11 @@ HttpStructuredCacheService::HandleRequest(HttpServerRequest& Request)
m_RequestRecorder.reset();
}
- HttpServerRequest::QueryParams Params = Request.GetQueryParams();
- std::string RecordPath = cpr::util::urlDecode(std::string(Params.GetValue("path")));
- uint32_t ThreadCount = std::thread::hardware_concurrency();
+ HttpServerRequest::QueryParams Params = Request.GetQueryParams();
+
+ std::string RecordPath = UrlDecode(Params.GetValue("path"));
+
+ uint32_t ThreadCount = std::thread::hardware_concurrency();
if (auto Param = Params.GetValue("thread_count"); Param.empty() == false)
{
if (auto Value = ParseInt<uint64_t>(Param))
@@ -602,7 +437,7 @@ HttpStructuredCacheService::HandleRequest(HttpServerRequest& Request)
std::unique_ptr<cache::IRpcRequestReplayer> Replayer(cache::MakeDiskRequestReplayer(RecordPath, false));
ReplayRequestRecorder(RequestContext, *Replayer, ThreadCount < 1 ? 1 : ThreadCount);
- ZEN_INFO("cache RPC replay STARTED");
+ ZEN_INFO("cache RPC replay COMPLETED");
Request.WriteResponse(HttpResponseCode::OK);
return;
@@ -614,8 +449,8 @@ HttpStructuredCacheService::HandleRequest(HttpServerRequest& Request)
return;
}
- HttpRequestData RequestData;
- if (!HttpRequestParseRelativeUri(Key, RequestData))
+ HttpCacheRequestData RequestData;
+ if (!HttpCacheRequestParseRelativeUri(Key, ZenCacheStore::DefaultNamespace, RequestData))
{
m_CacheStats.BadRequestCount++;
return Request.WriteResponse(HttpResponseCode::BadRequest); // invalid URL
@@ -740,7 +575,6 @@ HttpStructuredCacheService::HandleCacheNamespaceRequest(HttpServerRequest& Reque
ResponseWriter.AddInteger("MemCacheTargetFootprintBytes"sv, Info->Config.DiskLayerConfig.MemCacheTargetFootprintBytes);
ResponseWriter.AddInteger("MemCacheTrimIntervalSeconds"sv, Info->Config.DiskLayerConfig.MemCacheTrimIntervalSeconds);
ResponseWriter.AddInteger("MemCacheMaxAgeSeconds"sv, Info->Config.DiskLayerConfig.MemCacheMaxAgeSeconds);
- ResponseWriter.AddBool("EnableReferenceCaching"sv, Info->Config.DiskLayerConfig.BucketConfig.EnableReferenceCaching);
}
ResponseWriter.EndObject();
@@ -764,6 +598,82 @@ HttpStructuredCacheService::HandleCacheNamespaceRequest(HttpServerRequest& Reque
ResponseWriter.AddInteger("EntryCount", Info->DiskLayerInfo.EntryCount);
+ if (auto Buckets = HttpServerRequest::Decode(Request.GetQueryParams().GetValue("bucketsizes")); !Buckets.empty())
+ {
+ ResponseWriter.BeginObject("BucketSizes");
+
+ ResponseWriter.BeginArray("Buckets");
+
+ std::vector<std::string> BucketNames;
+ if (Buckets == "*") // Get all - empty FieldFilter equal getting all fields
+ {
+ BucketNames = Info.value().BucketNames;
+ }
+ else
+ {
+ ForEachStrTok(Buckets, ',', [&](std::string_view BucketName) {
+ BucketNames.push_back(std::string(BucketName));
+ return true;
+ });
+ }
+ WorkerThreadPool& WorkerPool = GetMediumWorkerPool(EWorkloadType::Background);
+ std::vector<IoHash> AllAttachments;
+ for (const std::string& BucketName : BucketNames)
+ {
+ ResponseWriter.BeginObject();
+ ResponseWriter << "Name" << BucketName;
+ CacheContentStats ContentStats;
+ bool Success = m_CacheStore.GetContentStats(NamespaceName, BucketName, ContentStats);
+ if (Success)
+ {
+ size_t ValuesSize = 0;
+ for (const uint64_t Size : ContentStats.ValueSizes)
+ {
+ ValuesSize += Size;
+ }
+
+ std::sort(ContentStats.Attachments.begin(), ContentStats.Attachments.end());
+ auto NewEnd = std::unique(ContentStats.Attachments.begin(), ContentStats.Attachments.end());
+ ContentStats.Attachments.erase(NewEnd, ContentStats.Attachments.end());
+
+ ResponseWriter << "Count" << ContentStats.ValueSizes.size();
+ ResponseWriter << "StructuredCount" << ContentStats.StructuredValuesCount;
+ ResponseWriter << "StandaloneCount" << ContentStats.StandaloneValuesCount;
+ ResponseWriter << "Size" << ValuesSize;
+ ResponseWriter << "AttachmentCount" << ContentStats.Attachments.size();
+
+ AllAttachments.insert(AllAttachments.end(), ContentStats.Attachments.begin(), ContentStats.Attachments.end());
+ }
+ ResponseWriter.EndObject();
+ }
+
+ ResponseWriter.EndArray();
+
+ ResponseWriter.BeginObject("Attachments");
+ std::sort(AllAttachments.begin(), AllAttachments.end());
+ auto NewEnd = std::unique(AllAttachments.begin(), AllAttachments.end());
+ AllAttachments.erase(NewEnd, AllAttachments.end());
+
+ uint64_t AttachmentsSize = 0;
+
+ m_CidStore.IterateChunks(
+ AllAttachments,
+ [&](size_t Index, const IoBuffer& Payload) {
+ ZEN_UNUSED(Index);
+ AttachmentsSize += Payload.GetSize();
+ return true;
+ },
+ &WorkerPool,
+ 8u * 1024u);
+
+ ResponseWriter << "Count" << AllAttachments.size();
+ ResponseWriter << "Size" << AttachmentsSize;
+
+ ResponseWriter.EndObject();
+
+ ResponseWriter.EndObject();
+ }
+
return Request.WriteResponse(HttpResponseCode::OK, ResponseWriter.Save());
}
break;
@@ -814,6 +724,46 @@ HttpStructuredCacheService::HandleCacheBucketRequest(HttpServerRequest& Request,
ResponseWriter.AddInteger("DiskEntryCount", Info->DiskLayerInfo.EntryCount);
+ if (auto GetBucketSize = Request.GetQueryParams().GetValue("bucketsize"); GetBucketSize == "true")
+ {
+ CacheContentStats ContentStats;
+ bool Success = m_CacheStore.GetContentStats(NamespaceName, BucketName, ContentStats);
+ if (Success)
+ {
+ size_t ValuesSize = 0;
+ for (const uint64_t Size : ContentStats.ValueSizes)
+ {
+ ValuesSize += Size;
+ }
+
+ std::sort(ContentStats.Attachments.begin(), ContentStats.Attachments.end());
+ auto NewEnd = std::unique(ContentStats.Attachments.begin(), ContentStats.Attachments.end());
+ ContentStats.Attachments.erase(NewEnd, ContentStats.Attachments.end());
+
+ ResponseWriter << "Count" << ContentStats.ValueSizes.size();
+ ResponseWriter << "StructuredCount" << ContentStats.StructuredValuesCount;
+ ResponseWriter << "StandaloneCount" << ContentStats.StandaloneValuesCount;
+ ResponseWriter << "Size" << ValuesSize;
+ ResponseWriter << "AttachmentCount" << ContentStats.Attachments.size();
+
+ uint64_t AttachmentsSize = 0;
+
+ WorkerThreadPool& WorkerPool = GetMediumWorkerPool(EWorkloadType::Background);
+
+ m_CidStore.IterateChunks(
+ ContentStats.Attachments,
+ [&](size_t Index, const IoBuffer& Payload) {
+ ZEN_UNUSED(Index);
+ AttachmentsSize += Payload.GetSize();
+ return true;
+ },
+ &WorkerPool,
+ 8u * 1024u);
+
+ ResponseWriter << "AttachmentsSize" << AttachmentsSize;
+ }
+ }
+
return Request.WriteResponse(HttpResponseCode::OK, ResponseWriter.Save());
}
break;
@@ -863,7 +813,8 @@ HttpStructuredCacheService::HandleGetCacheRecord(HttpServerRequest& Request, con
const bool SkipData = EnumHasAllFlags(PolicyFromUrl, CachePolicy::SkipData);
const bool PartialRecord = EnumHasAllFlags(PolicyFromUrl, CachePolicy::PartialRecord);
- bool Success = false;
+ bool Success = false;
+ uint32_t MissingCount = 0;
ZenCacheValue ClientResultValue;
if (!EnumHasAnyFlags(PolicyFromUrl, CachePolicy::Query))
{
@@ -885,37 +836,60 @@ HttpStructuredCacheService::HandleGetCacheRecord(HttpServerRequest& Request, con
{
if (ContentType == ZenContentType::kCbObject)
{
- CbPackage Package;
- uint32_t MissingCount = 0;
-
- CbObjectView CacheRecord(ClientResultValue.Value.Data());
- CacheRecord.IterateAttachments([this, &MissingCount, &Package, SkipData](CbFieldView AttachmentHash) {
- if (SkipData)
- {
- if (!m_CidStore.ContainsChunk(AttachmentHash.AsHash()))
- {
- MissingCount++;
- }
- }
- else
- {
- if (IoBuffer Chunk = m_CidStore.FindChunkByCid(AttachmentHash.AsHash()))
+ CbPackage Package;
+ CbValidateError ValidateError = CbValidateError::None;
+ if (CbObject PackageObject = ValidateAndReadCompactBinaryObject(std::move(ClientResultValue.Value), ValidateError);
+ ValidateError == CbValidateError::None)
+ {
+ CbObjectView CacheRecord(ClientResultValue.Value.Data());
+ CacheRecord.IterateAttachments([this, &MissingCount, &Package, SkipData](CbFieldView AttachmentHash) {
+ if (SkipData)
{
- CompressedBuffer Compressed = CompressedBuffer::FromCompressedNoValidate(std::move(Chunk));
- Package.AddAttachment(CbAttachment(Compressed, AttachmentHash.AsHash()));
+ if (!m_CidStore.ContainsChunk(AttachmentHash.AsHash()))
+ {
+ MissingCount++;
+ }
}
else
{
- MissingCount++;
+ if (IoBuffer Chunk = m_CidStore.FindChunkByCid(AttachmentHash.AsHash()))
+ {
+ CompressedBuffer Compressed = CompressedBuffer::FromCompressedNoValidate(std::move(Chunk));
+ if (Compressed)
+ {
+ Package.AddAttachment(CbAttachment(Compressed, AttachmentHash.AsHash()));
+ }
+ else
+ {
+ ZEN_WARN("invalid compressed binary returned for {}", AttachmentHash.AsHash());
+ MissingCount++;
+ }
+ }
+ else
+ {
+ MissingCount++;
+ }
}
- }
- });
+ });
- Success = MissingCount == 0 || PartialRecord;
+ Success = MissingCount == 0 || PartialRecord;
+ }
+ else
+ {
+ ZEN_WARN("Invalid compact binary payload returned for {}/{}/{} ({}). Reason: '{}'",
+ Ref.Namespace,
+ Ref.BucketSegment,
+ Ref.HashKey,
+ Ref.ValueContentId,
+ ToString(ValidateError));
+ Success = false;
+ }
if (Success)
{
- Package.SetObject(LoadCompactBinaryObject(ClientResultValue.Value));
+ CbObject PackageObject = LoadCompactBinaryObject(std::move(ClientResultValue.Value));
+
+ Package.SetObject(std::move(PackageObject));
BinaryWriter MemStream;
Package.Save(MemStream);
@@ -954,7 +928,9 @@ HttpStructuredCacheService::HandleGetCacheRecord(HttpServerRequest& Request, con
else
{
// kCbPackage handled SkipData when constructing the ClientResultValue, kcbObject ignores SkipData
- return Request.WriteResponse(HttpResponseCode::OK, ClientResultValue.Value.GetContentType(), ClientResultValue.Value);
+ return Request.WriteResponse((MissingCount == 0) ? HttpResponseCode::OK : HttpResponseCode::PartialContent,
+ ClientResultValue.Value.GetContentType(),
+ ClientResultValue.Value);
}
}
else if (!HasUpstream || !EnumHasAllFlags(PolicyFromUrl, CachePolicy::QueryRemote))
@@ -1014,8 +990,14 @@ HttpStructuredCacheService::HandleGetCacheRecord(HttpServerRequest& Request, con
if (Success && StoreLocal)
{
- m_CacheStore.Put(RequestContext, Ref.Namespace, Ref.BucketSegment, Ref.HashKey, ClientResultValue, {});
- m_CacheStats.WriteCount++;
+ const bool Overwrite = !EnumHasAllFlags(PolicyFromUrl, CachePolicy::QueryLocal);
+ ZenCacheStore::PutResult PutResult =
+ m_CacheStore
+ .Put(RequestContext, Ref.Namespace, Ref.BucketSegment, Ref.HashKey, ClientResultValue, {}, Overwrite, nullptr);
+ if (PutResult.Status == zen::PutStatus::Success)
+ {
+ m_CacheStats.WriteCount++;
+ }
}
}
else if (AcceptType == ZenContentType::kCbPackage)
@@ -1023,17 +1005,20 @@ HttpStructuredCacheService::HandleGetCacheRecord(HttpServerRequest& Request, con
CbPackage Package;
if (Package.TryLoad(ClientResultValue.Value))
{
- CbObject CacheRecord = Package.GetObject();
- AttachmentCount Count;
- size_t NumAttachments = Package.GetAttachments().size();
- std::vector<const CbAttachment*> AttachmentsToStoreLocally;
- std::vector<IoHash> ReferencedAttachments;
- AttachmentsToStoreLocally.reserve(NumAttachments);
+ CbObject CacheRecord = Package.GetObject();
+ AttachmentCount Count;
+ size_t NumAttachments = Package.GetAttachments().size();
+ std::vector<IoHash> ReferencedAttachments;
+ std::vector<IoBuffer> WriteAttachmentBuffers;
+ WriteAttachmentBuffers.reserve(NumAttachments);
+ std::vector<IoHash> WriteRawHashes;
+ WriteRawHashes.reserve(NumAttachments);
CacheRecord.IterateAttachments([this,
&Package,
&Ref,
- &AttachmentsToStoreLocally,
+ &WriteAttachmentBuffers,
+ &WriteRawHashes,
&ReferencedAttachments,
&Count,
QueryLocal,
@@ -1047,7 +1032,9 @@ HttpStructuredCacheService::HandleGetCacheRecord(HttpServerRequest& Request, con
{
if (StoreLocal)
{
- AttachmentsToStoreLocally.emplace_back(Attachment);
+ const CompressedBuffer& Chunk = Attachment->AsCompressedBinary();
+ WriteAttachmentBuffers.push_back(Chunk.GetCompressed().Flatten().AsIoBuffer());
+ WriteRawHashes.push_back(Attachment->GetHash());
}
Count.Valid++;
}
@@ -1095,20 +1082,34 @@ HttpStructuredCacheService::HandleGetCacheRecord(HttpServerRequest& Request, con
if (StoreLocal)
{
- m_CacheStore
- .Put(RequestContext, Ref.Namespace, Ref.BucketSegment, Ref.HashKey, CacheValue, ReferencedAttachments);
- m_CacheStats.WriteCount++;
- }
-
- for (const CbAttachment* Attachment : AttachmentsToStoreLocally)
- {
- ZEN_ASSERT_SLOW(StoreLocal);
- CompressedBuffer Chunk = Attachment->AsCompressedBinary();
- CidStore::InsertResult InsertResult =
- m_CidStore.AddChunk(Chunk.GetCompressed().Flatten().AsIoBuffer(), Attachment->GetHash());
- if (InsertResult.New)
+ const bool Overwrite = !EnumHasAllFlags(PolicyFromUrl, CachePolicy::QueryLocal);
+ ZenCacheStore::PutResult PutResult = m_CacheStore.Put(RequestContext,
+ Ref.Namespace,
+ Ref.BucketSegment,
+ Ref.HashKey,
+ CacheValue,
+ ReferencedAttachments,
+ Overwrite,
+ nullptr);
+ if (PutResult.Status == zen::PutStatus::Success)
{
- Count.New++;
+ m_CacheStats.WriteCount++;
+
+ if (!WriteAttachmentBuffers.empty())
+ {
+ std::vector<CidStore::InsertResult> InsertResults =
+ m_CidStore.AddChunks(WriteAttachmentBuffers, WriteRawHashes);
+ for (const CidStore::InsertResult& Result : InsertResults)
+ {
+ if (Result.New)
+ {
+ Count.New++;
+ }
+ }
+ }
+
+ WriteAttachmentBuffers = {};
+ WriteRawHashes = {};
}
}
@@ -1200,6 +1201,27 @@ HttpStructuredCacheService::HandlePutCacheRecord(HttpServerRequest& Request, con
return Request.WriteResponse(HttpResponseCode::InsufficientStorage);
}
+ auto WriteFailureResponse = [&Request](const ZenCacheStore::PutResult& PutResult) {
+ ZEN_UNUSED(PutResult);
+
+ HttpResponseCode ResponseCode = HttpResponseCode::InternalServerError;
+ switch (PutResult.Status)
+ {
+ case zen::PutStatus::Conflict:
+ ResponseCode = HttpResponseCode::Conflict;
+ break;
+ case zen::PutStatus::Invalid:
+ ResponseCode = HttpResponseCode::BadRequest;
+ break;
+ }
+
+ if (PutResult.Details)
+ {
+ Request.WriteResponse(ResponseCode, PutResult.Details);
+ }
+ return Request.WriteResponse(ResponseCode);
+ };
+
const HttpContentType ContentType = Request.RequestContentType();
Body.SetContentType(ContentType);
@@ -1228,12 +1250,20 @@ HttpStructuredCacheService::HandlePutCacheRecord(HttpServerRequest& Request, con
{
RawHash = IoHash::HashBuffer(SharedBuffer(Body));
}
- m_CacheStore.Put(RequestContext,
- Ref.Namespace,
- Ref.BucketSegment,
- Ref.HashKey,
- {.Value = Body, .RawSize = RawSize, .RawHash = RawHash},
- {});
+ const bool Overwrite = !EnumHasAllFlags(PolicyFromUrl, CachePolicy::QueryLocal);
+ // TODO: Propagation for rejected PUTs
+ ZenCacheStore::PutResult PutResult = m_CacheStore.Put(RequestContext,
+ Ref.Namespace,
+ Ref.BucketSegment,
+ Ref.HashKey,
+ {.Value = Body, .RawSize = RawSize, .RawHash = RawHash},
+ {},
+ Overwrite,
+ nullptr);
+ if (PutResult.Status != zen::PutStatus::Success)
+ {
+ return WriteFailureResponse(PutResult);
+ }
m_CacheStats.WriteCount++;
if (HasUpstream && EnumHasAllFlags(PolicyFromUrl, CachePolicy::StoreRemote))
@@ -1282,7 +1312,21 @@ HttpStructuredCacheService::HandlePutCacheRecord(HttpServerRequest& Request, con
TotalCount++;
});
- m_CacheStore.Put(RequestContext, Ref.Namespace, Ref.BucketSegment, Ref.HashKey, {.Value = Body}, ReferencedAttachments);
+ const bool Overwrite = !EnumHasAllFlags(PolicyFromUrl, CachePolicy::QueryLocal);
+
+ // TODO: Propagation for rejected PUTs
+ ZenCacheStore::PutResult PutResult = m_CacheStore.Put(RequestContext,
+ Ref.Namespace,
+ Ref.BucketSegment,
+ Ref.HashKey,
+ {.Value = Body},
+ ReferencedAttachments,
+ Overwrite,
+ nullptr);
+ if (PutResult.Status != zen::PutStatus::Success)
+ {
+ return WriteFailureResponse(PutResult);
+ }
m_CacheStats.WriteCount++;
ZEN_DEBUG("PUTCACHERECORD - '{}/{}/{}' {} '{}' attachments '{}/{}' (valid/total) in {}",
@@ -1326,23 +1370,27 @@ HttpStructuredCacheService::HandlePutCacheRecord(HttpServerRequest& Request, con
CbObject CacheRecord = Package.GetObject();
- AttachmentCount Count;
- size_t NumAttachments = Package.GetAttachments().size();
- std::vector<IoHash> ValidAttachments;
- std::vector<IoHash> ReferencedAttachments;
- std::vector<const CbAttachment*> AttachmentsToStoreLocally;
+ AttachmentCount Count;
+ size_t NumAttachments = Package.GetAttachments().size();
+ std::vector<IoHash> ValidAttachments;
+ std::vector<IoHash> ReferencedAttachments;
ValidAttachments.reserve(NumAttachments);
- AttachmentsToStoreLocally.reserve(NumAttachments);
+ std::vector<IoBuffer> WriteAttachmentBuffers;
+ std::vector<IoHash> WriteRawHashes;
+ WriteAttachmentBuffers.reserve(NumAttachments);
+ WriteRawHashes.reserve(NumAttachments);
CacheRecord.IterateAttachments(
- [this, &Ref, &Package, &AttachmentsToStoreLocally, &ValidAttachments, &ReferencedAttachments, &Count](CbFieldView HashView) {
+ [this, &Ref, &Package, &WriteAttachmentBuffers, &WriteRawHashes, &ValidAttachments, &ReferencedAttachments, &Count](
+ CbFieldView HashView) {
const IoHash Hash = HashView.AsHash();
ReferencedAttachments.push_back(Hash);
if (const CbAttachment* Attachment = Package.FindAttachment(Hash))
{
if (Attachment->IsCompressedBinary())
{
- AttachmentsToStoreLocally.emplace_back(Attachment);
+ WriteAttachmentBuffers.emplace_back(Attachment->AsCompressedBinary().GetCompressed().Flatten().AsIoBuffer());
+ WriteRawHashes.push_back(Hash);
ValidAttachments.emplace_back(Hash);
Count.Valid++;
}
@@ -1371,20 +1419,32 @@ HttpStructuredCacheService::HandlePutCacheRecord(HttpServerRequest& Request, con
return Request.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Invalid attachment(s)"sv);
}
+ const bool Overwrite = !EnumHasAllFlags(Policy, CachePolicy::QueryLocal);
+
ZenCacheValue CacheValue;
CacheValue.Value = CacheRecord.GetBuffer().AsIoBuffer();
CacheValue.Value.SetContentType(ZenContentType::kCbObject);
- m_CacheStore.Put(RequestContext, Ref.Namespace, Ref.BucketSegment, Ref.HashKey, CacheValue, ReferencedAttachments);
+ // TODO: Propagation for rejected PUTs
+ ZenCacheStore::PutResult PutResult =
+ m_CacheStore.Put(RequestContext, Ref.Namespace, Ref.BucketSegment, Ref.HashKey, CacheValue, ReferencedAttachments, Overwrite);
+ if (PutResult.Status != zen::PutStatus::Success)
+ {
+ return WriteFailureResponse(PutResult);
+ }
m_CacheStats.WriteCount++;
- for (const CbAttachment* Attachment : AttachmentsToStoreLocally)
+ if (!WriteAttachmentBuffers.empty())
{
- CompressedBuffer Chunk = Attachment->AsCompressedBinary();
- CidStore::InsertResult InsertResult = m_CidStore.AddChunk(Chunk.GetCompressed().Flatten().AsIoBuffer(), Attachment->GetHash());
- if (InsertResult.New)
+ std::vector<CidStore::InsertResult> InsertResults = m_CidStore.AddChunks(WriteAttachmentBuffers, WriteRawHashes);
+ for (const CidStore::InsertResult& InsertResult : InsertResults)
{
- Count.New++;
+ if (InsertResult.New)
+ {
+ Count.New++;
+ }
}
+ WriteAttachmentBuffers = {};
+ WriteRawHashes = {};
}
ZEN_DEBUG("PUTCACHERECORD - '{}/{}/{}' {} '{}', attachments '{}/{}/{}' (new/valid/total) in {}",
@@ -1580,15 +1640,26 @@ HttpStructuredCacheService::ReplayRequestRecorder(const CacheRequestContext& Co
WorkerThreadPool WorkerPool(ThreadCount);
uint64_t RequestCount = Replayer.GetRequestCount();
Stopwatch Timer;
- auto _ = MakeGuard([&]() { ZEN_INFO("Replayed {} requests in {}", RequestCount, NiceLatencyNs(Timer.GetElapsedTimeUs() * 1000)); });
- Latch JobLatch(RequestCount);
+ auto _ = MakeGuard([&]() { ZEN_INFO("Replayed {} requests in {}", RequestCount, NiceLatencyNs(Timer.GetElapsedTimeUs() * 1000)); });
+ std::atomic<bool> AbortFlag;
+ std::atomic<bool> PauseFlag;
+ ParallelWork Work(AbortFlag, PauseFlag, WorkerThreadPool::EMode::EnableBacklog);
ZEN_INFO("Replaying {} requests", RequestCount);
for (uint64_t RequestIndex = 0; RequestIndex < RequestCount; ++RequestIndex)
{
- WorkerPool.ScheduleWork([this, &Context, &JobLatch, &Replayer, RequestIndex]() {
+ if (AbortFlag)
+ {
+ break;
+ }
+ Work.ScheduleWork(WorkerPool, [this, &Context, &Replayer, RequestIndex](std::atomic<bool>& AbortFlag) {
IoBuffer Body;
zen::cache::RecordedRequestInfo RequestInfo = Replayer.GetRequest(RequestIndex, /* out */ Body);
+ if (AbortFlag)
+ {
+ return;
+ }
+
if (Body)
{
uint32_t AcceptMagic = 0;
@@ -1596,6 +1667,7 @@ HttpStructuredCacheService::ReplayRequestRecorder(const CacheRequestContext& Co
int TargetPid = 0;
CbPackage RpcResult;
if (m_RpcHandler.HandleRpcRequest(Context,
+ /* UriNamespace */ {},
RequestInfo.ContentType,
std::move(Body),
AcceptMagic,
@@ -1628,21 +1700,22 @@ HttpStructuredCacheService::ReplayRequestRecorder(const CacheRequestContext& Co
}
}
}
- JobLatch.CountDown();
});
}
- while (!JobLatch.Wait(10000))
- {
+ Work.Wait(10000, [&](bool IsAborted, bool IsPaused, std::ptrdiff_t PendingWork) {
+ ZEN_UNUSED(IsAborted, IsPaused);
ZEN_INFO("Replayed {} of {} requests, elapsed {}",
- RequestCount - JobLatch.Remaining(),
+ RequestCount - PendingWork,
RequestCount,
NiceLatencyNs(Timer.GetElapsedTimeUs() * 1000));
- }
+ });
}
void
-HttpStructuredCacheService::HandleRpcRequest(HttpServerRequest& Request)
+HttpStructuredCacheService::HandleRpcRequest(HttpServerRequest& Request, std::string_view UriNamespace)
{
+ ZEN_MEMSCOPE(GetCacheRpcTag());
+
ZEN_TRACE_CPU("z$::Http::HandleRpcRequest");
const bool HasUpstream = m_UpstreamCache.IsActive();
@@ -1663,85 +1736,70 @@ HttpStructuredCacheService::HandleRpcRequest(HttpServerRequest& Request)
return Request.WriteResponse(HttpResponseCode::BadRequest);
}
- auto HandleRpc =
- [this, RequestContext, Body = Request.ReadPayload(), ContentType, AcceptType](HttpServerRequest& AsyncRequest) mutable {
- uint64_t RequestIndex = ~0ull;
-
- if (m_RequestRecordingEnabled)
+ auto HandleRpc = [this,
+ RequestContext,
+ Body = Request.ReadPayload(),
+ ContentType,
+ AcceptType,
+ UriNamespaceString = std::string{UriNamespace}](HttpServerRequest& AsyncRequest) mutable {
+ if (m_RequestRecordingEnabled)
+ {
+ RwLock::SharedLockScope _(m_RequestRecordingLock);
+ if (m_RequestRecorder)
{
- RwLock::SharedLockScope _(m_RequestRecordingLock);
- if (m_RequestRecorder)
- {
- RequestIndex = m_RequestRecorder->RecordRequest(
- {.ContentType = ContentType, .AcceptType = AcceptType, .SessionId = RequestContext.SessionId},
- Body);
- }
+ m_RequestRecorder->RecordRequest(
+ {.ContentType = ContentType, .AcceptType = AcceptType, .SessionId = RequestContext.SessionId},
+ Body);
}
+ }
- uint32_t AcceptMagic = 0;
- RpcAcceptOptions AcceptFlags = RpcAcceptOptions::kNone;
- int TargetProcessId = 0;
- CbPackage RpcResult;
+ uint32_t AcceptMagic = 0;
+ RpcAcceptOptions AcceptFlags = RpcAcceptOptions::kNone;
+ int TargetProcessId = 0;
+ CbPackage RpcResult;
- CacheRpcHandler::RpcResponseCode ResultCode = m_RpcHandler.HandleRpcRequest(RequestContext,
- ContentType,
- std::move(Body),
- AcceptMagic,
- AcceptFlags,
- TargetProcessId,
- RpcResult);
+ CacheRpcHandler::RpcResponseCode ResultCode = m_RpcHandler.HandleRpcRequest(RequestContext,
+ UriNamespaceString,
+ ContentType,
+ std::move(Body),
+ /* out */ AcceptMagic,
+ /* out */ AcceptFlags,
+ /* out */ TargetProcessId,
+ /* out */ RpcResult);
- HttpResponseCode HttpResultCode = HttpResponseCode(int(ResultCode));
+ HttpResponseCode HttpResultCode = HttpResponseCode(int(ResultCode));
- if (!IsHttpSuccessCode(HttpResultCode))
- {
- return AsyncRequest.WriteResponse(HttpResultCode);
- }
+ if (!IsHttpSuccessCode(HttpResultCode))
+ {
+ return AsyncRequest.WriteResponse(HttpResultCode);
+ }
- if (AcceptMagic == kCbPkgMagic)
+ if (AcceptMagic == kCbPkgMagic)
+ {
+ void* TargetProcessHandle = nullptr;
+ FormatFlags Flags = FormatFlags::kDefault;
+ if (EnumHasAllFlags(AcceptFlags, RpcAcceptOptions::kAllowLocalReferences))
{
- void* TargetProcessHandle = nullptr;
- FormatFlags Flags = FormatFlags::kDefault;
- if (EnumHasAllFlags(AcceptFlags, RpcAcceptOptions::kAllowLocalReferences))
- {
- Flags |= FormatFlags::kAllowLocalReferences;
- if (!EnumHasAnyFlags(AcceptFlags, RpcAcceptOptions::kAllowPartialLocalReferences))
- {
- Flags |= FormatFlags::kDenyPartialLocalReferences;
- }
- TargetProcessHandle = m_OpenProcessCache.GetProcessHandle(RequestContext.SessionId, TargetProcessId);
- }
- CompositeBuffer RpcResponseBuffer = FormatPackageMessageBuffer(RpcResult, Flags, TargetProcessHandle);
- if (RequestIndex != ~0ull)
+ Flags |= FormatFlags::kAllowLocalReferences;
+ if (!EnumHasAnyFlags(AcceptFlags, RpcAcceptOptions::kAllowPartialLocalReferences))
{
- RwLock::SharedLockScope _(m_RequestRecordingLock);
- if (m_RequestRecorder)
- {
- m_RequestRecorder->RecordResponse(RequestIndex, HttpContentType::kCbPackage, RpcResponseBuffer);
- }
+ Flags |= FormatFlags::kDenyPartialLocalReferences;
}
- AsyncRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kCbPackage, RpcResponseBuffer);
+ TargetProcessHandle = m_OpenProcessCache.GetProcessHandle(RequestContext.SessionId, TargetProcessId);
}
- else
- {
- BinaryWriter MemStream;
- RpcResult.Save(MemStream);
+ CompositeBuffer RpcResponseBuffer = FormatPackageMessageBuffer(RpcResult, Flags, TargetProcessHandle);
+ AsyncRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kCbPackage, RpcResponseBuffer);
+ }
+ else
+ {
+ BinaryWriter MemStream;
+ RpcResult.Save(MemStream);
- if (RequestIndex != ~0ull)
- {
- RwLock::SharedLockScope _(m_RequestRecordingLock);
- if (m_RequestRecorder)
- {
- m_RequestRecorder->RecordResponse(RequestIndex,
- HttpContentType::kCbPackage,
- IoBuffer(IoBuffer::Wrap, MemStream.GetData(), MemStream.GetSize()));
- }
- }
- AsyncRequest.WriteResponse(HttpResponseCode::OK,
- HttpContentType::kCbPackage,
- IoBuffer(IoBuffer::Wrap, MemStream.GetData(), MemStream.GetSize()));
- }
- };
+ AsyncRequest.WriteResponse(HttpResponseCode::OK,
+ HttpContentType::kCbPackage,
+ IoBuffer(IoBuffer::Wrap, MemStream.GetData(), MemStream.GetSize()));
+ }
+ };
if (HasUpstream)
{
@@ -1766,6 +1824,8 @@ HttpStructuredCacheService::HandleRpcRequest(HttpServerRequest& Request)
void
HttpStructuredCacheService::HandleStatsRequest(HttpServerRequest& Request)
{
+ ZEN_MEMSCOPE(GetCacheHttpTag());
+
CbObjectWriter Cbo;
EmitSnapshot("requests", m_HttpRequests, Cbo);
@@ -1789,8 +1849,8 @@ HttpStructuredCacheService::HandleStatsRequest(HttpServerRequest& Request)
const uint64_t RpcChunkRequests = m_CacheStats.RpcChunkRequests;
const uint64_t RpcChunkBatchRequests = m_CacheStats.RpcChunkBatchRequests;
- const CidStoreSize CidSize = m_CidStore.TotalSize();
- const GcStorageSize CacheSize = m_CacheStore.StorageSize();
+ const CidStoreSize CidSize = m_CidStore.TotalSize();
+ const CacheStoreSize CacheSize = m_CacheStore.TotalSize();
bool ShowCidStoreStats = Request.GetQueryParams().GetValue("cidstorestats") == "true";
bool ShowCacheStoreStats = Request.GetQueryParams().GetValue("cachestorestats") == "true";
@@ -1989,106 +2049,4 @@ HttpStructuredCacheService::AreDiskWritesAllowed() const
return (m_DiskWriteBlocker == nullptr || m_DiskWriteBlocker->AreDiskWritesAllowed());
}
-#if ZEN_WITH_TESTS
-
-TEST_CASE("z$service.parse.relative.Uri")
-{
- HttpRequestData RootRequest;
- CHECK(HttpRequestParseRelativeUri("", RootRequest));
- CHECK(!RootRequest.Namespace.has_value());
- CHECK(!RootRequest.Bucket.has_value());
- CHECK(!RootRequest.HashKey.has_value());
- CHECK(!RootRequest.ValueContentId.has_value());
-
- RootRequest = {};
- CHECK(HttpRequestParseRelativeUri("/", RootRequest));
- CHECK(!RootRequest.Namespace.has_value());
- CHECK(!RootRequest.Bucket.has_value());
- CHECK(!RootRequest.HashKey.has_value());
- CHECK(!RootRequest.ValueContentId.has_value());
-
- HttpRequestData LegacyBucketRequestBecomesNamespaceRequest;
- CHECK(HttpRequestParseRelativeUri("test", LegacyBucketRequestBecomesNamespaceRequest));
- CHECK(LegacyBucketRequestBecomesNamespaceRequest.Namespace == "test"sv);
- CHECK(!LegacyBucketRequestBecomesNamespaceRequest.Bucket.has_value());
- CHECK(!LegacyBucketRequestBecomesNamespaceRequest.HashKey.has_value());
- CHECK(!LegacyBucketRequestBecomesNamespaceRequest.ValueContentId.has_value());
-
- HttpRequestData LegacyHashKeyRequest;
- CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", LegacyHashKeyRequest));
- CHECK(LegacyHashKeyRequest.Namespace == ZenCacheStore::DefaultNamespace);
- CHECK(LegacyHashKeyRequest.Bucket == "test"sv);
- CHECK(LegacyHashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv));
- CHECK(!LegacyHashKeyRequest.ValueContentId.has_value());
-
- HttpRequestData LegacyValueContentIdRequest;
- CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789",
- LegacyValueContentIdRequest));
- CHECK(LegacyValueContentIdRequest.Namespace == ZenCacheStore::DefaultNamespace);
- CHECK(LegacyValueContentIdRequest.Bucket == "test"sv);
- CHECK(LegacyValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv));
- CHECK(LegacyValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789"sv));
-
- HttpRequestData V2DefaultNamespaceRequest;
- CHECK(HttpRequestParseRelativeUri("ue4.ddc", V2DefaultNamespaceRequest));
- CHECK(V2DefaultNamespaceRequest.Namespace == "ue4.ddc");
- CHECK(!V2DefaultNamespaceRequest.Bucket.has_value());
- CHECK(!V2DefaultNamespaceRequest.HashKey.has_value());
- CHECK(!V2DefaultNamespaceRequest.ValueContentId.has_value());
-
- HttpRequestData V2NamespaceRequest;
- CHECK(HttpRequestParseRelativeUri("nicenamespace", V2NamespaceRequest));
- CHECK(V2NamespaceRequest.Namespace == "nicenamespace"sv);
- CHECK(!V2NamespaceRequest.Bucket.has_value());
- CHECK(!V2NamespaceRequest.HashKey.has_value());
- CHECK(!V2NamespaceRequest.ValueContentId.has_value());
-
- HttpRequestData V2BucketRequestWithDefaultNamespace;
- CHECK(HttpRequestParseRelativeUri("ue4.ddc/test", V2BucketRequestWithDefaultNamespace));
- CHECK(V2BucketRequestWithDefaultNamespace.Namespace == "ue4.ddc");
- CHECK(V2BucketRequestWithDefaultNamespace.Bucket == "test"sv);
- CHECK(!V2BucketRequestWithDefaultNamespace.HashKey.has_value());
- CHECK(!V2BucketRequestWithDefaultNamespace.ValueContentId.has_value());
-
- HttpRequestData V2BucketRequestWithNamespace;
- CHECK(HttpRequestParseRelativeUri("nicenamespace/test", V2BucketRequestWithNamespace));
- CHECK(V2BucketRequestWithNamespace.Namespace == "nicenamespace"sv);
- CHECK(V2BucketRequestWithNamespace.Bucket == "test"sv);
- CHECK(!V2BucketRequestWithNamespace.HashKey.has_value());
- CHECK(!V2BucketRequestWithNamespace.ValueContentId.has_value());
-
- HttpRequestData V2HashKeyRequest;
- CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", V2HashKeyRequest));
- CHECK(V2HashKeyRequest.Namespace == ZenCacheStore::DefaultNamespace);
- CHECK(V2HashKeyRequest.Bucket == "test");
- CHECK(V2HashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv));
- CHECK(!V2HashKeyRequest.ValueContentId.has_value());
-
- HttpRequestData V2ValueContentIdRequest;
- CHECK(
- HttpRequestParseRelativeUri("nicenamespace/test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789",
- V2ValueContentIdRequest));
- CHECK(V2ValueContentIdRequest.Namespace == "nicenamespace"sv);
- CHECK(V2ValueContentIdRequest.Bucket == "test"sv);
- CHECK(V2ValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv));
- CHECK(V2ValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789"sv));
-
- HttpRequestData Invalid;
- CHECK(!HttpRequestParseRelativeUri("bad\2_namespace", Invalid));
- CHECK(!HttpRequestParseRelativeUri("nice/\2\1bucket", Invalid));
- CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789a", Invalid));
- CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcdef1234", Invalid));
- CHECK(!HttpRequestParseRelativeUri("namespace/bucket/pppppppp89abcdef12340123456789abcdef1234", Invalid));
- CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcd", Invalid));
- CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/ppppppppdef12345678956789abcdef123456789",
- Invalid));
-}
-
-#endif
-
-void
-z$service_forcelink()
-{
-}
-
} // namespace zen