Zouxxyy commented on code in PR #8300:
URL: https://github.com/apache/paimon/pull/8300#discussion_r3447200213
##########
paimon-spark/paimon-spark-common/src/main/scala/org/apache/spark/sql/execution/SparkFormatTable.scala:
##########
@@ -107,28 +116,231 @@ object SparkFormatTable {
inferred
}
}
+}
- // Extend from InMemoryFileIndex to override partitionSchema
- private class PartitionedInMemoryFileIndex(
+/**
+ * A lazy [[PartitioningAwareFileIndex]] that defers file listing until
[[listFiles]] is called, and
+ * prunes partition directories level-by-level using partition filters.
Inspired by Spark's
+ * [[CatalogFileIndex]] which queries the metastore before listing; here we
discover matching
+ * partitions from the filesystem with per-level filter evaluation.
+ */
+class LazyPartitionPruningFileIndex(
+ sparkSession: SparkSession,
+ tableLocations: Seq[Path],
+ parameters: Map[String, String],
+ userSpecifiedSchema: Option[StructType],
+ fileStatusCache: FileStatusCache,
+ _partitionSchema: StructType)
+ extends PartitioningAwareFileIndex(sparkSession, parameters,
userSpecifiedSchema, fileStatusCache)
+ with Logging {
+
+ override val rootPaths: Seq[Path] = tableLocations
+
+ override def partitionSchema: StructType = _partitionSchema
+
+ private lazy val fullIndex: FullListingFileIndex = {
+ new FullListingFileIndex(
+ sparkSession,
+ tableLocations,
+ parameters,
+ userSpecifiedSchema,
+ fileStatusCache)
+ }
+
+ override protected def leafFiles
+ : mutable.LinkedHashMap[Path, _root_.org.apache.hadoop.fs.FileStatus] =
+ fullIndex.exposedLeafFiles
+
+ override protected def leafDirToChildrenFiles
+ : Map[Path, Array[_root_.org.apache.hadoop.fs.FileStatus]] =
+ fullIndex.exposedLeafDirToChildrenFiles
+
+ override def partitionSpec(): PartitionSpec =
+ SparkFormatTable.alignPartitionSpec(fullIndex.partitionSpec(),
_partitionSchema)
+
+ private class FullListingFileIndex(
sparkSession: SparkSession,
- rootPathsSpecified: Seq[Path],
+ rootPaths: Seq[Path],
parameters: Map[String, String],
userSpecifiedSchema: Option[StructType],
- fileStatusCache: FileStatusCache = NoopCache,
- userSpecifiedPartitionSpec: Option[PartitionSpec] = None,
- metadataOpsTimeNs: Option[Long] = None,
- override val partitionSchema: StructType)
+ fileStatusCache: FileStatusCache)
extends InMemoryFileIndex(
sparkSession,
- rootPathsSpecified,
+ rootPaths,
parameters,
userSpecifiedSchema,
- fileStatusCache,
- userSpecifiedPartitionSpec,
- metadataOpsTimeNs) {
+ fileStatusCache) {
+ def exposedLeafFiles: mutable.LinkedHashMap[Path,
_root_.org.apache.hadoop.fs.FileStatus] =
+ leafFiles
+ def exposedLeafDirToChildrenFiles: Map[Path,
Array[_root_.org.apache.hadoop.fs.FileStatus]] =
+ leafDirToChildrenFiles
+ }
+
+ override def refresh(): Unit = fileStatusCache.invalidateAll()
Review Comment:
Thanks for the review. I investigated the `refresh()` path:
`REFRESH TABLE` in Spark V2 goes through `RefreshTableExec` →
`catalog.invalidateTable(ident)`, which causes the next query to call
`loadTable()` and recreate the entire table instance (including a fresh
`LazyPartitionPruningFileIndex`). `FileIndex.refresh()` is not called in this
path. Same pattern as `CatalogFileIndex`, which also uses an immutable `val
sizeInBytes` and its `refresh()` only clears `fileStatusCache`.
Although `FileIndex.refresh()` is currently only called from V1 paths
(`InsertIntoHadoopFsRelationCommand`, `CacheManager.recacheByPath`) which
engine format tables don't hit, I've made `fullIndex` resettable via
`refresh()` (using `@volatile var` + double-checked locking) to avoid potential
issues in the future. This ensures `refresh()` behaves consistently with
`InMemoryFileIndex`.
Added a config `spark.paimon.format-table.engine.lazy-partition-pruning`
(default `true`). Set to `false` to fall back to eager listing, which may be
better for small tables queried repeatedly without partition filters — eager
listing caches all files at construction and avoids per-query directory
traversal overhead.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]