Skip to content
Merged
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 @@ -553,4 +553,16 @@ public final class PureJavaCrc32ByteBuffer extends ChecksumByteBuffer.CrcIntTabl
int[] getTable() {
return T;
}

/**
* 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) /* */]));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -557,4 +557,16 @@ public final class PureJavaCrc32CByteBuffer extends ChecksumByteBuffer.CrcIntTab
int[] getTable() {
return T;
}

/**
* 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) /* */]));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.function.LongToIntFunction;
import org.apache.hadoop.hdds.annotation.InterfaceAudience;
import org.apache.hadoop.hdds.annotation.InterfaceStability;
import org.apache.hadoop.ozone.common.PureJavaCrc32ByteBuffer;
import org.apache.hadoop.ozone.common.PureJavaCrc32CByteBuffer;
import org.apache.hadoop.util.DataChecksum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -34,11 +37,11 @@
*/
@InterfaceAudience.Private
@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 LongToIntFunction mod;
private final int precomputedMonomialForHint;
private final long bytesPerCrcHint;
private final long stripeLength;
Expand Down Expand Up @@ -76,28 +79,26 @@ public static CrcComposer newCrcComposer(DataChecksum.Type type, long bytesPerCr
* underlying data size which aligns with the specified stripe boundary.
*/
public static CrcComposer newStripedCrcComposer(DataChecksum.Type type, long bytesPerCrcHint, long stripeLength) {
final int polynomial = CrcUtil.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;
/** @return the mod function for the given type. */
static LongToIntFunction getModFunction(DataChecksum.Type type) {
switch (type) {
case CRC32:
return PureJavaCrc32ByteBuffer::mod;
case CRC32C:
return PureJavaCrc32CByteBuffer::mod;
default:
throw new IllegalArgumentException("Unexpected type: " + type);
}
}

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

curPositionInStripe += bytesPerCrc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
package org.apache.hadoop.ozone.client.checksum;

import java.util.Arrays;
import java.util.function.LongToIntFunction;
import org.apache.hadoop.hdds.annotation.InterfaceAudience;
import org.apache.hadoop.hdds.annotation.InterfaceStability;
import org.apache.hadoop.util.DataChecksum;

/**
* This class provides utilities for working with CRCs.
Expand All @@ -29,8 +29,7 @@
@InterfaceStability.Unstable
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;

/**
* Hide default constructor for a static utils class.
Expand All @@ -39,22 +38,51 @@ private CrcUtil() {
}

/**
* getCrcPolynomialForType.
*
* @param type type.
* @return the int representation of the polynomial associated with the
* CRC {@code type}, suitable for use with further CRC arithmetic.
* @return a * b (mod p),
* where mod p is computed by the given mod function.
*/
public static int getCrcPolynomialForType(DataChecksum.Type type) {
switch (type) {
case CRC32:
return GZIP_POLYNOMIAL;
case CRC32C:
return CASTAGNOLI_POLYNOMIAL;
default:
throw new IllegalArgumentException(
"No CRC polynomial could be associated with type: " + type);
}
static int multiplyMod(int a, int b, LongToIntFunction 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);
}

/**
Expand All @@ -66,7 +94,7 @@ public static int getCrcPolynomialForType(DataChecksum.Type type) {
* @param mod mod.
* @return monomial.
*/
public static int getMonomial(long lengthBytes, int mod) {
public static int getMonomial(long lengthBytes, LongToIntFunction mod) {
if (lengthBytes == 0) {
return MULTIPLICATIVE_IDENTITY;
} else if (lengthBytes < 0) {
Expand All @@ -85,9 +113,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 @@ -103,8 +131,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, LongToIntFunction mod) {
return multiplyMod(crcA, monomial, mod) ^ crcB;
}

/**
Expand All @@ -116,7 +144,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, LongToIntFunction mod) {
int monomial = getMonomial(lengthB, mod);
return composeWithMonomial(crcA, crcB, monomial, mod);
}
Expand Down Expand Up @@ -216,41 +244,4 @@ public static String toMultiCrcString(final byte[] bytes) {
sb.append(']');
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;
}
}
Loading