3838
3939#include < algorithm>
4040#include < functional>
41+ #include < magic_enum.hpp>
4142#include < utility>
4243
4344static const int SUCCESS_RESPONSE_MIN = 200 ;
4445static const int SUCCESS_RESPONSE_MAX = 299 ;
4546
4647namespace ProfileEvents
4748{
48- extern const Event S3ReadMicroseconds;
4949extern const Event S3ReadRequestsCount;
5050extern const Event S3ReadRequestsErrors;
5151extern const Event S3ReadRequestsThrottling;
5252extern const Event S3ReadRequestsRedirects;
53+ extern const Event S3ReadRequestsNotFound;
5354
54- extern const Event S3WriteMicroseconds;
5555extern const Event S3WriteRequestsCount;
5656extern const Event S3WriteRequestsErrors;
5757extern const Event S3WriteRequestsThrottling;
5858extern const Event S3WriteRequestsRedirects;
59+ extern const Event S3WriteRequestsNotFound;
5960
6061extern const Event S3GetRequestThrottlerCount;
6162extern const Event S3GetRequestThrottlerSleepMicroseconds;
@@ -175,14 +176,14 @@ PocoHTTPClient::S3MetricKind PocoHTTPClient::getMetricKind(const Aws::Http::Http
175176
176177void PocoHTTPClient::addMetric (const Aws::Http::HttpRequest & request, S3MetricType type, ProfileEvents::Count amount)
177178{
178- const ProfileEvents::Event events_map[static_cast < size_t >(S3MetricType::EnumSize )]
179- [static_cast < size_t >(S3MetricKind::EnumSize )]
179+ const ProfileEvents::Event events_map[magic_enum::enum_count<S3MetricType>( )]
180+ [magic_enum::enum_count<S3MetricKind>( )]
180181 = {
181- {ProfileEvents::S3ReadMicroseconds, ProfileEvents::S3WriteMicroseconds},
182182 {ProfileEvents::S3ReadRequestsCount, ProfileEvents::S3WriteRequestsCount},
183183 {ProfileEvents::S3ReadRequestsErrors, ProfileEvents::S3WriteRequestsErrors},
184184 {ProfileEvents::S3ReadRequestsThrottling, ProfileEvents::S3WriteRequestsThrottling},
185185 {ProfileEvents::S3ReadRequestsRedirects, ProfileEvents::S3WriteRequestsRedirects},
186+ {ProfileEvents::S3ReadRequestsNotFound, ProfileEvents::S3WriteRequestsNotFound},
186187 };
187188
188189 S3MetricKind kind = getMetricKind (request);
@@ -272,6 +273,7 @@ void PocoHTTPClient::makeRequestInternal(
272273 }
273274}
274275
276+ // Return redirect uri if redirect happens, otherwise return nullopt
275277template <typename Session>
276278std::optional<String> PocoHTTPClient::makeRequestOnce (
277279 const Poco::URI & target_uri,
@@ -342,8 +344,6 @@ std::optional<String> PocoHTTPClient::makeRequestOnce(
342344 for (const auto & [header_name, header_value] : extra_headers)
343345 poco_request.set (boost::algorithm::to_lower_copy (header_name), header_value);
344346
345- Poco::Net::HTTPResponse poco_response;
346-
347347 Stopwatch watch;
348348
349349 Poco::Net::HTTPSendMetrics metrics;
@@ -372,28 +372,38 @@ std::optional<String> PocoHTTPClient::makeRequestOnce(
372372
373373 if (enable_s3_requests_logging)
374374 LOG_DEBUG (tracing_logger, " Receiving response..." );
375+ Poco::Net::HTTPResponse poco_response;
375376 auto & response_body_stream = session->receiveResponse (poco_response);
376377 GET_METRIC (tiflash_storage_s3_http_request_seconds, type_response)
377378 .Observe (watch.elapsedMillisecondsFromLastTime () / 1000.0 );
378379
379380 int status_code = static_cast <int >(poco_response.getStatus ());
380- if (status_code >= SUCCESS_RESPONSE_MIN && status_code <= SUCCESS_RESPONSE_MAX)
381+ if (status_code >= SUCCESS_RESPONSE_MIN && status_code <= SUCCESS_RESPONSE_MAX) // 2xx
381382 {
382383 if (enable_s3_requests_logging)
383384 LOG_DEBUG (tracing_logger, " Response status: {}, {}" , status_code, poco_response.getReason ());
384385 }
386+ else if (status_code == Poco::Net::HTTPResponse::HTTP_NOT_FOUND) // 404
387+ {
388+ // / 404 Not Found is a valid response for some requests (e.g., GET/HEAD of non-existing object)
389+ // / so we just log it at DEBUG level when `enable_s3_requests_logging` is on.
390+ if (enable_s3_requests_logging)
391+ LOG_DEBUG (tracing_logger, " Response status: {}, {}" , status_code, poco_response.getReason ());
392+ }
385393 else
386394 {
387395 // / Error statuses are more important so we show them even if `enable_s3_requests_logging == false`.
388396 LOG_INFO (tracing_logger, " Response status: {}, {}" , status_code, poco_response.getReason ());
389397 }
398+
399+ // handle redirect status codes
390400 if (poco_response.getStatus () == Poco::Net::HTTPResponse::HTTP_TEMPORARY_REDIRECT
391401 || poco_response.getStatus () == Poco::Net::HTTPResponse::HTTP_FOUND)
392402 {
393403 auto location = poco_response.get (" location" );
394404 remote_host_filter->checkURL (Poco::URI (location));
395405 if (enable_s3_requests_logging)
396- LOG_DEBUG (tracing_logger, " Redirecting request to new location: {}" , location);
406+ LOG_INFO (tracing_logger, " Redirecting request to new location: {}" , location);
397407
398408 addMetric (request, S3MetricType::Redirects);
399409
@@ -420,7 +430,7 @@ std::optional<String> PocoHTTPClient::makeRequestOnce(
420430 response->AddHeader (header_name, header_value);
421431 }
422432
423- // / Request is successful but for some special requests we can have actual error message in body
433+ // / Request is successful (2xx) but for some special requests we can have actual error message in body
424434 if (status_code >= SUCCESS_RESPONSE_MIN && status_code <= SUCCESS_RESPONSE_MAX
425435 && checkRequestCanReturn2xxAndErrorInBody (request))
426436 {
@@ -456,10 +466,20 @@ std::optional<String> PocoHTTPClient::makeRequestOnce(
456466 }
457467 else
458468 {
459- if (status_code == 429 || status_code == 503 )
460- { // API throttling
469+ if (status_code == Poco::Net::HTTPResponse::HTTP_TOO_MANY_REQUESTS
470+ || status_code == Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE)
471+ {
472+ // API throttling from the server side
473+ // 429 Too Many Requests
474+ // 503 Service Unavailable
461475 addMetric (request, S3MetricType::Throttling);
462476 }
477+ else if (status_code == Poco::Net::HTTPResponse::HTTP_NOT_FOUND)
478+ {
479+ // Get/Head request to a non-existing object, returning 404 Not Found
480+ // is a valid response.
481+ addMetric (request, S3MetricType::ErrorNotFound);
482+ }
463483 else if (status_code >= 300 )
464484 {
465485 addMetric (request, S3MetricType::Errors);
0 commit comments