Skip to content

Fix swapped TX/RX byte counters (TxBytes/RxBytes mislabeled) - #112

Merged
fcostaoliveira merged 3 commits into
masterfrom
fix/txrx-byte-swap-111
Jul 13, 2026
Merged

Fix swapped TX/RX byte counters (TxBytes/RxBytes mislabeled)#112
fcostaoliveira merged 3 commits into
masterfrom
fix/txrx-byte-swap-111

Conversation

@fcostaoliveira

@fcostaoliveira fcostaoliveira commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Closes #111.

Problem

AddEntry declares its last two params as (rx, tx) (benchmark_runner/stat.go), but the single call site in cmd/ftsb_redisearch/cmd_processor.go passed them as (txBytesCount, rxBytesCount) — reversed. So the bytes sent to Redis were stored in the rx field and the reply bytes in the tx field. Downstream, txTotalBytes sums Tx() and rxTotalBytes sums Rx(), so the reported TxBytes/RxBytes (and their rate metrics) were mirror-labeled.

Because replies are currently discarded (the receiver rcv is a nil interface, so getRxLen returns 0), the practical effect was:

  • TxBytes (and overallTxByteRate) always reported 0.
  • RxBytes (and overallRxByteRate) reported the sent-byte total.

Ops/sec and latency were unaffected (they derive from command count and timing).

Fix

  • Swap the two arguments at the call site so received bytes land in Rx() and sent bytes in Tx().
  • Correct the duplicated // bytes received struct comment on the tx field.

Tests

  • benchmark_runner/stat_test.go: AddEntry and NewCmdStat map (rx, tx) into Rx()/Tx() in order.
  • cmd/ftsb_redisearch/send_stats_test.go: sendFlatCmd records the sent-byte count as Tx() (exercised with a fake radix.Client, no Redis needed). Verified this test fails on the pre-fix argument order (Tx() = 0, want 4096) and passes after the fix.
  • getRxLen sizing for string / []string / nil / other.

Both suites are wired into CI (make integration-test covers benchmark_runner; make unit-test covers cmd/...). gofmt/go vet/go test -race all clean.

Note (out of scope)

Redis replies are not currently captured (rcv is nil), so RxBytes reads 0 after this change (an honest 0, vs. the pre-fix value which put SENT bytes under the RX label). Making RxBytes meaningful is a multi-part change (pointer receiver + replies plumbing + extending getRxLen to the types radix returns) and is tracked, along with a --pipeline >1 panic and pipelined per-command byte miscounting, in #113. This fix is strictly the mislabeling on the working pipeline=1 path.

AddEntry takes (..., rx, tx), but the single call site passed
(txBytesCount, rxBytesCount), so sent bytes were stored as rx and received
bytes as tx. Downstream, TxBytes summed Tx() and RxBytes summed Rx(), leaving
both metrics mirror-labeled. Because replies are discarded (rcv is a nil
interface, getRxLen returns 0), the net effect was that TxBytes always reported
0 and RxBytes reported the sent-byte total.

Swap the two arguments at the call site so received bytes land in Rx() and sent
bytes in Rx()'s counterpart Tx(), and correct the duplicated struct comment.

Tests:
- benchmark_runner: AddEntry/NewCmdStat map (rx, tx) into Rx()/Tx() in order.
- cmd/ftsb_redisearch: sendFlatCmd records the sent-byte count as Tx() (via a
  fake radix.Client); verified this test fails on the pre-fix argument order.
- getRxLen sizing for string/[]string/nil/other.

Closes #111
Add fake-radix.Client tests for the error and i/o-timeout branches of
sendIfRequired, asserting the sent-byte count is still recorded in Tx() and the
error/timeout flags are set. Raises sendIfRequired coverage 58.8% -> 88.2%.
Review-driven hardening (no behavior change):
- Add TestGetTotalsMapMapsTxRxCorrectly: guards the GetTotalsMap aggregation
  labels (txTotalBytes -> "TxBytes", rxTotalBytes -> "RxBytes") -- the JSON the
  issue #111 symptom appeared in, previously untested.
- TestSendFlatCmdRecordsSentBytesAsTx now sets pipeline=1 explicitly (with
  save/restore) so a stray package global can't make the channel receive block.
- TestSendFlatCmdMarksTimeout now also asserts Tx() so it guards byte
  accounting on the timeout path, not just the timeout flag.
- Document that bytelen is an application-payload proxy (excludes RESP framing),
  accurate for large payloads, approximate for many-tiny-arg commands.
@sonarqubecloud

Copy link
Copy Markdown

@fcostaoliveira
fcostaoliveira merged commit c8e15d9 into master Jul 13, 2026
3 checks passed
@fcostaoliveira
fcostaoliveira deleted the fix/txrx-byte-swap-111 branch July 13, 2026 11:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TX/RX byte counters are swapped: reported TxBytes/RxBytes (and their rates) are mirror-labeled

1 participant