Skip to content

Commit 0981fb6

Browse files
committed
Revert "Add OderBy output stage spill (facebookincubator#7759)"
This reverts commit ddc3471.
1 parent 9052038 commit 0981fb6

File tree

9 files changed

+79
-252
lines changed

9 files changed

+79
-252
lines changed

velox/exec/OrderBy.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,24 @@ void OrderBy::reclaim(
7878
memory::MemoryReclaimer::Stats& stats) {
7979
VELOX_CHECK(canReclaim());
8080
VELOX_CHECK(!nonReclaimableSection_);
81+
auto* driver = operatorCtx_->driver();
8182

82-
// TODO: support fine-grain disk spilling based on 'targetBytes' after
83-
// having row container memory compaction support later.
84-
sortBuffer_->spill();
83+
// NOTE: an order by operator is reclaimable if it hasn't started output
84+
// processing and is not under non-reclaimable execution section.
85+
if (noMoreInput_) {
86+
// TODO: reduce the log frequency if it is too verbose.
87+
++stats.numNonReclaimableAttempts;
88+
LOG(WARNING)
89+
<< "Can't reclaim from order by operator which has started producing output: "
90+
<< pool()->name()
91+
<< ", usage: " << succinctBytes(pool()->currentBytes())
92+
<< ", reservation: " << succinctBytes(pool()->reservedBytes());
93+
return;
94+
}
8595

96+
// TODO: support fine-grain disk spilling based on 'targetBytes' after having
97+
// row container memory compaction support later.
98+
sortBuffer_->spill();
8699
// Release the minimum reserved memory.
87100
pool()->release();
88101
}

velox/exec/SortBuffer.cpp

Lines changed: 23 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "SortBuffer.h"
1818
#include "velox/exec/MemoryReclaimer.h"
19+
#include "velox/vector/BaseVector.h"
1920

2021
namespace facebook::velox::exec {
2122

@@ -132,7 +133,11 @@ void SortBuffer::noMoreInput() {
132133
// for now.
133134
spill();
134135

135-
finishSpill();
136+
// Finish spill, and we shouldn't get any rows from non-spilled partition as
137+
// there is only one hash partition for SortBuffer.
138+
VELOX_CHECK_NULL(spillMerger_);
139+
auto spillPartition = spiller_->finishSpill();
140+
spillMerger_ = spillPartition.createOrderedReader(pool());
136141
}
137142

138143
// Releases the unused memory reservation after procesing input.
@@ -165,11 +170,24 @@ void SortBuffer::spill() {
165170
}
166171
updateEstimatedOutputRowSize();
167172

168-
if (sortedRows_.empty()) {
169-
spillInput();
170-
} else {
171-
spillOutput();
173+
if (spiller_ == nullptr) {
174+
spiller_ = std::make_unique<Spiller>(
175+
Spiller::Type::kOrderBy,
176+
data_.get(),
177+
spillerStoreType_,
178+
data_->keyTypes().size(),
179+
sortCompareFlags_,
180+
spillConfig_->getSpillDirPathCb,
181+
spillConfig_->fileNamePrefix,
182+
spillConfig_->writeBufferSize,
183+
spillConfig_->compressionKind,
184+
memory::spillMemoryPool(),
185+
spillConfig_->executor);
186+
VELOX_CHECK_EQ(spiller_->state().maxPartitions(), 1);
172187
}
188+
189+
spiller_->spill();
190+
data_->clear();
173191
}
174192

175193
std::optional<uint64_t> SortBuffer::estimateOutputRowSize() const {
@@ -260,54 +278,6 @@ void SortBuffer::updateEstimatedOutputRowSize() {
260278
}
261279
}
262280

263-
void SortBuffer::spillInput() {
264-
if (spiller_ == nullptr) {
265-
VELOX_CHECK(!noMoreInput_);
266-
spiller_ = std::make_unique<Spiller>(
267-
Spiller::Type::kOrderByInput,
268-
data_.get(),
269-
spillerStoreType_,
270-
data_->keyTypes().size(),
271-
sortCompareFlags_,
272-
spillConfig_->getSpillDirPathCb,
273-
spillConfig_->fileNamePrefix,
274-
spillConfig_->writeBufferSize,
275-
spillConfig_->compressionKind,
276-
memory::spillMemoryPool(),
277-
spillConfig_->executor,
278-
spillConfig_->fileCreateConfig);
279-
}
280-
spiller_->spill();
281-
data_->clear();
282-
}
283-
284-
void SortBuffer::spillOutput() {
285-
if (spiller_ != nullptr) {
286-
// Already spilled.
287-
return;
288-
}
289-
290-
spiller_ = std::make_unique<Spiller>(
291-
Spiller::Type::kOrderByOutput,
292-
data_.get(),
293-
spillerStoreType_,
294-
spillConfig_->getSpillDirPathCb,
295-
spillConfig_->fileNamePrefix,
296-
spillConfig_->writeBufferSize,
297-
spillConfig_->compressionKind,
298-
memory::spillMemoryPool(),
299-
spillConfig_->executor,
300-
spillConfig_->fileCreateConfig);
301-
auto spillRows = std::vector<char*>(
302-
sortedRows_.begin() + numOutputRows_, sortedRows_.end());
303-
spiller_->spill(spillRows);
304-
data_->clear();
305-
sortedRows_.clear();
306-
// Finish right after spilling as the output spiller only spills at most
307-
// once.
308-
finishSpill();
309-
}
310-
311281
void SortBuffer::prepareOutput(uint32_t maxOutputRows) {
312282
VELOX_CHECK_GT(maxOutputRows, 0);
313283
VELOX_CHECK_GT(numInputRows_, numOutputRows_);
@@ -394,10 +364,4 @@ void SortBuffer::getOutputWithSpill() {
394364
numOutputRows_ += output_->size();
395365
}
396366

397-
void SortBuffer::finishSpill() {
398-
VELOX_CHECK_NULL(spillMerger_);
399-
auto spillPartition = spiller_->finishSpill();
400-
spillMerger_ = spillPartition.createOrderedReader(pool());
401-
}
402-
403367
} // namespace facebook::velox::exec

velox/exec/SortBuffer.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,6 @@ class SortBuffer {
8080
void prepareOutput(uint32_t maxOutputRows);
8181
void getOutputWithoutSpill();
8282
void getOutputWithSpill();
83-
// Spill during input stage.
84-
void spillInput();
85-
// Spill during output stage.
86-
void spillOutput();
87-
// Finish spill, and we shouldn't get any rows from non-spilled partition as
88-
// there is only one hash partition for SortBuffer.
89-
void finishSpill();
9083

9184
const RowTypePtr input_;
9285
const std::vector<CompareFlags> sortCompareFlags_;

velox/exec/SortWindowBuild.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ void SortWindowBuild::setupSpiller() {
140140

141141
spiller_ = std::make_unique<Spiller>(
142142
// TODO Replace Spiller::Type::kOrderBy.
143-
Spiller::Type::kOrderByInput,
143+
Spiller::Type::kOrderBy,
144144
data_.get(),
145145
inputType_,
146146
spillCompareFlags_.size(),

velox/exec/Spiller.cpp

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Spiller::Spiller(
6161
executor,
6262
fileCreateConfig) {
6363
VELOX_CHECK(
64-
type_ == Type::kOrderByInput || type_ == Type::kAggregateInput,
64+
type_ == Type::kOrderBy || type_ == Type::kAggregateInput,
6565
"Unexpected spiller type: {}",
6666
typeName(type_));
6767
VELOX_CHECK_EQ(state_.maxPartitions(), 1);
@@ -95,7 +95,7 @@ Spiller::Spiller(
9595
executor,
9696
fileCreateConfig) {
9797
VELOX_CHECK(
98-
type_ == Type::kAggregateOutput || type_ == Type::kOrderByOutput,
98+
type_ == Type::kAggregateOutput || type_ == Type::kOrderBy,
9999
"Unexpected spiller type: {}",
100100
typeName(type_));
101101
VELOX_CHECK_EQ(state_.maxPartitions(), 1);
@@ -446,11 +446,9 @@ void Spiller::runSpill() {
446446
VELOX_CHECK_EQ(numWritten, run.rows.size());
447447
run.clear();
448448
// When a sorted run ends, we start with a new file next time. For
449-
// aggregation output / orderby output spiller, we expect only one spill
450-
// call to spill all the rows starting from the specified row offset.
451-
if (needSort() ||
452-
(type_ == Spiller::Type::kAggregateOutput ||
453-
type_ == Spiller::Type::kOrderByOutput)) {
449+
// aggregation output spiller, we expect only one spill call to spill all
450+
// the rows starting from the specified row offset.
451+
if (needSort() || (type_ == Spiller::Type::kAggregateOutput)) {
454452
state_.finishFile(partition);
455453
}
456454
}
@@ -468,7 +466,7 @@ void Spiller::updateSpillSortTime(uint64_t timeUs) {
468466

469467
bool Spiller::needSort() const {
470468
return type_ != Type::kHashJoinProbe && type_ != Type::kHashJoinBuild &&
471-
type_ != Type::kAggregateOutput && type_ != Type::kOrderByOutput;
469+
type_ != Type::kAggregateOutput;
472470
}
473471

474472
void Spiller::spill() {
@@ -484,23 +482,15 @@ void Spiller::spill(const RowContainerIterator* startRowIter) {
484482
CHECK_NOT_FINALIZED();
485483
VELOX_CHECK_NE(type_, Type::kHashJoinProbe);
486484

487-
markAllPartitionsSpilled();
488-
489-
fillSpillRuns(startRowIter);
490-
runSpill();
491-
checkEmptySpillRuns();
492-
}
493-
494-
void Spiller::spill(std::vector<char*>& rows) {
495-
CHECK_NOT_FINALIZED();
496-
VELOX_CHECK_EQ(type_, Type::kOrderByOutput);
497-
if (rows.empty()) {
498-
return;
485+
// Marks all the partitions have been spilled as we don't support fine-grained
486+
// spilling as for now.
487+
for (auto partition = 0; partition < state_.maxPartitions(); ++partition) {
488+
if (!state_.isPartitionSpilled(partition)) {
489+
state_.setPartitionSpilled(partition);
490+
}
499491
}
500492

501-
markAllPartitionsSpilled();
502-
503-
fillSpillRun(rows);
493+
fillSpillRuns(startRowIter);
504494
runSpill();
505495
checkEmptySpillRuns();
506496
}
@@ -511,14 +501,6 @@ void Spiller::checkEmptySpillRuns() const {
511501
}
512502
}
513503

514-
void Spiller::markAllPartitionsSpilled() {
515-
for (auto partition = 0; partition < state_.maxPartitions(); ++partition) {
516-
if (!state_.isPartitionSpilled(partition)) {
517-
state_.setPartitionSpilled(partition);
518-
}
519-
}
520-
}
521-
522504
void Spiller::spill(uint32_t partition, const RowVectorPtr& spillVector) {
523505
CHECK_NOT_FINALIZED();
524506
VELOX_CHECK(
@@ -615,21 +597,6 @@ void Spiller::fillSpillRuns(const RowContainerIterator* startRowIter) {
615597
updateSpillFillTime(execTimeUs);
616598
}
617599

618-
void Spiller::fillSpillRun(std::vector<char*>& rows) {
619-
VELOX_CHECK_EQ(bits_.numPartitions(), 1);
620-
checkEmptySpillRuns();
621-
uint64_t execTimeUs{0};
622-
{
623-
MicrosecondTimer timer(&execTimeUs);
624-
spillRuns_[0].rows =
625-
SpillRows(rows.begin(), rows.end(), spillRuns_[0].rows.get_allocator());
626-
for (const auto* row : rows) {
627-
spillRuns_[0].numBytes += container_->rowSize(row);
628-
}
629-
}
630-
updateSpillFillTime(execTimeUs);
631-
}
632-
633600
std::string Spiller::toString() const {
634601
return fmt::format(
635602
"{}\t{}\tMAX_PARTITIONS:{}\tFINALIZED:{}",
@@ -642,10 +609,8 @@ std::string Spiller::toString() const {
642609
// static
643610
std::string Spiller::typeName(Type type) {
644611
switch (type) {
645-
case Type::kOrderByInput:
646-
return "ORDER_BY_INPUT";
647-
case Type::kOrderByOutput:
648-
return "ORDER_BY_OUTPUT";
612+
case Type::kOrderBy:
613+
return "ORDER_BY";
649614
case Type::kHashJoinBuild:
650615
return "HASH_JOIN_BUILD";
651616
case Type::kHashJoinProbe:

velox/exec/Spiller.h

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,11 @@ class Spiller {
3535
kHashJoinBuild = 2,
3636
// Used for hash join probe.
3737
kHashJoinProbe = 3,
38-
// Used for order by input processing stage.
39-
kOrderByInput = 4,
40-
// Used for order by output processing stage.
41-
kOrderByOutput = 5,
38+
// Used for order by.
39+
kOrderBy = 4,
4240
// Number of spiller types.
43-
kNumTypes = 6,
41+
kNumTypes = 5,
4442
};
45-
4643
static std::string typeName(Type);
4744

4845
using SpillRows = std::vector<char*, memory::StlAllocator<char*>>;
@@ -117,12 +114,6 @@ class Spiller {
117114
/// The caller needs to erase them from the row container.
118115
void spill(const RowContainerIterator& startRowIter);
119116

120-
/// Invoked to spill all the rows pointed by rows. This is used by
121-
/// 'kOrderByOutput' spiller type to spill during the order by
122-
/// output processing. Similarly, the spilled rows still stays in the row
123-
/// container. The caller needs to erase them from the row container.
124-
void spill(std::vector<char*>& rows);
125-
126117
/// Append 'spillVector' into the spill file of given 'partition'. It is now
127118
/// only used by the spilling operator which doesn't need data sort, such as
128119
/// hash join build and hash join probe.
@@ -279,19 +270,11 @@ class Spiller {
279270

280271
void checkEmptySpillRuns() const;
281272

282-
// Marks all the partitions have been spilled as we don't support
283-
// fine-grained spilling as for now.
284-
void markAllPartitionsSpilled();
285-
286273
// Prepares spill runs for the spillable data from all the hash partitions.
287274
// If 'startRowIter' is not null, we prepare runs starting from the offset
288275
// pointed by 'startRowIter'.
289276
void fillSpillRuns(const RowContainerIterator* startRowIter = nullptr);
290277

291-
// Prepares spill run of a single partition for the spillable data from the
292-
// rows.
293-
void fillSpillRun(std::vector<char*>& rows);
294-
295278
// Writes out all the rows collected in spillRuns_.
296279
void runSpill();
297280

velox/exec/TopNRowNumber.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ void TopNRowNumber::setupSpiller() {
737737

738738
spiller_ = std::make_unique<Spiller>(
739739
// TODO Replace Spiller::Type::kOrderBy.
740-
Spiller::Type::kOrderByInput,
740+
Spiller::Type::kOrderBy,
741741
data_.get(),
742742
inputType_,
743743
spillCompareFlags_.size(),

velox/exec/tests/OrderByTest.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,10 +1082,15 @@ DEBUG_ONLY_TEST_F(OrderByTest, reclaimDuringOutputProcessing) {
10821082

10831083
if (enableSpilling) {
10841084
ASSERT_GT(reclaimableBytes, 0);
1085-
reclaimerStats_.reset();
1086-
reclaimAndRestoreCapacity(op, reclaimableBytes, reclaimerStats_);
1087-
ASSERT_EQ(reclaimerStats_.reclaimedBytes, reclaimableBytes);
1085+
const auto usedMemoryBytes = op->pool()->currentBytes();
1086+
reclaimAndRestoreCapacity(
1087+
op,
1088+
folly::Random::oneIn(2) ? 0 : folly::Random::rand32(rng_),
1089+
reclaimerStats_);
1090+
ASSERT_GT(reclaimerStats_.reclaimedBytes, 0);
10881091
ASSERT_GT(reclaimerStats_.reclaimExecTimeUs, 0);
1092+
// No reclaim as the operator has started output processing.
1093+
ASSERT_EQ(usedMemoryBytes, op->pool()->currentBytes());
10891094
} else {
10901095
ASSERT_EQ(reclaimableBytes, 0);
10911096
VELOX_ASSERT_THROW(
@@ -1103,7 +1108,7 @@ DEBUG_ONLY_TEST_F(OrderByTest, reclaimDuringOutputProcessing) {
11031108
ASSERT_EQ(stats[0].operatorStats[1].spilledPartitions, 0);
11041109
OperatorTestBase::deleteTaskAndCheckSpillDirectory(task);
11051110
}
1106-
ASSERT_EQ(reclaimerStats_.numNonReclaimableAttempts, 0);
1111+
ASSERT_EQ(reclaimerStats_.numNonReclaimableAttempts, 1);
11071112
}
11081113

11091114
DEBUG_ONLY_TEST_F(OrderByTest, abortDuringOutputProcessing) {

0 commit comments

Comments
 (0)