]> git.feebdaed.xyz Git - 0xmirror/grpc.git/commitdiff
[PH2][CallV3] Fix off by one error in client call
authorAkshit Patel <akshitpatel@google.com>
Fri, 5 Dec 2025 07:25:19 +0000 (23:25 -0800)
committerCopybara-Service <copybara-worker@google.com>
Fri, 5 Dec 2025 07:28:07 +0000 (23:28 -0800)
The current while condition always skips the first pending batch which can cause some ops to never poll.

PiperOrigin-RevId: 840571167

src/core/call/client_call.cc
test/core/call/client_call_test.cc

index 2de111478feee7e48294eb60bcc0e6eb9bb63ceb..b3f521a29dd5d6401ec7e2000368686ecfbd1c52 100644 (file)
@@ -293,7 +293,7 @@ bool ClientCall::StartCallMaybeUpdateState(uintptr_t& cur_state,
                                               std::memory_order_acquire)) {
         call_destination_->StartCall(std::move(handler));
         auto unordered_start = reinterpret_cast<UnorderedStart*>(cur_state);
-        while (unordered_start->next != nullptr) {
+        while (unordered_start != nullptr) {
           unordered_start->start_pending_batch();
           auto next = unordered_start->next;
           delete unordered_start;
index 3f65356670973cebab91a03b2c0a012393248e16..5d59f5781b6ddb7ef701c7228c9c458dd76f70be 100644 (file)
@@ -201,6 +201,37 @@ CLIENT_CALL_TEST(SendInitialMetadataAndReceiveStatusAfterCancellation) {
   WaitForAllPendingWork();
 }
 
+// Test to assert unordered pending batches are executed.
+CLIENT_CALL_TEST(UnorderedStart) {
+  InitCall(CallOptions());
+  NewBatch(1).SendMessage("hello");
+  // SendMessage op is not expected to finish until the initial metadata is sent
+  // and pulled.
+  TickThroughCqExpectations(Duration::Seconds(1));
+  NewBatch(101).SendInitialMetadata({});
+  Expect(101, true);
+  TickThroughCqExpectations();
+  SpawnTestSeq(
+      handler(), "pull-initial-metadata-then-message",
+      [this]() { return handler().PullClientInitialMetadata(); },
+      [](ValueOrFailure<ClientMetadataHandle> md) {
+        CHECK(md.ok());
+        EXPECT_EQ((*md)->get_pointer(HttpPathMetadata())->as_string_view(),
+                  kDefaultPath);
+        return Immediate(Empty{});
+      },
+      [this]() { return handler().PullMessage(); },
+      [](auto msg) {
+        CHECK(msg.ok());
+        CHECK(msg.has_value());
+        EXPECT_EQ(msg.value().payload()->JoinIntoString(), "hello");
+        return Immediate(Empty{});
+      });
+  Expect(1, true);
+  TickThroughCqExpectations();
+  WaitForAllPendingWork();
+}
+
 CLIENT_CALL_TEST(SendInitialMetadataAndReceiveStatusAfterTimeout) {
   auto start = Timestamp::Now();
   InitCall(CallOptions().SetTimeout(Duration::Seconds(1)));