@@ -364,8 +364,15 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
364
364
enum class ETasteResult : i8 {
365
365
Init = -1 ,
366
366
Update,
367
- ConsumeRawData,
368
- ExtractRawData
367
+ ConsumeRawData
368
+ };
369
+
370
+ enum class EUpdateResult : i8 {
371
+ Yield = -1 ,
372
+ ExtractRawData,
373
+ ReadInput,
374
+ Extract,
375
+ Finish
369
376
};
370
377
TSpillingSupportState (
371
378
TMemoryUsageInfo* memInfo,
@@ -398,28 +405,29 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
398
405
bool IsProcessingRequired () const {
399
406
if (InputStatus != EFetchResult::Finish) return true ;
400
407
401
- return HasRawDataToExtract || HasDataForProcessing ;
408
+ return !SpilledBuckets. empty () && SpilledBuckets. front (). BucketState != TSpilledBucket::EBucketState::InMemory ;
402
409
}
403
410
404
- bool UpdateAndWait () {
411
+ EUpdateResult Update () {
412
+ if (IsEverythingExtracted) return EUpdateResult::Finish;
413
+
405
414
switch (GetMode ()) {
406
415
case EOperatingMode::InMemory: {
407
416
if (CheckMemoryAndSwitchToSpilling ()) {
408
- return UpdateAndWait ();
417
+ return Update ();
409
418
}
410
- return false ;
419
+ if (InputStatus == EFetchResult::Finish) return EUpdateResult::Extract;
420
+
421
+ return EUpdateResult::ReadInput;
411
422
}
412
-
413
- case EOperatingMode::ProcessSpilled:
414
- return ProcessSpilledDataAndWait ();
415
423
case EOperatingMode::Spilling: {
416
424
UpdateSpillingBuckets ();
417
425
418
- if (!HasMemoryForProcessing () && InputStatus != EFetchResult::Finish && TryToReduceMemoryAndWait ()) return true ;
426
+ if (!HasMemoryForProcessing () && InputStatus != EFetchResult::Finish && TryToReduceMemoryAndWait ()) return EUpdateResult::Yield ;
419
427
420
428
if (BufferForUsedInputItems.size ()) {
421
429
auto & bucket = SpilledBuckets[BufferForUsedInputItemsBucketId];
422
- if (bucket.AsyncWriteOperation .has_value ()) return true ;
430
+ if (bucket.AsyncWriteOperation .has_value ()) return EUpdateResult::Yield ;
423
431
424
432
bucket.AsyncWriteOperation = bucket.SpilledData ->WriteWideItem (BufferForUsedInputItems);
425
433
BufferForUsedInputItems.resize (0 ); // for freeing allocated key value asap
@@ -429,8 +437,10 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
429
437
430
438
// Prepare buffer for reading new key
431
439
BufferForKeyAndState.resize (KeyWidth);
432
- return false ;
440
+ return EUpdateResult::ReadInput ;
433
441
}
442
+ case EOperatingMode::ProcessSpilled:
443
+ return ProcessSpilledData ();
434
444
}
435
445
}
436
446
@@ -442,14 +452,6 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
442
452
return isNew ? ETasteResult::Init : ETasteResult::Update;
443
453
}
444
454
if (GetMode () == EOperatingMode::ProcessSpilled) {
445
- if (HasRawDataToExtract) {
446
- // Tongue not used here.
447
- Throat = BufferForUsedInputItems.data ();
448
- HasRawDataToExtract = false ;
449
- HasDataForProcessing = true ;
450
- return ETasteResult::ExtractRawData;
451
- }
452
- HasDataForProcessing = false ;
453
455
// while restoration we process buckets one by one starting from the first in a queue
454
456
bool isNew = SpilledBuckets.front ().InMemoryProcessingState ->TasteIt ();
455
457
Throat = SpilledBuckets.front ().InMemoryProcessingState ->Throat ;
@@ -476,20 +478,27 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
476
478
MKQL_ENSURE (BufferForUsedInputItems.size () == 0 , " Internal logic error" );
477
479
BufferForUsedInputItems.resize (ItemNodesSize);
478
480
BufferForUsedInputItemsBucketId = bucketId;
481
+
479
482
Throat = BufferForUsedInputItems.data ();
480
-
483
+
481
484
return ETasteResult::ConsumeRawData;
482
485
}
483
486
484
487
NUdf::TUnboxedValuePod* Extract () {
485
- if (GetMode () == EOperatingMode::InMemory) return static_cast <NUdf::TUnboxedValue*>(InMemoryProcessingState.Extract ());
488
+ NUdf::TUnboxedValue* value = nullptr ;
489
+ if (GetMode () == EOperatingMode::InMemory) {
490
+ value = static_cast <NUdf::TUnboxedValue*>(InMemoryProcessingState.Extract ());
491
+ if (!value) IsEverythingExtracted = true ;
492
+ return value;
493
+ }
486
494
487
495
MKQL_ENSURE (SpilledBuckets.front ().BucketState == TSpilledBucket::EBucketState::InMemory, " Internal logic error" );
488
496
MKQL_ENSURE (SpilledBuckets.size () > 0 , " Internal logic error" );
489
497
490
- auto value = static_cast <NUdf::TUnboxedValue*>(SpilledBuckets.front ().InMemoryProcessingState ->Extract ());
498
+ value = static_cast <NUdf::TUnboxedValue*>(SpilledBuckets.front ().InMemoryProcessingState ->Extract ());
491
499
if (!value) {
492
500
SpilledBuckets.pop_front ();
501
+ if (SpilledBuckets.empty ()) IsEverythingExtracted = true ;
493
502
}
494
503
495
504
return value;
@@ -503,7 +512,7 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
503
512
BufferForKeyAndState.resize (0 );
504
513
}
505
514
506
- bool FlushSpillingBuffersAndWait () {
515
+ EUpdateResult FlushSpillingBuffersAndWait () {
507
516
UpdateSpillingBuckets ();
508
517
509
518
ui64 finishedCount = 0 ;
@@ -519,11 +528,11 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
519
528
}
520
529
}
521
530
522
- if (finishedCount != SpilledBuckets.size ()) return true ;
531
+ if (finishedCount != SpilledBuckets.size ()) return EUpdateResult::Yield ;
523
532
524
533
SwitchMode (EOperatingMode::ProcessSpilled);
525
534
526
- return ProcessSpilledDataAndWait ();
535
+ return ProcessSpilledData ();
527
536
}
528
537
529
538
void SplitStateIntoBuckets () {
@@ -628,11 +637,9 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
628
637
return false ;
629
638
}
630
639
631
- bool ProcessSpilledDataAndWait () {
632
- if (SpilledBuckets.empty ()) return false ;
633
-
640
+ EUpdateResult ProcessSpilledData () {
634
641
if (AsyncReadOperation) {
635
- if (!AsyncReadOperation->HasValue ()) return true ;
642
+ if (!AsyncReadOperation->HasValue ()) return EUpdateResult::Yield ;
636
643
if (RecoverState) {
637
644
SpilledBuckets[0 ].SpilledState ->AsyncReadCompleted (AsyncReadOperation->ExtractValue ().value (), Ctx.HolderFactory );
638
645
} else {
@@ -642,20 +649,16 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
642
649
}
643
650
644
651
auto & bucket = SpilledBuckets.front ();
645
- if (bucket.BucketState == TSpilledBucket::EBucketState::InMemory) return false ;
646
- if (HasDataForProcessing) {
647
- Tongue = bucket.InMemoryProcessingState ->Tongue ;
648
- Throat = bucket.InMemoryProcessingState ->Throat ;
649
- return false ;
650
- }
652
+ if (bucket.BucketState == TSpilledBucket::EBucketState::InMemory) return EUpdateResult::Extract;
653
+
651
654
// recover spilled state
652
655
while (!bucket.SpilledState ->Empty ()) {
653
656
RecoverState = true ;
654
657
BufferForKeyAndState.resize (KeyAndStateType->GetElementsCount ());
655
658
AsyncReadOperation = bucket.SpilledState ->ExtractWideItem (BufferForKeyAndState);
656
659
if (AsyncReadOperation) {
657
660
BufferForKeyAndState.resize (0 );
658
- return true ;
661
+ return EUpdateResult::Yield ;
659
662
}
660
663
for (size_t i = 0 ; i< KeyWidth; ++i) {
661
664
// jumping into unsafe world, refusing ownership
@@ -675,18 +678,16 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
675
678
BufferForUsedInputItems.resize (UsedInputItemType->GetElementsCount ());
676
679
AsyncReadOperation = bucket.SpilledData ->ExtractWideItem (BufferForUsedInputItems);
677
680
if (AsyncReadOperation) {
678
- return true ;
681
+ return EUpdateResult::Yield ;
679
682
}
680
683
684
+ Throat = BufferForUsedInputItems.data ();
681
685
Tongue = bucket.InMemoryProcessingState ->Tongue ;
682
- Throat = bucket.InMemoryProcessingState ->Throat ;
683
686
684
- HasRawDataToExtract = true ;
685
- return false ;
687
+ return EUpdateResult::ExtractRawData;
686
688
}
687
689
bucket.BucketState = TSpilledBucket::EBucketState::InMemory;
688
- HasDataForProcessing = false ;
689
- return false ;
690
+ return EUpdateResult::Extract;
690
691
}
691
692
692
693
EOperatingMode GetMode () const {
@@ -744,9 +745,7 @@ class TSpillingSupportState : public TComputationValue<TSpillingSupportState> {
744
745
private:
745
746
ui64 NextBucketToSpill = 0 ;
746
747
747
- bool HasDataForProcessing = false ;
748
-
749
- bool HasRawDataToExtract = false ;
748
+ bool IsEverythingExtracted = false ;
750
749
751
750
TState InMemoryProcessingState;
752
751
const TMultiType* const UsedInputItemType;
@@ -1268,50 +1267,49 @@ using TBaseComputation = TStatefulWideFlowCodegeneratorNode<TWideLastCombinerWra
1268
1267
auto **fields = ctx.WideFields .data () + WideFieldsIndex;
1269
1268
1270
1269
while (true ) {
1271
- if (ptr->UpdateAndWait ()) {
1272
- return EFetchResult::Yield;
1273
- }
1274
- if (ptr-> InputStatus != EFetchResult::Finish) {
1275
- for ( auto i = 0U ; i < Nodes. ItemNodes . size (); ++i)
1276
- fields[i] = Nodes. GetUsedInputItemNodePtrOrNull (ctx, i);
1277
- switch (ptr-> InputStatus = Flow-> FetchValues (ctx, fields)) {
1278
- case EFetchResult::One :
1279
- break ;
1280
- case EFetchResult::Finish :
1281
- continue ;
1282
- case EFetchResult::Yield:
1283
- return EFetchResult::Yield ;
1270
+ switch (ptr->Update ()) {
1271
+ case TSpillingSupportState::EUpdateResult::ReadInput: {
1272
+ for ( auto i = 0U ; i < Nodes. ItemNodes . size (); ++i)
1273
+ fields[i] = Nodes. GetUsedInputItemNodePtrOrNull (ctx, i);
1274
+ switch (ptr-> InputStatus = Flow-> FetchValues (ctx, fields)) {
1275
+ case EFetchResult::One:
1276
+ break ;
1277
+ case EFetchResult::Finish :
1278
+ continue ;
1279
+ case EFetchResult::Yield :
1280
+ return EFetchResult::Yield ;
1281
+ }
1282
+ break ;
1284
1283
}
1284
+ case TSpillingSupportState::EUpdateResult::Yield:
1285
+ return EFetchResult::Yield;
1286
+ case TSpillingSupportState::EUpdateResult::ExtractRawData:
1287
+ Nodes.ExtractValues (ctx, static_cast <NUdf::TUnboxedValue*>(ptr->Throat ), fields);
1288
+ break ;
1289
+ case TSpillingSupportState::EUpdateResult::Extract:
1290
+ if (const auto values = static_cast <NUdf::TUnboxedValue*>(ptr->Extract ())) {
1291
+ Nodes.FinishItem (ctx, values, output);
1292
+ return EFetchResult::One;
1293
+ }
1294
+ continue ;
1295
+ case TSpillingSupportState::EUpdateResult::Finish:
1296
+ return EFetchResult::Finish;
1285
1297
}
1286
1298
1287
- if (ptr->IsProcessingRequired ()) {
1288
- Nodes.ExtractKey (ctx, fields, static_cast <NUdf::TUnboxedValue*>(ptr->Tongue ));
1299
+ Nodes.ExtractKey (ctx, fields, static_cast <NUdf::TUnboxedValue*>(ptr->Tongue ));
1289
1300
1290
- switch (ptr->TasteIt ()) {
1291
- case TSpillingSupportState::ETasteResult::Init:
1292
- Nodes.ProcessItem (ctx, nullptr , static_cast <NUdf::TUnboxedValue*>(ptr->Throat ));
1293
- break ;
1294
- case TSpillingSupportState::ETasteResult::Update:
1295
- Nodes.ProcessItem (ctx, static_cast <NUdf::TUnboxedValue*>(ptr->Tongue ), static_cast <NUdf::TUnboxedValue*>(ptr->Throat ));
1296
- break ;
1297
- case TSpillingSupportState::ETasteResult::ConsumeRawData:
1298
- Nodes.ExtractValues (ctx, fields, static_cast <NUdf::TUnboxedValue*>(ptr->Throat ));
1299
- break ;
1300
- case TSpillingSupportState::ETasteResult::ExtractRawData:
1301
- Nodes.ExtractValues (ctx, static_cast <NUdf::TUnboxedValue*>(ptr->Throat ), fields);
1302
- break ;
1303
- }
1304
- continue ;
1305
- }
1306
-
1307
- if (const auto values = static_cast <NUdf::TUnboxedValue*>(ptr->Extract ())) {
1308
- Nodes.FinishItem (ctx, values, output);
1309
- return EFetchResult::One;
1301
+ switch (ptr->TasteIt ()) {
1302
+ case TSpillingSupportState::ETasteResult::Init:
1303
+ Nodes.ProcessItem (ctx, nullptr , static_cast <NUdf::TUnboxedValue*>(ptr->Throat ));
1304
+ break ;
1305
+ case TSpillingSupportState::ETasteResult::Update:
1306
+ Nodes.ProcessItem (ctx, static_cast <NUdf::TUnboxedValue*>(ptr->Tongue ), static_cast <NUdf::TUnboxedValue*>(ptr->Throat ));
1307
+ break ;
1308
+ case TSpillingSupportState::ETasteResult::ConsumeRawData:
1309
+ Nodes.ExtractValues (ctx, fields, static_cast <NUdf::TUnboxedValue*>(ptr->Throat ));
1310
+ break ;
1310
1311
}
1311
1312
1312
- if (!ptr->HasAnyData ()) {
1313
- return EFetchResult::Finish;
1314
- }
1315
1313
}
1316
1314
}
1317
1315
Y_UNREACHABLE ();
@@ -1366,13 +1364,18 @@ using TBaseComputation = TStatefulWideFlowCodegeneratorNode<TWideLastCombinerWra
1366
1364
1367
1365
block = more;
1368
1366
1369
- const auto waitMoreFunc = ConstantInt::get (Type::getInt64Ty (context), GetMethodPtr (&TSpillingSupportState::UpdateAndWait));
1370
- const auto waitMoreFuncPtr = CastInst::Create (Instruction::IntToPtr, waitMoreFunc, PointerType::getUnqual (boolFuncType), " wait_more_func" , block);
1371
- const auto waitMore = CallInst::Create (boolFuncType, waitMoreFuncPtr, { stateArg }, " wait_more" , block);
1367
+ const auto updateFunc = ConstantInt::get (Type::getInt64Ty (context), GetMethodPtr (&TSpillingSupportState::Update));
1368
+ const auto updateType = FunctionType::get (wayType, {stateArg->getType ()}, false );
1369
+ const auto updateFuncPtr = CastInst::Create (Instruction::IntToPtr, updateFunc, PointerType::getUnqual (updateType), " update_func" , block);
1370
+ const auto update = CallInst::Create (updateType, updateFuncPtr, { stateArg }, " update" , block);
1372
1371
1373
1372
result->addIncoming (ConstantInt::get (statusType, static_cast <i32>(EFetchResult::Yield)), block);
1374
1373
1375
- BranchInst::Create (over, test, waitMore, block);
1374
+ const auto updateWay = SwitchInst::Create (update, test, 3U , block);
1375
+ updateWay->addCase (ConstantInt::get (wayType, static_cast <i8>(TSpillingSupportState::EUpdateResult::Yield)), over);
1376
+ // TODO add exctraction code and jmp there
1377
+ updateWay->addCase (ConstantInt::get (wayType, static_cast <i8>(TSpillingSupportState::EUpdateResult::ExtractRawData)), test);
1378
+ updateWay->addCase (ConstantInt::get (wayType, static_cast <i8>(TSpillingSupportState::EUpdateResult::Extract)), test);
1376
1379
1377
1380
block = test;
1378
1381
0 commit comments