SteNicholas commented on code in PR #3755:
URL: https://github.com/apache/celeborn/pull/3755#discussion_r3548609965


##########
cpp/celeborn/network/Message.h:
##########
@@ -322,5 +322,14 @@ class PushMergedData : public Message {
   std::vector<std::string> partitionUniqueIds_;
   std::vector<int32_t> batchOffsets_;
 };
+
+class Heartbeat : public Message {

Review Comment:
   Minor / optional (decode-only scope is otherwise fine):
   
   1. `Heartbeat` overrides neither `internalEncodedLength()` nor 
`internalEncodeTo()`, so `Message::encode()` on a `Heartbeat` hits the 
base-class `CELEBORN_UNREACHABLE`. That's acceptable while the C++ client only 
ever *receives* heartbeats, but if a future change needs it to originate or 
respond with one (Java does `respond(new Heartbeat())` and periodic 
`writeAndFlush(new Heartbeat())`), encode support will be required.
   2. Unlike every other `Message` subclass in this file, `Heartbeat` declares 
no copy constructor. Because the base `body_` is a `unique_ptr`, the implicit 
copy ctor is deleted, so `Heartbeat` is non-copyable — harmless today (the 
receive path only moves `unique_ptr<Message>`), but inconsistent with its 
siblings and would surface as a compile error the moment any code copies a 
`Heartbeat`.



##########
cpp/celeborn/network/Message.cpp:
##########
@@ -102,6 +102,8 @@ std::unique_ptr<Message> Message::decodeFrom(
       return ChunkFetchSuccess::decodeFrom(std::move(data));
     case CHUNK_FETCH_FAILURE:
       return ChunkFetchFailure::decodeFrom(std::move(data));
+    case HEARTBEAT:
+      return Heartbeat::decodeFrom(std::move(data));

Review Comment:
   Decoding the heartbeat here is correct, but note where the decoded message 
goes next: `MessageSerializeHandler::read` fires it to 
`MessageDispatcher::read` (the terminal handler attached via `setPipeline`), 
whose `switch` only handles `RPC_RESPONSE` / `RPC_FAILURE` / 
`CHUNK_FETCH_SUCCESS` / `CHUNK_FETCH_FAILURE`. A `HEARTBEAT` falls into the 
`default` branch, which does `LOG(ERROR) << "unsupported msg for dispatcher"`.
   
   So once worker heartbeat is enabled 
(`celeborn.worker.push.heartbeat.enabled` / 
`celeborn.worker.fetch.heartbeat.enabled`, sent every `heartbeat.interval`, 
default 60s), every received heartbeat now produces a spurious ERROR log for 
the life of each connection. This PR correctly removes the hard `CELEBORN_FAIL` 
on decode, but to make heartbeats truly benign please also add a `case 
Message::HEARTBEAT: return;` (or a `VLOG`) to `MessageDispatcher::read` so 
they're consumed silently — the frame arriving is all that matters for 
read-idle; its payload is ignored, matching the Java 
`TransportChannelHandler.channelRead` path which just propagates a received 
`Heartbeat` without erroring.



##########
cpp/celeborn/network/tests/MessageTest.cpp:
##########
@@ -255,3 +255,19 @@ TEST(MessageTest, pushMergedDataCopyConstructor) {
   EXPECT_EQ(copy.batchOffsets().size(), 2);
   EXPECT_EQ(copy.batchOffsets()[1], 4);
 }
+
+TEST(MessageTest, decodeHeartbeat) {
+  const int headerLength = sizeof(int32_t) + sizeof(uint8_t) + sizeof(int32_t);
+  const int encodedLength = 1;
+  const int bodyLength = 0;
+  size_t size = headerLength + encodedLength + bodyLength;
+  auto writeBuffer = memory::ByteBuffer::createWriteOnly(size);
+  writeBuffer->write<int32_t>(encodedLength);
+  writeBuffer->write<uint8_t>(Message::Type::HEARTBEAT);
+  writeBuffer->write<int32_t>(bodyLength);
+  writeBuffer->write<uint8_t>(0);
+  auto message = Message::decodeFrom(
+      memory::ByteBuffer::toReadOnly(std::move(writeBuffer)));
+  EXPECT_NE(message, nullptr);
+  EXPECT_EQ(message->type(), Message::Type::HEARTBEAT);

Review Comment:
   Minor (test coverage): the test asserts only that the message is non-null 
and `type() == HEARTBEAT`; it never verifies that the one encoded byte was 
consumed. The single new behavior this PR adds — `data->skip(1)` and the empty 
body — is therefore unchecked: dropping the `skip(1)`, skipping the wrong 
count, or routing the leftover byte into the body would all still pass. 
Consider adding e.g. `EXPECT_EQ(message->body()->remainingSize(), 0);` to lock 
the contract.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to