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
+ , LastProcessedKeyErasedOrMissing(State.LastProcessedKeyErasedOrMissing)
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. LastProcessedKeyErasedOrMissing ;
337
+ keyFromCells = TSerializedCellVec (LastProcessedKey);
338
+ fromInclusive = LastProcessedKeyErasedOrMissing;
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. LastProcessedKeyErasedOrMissing ;
347
+ keyToCells = TSerializedCellVec (LastProcessedKey);
348
+ toInclusive = LastProcessedKeyErasedOrMissing;
346
349
}
347
350
} else {
348
351
keyFromCells = range.From ;
@@ -505,6 +508,7 @@ class TReader {
505
508
while (FirstUnprocessedQuery < State.Request ->Ranges .size ()) {
506
509
if (ReachedTotalRowsLimit ()) {
507
510
FirstUnprocessedQuery = -1 ;
511
+ LastProcessedKey.clear ();
508
512
return true ;
509
513
}
510
514
@@ -531,6 +535,7 @@ class TReader {
531
535
FirstUnprocessedQuery++;
532
536
else
533
537
FirstUnprocessedQuery--;
538
+ LastProcessedKey.clear ();
534
539
}
535
540
536
541
return true ;
@@ -542,6 +547,7 @@ class TReader {
542
547
while (FirstUnprocessedQuery < State.Request ->Keys .size ()) {
543
548
if (ReachedTotalRowsLimit ()) {
544
549
FirstUnprocessedQuery = -1 ;
550
+ LastProcessedKey.clear ();
545
551
return true ;
546
552
}
547
553
@@ -567,6 +573,7 @@ class TReader {
567
573
FirstUnprocessedQuery++;
568
574
else
569
575
FirstUnprocessedQuery--;
576
+ LastProcessedKey.clear ();
570
577
}
571
578
572
579
return true ;
@@ -732,6 +739,28 @@ class TReader {
732
739
}
733
740
734
741
void UpdateState (TReadIteratorState& state, bool sentResult) {
742
+ if (state.FirstUnprocessedQuery == FirstUnprocessedQuery &&
743
+ state.LastProcessedKey && !LastProcessedKey)
744
+ {
745
+ LOG_CRIT_S (*TlsActivationContext, NKikimrServices::TX_DATASHARD,
746
+ " DataShard " << Self->TabletID () << " detected unexpected reset of LastProcessedKey:"
747
+ << " ReadId# " << State.ReadId
748
+ << " LastSeqNo# " << State.SeqNo
749
+ << " LastQuery# " << State.FirstUnprocessedQuery
750
+ << " RowsRead# " << RowsRead
751
+ << " RowsProcessed# " << RowsProcessed
752
+ << " RowsSinceLastCheck# " << RowsSinceLastCheck
753
+ << " BytesInResult# " << BytesInResult
754
+ << " DeletedRowSkips# " << DeletedRowSkips
755
+ << " InvisibleRowSkips# " << InvisibleRowSkips
756
+ << " Quota.Rows# " << State.Quota .Rows
757
+ << " Quota.Bytes# " << State.Quota .Bytes
758
+ << " State.TotalRows# " << State.TotalRows
759
+ << " State.TotalRowsLimit# " << State.TotalRowsLimit
760
+ << " State.MaxRowsInResult# " << State.MaxRowsInResult );
761
+ Self->IncCounterReadIteratorLastKeyReset ();
762
+ }
763
+
735
764
state.TotalRows += RowsRead;
736
765
state.FirstUnprocessedQuery = FirstUnprocessedQuery;
737
766
state.LastProcessedKey = LastProcessedKey;
@@ -1683,6 +1712,7 @@ class TDataShard::TReadOperation : public TOperation, public IReadOperation {
1683
1712
if (Reader->HasUnreadQueries ()) {
1684
1713
Reader->UpdateState (state, ResultSent);
1685
1714
if (!state.IsExhausted ()) {
1715
+ state.ReadContinuePending = true ;
1686
1716
ctx.Send (
1687
1717
Self->SelfId (),
1688
1718
new TEvDataShard::TEvReadContinue (ReadId.Sender , ReadId.ReadId ));
@@ -2333,6 +2363,15 @@ class TDataShard::TTxReadContinue : public NTabletFlatExecutor::TTransactionBase
2333
2363
Y_ASSERT (it->second );
2334
2364
auto & state = *it->second ;
2335
2365
2366
+ if (state.IsExhausted ()) {
2367
+ // iterator quota reduced and exhausted while ReadContinue was inflight
2368
+ LOG_TRACE_S (ctx, NKikimrServices::TX_DATASHARD, Self->TabletID () << " ReadContinue for iterator# " << ReadId
2369
+ << " , quota exhausted while rescheduling" );
2370
+ state.ReadContinuePending = false ;
2371
+ Result.reset ();
2372
+ return true ;
2373
+ }
2374
+
2336
2375
LOG_TRACE_S (ctx, NKikimrServices::TX_DATASHARD, Self->TabletID () << " ReadContinue for iterator# " << ReadId
2337
2376
<< " , firstUnprocessedQuery# " << state.FirstUnprocessedQuery );
2338
2377
@@ -2446,6 +2485,7 @@ class TDataShard::TTxReadContinue : public NTabletFlatExecutor::TTransactionBase
2446
2485
if (Reader->Read (txc, ctx)) {
2447
2486
// Retry later when dependencies are resolved
2448
2487
if (!Reader->GetVolatileReadDependencies ().empty ()) {
2488
+ state.ReadContinuePending = true ;
2449
2489
Self->WaitVolatileDependenciesThenSend (
2450
2490
Reader->GetVolatileReadDependencies (),
2451
2491
Self->SelfId (),
@@ -2532,6 +2572,8 @@ class TDataShard::TTxReadContinue : public NTabletFlatExecutor::TTransactionBase
2532
2572
Y_ABORT_UNLESS (it->second );
2533
2573
auto & state = *it->second ;
2534
2574
2575
+ state.ReadContinuePending = false ;
2576
+
2535
2577
if (!Result) {
2536
2578
LOG_DEBUG_S (ctx, NKikimrServices::TX_DATASHARD, Self->TabletID () << " read iterator# " << ReadId
2537
2579
<< " TTxReadContinue::Execute() finished without Result, aborting" );
@@ -2579,14 +2621,14 @@ class TDataShard::TTxReadContinue : public NTabletFlatExecutor::TTransactionBase
2579
2621
}
2580
2622
2581
2623
if (Reader->HasUnreadQueries ()) {
2582
- Y_ASSERT (it->second );
2583
- auto & state = *it->second ;
2624
+ bool wasExhausted = state.IsExhausted ();
2584
2625
Reader->UpdateState (state, useful);
2585
2626
if (!state.IsExhausted ()) {
2627
+ state.ReadContinuePending = true ;
2586
2628
ctx.Send (
2587
2629
Self->SelfId (),
2588
2630
new TEvDataShard::TEvReadContinue (ReadId.Sender , ReadId.ReadId ));
2589
- } else {
2631
+ } else if (!wasExhausted) {
2590
2632
Self->IncCounter (COUNTER_READ_ITERATORS_EXHAUSTED_COUNT);
2591
2633
LOG_DEBUG_S (ctx, NKikimrServices::TX_DATASHARD, Self->TabletID ()
2592
2634
<< " read iterator# " << ReadId << " exhausted" );
@@ -2859,14 +2901,19 @@ void TDataShard::Handle(TEvDataShard::TEvReadAck::TPtr& ev, const TActorContext&
2859
2901
bool wasExhausted = state.IsExhausted ();
2860
2902
state.UpQuota (
2861
2903
record.GetSeqNo (),
2862
- record.GetMaxRows (),
2863
- record.GetMaxBytes ());
2904
+ record.HasMaxRows () ? record. GetMaxRows () : Max<ui64> (),
2905
+ record.HasMaxBytes () ? record. GetMaxBytes () : Max<ui64> ());
2864
2906
2865
2907
if (wasExhausted && !state.IsExhausted ()) {
2866
2908
DecCounter (COUNTER_READ_ITERATORS_EXHAUSTED_COUNT);
2867
- ctx.Send (
2868
- SelfId (),
2869
- new TEvDataShard::TEvReadContinue (ev->Sender , record.GetReadId ()));
2909
+ if (!state.ReadContinuePending ) {
2910
+ state.ReadContinuePending = true ;
2911
+ ctx.Send (
2912
+ SelfId (),
2913
+ new TEvDataShard::TEvReadContinue (ev->Sender , record.GetReadId ()));
2914
+ }
2915
+ } else if (!wasExhausted && state.IsExhausted ()) {
2916
+ IncCounter (COUNTER_READ_ITERATORS_EXHAUSTED_COUNT);
2870
2917
}
2871
2918
2872
2919
LOG_TRACE_S (ctx, NKikimrServices::TX_DATASHARD, TabletID () << " ReadAck for read iterator# " << readId
@@ -2995,6 +3042,16 @@ void TDataShard::UnsubscribeReadIteratorSessions(const TActorContext& ctx) {
2995
3042
ReadIteratorSessions.clear ();
2996
3043
}
2997
3044
3045
+ void TDataShard::IncCounterReadIteratorLastKeyReset () {
3046
+ if (!CounterReadIteratorLastKeyReset) {
3047
+ CounterReadIteratorLastKeyReset = GetServiceCounters (AppData ()->Counters , " tablets" )
3048
+ ->GetSubgroup (" type" , " DataShard" )
3049
+ ->GetSubgroup (" category" , " app" )
3050
+ ->GetCounter (" DataShard/ReadIteratorLastKeyReset" , true );
3051
+ }
3052
+ ++*CounterReadIteratorLastKeyReset;
3053
+ }
3054
+
2998
3055
} // NKikimr::NDataShard
2999
3056
3000
3057
template <>
0 commit comments