|
17 | 17 |
|
18 | 18 | package org.apache.spark.io |
19 | 19 |
|
20 | | -import java.io.{InputStream, OutputStream} |
| 20 | +import java.io.{IOException, InputStream, OutputStream} |
21 | 21 |
|
22 | 22 | import com.ning.compress.lzf.{LZFInputStream, LZFOutputStream} |
23 | 23 | import net.jpountz.lz4.{LZ4BlockInputStream, LZ4BlockOutputStream} |
@@ -154,8 +154,53 @@ class SnappyCompressionCodec(conf: SparkConf) extends CompressionCodec { |
154 | 154 |
|
155 | 155 | override def compressedOutputStream(s: OutputStream): OutputStream = { |
156 | 156 | val blockSize = conf.getSizeAsBytes("spark.io.compression.snappy.blockSize", "32k").toInt |
157 | | - new SnappyOutputStream(s, blockSize) |
| 157 | + new SnappyOutputStreamWrapper(new SnappyOutputStream(s, blockSize)) |
158 | 158 | } |
159 | 159 |
|
160 | 160 | override def compressedInputStream(s: InputStream): InputStream = new SnappyInputStream(s) |
161 | 161 | } |
| 162 | + |
| 163 | +/** |
| 164 | + * Wrapper over [[SnappyOutputStream]] which guards against write-after-close and double-close |
| 165 | + * issues. See SPARK-7660 for more details. This wrapping can be removed if we upgrade to a version |
| 166 | + * of snappy-java that contains the fix for https://github.com/xerial/snappy-java/issues/107. |
| 167 | + */ |
| 168 | +private final class SnappyOutputStreamWrapper(os: SnappyOutputStream) extends OutputStream { |
| 169 | + |
| 170 | + private[this] var closed: Boolean = false |
| 171 | + |
| 172 | + override def write(b: Int): Unit = { |
| 173 | + if (closed) { |
| 174 | + throw new IOException("Stream is closed") |
| 175 | + } |
| 176 | + os.write(b) |
| 177 | + } |
| 178 | + |
| 179 | + override def write(b: Array[Byte]): Unit = { |
| 180 | + if (closed) { |
| 181 | + throw new IOException("Stream is closed") |
| 182 | + } |
| 183 | + os.write(b) |
| 184 | + } |
| 185 | + |
| 186 | + override def write(b: Array[Byte], off: Int, len: Int): Unit = { |
| 187 | + if (closed) { |
| 188 | + throw new IOException("Stream is closed") |
| 189 | + } |
| 190 | + os.write(b, off, len) |
| 191 | + } |
| 192 | + |
| 193 | + override def flush(): Unit = { |
| 194 | + if (closed) { |
| 195 | + throw new IOException("Stream is closed") |
| 196 | + } |
| 197 | + os.flush() |
| 198 | + } |
| 199 | + |
| 200 | + override def close(): Unit = { |
| 201 | + if (!closed) { |
| 202 | + closed = true |
| 203 | + os.close() |
| 204 | + } |
| 205 | + } |
| 206 | +} |
0 commit comments