Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the row reading logic in both AsyncRowReader and DefaultRowReader to correctly handle edge cases around row limits, row set boundaries, and parser failures. Specifically, it ensures that parser failures are not swallowed when a row limit is reached or a row set is exhausted, and it adds validation to reject negative row limits with an invalid argument error. It also updates DataConnectionImpl to properly drain streams when a single row is requested and adds comprehensive unit tests covering these scenarios. There are no review comments provided, so I have no additional feedback to offer.
a3ee8e6 to
f74b27d
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #16660 +/- ##
==========================================
- Coverage 92.53% 92.50% -0.03%
==========================================
Files 2269 2269
Lines 222896 223604 +708
==========================================
+ Hits 206250 206853 +603
- Misses 16646 16751 +105 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
1. [Bug / Asymmetry] Synchronous
|
f74b27d to
662a5d6
Compare
|
Thanks for the catch! Addressed all 4 items in
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors AsyncRowReader, DefaultRowReader, and DataConnectionImpl to properly handle negative row limits, track parser failures, and ensure that parser errors are not swallowed when row limits are reached or row sets are exhausted. It also adds comprehensive unit tests for these edge cases. Feedback on the changes suggests a minor improvement in data_connection_impl.cc to use it->status() instead of std::move(*it).status() for consistency and to avoid an unnecessary move on a dereferenced iterator.
662a5d6 to
b698107
Compare
Fix error-handling and resumption boundary issues in DefaultRowReader, AsyncRowReader, and DataConnectionImpl::ReadRow / AsyncReadRow: - Reject negative rows_limit immediately with client-side INVALID_ARGUMENT without issuing an RPC. - Preserve user cancellations and ReadRowsParser failures (including HandleEndOfStream errors on a clean EOF when rows_limit was not reached) at rows_limit and empty-RowSet boundaries. - Apply response_.last_scanned_row_key() in DefaultRowReader::NextChunk after consuming all chunks in the response. - Drain rows_limit = 1 streams cleanly in DataConnectionImpl::AsyncReadRow without triggering client cancellation, and propagate post-row parser errors in both DataConnectionImpl::ReadRow and AsyncReadRow.
b698107 to
da1ea01
Compare
Summary
Fixes four error-handling and resumption boundary issues in
DefaultRowReader,AsyncRowReader, andDataConnectionImpl::ReadRow/AsyncReadRow:rows_limitsilently returns 0 rows (OK): Becauserows_limit_ != NO_ROWS_LIMIT && rows_limit_ <= rows_count_(NO_ROWS_LIMIT == 0) evaluatedtruefor any negativerows_limitwhenrows_count_ == 0, negativerows_limitvalues suppressed errors and terminated as an emptyOKscan instead of failing fast with client-sideINVALID_ARGUMENT.rows_limitwas reached orrow_set_became empty after the last delivered/scanned row,DefaultRowReader::AdvanceandAsyncRowReader::OnStreamFinishedunconditionally overwrotestatuswithOK, masking user cancellations (Cancel/OnRowreturningfalseor throwing), mid-streamReadRowsParserprotocol errors (INTERNAL), andHandleEndOfStreamerrors on a clean EOF whenrows_limithad not been reached.last_scanned_row_keyoverwrite inDefaultRowReader::NextChunk: Updatinglast_read_row_key_fromresponse_.last_scanned_row_key()immediately onstream_->Read(&response_)(before consumingresponse_.chunks()) allowedAdvance()to overwritelast_read_row_key_with an earlier chunk'sparsed_row.row_key(), causing retries to re-request already-scanned rows up tolast_scanned_row_key.ReadRow/AsyncReadRow: Returningmake_ready_future(false)fromAsyncReadRowHandler::OnRowtriggeredAsyncRowReader::Cancel("User cancelled")on every single-row read (rows_limit = 1); returningtruelets therows_limit = 1stream close cleanly withOK, while bothReadRowandAsyncReadRowpropagate post-row parser errors (INTERNAL) and still reject unexpected extra rows.Changes
rows_limit_ < 0inDefaultRowReader::AdvanceandAsyncRowReader::MakeRequest, returningINVALID_ARGUMENTwithout issuing an RPC.parser_failed_/user_cancelled_(includingHandleEndOfStreamfailures on clean EOF when!ReachedRowsLimit(...)) and preserve those statuses atrows_limitand empty-RowSetscan boundaries while still ignoring benign trailing transport errors once all requested rows have been delivered.response_.last_scanned_row_key()inDefaultRowReader::NextChunkafter all chunks inresponse_have been consumed.OKstatuses inDataConnectionImpl::ReadRow(if (!*it) return std::move(*it).status();) andDataConnectionImpl::AsyncReadRow, while drainingrows_limit = 1streams cleanly without cancelling.default_row_reader_test.cc,async_row_reader_test.cc, anddata_connection_impl_test.cc.