/**
* Copyright 2016 Yahoo Inc.
*
* Licensed 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
*
* http://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 com.yahoo.pulsar.common.compression;
import static com.scurrilous.circe.params.CrcParameters.CRC32C;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
import com.scurrilous.circe.IncrementalIntHash;
import com.scurrilous.circe.crc.StandardCrcProvider;
import com.yahoo.pulsar.checksum.utils.Crc32cChecksum;
import com.yahoo.pulsar.checksum.utils.Crc32cSse42Provider;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
public class Crc32cChecksumTest {
private static final byte[] inputBytes = "data".getBytes();
private static final int expectedChecksum = 0xaed87dd1;
private static final IncrementalIntHash SOFTWARE_CRC32C_HASH = new StandardCrcProvider().getIncrementalInt(CRC32C);
private static final IncrementalIntHash HARDWARE_CRC32C_HASH;
static {
IncrementalIntHash hardwareCRC32C = null;
try {
hardwareCRC32C = new Crc32cSse42Provider().getIncrementalInt(CRC32C);
} catch (Throwable t) {
// Native CRC32C Not supported, skip tests
hardwareCRC32C = null;
}
HARDWARE_CRC32C_HASH = hardwareCRC32C;
}
@Test
public void testCrc32c() {
ByteBuf payload = Unpooled.wrappedBuffer(inputBytes);
int checksum = Crc32cChecksum.computeChecksum(payload);
payload.release();
assertEquals(expectedChecksum, checksum);
}
@Test
public void testCrc32cHardware() {
if (HARDWARE_CRC32C_HASH == null) {
return;
}
ByteBuf payload = Unpooled.wrappedBuffer(inputBytes);
// compute checksum using sse4.2 hw instruction
int hw = HARDWARE_CRC32C_HASH.calculate(payload.array(), payload.arrayOffset() + payload.readerIndex(),
payload.readableBytes());
assertEquals(hw, expectedChecksum);
}
@Test
public void testCrc32cSoftware() {
ByteBuf payload = Unpooled.wrappedBuffer(inputBytes);
// compute checksum using sw algo
int sw = SOFTWARE_CRC32C_HASH.calculate(payload.array(), payload.arrayOffset() + payload.readerIndex(),
payload.readableBytes());
assertEquals(sw, expectedChecksum);
}
@Test
public void testCrc32cDirectMemoryHardware() {
if (HARDWARE_CRC32C_HASH == null) {
return;
}
ByteBuf payload = ByteBufAllocator.DEFAULT.directBuffer(inputBytes.length);
payload.writeBytes(inputBytes);
// read directly from memory address
int checksum = HARDWARE_CRC32C_HASH.calculate(payload.memoryAddress(), payload.readableBytes());
payload.release();
assertEquals(checksum, expectedChecksum);
}
@Test
public void testCrc32cIncremental() {
if (HARDWARE_CRC32C_HASH == null) {
return;
}
String data = "data-abcd-data-123-$%#";
for (int i = 0; i < 20; i++) {
String doubleData = data + data;
int doubleDataCrcHW = HARDWARE_CRC32C_HASH.calculate(doubleData.getBytes());
int data1CrcHW = HARDWARE_CRC32C_HASH.calculate(data.getBytes());
int data2CrcHW = HARDWARE_CRC32C_HASH.resume(data1CrcHW, data.getBytes());
assertEquals(doubleDataCrcHW, data2CrcHW);
int doubleDataCrcSW = SOFTWARE_CRC32C_HASH.calculate(doubleData.getBytes());
int data1CrcSW = SOFTWARE_CRC32C_HASH.calculate(data.getBytes());
int data2CrcSW = SOFTWARE_CRC32C_HASH.resume(data1CrcSW, data.getBytes());
assertEquals(doubleDataCrcSW, data2CrcSW);
assertEquals(doubleDataCrcHW, doubleDataCrcSW);
data += data;
}
}
@Test
public void testCrc32cIncrementalUsingProvider() {
final byte[] data = "data".getBytes();
final byte[] doubleData = "datadata".getBytes();
ByteBuf payload = Unpooled.wrappedBuffer(data);
ByteBuf doublePayload = Unpooled.wrappedBuffer(doubleData);
int expectedChecksum = Crc32cChecksum.computeChecksum(doublePayload);
// (1) heap-memory
int checksum = Crc32cChecksum.computeChecksum(payload);
int incrementalChecksum = Crc32cChecksum.resumeChecksum(checksum, payload);
assertEquals(expectedChecksum, incrementalChecksum);
payload.release();
doublePayload.release();
// (2) direct-memory
payload = ByteBufAllocator.DEFAULT.directBuffer(data.length);
payload.writeBytes(data);
checksum = Crc32cChecksum.computeChecksum(payload);
incrementalChecksum = Crc32cChecksum.resumeChecksum(checksum, payload);
assertEquals(expectedChecksum, incrementalChecksum);
payload.release();
}
}