Skip to content

Commit 4f6a640

Browse files
One-partition throughput on default delivery settings
commit_hash:830f706fc9e7b9c334b1c66737d1b78afc78b9aa
1 parent 24410b4 commit 4f6a640

4 files changed

Lines changed: 69 additions & 11 deletions

File tree

yt/yt/flow/library/cpp/common/spec.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -985,9 +985,9 @@ void TDynamicBufferStateManagerSpec::Register(TRegistrar registrar)
985985
void TDynamicMessageDistributorSpec::Register(TRegistrar registrar)
986986
{
987987
registrar.Parameter("send_queue_max_rows_per_batch", &TThis::SendQueueMaxRowsPerBatch)
988-
.Default(NYTree::TSize(1000));
988+
.Default(NYTree::TSize(10'000));
989989
registrar.Parameter("send_queue_max_bytes_per_batch", &TThis::SendQueueMaxBytesPerBatch)
990-
.Default(NYTree::TSize(1_MB));
990+
.Default(NYTree::TSize(10_MB));
991991
registrar.Parameter("send_queue_batch_duration", &TThis::SendQueueBatchDuration)
992992
.Default(TDuration::MilliSeconds(100));
993993

yt/yt/flow/library/cpp/worker/input_buffer_detail.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,15 @@ void TInputBuffer::DoAddConnectionOffer(TGuid connectionId, TConnectionOffer off
325325
connectionState.UpdateEpoch = streamState.Epoch;
326326
}
327327

328-
// Just double function amortized complexity.
329-
if (--streamState.RecalculateCounter <= 0) {
330-
RecalculateStreamLimits(streamState);
328+
// Just double function amortized complexity. A manager-side limit change bypasses the
329+
// amortization so the raised limit turns into grants on the first offer, not the Nth;
330+
// the bypass must not advance the connection-GC epoch: the recomputed limit jitters on
331+
// every manage tick, and the GC horizon must stay measured in offer rounds.
332+
const bool offerRoundElapsed = --streamState.RecalculateCounter <= 0;
333+
if (offerRoundElapsed ||
334+
streamState.LimitUsageState->GetLimitBytes() != streamState.LastRecalculatedLimitBytes)
335+
{
336+
RecalculateStreamLimits(streamState, /*collectStaleConnections*/ offerRoundElapsed);
331337
streamState.Usage.PendingInflatedBytes = GetPendingSize(streamState);
332338
streamState.LimitUsageState->Update(streamState.Usage);
333339
}
@@ -445,6 +451,7 @@ TFuture<std::vector<TInputMessageConstPtr>> TInputBuffer::DoGetInputBatch(THashS
445451

446452
using TPriority = std::pair<TSystemTimestamp, ui64>;
447453
std::vector<std::pair<TMessagesPriorityQueue*, std::function<TPriority()>>> queues;
454+
std::vector<TStreamState*> extractionStreamStates;
448455
size_t queuedMessageCount = 0;
449456
for (auto& [streamId, streamState] : StreamStates_) {
450457
if (!streamState.Messages.empty() && allowedStreams.contains(streamId)) {
@@ -454,6 +461,7 @@ TFuture<std::vector<TInputMessageConstPtr>> TInputBuffer::DoGetInputBatch(THashS
454461
const auto& front = messagesPtr->front();
455462
return {TSystemTimestamp(front.AlignmentTimestamp.Underlying() + bias), front.SeqNo};
456463
});
464+
extractionStreamStates.push_back(&streamState);
457465
queuedMessageCount += streamState.Messages.size();
458466
}
459467
}
@@ -480,22 +488,31 @@ TFuture<std::vector<TInputMessageConstPtr>> TInputBuffer::DoGetInputBatch(THashS
480488
LastNotFullBatchInstant_ = TInstant::Now();
481489
}
482490

491+
// Extraction freed buffer space; regrant connection windows right away so the next
492+
// PushMessages response carries fresh limits instead of waiting out the offer amortization.
493+
if (!batch.empty()) {
494+
for (auto* streamState : extractionStreamStates) {
495+
RecalculateStreamLimits(*streamState, /*collectStaleConnections*/ false);
496+
streamState->Usage.PendingInflatedBytes = GetPendingSize(*streamState);
497+
}
498+
}
499+
483500
for (auto& [streamId, streamState] : StreamStates_) {
484501
streamState.LimitUsageState->Update(streamState.Usage);
485502
}
486503

487504
return MakeFuture<std::vector<TInputMessageConstPtr>>(std::move(batch));
488505
}
489506

490-
void TInputBuffer::RecalculateStreamLimits(TStreamState& streamState)
507+
void TInputBuffer::RecalculateStreamLimits(TStreamState& streamState, bool collectStaleConnections)
491508
{
492509
using THeapElement = std::pair<TConnectionState*, i64>; // (it, currentBucketIndex).
493510

494511
constexpr i64 lastEpochStoreCount = 5; // TODO: something better? Configurable?
495512

496513
// Cleanup.
497514
for (auto it = streamState.ConnectionStates.begin(); it != streamState.ConnectionStates.end();) {
498-
if (it->second.UpdateEpoch + lastEpochStoreCount < streamState.Epoch) {
515+
if (collectStaleConnections && it->second.UpdateEpoch + lastEpochStoreCount < streamState.Epoch) {
499516
streamState.ConnectionStates.erase(it++);
500517
} else {
501518
it->second.InflatedByteLimit = 0;
@@ -520,6 +537,7 @@ void TInputBuffer::RecalculateStreamLimits(TStreamState& streamState)
520537
// Match the manager's accounting: limit is inflated, so used must be inflated too.
521538
i64 inflatedUsedBytes = streamState.Usage.GetInflatedInflightBytes(streamState.LimitUsageState->GetInflationPerMessage());
522539
i64 inflatedLimitBytes = streamState.LimitUsageState->GetLimitBytes();
540+
streamState.LastRecalculatedLimitBytes = inflatedLimitBytes;
523541
// Do not allocate small share of buffer to reduce retransmits.
524542
i64 inflatedFreeBytes = std::max<i64>(inflatedLimitBytes * 0.9 - inflatedUsedBytes, 0);
525543

@@ -547,8 +565,10 @@ void TInputBuffer::RecalculateStreamLimits(TStreamState& streamState)
547565
}
548566
}
549567

550-
streamState.Epoch += 1;
551-
streamState.RecalculateCounter = std::ssize(streamState.ConnectionStates);
568+
if (collectStaleConnections) {
569+
streamState.Epoch += 1;
570+
streamState.RecalculateCounter = std::ssize(streamState.ConnectionStates);
571+
}
552572
}
553573

554574
i64 TInputBuffer::GetPendingSize(const TStreamState& streamState)

yt/yt/flow/library/cpp/worker/input_buffer_detail.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ class TInputBuffer
7676

7777
TConnectionStates ConnectionStates;
7878
i64 RecalculateCounter = 0;
79-
i64 Epoch = 0; // How many recalculations (~ updates of all connections) were done.
79+
i64 Epoch = 0; // How many offer-driven recalculations (~ updates of all connections) were done.
80+
i64 LastRecalculatedLimitBytes = -1;
8081

8182
TMessagesPriorityQueue Messages;
8283

@@ -119,7 +120,10 @@ class TInputBuffer
119120

120121
TSystemTimestamp GetMinStabilizedEventTimestamp() override;
121122

122-
static void RecalculateStreamLimits(TStreamState& streamState);
123+
// |collectStaleConnections| must be set only on the offer-driven cadence: connection GC is
124+
// measured in recalculation epochs, so high-frequency extraction regrants would otherwise
125+
// erase live connections between their offers.
126+
static void RecalculateStreamLimits(TStreamState& streamState, bool collectStaleConnections = true);
123127
static i64 GetPendingSize(const TStreamState& streamState);
124128

125129
double ComputeStreamBias(TStreamId streamId, const TInputMessageConstPtr& frontMessage) const;

yt/yt/flow/library/cpp/worker/unittests/input_buffer_ut.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,40 @@ TEST(TInputBufferRecalculateStreamLimitsTest, Cleanup)
167167
EXPECT_EQ(0, streamState.ConnectionStates.at(connectionId1).InflatedByteLimit);
168168
}
169169

170+
TEST(TInputBufferRecalculateStreamLimitsTest, RegrantKeepsStaleConnections)
171+
{
172+
auto staleConnectionId = TGuid::Create();
173+
auto freshConnectionId = TGuid::Create();
174+
TStreamState streamState = {
175+
.ConnectionStates = {
176+
{
177+
staleConnectionId,
178+
TConnectionState{
179+
.UpdateEpoch = 0,
180+
.Offer = {{TSystemTimestamp(12), 100}, {TSystemTimestamp(5), 200}},
181+
.InflatedByteLimit = 100500,
182+
},
183+
},
184+
{
185+
freshConnectionId,
186+
TConnectionState{
187+
.UpdateEpoch = 100,
188+
.Offer = {{TSystemTimestamp(10), 800}, {TSystemTimestamp(9), 400}},
189+
},
190+
},
191+
},
192+
.RecalculateCounter = 42,
193+
.Epoch = 101,
194+
.LimitUsageState = MakeLimitState(1000),
195+
};
196+
TInputBuffer::RecalculateStreamLimits(streamState, /*collectStaleConnections*/ false);
197+
ASSERT_TRUE(streamState.ConnectionStates.contains(staleConnectionId));
198+
EXPECT_EQ(200, streamState.ConnectionStates.at(staleConnectionId).InflatedByteLimit);
199+
EXPECT_EQ(400, streamState.ConnectionStates.at(freshConnectionId).InflatedByteLimit);
200+
EXPECT_EQ(101, streamState.Epoch);
201+
EXPECT_EQ(42, streamState.RecalculateCounter);
202+
}
203+
170204
TEST(TInputBufferGetPendingSizeTest, Simple)
171205
{
172206
auto connectionId1 = TGuid::Create();

0 commit comments

Comments
 (0)