Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@LGLO
Copy link
Contributor

@LGLO LGLO commented Jun 16, 2020

Resolves #3879

Ready for review

  • docs
  • same and better exceptions in inflate and ungzip
  • property test for random input compressed with Java, decompressed by this code
  • tests for gzipped headers with extra, file name, file comment, with/without CRC16 of header

deflate and gzip are out of scope of this PR, decompression only

@LGLO LGLO requested a review from iravid as a code owner June 16, 2020 21:25
@LGLO LGLO added help wanted Extra attention is needed stream ZIO Stream WIP Work in progress labels Jun 16, 2020
@simpadjo
Copy link
Contributor

Would be great to have property-based tests:

  1. doSomething(bytes) == doSomethingUsingJavaLib(bytes)
  2. undoSomethingUsingJavaLib(doSomething(bytes)) == bytes

@LGLO
Copy link
Contributor Author

LGLO commented Jun 17, 2020

There is only decompression implemented in this PR, so I think I could add decompress(compressWithJava(input)) == input property tests only, it's equivalent to
decompressWithJava(compressWithJava(input)) == decompress(compressWithJava(input)).

Copy link
Member

@iravid iravid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work @LGLO. I left some minor comments and agree on the necessity of the property check. Big big thanks for working on this!

}
.map {
case (buffer, inflater) => {
case None => ZIO.succeed(Chunk.empty)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a transducer receives a None, it should treat it as an end-of-stream marker, so at this point, it should flush everything it has (so it should do inflater.inflate) and prepare for a new set of input chunks (inflater.reset).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pullOutput, which I'll rename to pullAllOutput does it, when after reading some part of data it is .finished(). What is more if there are multiple delfated parts inside one stream, it would work.
However it wouldn't work if not whole deflated part was transduced (Inflater wouldn't be .finished()). Thanks for catching this! I'll add test for this case and fix!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iravid actually I don't know if I can test it at ZStream level, should I write the test on level of calling push?


import zio._

private[compression] class Gunzipper private (var state: Gunzipper.State) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest making the functionality in this file mutable and ZIO-less. It'd be much faster this way and you're only doing synchronous effects and error handling, so you can just replace that with exceptions.


private val fixedHeaderLength = 10

sealed trait State {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love how you organized the steps here. I'm not knowledgeable about the GZIP encoding, so I won't review everything here, but it looks great from the maintenance angle.

Hopefully ZIO Codec will make such parsers easier to write 💪🏻

@iravid
Copy link
Member

iravid commented Jun 21, 2020 via email

@LGLO LGLO force-pushed the comprezzion branch 3 times, most recently from b733b8b to 6bfc164 Compare June 22, 2020 21:34
iravid
iravid previously approved these changes Jun 26, 2020
Copy link
Member

@iravid iravid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LGLO Looks excellent. This is good to merge by me if you don't have any planned follow-ups. I left some minor comments but they're not critical.


def close(): Unit = state.close()

def onChunk(c: Chunk[Byte]): ZIO[Any, CompressionException, Chunk[Byte]] =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In terms of code organization, I'd be fine with this just being : Chunk[Byte] and wrapping the exceptions into the CompressionException in compression.gunzip.

.map {
case (buffer, inflater) => {
case None =>
ZIO.succeed {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically this should be ZIO.effectTotal (ZIO.succeed is lazy and just forwards to effectTotal but it's nicer for maintainability to use effectTotal).


private class ParseHeaderStep(acc: Array[Byte], crc32: CRC32) extends State {

//TODO: If whole input is shorther than fixed header, not output is produced and no error is singaled. Is it ok?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like we should throw an exception if the input does not contain a valid header. Is that possible to do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I change:

case None =>
              ZIO.succeed {
                gunzipper.reset()
                Chunk.empty
              }

to

case None =>
              ZIO.succeed {
                if(gunzipper.isFinished()){
                  gunzipper.reset()
                  Chunk.empty
                } else {
                  <fail because stream wasn't complete gzipped>
                }
              }
``` ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer the error and not the empty chunk :) Is there an "auto decompress" path that decompresses if the header exists, and leaves the bytes intact if not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we would like to have such path, then invalid header would have to fallback to clear text stream. Because there is no criterion to distinguish between invalid header and no header.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LGLO To your question: Yes, you should add that else branch, but you should use ZIO.effect instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
I didn't left this work here. Hopefully I could spend some time today in the evening and next week.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @LGLO!

@iravid
Copy link
Member

iravid commented Jun 26, 2020

Oh, one last request: can we move the inflate and gunzip transducer constructors to a platform-specific trait mixed into ZTransducer?

@LGLO
Copy link
Contributor Author

LGLO commented Jun 27, 2020

I'll move this to trait and mix in to platform 👍
I'd like to add test for valid and invalid headers with various properties

@LGLO LGLO requested a review from iravid July 7, 2020 18:58
@LGLO
Copy link
Contributor Author

LGLO commented Jul 7, 2020

Docs are added. Tests against more involved headers are added (and some bugs fixed as well). Removed WIP.

@LGLO LGLO changed the title WIP of un-deflate and un-gzip transducers inflate and gunzip transducers Jul 7, 2020
@iravid
Copy link
Member

iravid commented Jul 7, 2020

@LGLO Fantastic work and coverage. Thank you!!

@LGLO LGLO merged commit f0c31bc into master Jul 8, 2020
@LGLO LGLO deleted the comprezzion branch July 8, 2020 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

help wanted Extra attention is needed stream ZIO Stream WIP Work in progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ZTransducer.inflate, ZTransducer.gunzip

5 participants