@@ -239,8 +239,8 @@ class TState : public TComputationValue<TState> {
239
239
return KeyWidth + StateWidth;
240
240
}
241
241
public:
242
- TState (TMemoryUsageInfo* memInfo, ui32 keyWidth, ui32 stateWidth, const THashFunc& hash, const TEqualsFunc& equal)
243
- : TBase(memInfo), KeyWidth(keyWidth), StateWidth(stateWidth), States(hash, equal, CountRowsOnPage) {
242
+ TState (TMemoryUsageInfo* memInfo, ui32 keyWidth, ui32 stateWidth, const THashFunc& hash, const TEqualsFunc& equal, bool allowOutOfMemory = false )
243
+ : TBase(memInfo), KeyWidth(keyWidth), StateWidth(stateWidth), AllowOutOfMemory(allowOutOfMemory), States(hash, equal, CountRowsOnPage) {
244
244
CurrentPage = &Storage.emplace_back (RowSize () * CountRowsOnPage, NUdf::TUnboxedValuePod ());
245
245
CurrentPosition = 0 ;
246
246
Tongue = CurrentPage->data ();
@@ -275,11 +275,28 @@ class TState : public TComputationValue<TState> {
275
275
}
276
276
Throat = States.GetKey (itInsert) + KeyWidth;
277
277
if (isNew) {
278
- States. CheckGrow ();
278
+ GrowStates ();
279
279
}
280
280
return isNew;
281
281
}
282
282
283
+ void GrowStates () {
284
+ try {
285
+ States.CheckGrow ();
286
+ } catch (TMemoryLimitExceededException) {
287
+ YQL_LOG (INFO) << " State failed to grow" ;
288
+ if (IsOutOfMemory || !AllowOutOfMemory) {
289
+ throw ;
290
+ } else {
291
+ IsOutOfMemory = true ;
292
+ }
293
+ }
294
+ }
295
+
296
+ bool CheckIsOutOfMemory () const {
297
+ return IsOutOfMemory;
298
+ }
299
+
283
300
template <bool SkipYields>
284
301
bool ReadMore () {
285
302
if constexpr (SkipYields) {
@@ -331,6 +348,8 @@ class TState : public TComputationValue<TState> {
331
348
private:
332
349
std::optional<TStorageIterator> ExtractIt;
333
350
const ui32 KeyWidth, StateWidth;
351
+ const bool AllowOutOfMemory;
352
+ bool IsOutOfMemory = false ;
334
353
ui64 CurrentPosition = 0 ;
335
354
TRow* CurrentPage = nullptr ;
336
355
TStorage Storage;
@@ -386,7 +405,7 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
386
405
const THashFunc& hash, const TEqualsFunc& equal, bool allowSpilling, TComputationContext& ctx
387
406
)
388
407
: TBase(memInfo)
389
- , InMemoryProcessingState(memInfo, keyWidth, keyAndStateType->GetElementsCount () - keyWidth, hash, equal)
408
+ , InMemoryProcessingState(memInfo, keyWidth, keyAndStateType->GetElementsCount () - keyWidth, hash, equal, allowSpilling && ctx.SpillerFactory )
390
409
, UsedInputItemType(usedInputItemType)
391
410
, KeyAndStateType(keyAndStateType)
392
411
, KeyWidth(keyWidth)
@@ -451,6 +470,9 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
451
470
ETasteResult TasteIt () {
452
471
if (GetMode () == EOperatingMode::InMemory) {
453
472
bool isNew = InMemoryProcessingState.TasteIt ();
473
+ if (InMemoryProcessingState.CheckIsOutOfMemory ()) {
474
+ StateWantsToSpill = true ;
475
+ }
454
476
Throat = InMemoryProcessingState.Throat ;
455
477
return isNew ? ETasteResult::Init : ETasteResult::Update;
456
478
}
@@ -649,7 +671,11 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
649
671
}
650
672
651
673
bool CheckMemoryAndSwitchToSpilling () {
652
- if (AllowSpilling && Ctx.SpillerFactory && IsSwitchToSpillingModeCondition ()) {
674
+ if (!(AllowSpilling && Ctx.SpillerFactory )) {
675
+ return false ;
676
+ }
677
+ if (StateWantsToSpill || IsSwitchToSpillingModeCondition ()) {
678
+ StateWantsToSpill = false ;
653
679
LogMemoryUsage ();
654
680
655
681
SwitchMode (EOperatingMode::SplittingState);
@@ -840,6 +866,7 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
840
866
NUdf::TUnboxedValuePod* Throat = nullptr ;
841
867
842
868
private:
869
+ bool StateWantsToSpill = false ;
843
870
bool IsEverythingExtracted = false ;
844
871
845
872
TState InMemoryProcessingState;
0 commit comments