Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.function.ToIntFunction;

/**
* Encapsulates logic for composing multiple CRCs into one or more combined CRCs
Expand All @@ -35,11 +36,11 @@
*/
@InterfaceAudience.LimitedPrivate({"Common", "HDFS", "MapReduce", "Yarn"})
@InterfaceStability.Unstable
public class CrcComposer {
public final class CrcComposer {
private static final int CRC_SIZE_BYTES = 4;
private static final Logger LOG = LoggerFactory.getLogger(CrcComposer.class);

private final int crcPolynomial;
private final ToIntFunction<Long> mod;
private final int precomputedMonomialForHint;
private final long bytesPerCrcHint;
private final long stripeLength;
Expand Down Expand Up @@ -79,28 +80,14 @@ public static CrcComposer newCrcComposer(
*/
public static CrcComposer newStripedCrcComposer(
DataChecksum.Type type, long bytesPerCrcHint, long stripeLength) {
int polynomial = DataChecksum.getCrcPolynomialForType(type);
return new CrcComposer(
polynomial,
CrcUtil.getMonomial(bytesPerCrcHint, polynomial),
bytesPerCrcHint,
stripeLength);
return new CrcComposer(type, bytesPerCrcHint, stripeLength);
}

CrcComposer(
int crcPolynomial,
int precomputedMonomialForHint,
long bytesPerCrcHint,
long stripeLength) {
LOG.debug(
"crcPolynomial=0x{}, precomputedMonomialForHint=0x{}, "
+ "bytesPerCrcHint={}, stripeLength={}",
Integer.toString(crcPolynomial, 16),
Integer.toString(precomputedMonomialForHint, 16),
bytesPerCrcHint,
stripeLength);
this.crcPolynomial = crcPolynomial;
this.precomputedMonomialForHint = precomputedMonomialForHint;
private CrcComposer(DataChecksum.Type type, long bytesPerCrcHint, long stripeLength) {
LOG.debug("type={}, bytesPerCrcHint={}, stripeLength={}",
type, bytesPerCrcHint, stripeLength);
this.mod = DataChecksum.getModFunction(type);
this.precomputedMonomialForHint = CrcUtil.getMonomial(bytesPerCrcHint, mod);
this.bytesPerCrcHint = bytesPerCrcHint;
this.stripeLength = stripeLength;
}
Expand Down Expand Up @@ -161,10 +148,10 @@ public void update(int crcB, long bytesPerCrc) {
curCompositeCrc = crcB;
} else if (bytesPerCrc == bytesPerCrcHint) {
curCompositeCrc = CrcUtil.composeWithMonomial(
curCompositeCrc, crcB, precomputedMonomialForHint, crcPolynomial);
curCompositeCrc, crcB, precomputedMonomialForHint, mod);
} else {
curCompositeCrc = CrcUtil.compose(
curCompositeCrc, crcB, bytesPerCrc, crcPolynomial);
curCompositeCrc, crcB, bytesPerCrc, mod);
}

curPositionInStripe += bytesPerCrc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.hadoop.classification.InterfaceStability;

import java.util.Arrays;
import java.util.function.ToIntFunction;

/**
* This class provides utilities for working with CRCs.
Expand All @@ -32,6 +33,55 @@ public final class CrcUtil {
public static final int MULTIPLICATIVE_IDENTITY = 0x80000000;
public static final int GZIP_POLYNOMIAL = 0xEDB88320;
public static final int CASTAGNOLI_POLYNOMIAL = 0x82F63B78;
private static final long UNIT = 0x8000_0000_0000_0000L;

/**
* @return a * b (mod p),
* where mod p is computed by the given mod function.
*/
static int multiplyMod(int a, int b, ToIntFunction<Long> mod) {
final long left = ((long)a) << 32;
final long right = ((long)b) << 32;

final long product
= ((((((left & (UNIT /* */)) == 0L? 0L : right)
^ ((left & (UNIT >>> 1)) == 0L? 0L : right >>> 1))
^ (((left & (UNIT >>> 2)) == 0L? 0L : right >>> 2)
^ ((left & (UNIT >>> 3)) == 0L? 0L : right >>> 3)))
^ ((((left & (UNIT >>> 4)) == 0L? 0L : right >>> 4)
^ ((left & (UNIT >>> 5)) == 0L? 0L : right >>> 5))
^ (((left & (UNIT >>> 6)) == 0L? 0L : right >>> 6)
^ ((left & (UNIT >>> 7)) == 0L? 0L : right >>> 7))))

^ (((((left & (UNIT >>> 8)) == 0L? 0L : right >>> 8)
^ ((left & (UNIT >>> 9)) == 0L? 0L : right >>> 9))
^ (((left & (UNIT >>> 10)) == 0L? 0L : right >>> 10)
^ ((left & (UNIT >>> 11)) == 0L? 0L : right >>> 11)))
^ ((((left & (UNIT >>> 12)) == 0L? 0L : right >>> 12)
^ ((left & (UNIT >>> 13)) == 0L? 0L : right >>> 13))
^ (((left & (UNIT >>> 14)) == 0L? 0L : right >>> 14)
^ ((left & (UNIT >>> 15)) == 0L? 0L : right >>> 15)))))

^ ((((((left & (UNIT >>> 16)) == 0L? 0L : right >>> 16)
^ ((left & (UNIT >>> 17)) == 0L? 0L : right >>> 17))
^ (((left & (UNIT >>> 18)) == 0L? 0L : right >>> 18)
^ ((left & (UNIT >>> 19)) == 0L? 0L : right >>> 19)))
^ ((((left & (UNIT >>> 20)) == 0L? 0L : right >>> 20)
^ ((left & (UNIT >>> 21)) == 0L? 0L : right >>> 21))
^ (((left & (UNIT >>> 22)) == 0L? 0L : right >>> 22)
^ ((left & (UNIT >>> 23)) == 0L? 0L : right >>> 23))))

^ (((((left & (UNIT >>> 24)) == 0L? 0L : right >>> 24)
^ ((left & (UNIT >>> 25)) == 0L? 0L : right >>> 25))
^ (((left & (UNIT >>> 26)) == 0L? 0L : right >>> 26)
^ ((left & (UNIT >>> 27)) == 0L? 0L : right >>> 27)))
^ ((((left & (UNIT >>> 28)) == 0L? 0L : right >>> 28)
^ ((left & (UNIT >>> 29)) == 0L? 0L : right >>> 29))
^ (((left & (UNIT >>> 30)) == 0L? 0L : right >>> 30)
^ ((left & (UNIT >>> 31)) == 0L? 0L : right >>> 31)))));

return mod.applyAsInt(product);
}

/**
* Hide default constructor for a static utils class.
Expand All @@ -48,7 +98,7 @@ private CrcUtil() {
* @param mod mod.
* @return monomial.
*/
public static int getMonomial(long lengthBytes, int mod) {
public static int getMonomial(long lengthBytes, ToIntFunction<Long> mod) {
if (lengthBytes == 0) {
return MULTIPLICATIVE_IDENTITY;
} else if (lengthBytes < 0) {
Expand All @@ -67,9 +117,9 @@ public static int getMonomial(long lengthBytes, int mod) {
while (degree > 0) {
if ((degree & 1) != 0) {
product = (product == MULTIPLICATIVE_IDENTITY) ? multiplier :
galoisFieldMultiply(product, multiplier, mod);
multiplyMod(product, multiplier, mod);
}
multiplier = galoisFieldMultiply(multiplier, multiplier, mod);
multiplier = multiplyMod(multiplier, multiplier, mod);
degree >>= 1;
}
return product;
Expand All @@ -85,8 +135,8 @@ public static int getMonomial(long lengthBytes, int mod) {
* @return compose with monomial.
*/
public static int composeWithMonomial(
int crcA, int crcB, int monomial, int mod) {
return galoisFieldMultiply(crcA, monomial, mod) ^ crcB;
int crcA, int crcB, int monomial, ToIntFunction<Long> mod) {
return multiplyMod(crcA, monomial, mod) ^ crcB;
}

/**
Expand All @@ -98,7 +148,7 @@ public static int composeWithMonomial(
* @param mod mod.
* @return compose result.
*/
public static int compose(int crcA, int crcB, long lengthB, int mod) {
public static int compose(int crcA, int crcB, long lengthB, ToIntFunction<Long> mod) {
int monomial = getMonomial(lengthB, mod);
return composeWithMonomial(crcA, crcB, monomial, mod);
}
Expand Down Expand Up @@ -199,40 +249,5 @@ public static String toMultiCrcString(final byte[] bytes) {
return sb.toString();
}

/**
* Galois field multiplication of {@code p} and {@code q} with the
* generator polynomial {@code m} as the modulus.
*
* @param m The little-endian polynomial to use as the modulus when
* multiplying p and q, with implicit "1" bit beyond the bottom bit.
*/
private static int galoisFieldMultiply(int p, int q, int m) {
int summation = 0;

// Top bit is the x^0 place; each right-shift increments the degree of the
// current term.
int curTerm = MULTIPLICATIVE_IDENTITY;

// Iteratively multiply p by x mod m as we go to represent the q[i] term
// (of degree x^i) times p.
int px = p;

while (curTerm != 0) {
if ((q & curTerm) != 0) {
summation ^= px;
}

// Bottom bit represents highest degree since we're little-endian; before
// we multiply by "x" for the next term, check bottom bit to know whether
// the resulting px will thus have a term matching the implicit "1" term
// of "m" and thus will need to subtract "m" after mutiplying by "x".
boolean hasMaxDegree = ((px & 1) != 0);
px >>>= 1;
if (hasMaxDegree) {
px ^= m;
}
curTerm >>>= 1;
}
return summation;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
Expand All @@ -22,6 +22,7 @@
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.function.ToIntFunction;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

Expand Down Expand Up @@ -118,15 +119,14 @@ static Checksum newCrc32C() {
* @return the int representation of the polynomial associated with the
* CRC {@code type}, suitable for use with further CRC arithmetic.
*/
public static int getCrcPolynomialForType(Type type) {
static ToIntFunction<Long> getModFunction(Type type) {
switch (type) {
case CRC32:
return CrcUtil.GZIP_POLYNOMIAL;
return PureJavaCrc32::mod;
case CRC32C:
return CrcUtil.CASTAGNOLI_POLYNOMIAL;
return PureJavaCrc32C::mod;
default:
throw new IllegalArgumentException(
"No CRC polynomial could be associated with type: " + type);
throw new IllegalArgumentException("Unexpected type: " + type);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
Expand Down Expand Up @@ -90,6 +90,18 @@ public void update(final byte[] b, final int offset, final int len) {
crc = localCrc;
}

/**
* Compute x mod p, where p is the CRC32 polynomial.
* @param x the input value
* @return x mod p
*/
public static int mod(long x) {
final int y = (int)(x);
return (int)(x >> 32)
^ ((T[((y << 24) >>> 24) + 0x300] ^ T[((y << 16) >>> 24) + 0x200])
^ (T[((y << 8) >>> 24) + 0x100] ^ T[((y /* */) >>> 24) /* */]));
}

@Override
final public void update(int b) {
crc = (crc >>> 8) ^ T[(((crc ^ b) << 24) >>> 24)];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
Expand Down Expand Up @@ -100,6 +100,18 @@ public void update(byte[] b, int off, int len) {
crc = localCrc;
}

/**
* Compute x mod p, where p is the CRC32C polynomial.
* @param x the input value
* @return x mod p
*/
public static int mod(long x) {
final int y = (int)(x);
return (int)(x >> 32)
^ ((T[((y << 24) >>> 24) + 0x300] ^ T[((y << 16) >>> 24) + 0x200])
^ (T[((y << 8) >>> 24) + 0x100] ^ T[((y /* */) >>> 24) /* */]));
}

@Override
final public void update(int b) {
crc = (crc >>> 8) ^ T[T8_0_start + ((crc ^ b) & 0xff)];
Expand Down
Loading