diff options
| author | Dan Engelbrecht <[email protected]> | 2023-08-14 13:01:55 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-08-14 13:01:55 +0200 |
| commit | 126cd15dbca6e322360ece085563deba449926c6 (patch) | |
| tree | 22d132c528b80bd5c8e61c3f75eb7e8fe6e5a4ac /src/zenserver/projectstore/httpprojectstore.cpp | |
| parent | update vcpkg dependencies (#356) (diff) | |
| download | zen-126cd15dbca6e322360ece085563deba449926c6.tar.xz zen-126cd15dbca6e322360ece085563deba449926c6.zip | |
project store stats (#357)
* add basic stats for project store
* stats for BadRequest in ProjectStore::Rpc
* changelog
* group stats
fix ChunkWriteCount when accepting ops
Diffstat (limited to 'src/zenserver/projectstore/httpprojectstore.cpp')
| -rw-r--r-- | src/zenserver/projectstore/httpprojectstore.cpp | 139 |
1 files changed, 132 insertions, 7 deletions
diff --git a/src/zenserver/projectstore/httpprojectstore.cpp b/src/zenserver/projectstore/httpprojectstore.cpp index 7e7517c33..f52473d99 100644 --- a/src/zenserver/projectstore/httpprojectstore.cpp +++ b/src/zenserver/projectstore/httpprojectstore.cpp @@ -315,6 +315,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, if (Payload.Size() <= sizeof(RequestHeader)) { + m_ProjectStats.BadRequestCount++; HttpReq.WriteResponse(HttpResponseCode::BadRequest); } @@ -323,6 +324,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, if (RequestHdr.Magic != RequestHeader::kMagic) { + m_ProjectStats.BadRequestCount++; HttpReq.WriteResponse(HttpResponseCode::BadRequest); } @@ -394,6 +396,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, memcpy(ResponsePtr, &ResponseChunk, sizeof(ResponseChunk)); ResponsePtr += sizeof(ResponseChunk); } + m_ProjectStats.ChunkHitCount += RequestHdr.ChunkCount; return HttpReq.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, OutBlobs); }, HttpVerb::kPost); @@ -421,6 +424,10 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, } else { + if (Result.first == HttpResponseCode::BadRequest) + { + m_ProjectStats.BadRequestCount++; + } ZEN_DEBUG("Request {}: '{}' failed with {}. Reason: `{}`", ToString(HttpReq.RequestVerb()), HttpReq.QueryString(), @@ -448,14 +455,20 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, std::pair<HttpResponseCode, std::string> Result = m_ProjectStore->GetChunkInfo(ProjectId, OplogId, ChunkId, ResponsePayload); if (Result.first == HttpResponseCode::OK) { + m_ProjectStats.ChunkHitCount++; return HttpReq.WriteResponse(HttpResponseCode::OK, ResponsePayload); } else if (Result.first == HttpResponseCode::NotFound) { + m_ProjectStats.ChunkMissCount++; ZEN_DEBUG("chunk - '{}/{}/{}' MISSING", ProjectId, OplogId, ChunkId); } else { + if (Result.first == HttpResponseCode::BadRequest) + { + m_ProjectStats.BadRequestCount++; + } ZEN_DEBUG("Request {}: '{}' failed with {}. Reason: `{}`", ToString(HttpReq.RequestVerb()), HttpReq.QueryString(), @@ -492,6 +505,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, } else { + m_ProjectStats.BadRequestCount++; return HttpReq.WriteResponse(HttpResponseCode::BadRequest); } } @@ -504,6 +518,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, } else { + m_ProjectStats.BadRequestCount++; return HttpReq.WriteResponse(HttpResponseCode::BadRequest); } } @@ -515,15 +530,21 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, m_ProjectStore->GetChunkRange(ProjectId, OplogId, ChunkId, Offset, Size, AcceptType, Chunk); if (Result.first == HttpResponseCode::OK) { + m_ProjectStats.ChunkHitCount++; ZEN_DEBUG("chunk - '{}/{}/{}' '{}'", ProjectId, OplogId, ChunkId, ToString(Chunk.GetContentType())); return HttpReq.WriteResponse(HttpResponseCode::OK, Chunk.GetContentType(), Chunk); } else if (Result.first == HttpResponseCode::NotFound) { + m_ProjectStats.ChunkMissCount++; ZEN_DEBUG("chunk - '{}/{}/{}' MISSING", ProjectId, OplogId, ChunkId); } else { + if (Result.first == HttpResponseCode::BadRequest) + { + m_ProjectStats.BadRequestCount++; + } ZEN_DEBUG("Request {}: '{}' failed with {}. Reason: `{}`", ToString(HttpReq.RequestVerb()), HttpReq.QueryString(), @@ -559,14 +580,20 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, if (Result.first == HttpResponseCode::OK) { + m_ProjectStats.ChunkHitCount++; return HttpReq.WriteResponse(HttpResponseCode::OK, Value.GetContentType(), Value); } else if (Result.first == HttpResponseCode::NotFound) { + m_ProjectStats.ChunkMissCount++; ZEN_DEBUG("chunk - '{}/{}/{}' MISSING", ProjectId, OplogId, Cid); } else { + if (Result.first == HttpResponseCode::BadRequest) + { + m_ProjectStats.BadRequestCount++; + } ZEN_DEBUG("Request {}: '{}' failed with {}. Reason: `{}`", ToString(HttpReq.RequestVerb()), HttpReq.QueryString(), @@ -589,10 +616,15 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, m_ProjectStore->PutChunk(ProjectId, OplogId, Cid, RequestType, HttpReq.ReadPayload()); if (Result.first == HttpResponseCode::OK || Result.first == HttpResponseCode::Created) { + m_ProjectStats.ChunkWriteCount++; return HttpReq.WriteResponse(Result.first); } else { + if (Result.first == HttpResponseCode::BadRequest) + { + m_ProjectStats.BadRequestCount++; + } ZEN_DEBUG("Request {}: '{}' failed with {}. Reason: `{}`", ToString(HttpReq.RequestVerb()), HttpReq.QueryString(), @@ -771,37 +803,59 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, WriteFile(BadPackagePath, Payload); + m_ProjectStats.BadRequestCount++; return HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, u8"request body must be a compact binary object or package in legacy format"); } } + m_ProjectStats.ChunkMissCount += MissingChunks.size(); + if (!IsValid) { - // TODO: emit diagnostics identifying missing chunks + ExtendableStringBuilder<256> ResponseText; + ResponseText.Append("Missing chunk references: "); + + bool IsFirst = true; + for (const auto& Hash : MissingChunks) + { + if (IsFirst) + { + IsFirst = false; + } + else + { + ResponseText.Append(", "); + } + Hash.ToHexString(ResponseText); + } - return HttpReq.WriteResponse(HttpResponseCode::NotFound, HttpContentType::kText, "Missing chunk reference"); + return HttpReq.WriteResponse(HttpResponseCode::NotFound, HttpContentType::kText, ResponseText); } CbObject Core = Package.GetObject(); if (!Core["key"sv]) { + m_ProjectStats.BadRequestCount++; return HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "No oplog entry key specified"); } // Write core to oplog - const uint32_t OpLsn = Oplog.AppendNewOplogEntry(Package); + size_t AttachmentCount = Package.GetAttachments().size(); + const uint32_t OpLsn = Oplog.AppendNewOplogEntry(Package); if (OpLsn == ProjectStore::Oplog::kInvalidOp) { + m_ProjectStats.BadRequestCount++; return HttpReq.WriteResponse(HttpResponseCode::BadRequest); } + m_ProjectStats.ChunkWriteCount += AttachmentCount; + m_ProjectStats.OpWriteCount++; ZEN_DEBUG("'{}/{}' op #{} ({}) - '{}'", ProjectId, OplogId, OpLsn, NiceBytes(Payload.Size()), Core["key"sv].AsString()); - HttpReq.WriteResponse(HttpResponseCode::Created); }, HttpVerb::kPost); @@ -885,17 +939,18 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, } } }); - + m_ProjectStats.OpHitCount++; return HttpReq.WriteResponse(HttpResponseCode::Accepted, Package); } else { // Client cannot accept a package, so we only send the core object + m_ProjectStats.OpHitCount++; return HttpReq.WriteResponse(HttpResponseCode::Accepted, Op); } } } - + m_ProjectStats.OpMissCount++; return HttpReq.WriteResponse(HttpResponseCode::NotFound); }, HttpVerb::kGet); @@ -939,6 +994,8 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, << Log.OplogCount() << "expired"sv << Project->IsExpired(GcClock::TimePoint::min(), Log); HttpReq.WriteResponse(HttpResponseCode::OK, Cb.Save()); + + m_ProjectStats.OpLogReadCount++; } break; @@ -964,6 +1021,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, } Project->TouchOplog(OplogId); + m_ProjectStats.OpLogWriteCount++; ZEN_INFO("established oplog '{}/{}', gc marker file at '{}'", ProjectId, OplogId, OplogMarkerPath); return HttpReq.WriteResponse(HttpResponseCode::Created); @@ -972,6 +1030,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, // I guess this should ultimately be used to execute RPCs but for now, it // does absolutely nothing + m_ProjectStats.BadRequestCount++; return HttpReq.WriteResponse(HttpResponseCode::BadRequest); } break; @@ -982,6 +1041,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, Project->DeleteOplog(OplogId); + m_ProjectStats.OpLogDeleteCount++; return HttpReq.WriteResponse(HttpResponseCode::OK); } break; @@ -1085,6 +1145,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, ProjectFilePath, ProjectFilePath.empty() ? ", project will not be GCd due to empty project file path" : ""); + m_ProjectStats.ProjectWriteCount++; HttpReq.WriteResponse(HttpResponseCode::Created); } break; @@ -1119,6 +1180,8 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, Response.EndArray(); // oplogs HttpReq.WriteResponse(HttpResponseCode::OK, Response.Save()); + + m_ProjectStats.ProjectReadCount++; } break; @@ -1140,6 +1203,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, fmt::format("project {} is in use", ProjectId)); } + m_ProjectStats.ProjectDeleteCount++; return HttpReq.WriteResponse(HttpResponseCode::NoContent); } break; @@ -1167,6 +1231,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, const auto& OplogId = Req.GetCapture(2); if (HttpReq.RequestContentType() != HttpContentType::kCbObject) { + m_ProjectStats.BadRequestCount++; return HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Invalid content type"); } IoBuffer Payload = HttpReq.ReadPayload(); @@ -1177,6 +1242,18 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, { return HttpReq.WriteResponse(HttpResponseCode::OK, Response); } + else + { + if (Result.first == HttpResponseCode::BadRequest) + { + m_ProjectStats.BadRequestCount++; + } + ZEN_DEBUG("Request {}: '{}' failed with {}. Reason: `{}`", + ToString(HttpReq.RequestVerb()), + HttpReq.QueryString(), + static_cast<int>(Result.first), + Result.second); + } if (Result.second.empty()) { return HttpReq.WriteResponse(Result.first); @@ -1196,6 +1273,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, const auto& OplogId = Req.GetCapture(2); if (HttpReq.AcceptContentType() != HttpContentType::kCbObject) { + m_ProjectStats.BadRequestCount++; return HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Invalid accept content type"); } IoBuffer Payload = HttpReq.ReadPayload(); @@ -1207,6 +1285,18 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, { return HttpReq.WriteResponse(HttpResponseCode::OK, Response); } + else + { + if (Result.first == HttpResponseCode::BadRequest) + { + m_ProjectStats.BadRequestCount++; + } + ZEN_DEBUG("Request {}: '{}' failed with {}. Reason: `{}`", + ToString(HttpReq.RequestVerb()), + HttpReq.QueryString(), + static_cast<int>(Result.first), + Result.second); + } if (Result.second.empty()) { return HttpReq.WriteResponse(Result.first); @@ -1225,7 +1315,11 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, const auto& OplogId = Req.GetCapture(2); IoBuffer Payload = HttpReq.ReadPayload(); - m_ProjectStore->Rpc(HttpReq, ProjectId, OplogId, std::move(Payload), m_AuthMgr); + bool OkRequest = m_ProjectStore->Rpc(HttpReq, ProjectId, OplogId, std::move(Payload), m_AuthMgr); + if (!OkRequest) + { + m_ProjectStats.BadRequestCount++; + } }, HttpVerb::kPost); @@ -1408,6 +1502,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects, if (ChunkId.size() != 2 * sizeof(Oid::OidBits)) { + m_ProjectStats.BadRequestCount++; return HttpReq.WriteResponse( HttpResponseCode::BadRequest, HttpContentType::kText, @@ -1486,6 +1581,36 @@ HttpProjectService::HandleStatsRequest(HttpServerRequest& HttpReq) Cbo << "memory" << StoreSize.MemorySize; } Cbo.EndObject(); + + Cbo.BeginObject("project"); + { + Cbo << "readcount" << m_ProjectStats.ProjectReadCount << "writecount" << m_ProjectStats.ProjectWriteCount << "deletecount" + << m_ProjectStats.ProjectDeleteCount; + } + Cbo.EndObject(); + + Cbo.BeginObject("oplog"); + { + Cbo << "readcount" << m_ProjectStats.OpLogReadCount << "writecount" << m_ProjectStats.OpLogWriteCount << "deletecount" + << m_ProjectStats.OpLogDeleteCount; + } + Cbo.EndObject(); + + Cbo.BeginObject("op"); + { + Cbo << "hitcount" << m_ProjectStats.OpHitCount << "misscount" << m_ProjectStats.OpMissCount << "writecount" + << m_ProjectStats.OpWriteCount; + } + Cbo.EndObject(); + + Cbo.BeginObject("chunk"); + { + Cbo << "hitcount" << m_ProjectStats.ChunkHitCount << "misscount" << m_ProjectStats.ChunkMissCount << "writecount" + << m_ProjectStats.ChunkWriteCount; + } + Cbo.EndObject(); + + Cbo << "badrequestcount" << m_ProjectStats.BadRequestCount; } Cbo.EndObject(); |