Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Gzip, ZStandard, LZ4 compresssion support over memcacheClient #73

Merged
merged 1 commit into from
Mar 29, 2017

Conversation

baruchshushi
Copy link

No description provided.

<dependency>
<groupId>net.jpountz.lz4</groupId>
<artifactId>lz4</artifactId>
<version>1.3.0</version>
Copy link
Contributor

Choose a reason for hiding this comment

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

please move both versions to main pom dependency management
also, I'm thinking if we're doing here right that we enforce that dependency, but not a blocker for now..

private static LZ4Factory lz4Factory = LZ4Factory.fastestInstance();

public Compressor getInstance() {
switch (this) {
Copy link
Contributor

Choose a reason for hiding this comment

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

no need for the switch
just make #getInstance be abstract method and implement each one at the specific enum value

for exmaple:

LZ4 {
...getInstance() {
return new ...();
}
}

}
}

private Function<byte[], byte[]> gzipDecompress() {
Copy link
Contributor

Choose a reason for hiding this comment

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

about the abstraction:
we can change Compressor to be interface, with implementation for each of the algorithms specified - removing all the impl related logic here (those methods, lz4 instance, etc)

Copy link
Author

Choose a reason for hiding this comment

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

That's what i've originally did, but when it turned that Zstandard and LZ4 compress/decompress is a one liner, it seemed more elegant to simply provide the function.

private final Compressor compressor;

public CompressionTranscoder(final Transcoder<T> delegate, Compressor compressor) {
this.delegate = Objects.requireNonNull(delegate);
Copy link
Contributor

Choose a reason for hiding this comment

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

code style thing: requireNonNull accepts also message, please add one

Copy link
Contributor

Choose a reason for hiding this comment

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

(same for all assertions)

@Override
public T decode(byte[] bytes) {
Objects.requireNonNull(bytes);
byte[] decompress = compressor.decompress(bytes);
Copy link
Contributor

Choose a reason for hiding this comment

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

code style thing: please add final for all defined variables (and method arguments)

}

public MemcachedClientBuilder<T> withCompression() {
compressionApplier = (transcoder) -> new CompressionTranscoder<T>(transcoder, CompressionAlgorithm.LZ4.getInstance());
Copy link
Contributor

Choose a reason for hiding this comment

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

CompressionAlgorithm can have 'default' method returning default impl, and this will just call it

return this;
}

public MemcacheClientBuilder<T> build() {
if(compressionApplier != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

try the following:

    private Function<Transcoder<T>, Transcoder<T>> objectSizeMonitoringApplier = Function.identity();
    private Function<Transcoder<T>, Transcoder<T>> compressionApplier = Function.identity();

    // setters as they now..

    build() {
      final Transcoder<T> wrappedTranscoder = objectSizeMonitoringApplier.compose(compressionApplier).apply(transcoder);
      return wrappedTranscoder; // this also can be inlined - just for the example
    }

* Created by bshushi on 26/03/2017.
*/
@RunWith(MockitoJUnitRunner.class)
public class CompressionTranscoderTest {
Copy link
Contributor

Choose a reason for hiding this comment

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

the tests we really want here is to check all compressions types as you did, using directly the compression implementation, without doing any mocking - just providing sample byte[], checking compress & de-compress works. even better - define a sample value that should be compressed, and check the size.

about the CompressionTranscoder test, it should be really thin test just checking the contract of the class - provide mocked delegator and mocked compressor and just make sure the contract is being valid.

@marenzo
Copy link
Contributor

marenzo commented Mar 29, 2017

LGTM

@marenzo marenzo merged commit e5163e6 into outbrain:master Mar 29, 2017
@Override
public byte[] compress(final byte[] data) {
if (data == null) {
throw new NullPointerException("Can't compress null");
Copy link
Contributor

Choose a reason for hiding this comment

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

This may break existing code

private final Compressor compressor;

public CompressionTranscoder(final Transcoder<T> delegate, Compressor compressor) {
this.delegate = Objects.requireNonNull(delegate, "Delegated Transcoder cannot be null.");
Copy link
Contributor

Choose a reason for hiding this comment

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

This may break existing code


@Override
public T decode(byte[] bytes) {
Objects.requireNonNull(bytes, "Decompression data target cannot be null.");
Copy link
Contributor

Choose a reason for hiding this comment

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

This may break existing code

}

@Test
public void testCompressionTranscoder() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd separate this into several test cases. This will also remove the need for that somewhat almost complete implementation using mocks in the setup method

@@ -350,6 +350,18 @@
</dependency>

<dependency>
<groupId>net.jpountz.lz4</groupId>
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd make these guys optional, to avoid having to have these deps when you don't use them

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants