io.netty.handler.codec.compression.Lz4XXHash32 Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.compression;
import io.netty.buffer.ByteBuf;
import net.jpountz.xxhash.StreamingXXHash32;
import net.jpountz.xxhash.XXHash32;
import net.jpountz.xxhash.XXHashFactory;
import java.nio.ByteBuffer;
import java.util.zip.Checksum;
/**
* A special-purpose {@link ByteBufChecksum} implementation for use with
* {@link Lz4FrameEncoder} and {@link Lz4FrameDecoder}.
*
* {@link StreamingXXHash32#asChecksum()} has a particularly nasty implementation
* of {@link Checksum#update(int)} that allocates a single-element byte array for
* every invocation.
*
* In addition to that, it doesn't implement an overload that accepts a {@link ByteBuffer}
* as an argument.
*
* Combined, this means that we can't use {@code ReflectiveByteBufChecksum} at all,
* and can't use {@code SlowByteBufChecksum} because of its atrocious performance
* with direct byte buffers (allocating an array and making a JNI call for every byte
* checksummed might be considered sub-optimal by some).
*
* Block version of xxHash32 ({@link XXHash32}), however, does provide
* {@link XXHash32#hash(ByteBuffer, int)} method that is efficient and does exactly
* what we need, with a caveat that we can only invoke it once before having to reset.
* This, however, is fine for our purposes, given the way we use it in
* {@link Lz4FrameEncoder} and {@link Lz4FrameDecoder}:
* {@code reset()}, followed by one {@code update()}, followed by {@code getValue()}.
*/
public final class Lz4XXHash32 extends ByteBufChecksum {
private static final XXHash32 XXHASH32 = XXHashFactory.fastestInstance().hash32();
private final int seed;
private boolean used;
private int value;
@SuppressWarnings("WeakerAccess")
public Lz4XXHash32(int seed) {
this.seed = seed;
}
@Override
public void update(int b) {
throw new UnsupportedOperationException();
}
@Override
public void update(byte[] b, int off, int len) {
if (used) {
throw new IllegalStateException();
}
value = XXHASH32.hash(b, off, len, seed);
used = true;
}
@Override
public void update(ByteBuf b, int off, int len) {
if (used) {
throw new IllegalStateException();
}
if (b.hasArray()) {
value = XXHASH32.hash(b.array(), b.arrayOffset() + off, len, seed);
} else {
value = XXHASH32.hash(CompressionUtil.safeNioBuffer(b, off, len), seed);
}
used = true;
}
@Override
public long getValue() {
if (!used) {
throw new IllegalStateException();
}
/*
* If you look carefully, you'll notice that the most significant nibble
* is being discarded; we believe this to be a bug, but this is what
* StreamingXXHash32#asChecksum() implementation of getValue() does,
* so we have to retain this behaviour for compatibility reasons.
*/
return value & 0xFFFFFFFL;
}
@Override
public void reset() {
used = false;
}
}