cloud-fan commented on code in PR #56784:
URL: https://github.com/apache/spark/pull/56784#discussion_r3479025094


##########
sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/ArchiveReader.scala:
##########
@@ -181,90 +286,19 @@ class TarArchiveReader(path: Path) extends 
ArchiveReader(path) {
         throw e
     }
   }
+}
 
-  /**
-   * Wraps the shared tar stream as a view over exactly the current entry's 
bytes
-   * (`TarArchiveInputStream.read` returns -1 at the entry boundary). 
[[CloseShieldInputStream]]
-   * ignores `close()`, so a parser closing its input does not close the 
underlying archive; any
-   * unread remainder of an entry is skipped by `getNextEntry()` when 
advancing.
-   */
-  private def entryStream(tar: TarArchiveInputStream): InputStream =
-    CloseShieldInputStream.wrap(tar)
-
-  override def readEntries[T](
-      conf: Configuration,
-      ignoredPathSegmentRegex: Pattern)(
-      parseEntry: (String, InputStream) => Iterator[T]): Iterator[T] = {
-    val tar = openTarStream(conf)
-    var closed = false
-
-    def cleanup(): Unit = {
-      if (!closed) {
-        closed = true
-        try tar.close() catch { case NonFatal(_) => }
-      }
-    }
-
-    Option(TaskContext.get()).foreach(_.addTaskCompletionListener[Unit](_ => 
cleanup()))
-
-    val entries = new Iterator[T] with Closeable {
-      private var currentIter: Iterator[T] = Iterator.empty
-      private var done = false
-
-      // Move to the next entry whose iterator has elements (releasing each 
exhausted entry's
-      // reader and skipping any unread bytes), or mark the stream done once 
entries run out.
-      // Advancing here -- driven by `hasNext` -- rather than eagerly after 
producing a row in
-      // `next` is essential for parsers that reuse a single mutable row and 
look ahead on
-      // `hasNext`: probing the current entry right after returning a row 
would overwrite that row's
-      // contents before the caller has copied it.
-      private def advance(): Unit = {
-        while (!done && !currentIter.hasNext) {
-          currentIter match {
-            case c: Closeable => try c.close() catch { case NonFatal(_) => }
-            case _ =>
-          }
-          var entry = tar.getNextEntry
-          while (entry != null && shouldSkipEntry(entry, 
ignoredPathSegmentRegex)) {
-            entry = tar.getNextEntry
-          }
-          if (entry == null) {
-            done = true
-            cleanup()
-          } else {
-            currentIter = parseEntry(entry.getName, entryStream(tar))
-          }
-        }
-      }
-
-      override def hasNext: Boolean = {
-        advance()
-        !done && currentIter.hasNext
-      }
-
-      override def next(): T = {
-        if (!hasNext) throw new NoSuchElementException
-        currentIter.next()
-      }
-
-      override def close(): Unit = {
-        done = true
-        currentIter = Iterator.empty
-        cleanup()
-      }
-    }
+/**
+ * [[ArchiveReader]] for zip archives (`.zip`). Each entry is individually 
compressed inside the
+ * container (the container itself is not gzip-wrapped), so 
`ZipArchiveInputStream` decompresses
+ * entries as they are streamed and no Hadoop codec layer is applied. The 
stream reads local file
+ * headers sequentially rather than the central directory, matching the tar 
reader's pure-streaming
+ * model: a few unusual zips (e.g. a deflated entry whose size is recorded 
only in a trailing data

Review Comment:
   The Scaladoc cites "a **deflated** entry whose size is recorded only in a 
trailing data descriptor" as not streamable, but per commons-compress 1.28.0 a 
DEFLATED entry with a data descriptor *is* streamable: 
`supportsDataDescriptorFor` and `supportsCompressedSizeFor` both return true 
when `method == DEFLATED`, and `readDeflated` detects end-of-stream via 
`inf.finished()` independent of the declared size, so `canReadEntryData` is 
true and `read()` doesn't throw.
   
   The actually non-streamable case is a **STORED** entry with a data 
descriptor — `supportsDataDescriptorFor` returns false (STORED + data 
descriptor, with `allowStoredEntriesWithDataDescriptor` false by default), so 
`read()` throws `UnsupportedZipFeatureException`. Your own self-review says 
"STORED", and `ZipArchiveTestUtils.writeArchive` (writing through a 
non-seekable `FileOutputStream`, which forces data descriptors on DEFLATED 
entries) produces DEFLATED+data-descriptor entries that stream fine — which 
confirms the doc's example is the streamable case. Same wording is worth fixing 
in the PR description too.
   
   ```suggestion
    * model: a few unusual zips (e.g. a stored entry whose size is recorded 
only in a trailing data
   ```



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to