Skip to content

Commit b4335e5

Browse files
committed
Fix race condition causing interleaved logs
The output of the `DUMP_HEADER` macro was being written in multiple calls to fprintf() that raced with other logging, resulting in interleaved output that intermittently failed the ja3_fingerprint AuTest on CI. Whether other AuTest failures were related to the same issue is unknown at this point. This fixes the race condition by batching the calls to a single fprintf() call. This also refactors the macro to two inline functions. In a benchmark using an expanded version of the headers in the HttpTransact tests, a 60% speedup was measured over the macro if all the header data fit in the buffer. In the worst case that the buffer could only hold a byte at a time, the speedup was 80%. The benchmark was compiled with -O3 and stderr was piped to /dev/null. These were the headers used for the benchmark: ``` header input1[] = { {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "111111111111111111111111"}, {"BBB", "222" }, {"CCC", "333" }, {"DDD", "333" }, {"EEE", "333" }, {"FFF", "333" }, {"GGG", "333" }, {"HHH", "333" }, {"III", "333" }, {"JJJ", "333" }, {"KKK", "333" }, }; ``` This fixes #11431.
1 parent c72ca91 commit b4335e5

File tree

3 files changed

+62
-37
lines changed

3 files changed

+62
-37
lines changed

include/proxy/http/HttpTransact.h

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <cstddef>
2727

28+
#include "tsutil/DbgCtl.h"
2829
#include "tscore/ink_assert.h"
2930
#include "tscore/ink_platform.h"
3031
#include "iocore/hostdb/HostDB.h"
@@ -45,31 +46,55 @@
4546
#include "proxy/ProxySession.h"
4647
#include "tscore/MgmtDefs.h"
4748

49+
#include <cstdint>
50+
#include <cstdio>
51+
#include <string>
52+
#include <string_view>
53+
4854
#define HTTP_OUR_VIA_MAX_LENGTH 1024 // 512-bytes for hostname+via string, 512-bytes for the debug info
4955

5056
#define HTTP_RELEASE_ASSERT(X) ink_release_assert(X)
5157

52-
#define DUMP_HEADER(C, H, I, S) \
53-
{ \
54-
if ((C).on()) { \
55-
fprintf(stderr, "+++++++++ %s +++++++++\n", S); \
56-
fprintf(stderr, "-- State Machine Id: %" PRId64 "\n", I); \
57-
char b[4096]; \
58-
int used, tmp, offset; \
59-
int done; \
60-
offset = 0; \
61-
if ((H)->valid()) { \
62-
do { \
63-
used = 0; \
64-
tmp = offset; \
65-
done = (H)->print(b, 4095, &used, &tmp); \
66-
offset += used; \
67-
b[used] = '\0'; \
68-
fprintf(stderr, "%s", b); \
69-
} while (!done); \
70-
} \
71-
} \
58+
inline void
59+
s_dump_header(HTTPHdr const *hdr, std::string &out)
60+
{
61+
int offset{0};
62+
int done{0};
63+
do {
64+
int used{0};
65+
char b[4096];
66+
// The buffer offset is taken non-const and it is apparently
67+
// modified in some code path, but in my testing it does
68+
// not change, it seems. Since we manually bump the offset,
69+
// the use of tmp is precautionary to make sure our logic
70+
// doesn't break in case it does change in some circumstance.
71+
int tmp{offset};
72+
done = hdr->print(b, 4095, &used, &tmp);
73+
offset += used;
74+
b[used] = '\0';
75+
out.append(b);
76+
} while (0 == done);
77+
}
78+
79+
inline void
80+
dump_header(DbgCtl const &ctl, HTTPHdr const *hdr, std::int64_t sm_id, std::string_view description)
81+
{
82+
if (true) {
83+
std::string output;
84+
output.append("+++++++++ ");
85+
output.append(description);
86+
output.append(" +++++++++\n");
87+
output.append("-- State Machine Id: ");
88+
output.append(std::to_string(sm_id));
89+
output.push_back('\n');
90+
if (hdr->valid()) {
91+
s_dump_header(hdr, output);
92+
}
93+
// We make a single call to fprintf so that the output does not get
94+
// interleaved with output from other threads performing I/O.
95+
fprintf(stderr, "%s", output.c_str());
7296
}
97+
}
7398

7499
using ink_time_t = time_t;
75100

src/proxy/http/HttpSM.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6599,7 +6599,7 @@ HttpSM::setup_server_send_request()
65996599
t_state.hdr_info.server_request.value_set_int64(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH, msg_len);
66006600
}
66016601

6602-
DUMP_HEADER(dbg_ctl_http_hdrs, &(t_state.hdr_info.server_request), sm_id, "Proxy's Request after hooks");
6602+
dump_header(dbg_ctl_http_hdrs, &(t_state.hdr_info.server_request), sm_id, "Proxy's Request after hooks");
66036603

66046604
// We need a reader so bytes don't fall off the end of
66056605
// the buffer
@@ -8483,7 +8483,7 @@ HttpSM::redirect_request(const char *arg_redirect_url, const int arg_redirect_le
84838483
}
84848484
}
84858485

8486-
DUMP_HEADER(dbg_ctl_http_hdrs, &t_state.hdr_info.client_request, sm_id, "Framed Client Request..checking");
8486+
dump_header(dbg_ctl_http_hdrs, &t_state.hdr_info.client_request, sm_id, "Framed Client Request..checking");
84878487
}
84888488

84898489
void

src/proxy/http/HttpTransact.cc

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ HttpTransact::StartRemapRequest(State *s)
10221022
TxnDbg(dbg_ctl_http_trans, "Before Remapping:");
10231023
obj_describe(s->hdr_info.client_request.m_http, true);
10241024
}
1025-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.client_request, s->state_machine_id(), "Incoming Request");
1025+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.client_request, s->state_machine_id(), "Incoming Request");
10261026
10271027
if (s->http_config_param->referer_filter_enabled) {
10281028
s->filter_mask = URL_REMAP_FILTER_REFERER;
@@ -2264,9 +2264,9 @@ HttpTransact::HandlePushResponseHdr(State *s)
22642264
s->hdr_info.server_request.method_set(HTTP_METHOD_GET, HTTP_LEN_GET);
22652265
s->hdr_info.server_request.value_set("X-Inktomi-Source", 16, "http PUSH", 9);
22662266

2267-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.server_response, s->state_machine_id(), "Pushed Response Header");
2267+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.server_response, s->state_machine_id(), "Pushed Response Header");
22682268

2269-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.server_request, s->state_machine_id(), "Generated Request Header");
2269+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.server_request, s->state_machine_id(), "Generated Request Header");
22702270

22712271
s->response_received_time = s->request_sent_time = ink_local_time();
22722272

@@ -2447,7 +2447,7 @@ HttpTransact::issue_revalidate(State *s)
24472447
// the client has the right credentials
24482448
// this cache action is just to get us into the hcoofsr function
24492449
s->cache_info.action = CACHE_DO_UPDATE;
2450-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.server_request, s->state_machine_id(), "Proxy's Request (Conditionalized)");
2450+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.server_request, s->state_machine_id(), "Proxy's Request (Conditionalized)");
24512451
return;
24522452
}
24532453

@@ -2520,7 +2520,7 @@ HttpTransact::issue_revalidate(State *s)
25202520
if (str) {
25212521
s->hdr_info.server_request.value_set(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE, str, length);
25222522
}
2523-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.server_request, s->state_machine_id(), "Proxy's Request (Conditionalized)");
2523+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.server_request, s->state_machine_id(), "Proxy's Request (Conditionalized)");
25242524
}
25252525
// if Etag exists, also add if-non-match header
25262526
if (c_resp->presence(MIME_PRESENCE_ETAG) && (s->hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_GET ||
@@ -2534,7 +2534,7 @@ HttpTransact::issue_revalidate(State *s)
25342534
}
25352535
s->hdr_info.server_request.value_set(MIME_FIELD_IF_NONE_MATCH, MIME_LEN_IF_NONE_MATCH, etag, length);
25362536
}
2537-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.server_request, s->state_machine_id(), "Proxy's Request (Conditionalized)");
2537+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.server_request, s->state_machine_id(), "Proxy's Request (Conditionalized)");
25382538
}
25392539
break;
25402540
case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION: // 203
@@ -3430,7 +3430,7 @@ HttpTransact::HandleResponse(State *s)
34303430
s->current.now = s->response_received_time;
34313431

34323432
TxnDbg(dbg_ctl_http_trans, "response_received_time: %" PRId64, (int64_t)s->response_received_time);
3433-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.server_response, s->state_machine_id(), "Incoming O.S. Response");
3433+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.server_response, s->state_machine_id(), "Incoming O.S. Response");
34343434

34353435
Metrics::Counter::increment(http_rsb.incoming_responses);
34363436

@@ -4074,7 +4074,7 @@ HttpTransact::build_response_copy(State *s, HTTPHdr *base_response, HTTPHdr *out
40744074
HttpTransactHeaders::convert_response(outgoing_version, outgoing_response); // http version conversion
40754075
HttpTransactHeaders::add_server_header_to_response(s->txn_conf, outgoing_response);
40764076

4077-
DUMP_HEADER(dbg_ctl_http_hdrs, outgoing_response, s->state_machine_id(), "Proxy's Response");
4077+
dump_header(dbg_ctl_http_hdrs, outgoing_response, s->state_machine_id(), "Proxy's Response");
40784078
}
40794079

40804080
//////////////////////////////////////////////////////////////////////////
@@ -4616,7 +4616,7 @@ HttpTransact::handle_cache_operation_on_forward_server_response(State *s)
46164616
warn_text, strlen(warn_text));
46174617
}
46184618

4619-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.client_response, s->state_machine_id(), "Proxy's Response (Client Conditionals)");
4619+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.client_response, s->state_machine_id(), "Proxy's Response (Client Conditionals)");
46204620
return;
46214621
}
46224622
// all other responses (not 304, 412, 416) are handled here
@@ -4839,7 +4839,7 @@ HttpTransact::handle_transform_ready(State *s)
48394839
s->pre_transform_source = s->source;
48404840
s->source = SOURCE_TRANSFORM;
48414841

4842-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.transform_response, s->state_machine_id(), "Header From Transform");
4842+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.transform_response, s->state_machine_id(), "Header From Transform");
48434843

48444844
build_response(s, &s->hdr_info.transform_response, &s->hdr_info.client_response, s->client_info.http_version);
48454845

@@ -4887,7 +4887,7 @@ HttpTransact::set_header_for_transform(State *s, HTTPHdr *base_header)
48874887
// in the chain
48884888
s->hdr_info.transform_response.field_delete(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
48894889

4890-
DUMP_HEADER(dbg_ctl_http_hdrs, &s->hdr_info.transform_response, s->state_machine_id(), "Header To Transform");
4890+
dump_header(dbg_ctl_http_hdrs, &s->hdr_info.transform_response, s->state_machine_id(), "Header To Transform");
48914891
}
48924892

48934893
void
@@ -4947,7 +4947,7 @@ HttpTransact::set_headers_for_cache_write(State *s, HTTPInfo *cache_info, HTTPHd
49474947
cache_info->response_get()->field_delete(MIME_FIELD_WWW_AUTHENTICATE, MIME_LEN_WWW_AUTHENTICATE);
49484948
}
49494949

4950-
DUMP_HEADER(dbg_ctl_http_hdrs, cache_info->request_get(), s->state_machine_id(), "Cached Request Hdr");
4950+
dump_header(dbg_ctl_http_hdrs, cache_info->request_get(), s->state_machine_id(), "Cached Request Hdr");
49514951
}
49524952

49534953
void
@@ -7770,7 +7770,7 @@ HttpTransact::build_request(State *s, HTTPHdr *base_request, HTTPHdr *outgoing_r
77707770
ink_assert(s->request_sent_time >= s->response_received_time);
77717771

77727772
TxnDbg(dbg_ctl_http_trans, "request_sent_time: %" PRId64, (int64_t)s->request_sent_time);
7773-
DUMP_HEADER(dbg_ctl_http_hdrs, outgoing_request, s->state_machine_id(), "Proxy's Request");
7773+
dump_header(dbg_ctl_http_hdrs, outgoing_request, s->state_machine_id(), "Proxy's Request");
77747774

77757775
Metrics::Counter::increment(http_rsb.outgoing_requests);
77767776
}
@@ -7943,10 +7943,10 @@ HttpTransact::build_response(State *s, HTTPHdr *base_response, HTTPHdr *outgoing
79437943

79447944
if (dbg_ctl_http_hdrs.on()) {
79457945
if (base_response) {
7946-
DUMP_HEADER(dbg_ctl_http_hdrs, base_response, s->state_machine_id(), "Base Header for Building Response");
7946+
dump_header(dbg_ctl_http_hdrs, base_response, s->state_machine_id(), "Base Header for Building Response");
79477947
}
79487948

7949-
DUMP_HEADER(dbg_ctl_http_hdrs, outgoing_response, s->state_machine_id(), "Proxy's Response 2");
7949+
dump_header(dbg_ctl_http_hdrs, outgoing_response, s->state_machine_id(), "Proxy's Response 2");
79507950
}
79517951

79527952
return;

0 commit comments

Comments
 (0)