Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ trait DeltaSQLCommandTest extends SharedSparkSession {
.set(VeloxDeltaConfig.ENABLE_NATIVE_WRITE.key, "true")
.set("spark.databricks.delta.snapshotPartitions", "2")
.set("spark.gluten.sql.fallbackUnexpectedMetadataParquet", "true")
// Validate every operator's output vector. A Delta deletion-vector write scans only
// synthesized columns with a pushed-down filter, and on that path Velox emits a
// RowVector whose row-index child has no rows; the child is then wrapped in a
// dictionary, and reading it goes out of bounds and yields arbitrary heap values.
// Without this the failure is intermittent and reports a meaningless row index, which
// is how it went unnoticed for so long. With it, the scan is caught the moment it
// produces the malformed vector, so the suite fails deterministically and names the
// operator responsible.
// Velox issue: https://github.com/facebookincubator/velox/issues/18535
// Velox fix: https://github.com/facebookincubator/velox/pull/18536
// Remove this once that fix is picked up, at which point the suite must go green
// again -- which is what validates the fix.
.set("spark.gluten.sql.columnar.backend.velox.validateOutputFromOperators", "true")
}
}
// spotless:on
2 changes: 2 additions & 0 deletions cpp/velox/compute/WholeStageResultIterator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,8 @@ void WholeStageResultIterator::collectMetrics() {
std::unordered_map<std::string, std::string> WholeStageResultIterator::getQueryContextConf() {
std::unordered_map<std::string, std::string> configs = {};
// Find batch size from Spark confs. If found, set the preferred and max batch size.
configs[velox::core::QueryConfig::kValidateOutputFromOperators] =
veloxCfg_->get<bool>(kValidateOutputFromOperators, kValidateOutputFromOperatorsDefault) ? "true" : "false";
configs[velox::core::QueryConfig::kPreferredOutputBatchRows] =
std::to_string(veloxCfg_->get<uint32_t>(kSparkBatchSize, 4096));
configs[velox::core::QueryConfig::kMaxOutputBatchRows] =
Expand Down
8 changes: 8 additions & 0 deletions cpp/velox/config/VeloxConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ const std::string kValueStreamDynamicFilterEnabled =
"spark.gluten.sql.columnar.backend.velox.valueStream.dynamicFilter.enabled";
const bool kValueStreamDynamicFilterEnabledDefault = false;

/// Turns on Velox's per-operator output vector validation
/// (`debug.validate_output_from_operators`). Every operator's output is checked for
/// structural consistency -- among other things that a dictionary's indexes address rows its
/// base vector actually has -- and the first operator to emit a malformed vector is named.
/// Debugging aid only: it costs a pass over every output batch, so it is off by default.
const std::string kValidateOutputFromOperators = "spark.gluten.sql.columnar.backend.velox.validateOutputFromOperators";
const bool kValidateOutputFromOperatorsDefault = false;

const std::string kShowTaskMetricsWhenFinished = "spark.gluten.sql.columnar.backend.velox.showTaskMetricsWhenFinished";
const bool kShowTaskMetricsWhenFinishedDefault = false;

Expand Down
Loading