@@ -40,7 +40,6 @@ bool TDatabase::TChangeCounter::operator<(const TChangeCounter& rhs) const {
4040
4141TDatabase::TDatabase (TDatabaseImpl *databaseImpl) noexcept
4242 : DatabaseImpl(databaseImpl ? databaseImpl : new TDatabaseImpl(0 , new TScheme, nullptr ))
43- , NoMoreReadsFlag(true )
4443{
4544
4645}
@@ -59,7 +58,7 @@ TIntrusiveConstPtr<TRowScheme> TDatabase::GetRowScheme(ui32 table) const noexcep
5958
6059TAutoPtr<TTableIter> TDatabase::Iterate (ui32 table, TRawVals key, TTagsRef tags, ELookup mode) const noexcept
6160{
62- Y_ABORT_UNLESS (!NoMoreReadsFlag, " Trying to read after reads prohibited, table %u " , table);
61+ CheckReadAllowed ( table);
6362
6463 const auto seekBy = [](TRawVals key, ELookup mode) {
6564 if (!key && mode != ELookup::ExactMatch) {
@@ -92,7 +91,7 @@ TAutoPtr<TTableIter> TDatabase::IterateExact(ui32 table, TRawVals key, TTagsRef
9291 const ITransactionMapPtr& visible,
9392 const ITransactionObserverPtr& observer) const noexcept
9493{
95- Y_ABORT_UNLESS (!NoMoreReadsFlag, " Trying to read after reads prohibited, table %u " , table);
94+ CheckReadAllowed ( table);
9695
9796 auto iter = Require (table)->Iterate (key, tags, Env, ESeek::Exact, snapshot, visible, observer);
9897
@@ -144,7 +143,7 @@ TAutoPtr<TTableIter> TDatabase::IterateRange(ui32 table, const TKeyRange& range,
144143 const ITransactionMapPtr& visible,
145144 const ITransactionObserverPtr& observer) const noexcept
146145{
147- Y_ABORT_UNLESS (!NoMoreReadsFlag, " Trying to read after reads prohibited, table %u " , table);
146+ CheckReadAllowed ( table);
148147
149148 Y_DEBUG_ABORT_UNLESS (!IsAmbiguousRange (range, Require (table)->GetScheme ()->Keys ->Size ()),
150149 " %s" , IsAmbiguousRangeReason (range, Require (table)->GetScheme ()->Keys ->Size ()));
@@ -171,7 +170,7 @@ TAutoPtr<TTableReverseIter> TDatabase::IterateRangeReverse(ui32 table, const TKe
171170 const ITransactionMapPtr& visible,
172171 const ITransactionObserverPtr& observer) const noexcept
173172{
174- Y_ABORT_UNLESS (!NoMoreReadsFlag, " Trying to read after reads prohibited, table %u " , table);
173+ CheckReadAllowed ( table);
175174
176175 Y_DEBUG_ABORT_UNLESS (!IsAmbiguousRange (range, Require (table)->GetScheme ()->Keys ->Size ()),
177176 " %s" , IsAmbiguousRangeReason (range, Require (table)->GetScheme ()->Keys ->Size ()));
@@ -226,7 +225,7 @@ EReady TDatabase::Select(ui32 table, TRawVals key, TTagsRef tags, TRowState &row
226225 const ITransactionObserverPtr& observer) const noexcept
227226{
228227 TempIterators.clear ();
229- Y_ABORT_UNLESS (!NoMoreReadsFlag, " Trying to read after reads prohibited, table %u " , table);
228+ CheckReadAllowed ( table);
230229
231230 auto prevSieved = stats.Sieved ;
232231 auto prevWeeded = stats.Weeded ;
@@ -268,7 +267,8 @@ void TDatabase::CalculateReadSize(TSizeEnv& env, ui32 table, TRawVals minKey, TR
268267 TTagsRef tags, ui64 flg, ui64 items, ui64 bytes,
269268 EDirection direction, TRowVersion snapshot)
270269{
271- Y_ABORT_UNLESS (!NoMoreReadsFlag, " Trying to do precharge after reads prohibited, table %u" , table);
270+ CheckReadAllowed (table);
271+
272272 TSelectStats stats;
273273 Require (table)->Precharge (minKey, maxKey, tags, &env, flg, items, bytes, direction, snapshot, stats);
274274}
@@ -277,7 +277,8 @@ bool TDatabase::Precharge(ui32 table, TRawVals minKey, TRawVals maxKey,
277277 TTagsRef tags, ui64 flg, ui64 items, ui64 bytes,
278278 EDirection direction, TRowVersion snapshot)
279279{
280- Y_ABORT_UNLESS (!NoMoreReadsFlag, " Trying to do precharge after reads prohibited, table %u" , table);
280+ CheckPrechargeAllowed (table, minKey, maxKey);
281+
281282 TSelectStats stats;
282283 auto ready = Require (table)->Precharge (minKey, maxKey, tags, Env, flg, items, bytes, direction, snapshot, stats);
283284 Change->Stats .ChargeSieved += stats.Sieved ;
@@ -428,6 +429,10 @@ void TDatabase::NoMoreReadsForTx() {
428429 NoMoreReadsFlag = true ;
429430}
430431
432+ void TDatabase::NoMoreUnprechargedReadsForTx () {
433+ NoMoreUnprechargedReadsFlag = true ;
434+ }
435+
431436void TDatabase::Begin (TTxStamp stamp, IPages& env)
432437{
433438 Y_ABORT_UNLESS (!Redo, " Transaction already in progress" );
@@ -438,6 +443,8 @@ void TDatabase::Begin(TTxStamp stamp, IPages& env)
438443 Change = MakeHolder<TChange>(stamp, DatabaseImpl->Serial ());
439444 Env = &env;
440445 NoMoreReadsFlag = false ;
446+ NoMoreUnprechargedReadsFlag = false ;
447+ PrechargedTables.clear ();
441448}
442449
443450void TDatabase::RollbackChanges ()
@@ -802,6 +809,30 @@ TTable* TDatabase::RequireForUpdate(ui32 table) const noexcept
802809 return DatabaseImpl->GetForUpdate (table).Self .Get ();
803810}
804811
812+ void TDatabase::CheckReadAllowed (ui32 table) const noexcept
813+ {
814+ Y_ABORT_UNLESS (!NoMoreReadsFlag, " Trying to read after reads prohibited, table %u" , table);
815+ if (NoMoreUnprechargedReadsFlag) [[unlikely]] {
816+ Y_DEBUG_ABORT_UNLESS (
817+ std::find (PrechargedTables.begin (), PrechargedTables.end (), table) != PrechargedTables.end (),
818+ " Trying to read a previously unprecharged table %u" , table);
819+ }
820+ }
821+
822+ void TDatabase::CheckPrechargeAllowed (ui32 table, TRawVals minKey, TRawVals maxKey) const noexcept
823+ {
824+ Y_ABORT_UNLESS (!NoMoreReadsFlag, " Trying to precharge after reads prohibited, table %u" , table);
825+ if (NoMoreUnprechargedReadsFlag) [[unlikely]] {
826+ Y_DEBUG_ABORT_UNLESS (
827+ std::find (PrechargedTables.begin (), PrechargedTables.end (), table) != PrechargedTables.end (),
828+ " Trying to precharge a previously unprecharged table %u" , table);
829+ } else if (!minKey && !maxKey) {
830+ // Note: tables are usually fully precharged only in init transcations
831+ // This vector is small or empty most of the time and not worth using a hash table
832+ PrechargedTables.push_back (table);
833+ }
834+ }
835+
805836TGarbage TDatabase::RollUp (TTxStamp stamp, TArrayRef<const char > delta, TArrayRef<const char > redo,
806837 TMemGlobs annex)
807838{
0 commit comments