5
5
#include " datashard_locks_db.h"
6
6
#include " probes.h"
7
7
8
+ #include < ydb/core/base/counters.h>
8
9
#include < ydb/core/formats/arrow/arrow_batch_builder.h>
9
10
10
11
#include < ydb/library/actors/core/monotonic_provider.h>
@@ -315,6 +316,8 @@ class TReader {
315
316
, Self(self)
316
317
, TableId(state.PathId.OwnerId, state.PathId.LocalPathId, state.SchemaVersion)
317
318
, FirstUnprocessedQuery(State.FirstUnprocessedQuery)
319
+ , LastProcessedKey(State.LastProcessedKey)
320
+ , LastProcessedKeyErased(State.LastProcessedKeyErased)
318
321
{
319
322
GetTimeFast (&StartTime);
320
323
EndTime = StartTime;
@@ -329,10 +332,10 @@ class TReader {
329
332
bool toInclusive;
330
333
TSerializedCellVec keyFromCells;
331
334
TSerializedCellVec keyToCells;
332
- if (Y_UNLIKELY (FirstUnprocessedQuery == State. FirstUnprocessedQuery && State. LastProcessedKey ) ) {
335
+ if (LastProcessedKey) {
333
336
if (!State.Reverse ) {
334
- keyFromCells = TSerializedCellVec (State. LastProcessedKey );
335
- fromInclusive = State. LastProcessedKeyErased ;
337
+ keyFromCells = TSerializedCellVec (LastProcessedKey);
338
+ fromInclusive = LastProcessedKeyErased;
336
339
337
340
keyToCells = range.To ;
338
341
toInclusive = range.ToInclusive ;
@@ -341,8 +344,8 @@ class TReader {
341
344
keyFromCells = range.From ;
342
345
fromInclusive = range.FromInclusive ;
343
346
344
- keyToCells = TSerializedCellVec (State. LastProcessedKey );
345
- toInclusive = State. LastProcessedKeyErased ;
347
+ keyToCells = TSerializedCellVec (LastProcessedKey);
348
+ toInclusive = LastProcessedKeyErased;
346
349
}
347
350
} else {
348
351
keyFromCells = range.From ;
@@ -500,6 +503,7 @@ class TReader {
500
503
while (FirstUnprocessedQuery < State.Request ->Ranges .size ()) {
501
504
if (ReachedTotalRowsLimit ()) {
502
505
FirstUnprocessedQuery = -1 ;
506
+ LastProcessedKey.clear ();
503
507
return true ;
504
508
}
505
509
@@ -526,6 +530,7 @@ class TReader {
526
530
FirstUnprocessedQuery++;
527
531
else
528
532
FirstUnprocessedQuery--;
533
+ LastProcessedKey.clear ();
529
534
}
530
535
531
536
return true ;
@@ -537,6 +542,7 @@ class TReader {
537
542
while (FirstUnprocessedQuery < State.Request ->Keys .size ()) {
538
543
if (ReachedTotalRowsLimit ()) {
539
544
FirstUnprocessedQuery = -1 ;
545
+ LastProcessedKey.clear ();
540
546
return true ;
541
547
}
542
548
@@ -562,6 +568,7 @@ class TReader {
562
568
FirstUnprocessedQuery++;
563
569
else
564
570
FirstUnprocessedQuery--;
571
+ LastProcessedKey.clear ();
565
572
}
566
573
567
574
return true ;
@@ -727,6 +734,28 @@ class TReader {
727
734
}
728
735
729
736
void UpdateState (TReadIteratorState& state, bool sentResult) {
737
+ if (state.FirstUnprocessedQuery == FirstUnprocessedQuery &&
738
+ state.LastProcessedKey && !LastProcessedKey)
739
+ {
740
+ LOG_CRIT_S (*TlsActivationContext, NKikimrServices::TX_DATASHARD,
741
+ " DataShard " << Self->TabletID () << " detected unexpected reset of LastProcessedKey:"
742
+ << " ReadId# " << State.ReadId
743
+ << " LastSeqNo# " << State.SeqNo
744
+ << " LastQuery# " << State.FirstUnprocessedQuery
745
+ << " RowsRead# " << RowsRead
746
+ << " RowsProcessed# " << RowsProcessed
747
+ << " RowsSinceLastCheck# " << RowsSinceLastCheck
748
+ << " BytesInResult# " << BytesInResult
749
+ << " DeletedRowSkips# " << DeletedRowSkips
750
+ << " InvisibleRowSkips# " << InvisibleRowSkips
751
+ << " Quota.Rows# " << State.Quota .Rows
752
+ << " Quota.Bytes# " << State.Quota .Bytes
753
+ << " State.TotalRows# " << State.TotalRows
754
+ << " State.TotalRowsLimit# " << State.TotalRowsLimit
755
+ << " State.MaxRowsInResult# " << State.MaxRowsInResult );
756
+ Self->IncCounterReadIteratorLastKeyReset ();
757
+ }
758
+
730
759
state.TotalRows += RowsRead;
731
760
state.FirstUnprocessedQuery = FirstUnprocessedQuery;
732
761
state.LastProcessedKey = LastProcessedKey;
@@ -1632,6 +1661,7 @@ class TDataShard::TReadOperation : public TOperation, public IReadOperation {
1632
1661
if (Reader->HasUnreadQueries ()) {
1633
1662
Reader->UpdateState (state, ResultSent);
1634
1663
if (!state.IsExhausted ()) {
1664
+ state.ReadContinuePending = true ;
1635
1665
ctx.Send (
1636
1666
Self->SelfId (),
1637
1667
new TEvDataShard::TEvReadContinue (ReadId.Sender , ReadId.ReadId ));
@@ -2282,6 +2312,15 @@ class TDataShard::TTxReadContinue : public NTabletFlatExecutor::TTransactionBase
2282
2312
Y_ASSERT (it->second );
2283
2313
auto & state = *it->second ;
2284
2314
2315
+ if (state.IsExhausted ()) {
2316
+ // iterator quota reduced and exhausted while ReadContinue was inflight
2317
+ LOG_TRACE_S (ctx, NKikimrServices::TX_DATASHARD, Self->TabletID () << " ReadContinue for iterator# " << ReadId
2318
+ << " , quota exhausted while rescheduling" );
2319
+ state.ReadContinuePending = false ;
2320
+ Result.reset ();
2321
+ return true ;
2322
+ }
2323
+
2285
2324
LOG_TRACE_S (ctx, NKikimrServices::TX_DATASHARD, Self->TabletID () << " ReadContinue for iterator# " << ReadId
2286
2325
<< " , firstUnprocessedQuery# " << state.FirstUnprocessedQuery );
2287
2326
@@ -2394,6 +2433,7 @@ class TDataShard::TTxReadContinue : public NTabletFlatExecutor::TTransactionBase
2394
2433
if (Reader->Read (txc, ctx)) {
2395
2434
// Retry later when dependencies are resolved
2396
2435
if (!Reader->GetVolatileReadDependencies ().empty ()) {
2436
+ state.ReadContinuePending = true ;
2397
2437
Self->WaitVolatileDependenciesThenSend (
2398
2438
Reader->GetVolatileReadDependencies (),
2399
2439
Self->SelfId (),
@@ -2480,6 +2520,8 @@ class TDataShard::TTxReadContinue : public NTabletFlatExecutor::TTransactionBase
2480
2520
Y_ABORT_UNLESS (it->second );
2481
2521
auto & state = *it->second ;
2482
2522
2523
+ state.ReadContinuePending = false ;
2524
+
2483
2525
if (!Result) {
2484
2526
LOG_DEBUG_S (ctx, NKikimrServices::TX_DATASHARD, Self->TabletID () << " read iterator# " << ReadId
2485
2527
<< " TTxReadContinue::Execute() finished without Result, aborting" );
@@ -2527,14 +2569,14 @@ class TDataShard::TTxReadContinue : public NTabletFlatExecutor::TTransactionBase
2527
2569
}
2528
2570
2529
2571
if (Reader->HasUnreadQueries ()) {
2530
- Y_ASSERT (it->second );
2531
- auto & state = *it->second ;
2572
+ bool wasExhausted = state.IsExhausted ();
2532
2573
Reader->UpdateState (state, useful);
2533
2574
if (!state.IsExhausted ()) {
2575
+ state.ReadContinuePending = true ;
2534
2576
ctx.Send (
2535
2577
Self->SelfId (),
2536
2578
new TEvDataShard::TEvReadContinue (ReadId.Sender , ReadId.ReadId ));
2537
- } else {
2579
+ } else if (!wasExhausted) {
2538
2580
Self->IncCounter (COUNTER_READ_ITERATORS_EXHAUSTED_COUNT);
2539
2581
LOG_DEBUG_S (ctx, NKikimrServices::TX_DATASHARD, Self->TabletID ()
2540
2582
<< " read iterator# " << ReadId << " exhausted" );
@@ -2807,14 +2849,19 @@ void TDataShard::Handle(TEvDataShard::TEvReadAck::TPtr& ev, const TActorContext&
2807
2849
bool wasExhausted = state.IsExhausted ();
2808
2850
state.UpQuota (
2809
2851
record.GetSeqNo (),
2810
- record.GetMaxRows (),
2811
- record.GetMaxBytes ());
2852
+ record.HasMaxRows () ? record. GetMaxRows () : Max<ui64> (),
2853
+ record.HasMaxBytes () ? record. GetMaxBytes () : Max<ui64> ());
2812
2854
2813
2855
if (wasExhausted && !state.IsExhausted ()) {
2814
2856
DecCounter (COUNTER_READ_ITERATORS_EXHAUSTED_COUNT);
2815
- ctx.Send (
2816
- SelfId (),
2817
- new TEvDataShard::TEvReadContinue (ev->Sender , record.GetReadId ()));
2857
+ if (!state.ReadContinuePending ) {
2858
+ state.ReadContinuePending = true ;
2859
+ ctx.Send (
2860
+ SelfId (),
2861
+ new TEvDataShard::TEvReadContinue (ev->Sender , record.GetReadId ()));
2862
+ }
2863
+ } else if (!wasExhausted && state.IsExhausted ()) {
2864
+ IncCounter (COUNTER_READ_ITERATORS_EXHAUSTED_COUNT);
2818
2865
}
2819
2866
2820
2867
LOG_TRACE_S (ctx, NKikimrServices::TX_DATASHARD, TabletID () << " ReadAck for read iterator# " << readId
@@ -2943,6 +2990,16 @@ void TDataShard::UnsubscribeReadIteratorSessions(const TActorContext& ctx) {
2943
2990
ReadIteratorSessions.clear ();
2944
2991
}
2945
2992
2993
+ void TDataShard::IncCounterReadIteratorLastKeyReset () {
2994
+ if (!CounterReadIteratorLastKeyReset) {
2995
+ CounterReadIteratorLastKeyReset = GetServiceCounters (AppData ()->Counters , " tablets" )
2996
+ ->GetSubgroup (" type" , " DataShard" )
2997
+ ->GetSubgroup (" category" , " app" )
2998
+ ->GetCounter (" DataShard/ReadIteratorLastKeyReset" , true );
2999
+ }
3000
+ ++*CounterReadIteratorLastKeyReset;
3001
+ }
3002
+
2946
3003
} // NKikimr::NDataShard
2947
3004
2948
3005
template <>
0 commit comments