This is an automated email from the ASF dual-hosted git repository.

zaynt4606 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/celeborn.git


The following commit(s) were added to refs/heads/main by this push:
     new 69200e209a [CELEBORN-2220][CIP-14] Support Slow Start Push in C++ 
Client
69200e209a is described below

commit 69200e209a21168d29faa17be03dadfb5a6f259f
Author: afterincomparableyum 
<[email protected]>
AuthorDate: Tue Oct 20 11:23:09 2026 +0800

    [CELEBORN-2220][CIP-14] Support Slow Start Push in C++ Client
    
    ### What changes were proposed in this pull request?
    
    Add `SlowStartPushStrategy` to the C++ client, a port of the Java client's 
TCP-like push congestion control:
    
    - Keeps per-worker congestion state: the in-flight request limit grows by 
one per successful push until it reaches 
`celeborn.client.push.maxReqsInFlight.perWorker`, then grows linearly. The 
limit halves when a worker responds with 
`PUSH_DATA_SUCCESS_{PRIMARY,REPLICA}_CONGESTED`, and pushes sleep while the 
limit is below the maximum.
    - Selected with `celeborn.client.push.limit.strategy=SLOWSTART` 
(case-insensitive, as in Java). Before this change, the C++ client rejected 
`SLOWSTART`.
    - Adds `celeborn.client.push.slowStart.initialSleepTime` (default `500ms`) 
and `celeborn.client.push.slowStart.maxSleepTime` (default `2s`), with the same 
keys and defaults as Java.
    
    The C++ push callbacks and `PushState` already call `onSuccess`, 
`onCongestControl`, `limitPushSpeed` and `getCurrentMaxReqsInFlight`, so this 
PR only adds the strategy itself.
    
    #3730 is closed as stale. That PR's review comments are addressed here.
    
    ### Why are the changes needed?
    
    To close a feature gap between the C++ and Java clients (CIP-14).
    
    ### Does this PR resolve a correctness bug?
    
    - [ ] Yes
    
    ### Does this PR introduce _any_ user-facing change?
    
    - [x] Yes
    
    C++ client users can set `celeborn.client.push.limit.strategy=SLOWSTART` 
and the two `celeborn.client.push.slowStart.*` configs. The default strategy is 
still `SIMPLE`. Like the Java client, SLOWSTART only backs off when workers 
have `celeborn.worker.congestionControl.enabled=true`.
    
    ### How was this patch tested?
    
    - New `PushStrategyTest`: strategy selection, sleep-time calculation, slow 
start and congestion avoidance, and isolation between hosts. Its assertions 
mirror Java's `SlowStartPushStrategyTest`.
    - `CelebornConfTest`: defaults and overrides for the new configs.
    
    Closes #3878 from afterincomparableyum/CELEBORN-2220.
    
    Authored-by: afterincomparableyum 
<[email protected]>
    Signed-off-by: zhengtao <[email protected]>
    
    AI-Contributed/Feature: 0/194
    AI-Contributed/UT: 0/175
---
 cpp/celeborn/client/tests/CMakeLists.txt       |   1 +
 cpp/celeborn/client/tests/PushStrategyTest.cpp | 161 +++++++++++++++++++++++++
 cpp/celeborn/client/writer/PushStrategy.cpp    | 101 ++++++++++++++++
 cpp/celeborn/client/writer/PushStrategy.h      |  65 +++++++++-
 cpp/celeborn/conf/CelebornConf.cpp             |  16 +++
 cpp/celeborn/conf/CelebornConf.h               |  12 ++
 cpp/celeborn/conf/tests/CelebornConfTest.cpp   |  13 ++
 7 files changed, 368 insertions(+), 1 deletion(-)

diff --git a/cpp/celeborn/client/tests/CMakeLists.txt 
b/cpp/celeborn/client/tests/CMakeLists.txt
index 08623486b2..fa50f2e879 100644
--- a/cpp/celeborn/client/tests/CMakeLists.txt
+++ b/cpp/celeborn/client/tests/CMakeLists.txt
@@ -22,6 +22,7 @@ add_executable(
         CelebornInputStreamTest.cpp
         CelebornInputStreamRetryTest.cpp
         PushStateTest.cpp
+        PushStrategyTest.cpp
         ReviveManagerTest.cpp
         Lz4DecompressorTest.cpp
         ZstdDecompressorTest.cpp
diff --git a/cpp/celeborn/client/tests/PushStrategyTest.cpp 
b/cpp/celeborn/client/tests/PushStrategyTest.cpp
new file mode 100644
index 0000000000..094cf1ef3d
--- /dev/null
+++ b/cpp/celeborn/client/tests/PushStrategyTest.cpp
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "celeborn/client/writer/PushStrategy.h"
+
+using namespace celeborn;
+using namespace celeborn::client;
+
+namespace {
+std::unique_ptr<SlowStartPushStrategy> createSlowStartStrategy(
+    int maxReqsInFlightPerWorker,
+    const std::string& maxSleepTime) {
+  conf::CelebornConf conf;
+  conf.registerProperty(
+      conf::CelebornConf::kClientPushMaxReqsInFlightPerWorker,
+      std::to_string(maxReqsInFlightPerWorker));
+  conf.registerProperty(
+      conf::CelebornConf::kClientPushSlowStartMaxSleepTime, maxSleepTime);
+  // Strategy selection through PushStrategy::create is covered by the
+  // createStrategy test.
+  return std::make_unique<SlowStartPushStrategy>(conf);
+}
+} // namespace
+
+TEST(PushStrategyTest, createStrategy) {
+  conf::CelebornConf conf;
+  // Default strategy is SIMPLE.
+  EXPECT_NE(
+      dynamic_cast<SimplePushStrategy*>(PushStrategy::create(conf).get()),
+      nullptr);
+
+  // The strategy name is case-insensitive, as the Java config entry
+  // uppercases the configured value.
+  conf.registerProperty(
+      conf::CelebornConf::kClientPushLimitStrategy, "slowstart");
+  EXPECT_NE(
+      dynamic_cast<SlowStartPushStrategy*>(PushStrategy::create(conf).get()),
+      nullptr);
+
+  conf.registerProperty(
+      conf::CelebornConf::kClientPushLimitStrategy, "UNKNOWN");
+  EXPECT_THROW(PushStrategy::create(conf), std::exception);
+}
+
+TEST(PushStrategyTest, sleepTime) {
+  auto strategy = createSlowStartStrategy(32, "3s");
+  const std::string dummyHostPort = "test:9087";
+  auto context = strategy->getCongestControlContextByAddress(dummyHostPort);
+
+  // If the currentReq is 1, should sleep 440 ms
+  EXPECT_EQ(440, strategy->getSleepTime(*context));
+
+  // If the currentReq is 8, should sleep 20 ms
+  for (int i = 0; i < 7; i++) {
+    strategy->onSuccess(dummyHostPort);
+  }
+  EXPECT_EQ(20, strategy->getSleepTime(*context));
+
+  // If the currentReq is 16, should sleep 0 ms
+  for (int i = 0; i < 8; i++) {
+    strategy->onSuccess(dummyHostPort);
+  }
+  EXPECT_EQ(0, strategy->getSleepTime(*context));
+
+  // Congest the requests, the currentReq reduced to 8, should sleep 20 ms
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(20, strategy->getSleepTime(*context));
+
+  // Congest the requests, the currentReq reduced to 4, should sleep 260 ms
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(260, strategy->getSleepTime(*context));
+  // Congest the requests, the currentReq reduced to 2, should sleep 380 ms
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(380, strategy->getSleepTime(*context));
+  // Congest the requests, the currentReq reduced to 1, should sleep 440 ms
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(440, strategy->getSleepTime(*context));
+  // Keep congest the requests even the currentReq reduced to 1, will increase
+  // the sleep time 1s
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(1440, strategy->getSleepTime(*context));
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(2440, strategy->getSleepTime(*context));
+
+  // Cannot exceed the max sleep time
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(3000, strategy->getSleepTime(*context));
+
+  // If start to return success, the currentReq is increased to 2, should
+  // sleep 380 ms
+  strategy->onSuccess(dummyHostPort);
+  EXPECT_EQ(380, strategy->getSleepTime(*context));
+}
+
+TEST(PushStrategyTest, congestStrategy) {
+  auto strategy = createSlowStartStrategy(5, "4s");
+  const std::string dummyHostPort = "test:9087";
+  // Slow start, should exponentially increase the currentReq
+  strategy->onSuccess(dummyHostPort);
+  EXPECT_EQ(2, strategy->getCurrentMaxReqsInFlight(dummyHostPort));
+  strategy->onSuccess(dummyHostPort);
+  strategy->onSuccess(dummyHostPort);
+  EXPECT_EQ(4, strategy->getCurrentMaxReqsInFlight(dummyHostPort));
+  strategy->onSuccess(dummyHostPort);
+  strategy->onSuccess(dummyHostPort);
+  strategy->onSuccess(dummyHostPort);
+  strategy->onSuccess(dummyHostPort);
+
+  // Will linearly increase the currentReq if meet the maxReqsInFlight
+  EXPECT_EQ(5, strategy->getCurrentMaxReqsInFlight(dummyHostPort));
+  strategy->onSuccess(dummyHostPort);
+  strategy->onSuccess(dummyHostPort);
+  strategy->onSuccess(dummyHostPort);
+  strategy->onSuccess(dummyHostPort);
+  strategy->onSuccess(dummyHostPort);
+  EXPECT_EQ(6, strategy->getCurrentMaxReqsInFlight(dummyHostPort));
+
+  // Congest controlled, should half the currentReq
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(3, strategy->getCurrentMaxReqsInFlight(dummyHostPort));
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(1, strategy->getCurrentMaxReqsInFlight(dummyHostPort));
+
+  // Cannot lower than 1
+  strategy->onCongestControl(dummyHostPort);
+  EXPECT_EQ(1, strategy->getCurrentMaxReqsInFlight(dummyHostPort));
+}
+
+TEST(PushStrategyTest, multiHosts) {
+  auto strategy = createSlowStartStrategy(3, "3s");
+  const std::string dummyHostPort1 = "test1:9087";
+  const std::string dummyHostPort2 = "test2:9087";
+  auto context1 = strategy->getCongestControlContextByAddress(dummyHostPort1);
+  auto context2 = strategy->getCongestControlContextByAddress(dummyHostPort2);
+
+  EXPECT_EQ(440, strategy->getSleepTime(*context1));
+  EXPECT_EQ(440, strategy->getSleepTime(*context2));
+
+  // Control the dummyHostPort1, should not affect dummyHostPort2
+  for (int i = 0; i < 3; i++) {
+    strategy->onSuccess(dummyHostPort1);
+  }
+  EXPECT_EQ(0, strategy->getSleepTime(*context1));
+  EXPECT_EQ(440, strategy->getSleepTime(*context2));
+}
diff --git a/cpp/celeborn/client/writer/PushStrategy.cpp 
b/cpp/celeborn/client/writer/PushStrategy.cpp
index 66dad6c4e4..ab4ce08e30 100644
--- a/cpp/celeborn/client/writer/PushStrategy.cpp
+++ b/cpp/celeborn/client/writer/PushStrategy.cpp
@@ -17,18 +17,119 @@
 
 #include "celeborn/client/writer/PushStrategy.h"
 
+#include <algorithm>
+#include <cctype>
+#include <thread>
+
 namespace celeborn {
 namespace client {
 
 std::unique_ptr<PushStrategy> PushStrategy::create(
     const conf::CelebornConf& conf) {
   auto strategyName = conf.clientPushLimitStrategy();
+  // The Java config entry uppercases the configured value.
+  std::transform(
+      strategyName.begin(),
+      strategyName.end(),
+      strategyName.begin(),
+      [](unsigned char c) { return static_cast<char>(std::toupper(c)); });
   if (strategyName == conf::CelebornConf::kSimplePushStrategy) {
     return std::make_unique<SimplePushStrategy>(conf);
+  } else if (strategyName == conf::CelebornConf::kSlowStartPushStrategy) {
+    return std::make_unique<SlowStartPushStrategy>(conf);
   } else {
     CELEBORN_FAIL("unsupported pushStrategy: " + strategyName);
   }
 }
 
+void SlowStartPushStrategy::CongestControlContext::increaseCurrentMaxReqs() {
+  std::lock_guard<std::mutex> lock(mutex_);
+  continueCongestedNumber_.store(0);
+  if (currentMaxReqsInFlight_.load() >= reqsInFlightBlockThreshold_) {
+    // Congestion avoidance
+    congestionAvoidanceFlag_++;
+    if (congestionAvoidanceFlag_ >= currentMaxReqsInFlight_.load()) {
+      currentMaxReqsInFlight_.fetch_add(1);
+      congestionAvoidanceFlag_ = 0;
+    }
+  } else {
+    // Slow start
+    currentMaxReqsInFlight_.fetch_add(1);
+  }
+}
+
+void SlowStartPushStrategy::CongestControlContext::decreaseCurrentMaxReqs() {
+  std::lock_guard<std::mutex> lock(mutex_);
+  if (currentMaxReqsInFlight_.load() <= 1) {
+    currentMaxReqsInFlight_.store(1);
+    continueCongestedNumber_.fetch_add(1);
+  } else {
+    currentMaxReqsInFlight_.store(currentMaxReqsInFlight_.load() / 2);
+  }
+  reqsInFlightBlockThreshold_ = currentMaxReqsInFlight_.load();
+  congestionAvoidanceFlag_ = 0;
+}
+
+std::shared_ptr<SlowStartPushStrategy::CongestControlContext>
+SlowStartPushStrategy::getCongestControlContextByAddress(
+    const std::string& hostAndPushPort) {
+  return congestControlInfoPerAddress_.computeIfAbsent(hostAndPushPort, [&]() {
+    return std::make_shared<CongestControlContext>(maxInFlightPerWorker_);
+  });
+}
+
+void SlowStartPushStrategy::onSuccess(const std::string& hostAndPushPort) {
+  getCongestControlContextByAddress(hostAndPushPort)->increaseCurrentMaxReqs();
+}
+
+void SlowStartPushStrategy::onCongestControl(
+    const std::string& hostAndPushPort) {
+  getCongestControlContextByAddress(hostAndPushPort)->decreaseCurrentMaxReqs();
+}
+
+long SlowStartPushStrategy::getSleepTime(CongestControlContext& context) const 
{
+  int currentMaxReqs = context.getCurrentMaxReqsInFlight();
+  if (currentMaxReqs >= maxInFlightPerWorker_) {
+    return 0;
+  }
+
+  long sleepInterval = initialSleepMills_ - 60L * currentMaxReqs;
+
+  if (currentMaxReqs == 1) {
+    return std::min(
+        sleepInterval + context.getContinueCongestedNumber() * 1000L,
+        maxSleepMills_);
+  }
+
+  return std::max(sleepInterval, 0L);
+}
+
+void SlowStartPushStrategy::limitPushSpeed(
+    PushState& pushState,
+    const std::string& hostAndPushPort) {
+  auto exceptionMsg = pushState.getExceptionMsg();
+  if (exceptionMsg.has_value()) {
+    CELEBORN_FAIL(exceptionMsg.value());
+  }
+  auto congestControlContext =
+      getCongestControlContextByAddress(hostAndPushPort);
+  long sleepInterval = getSleepTime(*congestControlContext);
+  if (sleepInterval > 0L) {
+    VLOG(1) << "Will sleep " << sleepInterval
+            << " ms to control the push speed to " << hostAndPushPort << ".";
+    std::this_thread::sleep_for(utils::MS(sleepInterval));
+  }
+}
+
+int SlowStartPushStrategy::getCurrentMaxReqsInFlight(
+    const std::string& hostAndPushPort) {
+  return getCongestControlContextByAddress(hostAndPushPort)
+      ->getCurrentMaxReqsInFlight();
+}
+
+void SlowStartPushStrategy::clear() {
+  congestControlInfoPerAddress_.clear();
+}
+
 } // namespace client
 } // namespace celeborn
diff --git a/cpp/celeborn/client/writer/PushStrategy.h 
b/cpp/celeborn/client/writer/PushStrategy.h
index 60a40f5934..7e7b35d026 100644
--- a/cpp/celeborn/client/writer/PushStrategy.h
+++ b/cpp/celeborn/client/writer/PushStrategy.h
@@ -17,10 +17,13 @@
 
 #pragma once
 
+#include <atomic>
 #include <memory>
+#include <mutex>
 
 #include "celeborn/client/writer/PushState.h"
 #include "celeborn/conf/CelebornConf.h"
+#include "celeborn/utils/CelebornUtils.h"
 
 namespace celeborn {
 namespace client {
@@ -73,7 +76,67 @@ class SimplePushStrategy : public PushStrategy {
   const int maxInFlightPerWorker_;
 };
 
-// TODO: support SlowStartPushStrategy
+class SlowStartPushStrategy : public PushStrategy {
+ public:
+  class CongestControlContext {
+   public:
+    CongestControlContext(int reqsInFlightBlockThreshold)
+        : reqsInFlightBlockThreshold_(reqsInFlightBlockThreshold) {}
+
+    void increaseCurrentMaxReqs();
+
+    void decreaseCurrentMaxReqs();
+
+    int getCurrentMaxReqsInFlight() const {
+      return currentMaxReqsInFlight_.load();
+    }
+
+    int getContinueCongestedNumber() const {
+      return continueCongestedNumber_.load();
+    }
+
+   private:
+    std::mutex mutex_;
+    std::atomic<int> currentMaxReqsInFlight_{1};
+    // Indicate the number of congested times even after the in flight
+    // requests reduced to 1.
+    std::atomic<int> continueCongestedNumber_{0};
+    int congestionAvoidanceFlag_{0};
+    int reqsInFlightBlockThreshold_;
+  };
+
+  SlowStartPushStrategy(const conf::CelebornConf& conf)
+      : maxInFlightPerWorker_(conf.clientPushMaxReqsInFlightPerWorker()),
+        initialSleepMills_(conf.clientPushSlowStartInitialSleepTimeMs()),
+        maxSleepMills_(conf.clientPushSlowStartMaxSleepTimeMs()) {}
+
+  ~SlowStartPushStrategy() override = default;
+
+  void onSuccess(const std::string& hostAndPushPort) override;
+
+  void onCongestControl(const std::string& hostAndPushPort) override;
+
+  void clear() override;
+
+  void limitPushSpeed(PushState& pushState, const std::string& hostAndPushPort)
+      override;
+
+  int getCurrentMaxReqsInFlight(const std::string& hostAndPushPort) override;
+
+  // Visible for testing.
+  std::shared_ptr<CongestControlContext> getCongestControlContextByAddress(
+      const std::string& hostAndPushPort);
+
+  // Visible for testing.
+  long getSleepTime(CongestControlContext& context) const;
+
+ private:
+  const int maxInFlightPerWorker_;
+  const long initialSleepMills_;
+  const long maxSleepMills_;
+  utils::ConcurrentHashMap<std::string, std::shared_ptr<CongestControlContext>>
+      congestControlInfoPerAddress_;
+};
 
 } // namespace client
 } // namespace celeborn
diff --git a/cpp/celeborn/conf/CelebornConf.cpp 
b/cpp/celeborn/conf/CelebornConf.cpp
index c8ca58d1f9..20257b62a0 100644
--- a/cpp/celeborn/conf/CelebornConf.cpp
+++ b/cpp/celeborn/conf/CelebornConf.cpp
@@ -147,6 +147,8 @@ CelebornConf::defaultProperties() {
           NUM_PROP(kClientPushReviveBatchSize, 2048),
           NUM_PROP(kClientPushMaxReviveTimes, 5),
           STR_PROP(kClientPushLimitStrategy, kSimplePushStrategy),
+          STR_PROP(kClientPushSlowStartInitialSleepTime, "500ms"),
+          STR_PROP(kClientPushSlowStartMaxSleepTime, "2s"),
           NUM_PROP(kClientPushMaxReqsInFlightPerWorker, 32),
           NUM_PROP(kClientPushMaxReqsInFlightTotal, 256),
           NUM_PROP(kClientPushLimitInFlightTimeoutMs, 240000),
@@ -258,6 +260,20 @@ std::string CelebornConf::clientPushLimitStrategy() const {
   return optionalProperty(kClientPushLimitStrategy).value();
 }
 
+long CelebornConf::clientPushSlowStartInitialSleepTimeMs() const {
+  return utils::toTimeout(
+             toDuration(optionalProperty(kClientPushSlowStartInitialSleepTime)
+                            .value()))
+      .count();
+}
+
+long CelebornConf::clientPushSlowStartMaxSleepTimeMs() const {
+  return utils::toTimeout(
+             toDuration(
+                 optionalProperty(kClientPushSlowStartMaxSleepTime).value()))
+      .count();
+}
+
 int CelebornConf::clientPushMaxReqsInFlightPerWorker() const {
   return std::stoi(
       optionalProperty(kClientPushMaxReqsInFlightPerWorker).value());
diff --git a/cpp/celeborn/conf/CelebornConf.h b/cpp/celeborn/conf/CelebornConf.h
index 860911eb41..ac9684c79c 100644
--- a/cpp/celeborn/conf/CelebornConf.h
+++ b/cpp/celeborn/conf/CelebornConf.h
@@ -77,6 +77,14 @@ class CelebornConf : public BaseConf {
 
   static constexpr std::string_view kSimplePushStrategy{"SIMPLE"};
 
+  static constexpr std::string_view kSlowStartPushStrategy{"SLOWSTART"};
+
+  static constexpr std::string_view kClientPushSlowStartInitialSleepTime{
+      "celeborn.client.push.slowStart.initialSleepTime"};
+
+  static constexpr std::string_view kClientPushSlowStartMaxSleepTime{
+      "celeborn.client.push.slowStart.maxSleepTime"};
+
   static constexpr std::string_view kClientPushMaxReqsInFlightPerWorker{
       "celeborn.client.push.maxReqsInFlight.perWorker"};
 
@@ -185,6 +193,10 @@ class CelebornConf : public BaseConf {
 
   std::string clientPushLimitStrategy() const;
 
+  long clientPushSlowStartInitialSleepTimeMs() const;
+
+  long clientPushSlowStartMaxSleepTimeMs() const;
+
   int clientPushMaxReqsInFlightPerWorker() const;
 
   int clientPushMaxReqsInFlightTotal() const;
diff --git a/cpp/celeborn/conf/tests/CelebornConfTest.cpp 
b/cpp/celeborn/conf/tests/CelebornConfTest.cpp
index 3686660330..f541b454a1 100644
--- a/cpp/celeborn/conf/tests/CelebornConfTest.cpp
+++ b/cpp/celeborn/conf/tests/CelebornConfTest.cpp
@@ -54,6 +54,9 @@ void testDefaultValues(CelebornConf* conf) {
   EXPECT_EQ(conf->clientFetchMaxRetriesForEachReplica(), 3);
   EXPECT_EQ(conf->networkIoRetryWait(), SECOND(5));
   EXPECT_FALSE(conf->clientPushReplicateEnabled());
+  EXPECT_EQ(conf->clientPushLimitStrategy(), 
CelebornConf::kSimplePushStrategy);
+  EXPECT_EQ(conf->clientPushSlowStartInitialSleepTimeMs(), 500);
+  EXPECT_EQ(conf->clientPushSlowStartMaxSleepTimeMs(), 2000);
   EXPECT_FALSE(conf->clientFetchExcludeWorkerOnFailureEnabled());
   EXPECT_EQ(conf->clientFetchExcludedWorkerExpireTimeout(), SECOND(60));
   EXPECT_FALSE(conf->clientAdaptiveOptimizeSkewedPartitionReadEnabled());
@@ -101,6 +104,16 @@ TEST(CelebornConfTest, setValues) {
   EXPECT_TRUE(conf->clientPushReplicateEnabled());
   conf->registerProperty(CelebornConf::kClientPushReplicateEnabled, "false");
   EXPECT_FALSE(conf->clientPushReplicateEnabled());
+  conf->registerProperty(
+      CelebornConf::kClientPushLimitStrategy,
+      std::string(CelebornConf::kSlowStartPushStrategy));
+  EXPECT_EQ(
+      conf->clientPushLimitStrategy(), CelebornConf::kSlowStartPushStrategy);
+  conf->registerProperty(
+      CelebornConf::kClientPushSlowStartInitialSleepTime, "1s");
+  EXPECT_EQ(conf->clientPushSlowStartInitialSleepTimeMs(), 1000);
+  conf->registerProperty(CelebornConf::kClientPushSlowStartMaxSleepTime, "3s");
+  EXPECT_EQ(conf->clientPushSlowStartMaxSleepTimeMs(), 3000);
   conf->registerProperty(
       CelebornConf::kClientFetchExcludeWorkerOnFailureEnabled, "true");
   EXPECT_TRUE(conf->clientFetchExcludeWorkerOnFailureEnabled());

Reply via email to