Skip to content

Commit b508364

Browse files
authored
HDDS-10489. Use CRC tables to speed up galoisFieldMultiply in CrcUtil. (#10155)
1 parent 5797d63 commit b508364

5 files changed

Lines changed: 247 additions & 85 deletions

File tree

hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/common/PureJavaCrc32ByteBuffer.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,4 +553,16 @@ public final class PureJavaCrc32ByteBuffer extends ChecksumByteBuffer.CrcIntTabl
553553
int[] getTable() {
554554
return T;
555555
}
556+
557+
/**
558+
* Compute x mod p, where p is the CRC32 polynomial.
559+
* @param x the input value
560+
* @return x mod p
561+
*/
562+
public static int mod(long x) {
563+
final int y = (int)(x);
564+
return (int)(x >> 32)
565+
^ ((T[((y << 24) >>> 24) + 0x300] ^ T[((y << 16) >>> 24) + 0x200])
566+
^ (T[((y << 8) >>> 24) + 0x100] ^ T[((y /* */) >>> 24) /* */]));
567+
}
556568
}

hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/common/PureJavaCrc32CByteBuffer.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,4 +557,16 @@ public final class PureJavaCrc32CByteBuffer extends ChecksumByteBuffer.CrcIntTab
557557
int[] getTable() {
558558
return T;
559559
}
560+
561+
/**
562+
* Compute x mod p, where p is the CRC32C polynomial.
563+
* @param x the input value
564+
* @return x mod p
565+
*/
566+
public static int mod(long x) {
567+
final int y = (int)(x);
568+
return (int)(x >> 32)
569+
^ ((T[((y << 24) >>> 24) + 0x300] ^ T[((y << 16) >>> 24) + 0x200])
570+
^ (T[((y << 8) >>> 24) + 0x100] ^ T[((y /* */) >>> 24) /* */]));
571+
}
560572
}

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/client/checksum/CrcComposer.java

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
import java.io.ByteArrayOutputStream;
2121
import java.io.DataInputStream;
2222
import java.io.IOException;
23+
import java.util.function.LongToIntFunction;
2324
import org.apache.hadoop.hdds.annotation.InterfaceAudience;
2425
import org.apache.hadoop.hdds.annotation.InterfaceStability;
26+
import org.apache.hadoop.ozone.common.PureJavaCrc32ByteBuffer;
27+
import org.apache.hadoop.ozone.common.PureJavaCrc32CByteBuffer;
2528
import org.apache.hadoop.util.DataChecksum;
2629
import org.slf4j.Logger;
2730
import org.slf4j.LoggerFactory;
@@ -34,11 +37,11 @@
3437
*/
3538
@InterfaceAudience.Private
3639
@InterfaceStability.Unstable
37-
public class CrcComposer {
40+
public final class CrcComposer {
3841
private static final int CRC_SIZE_BYTES = 4;
3942
private static final Logger LOG = LoggerFactory.getLogger(CrcComposer.class);
4043

41-
private final int crcPolynomial;
44+
private final LongToIntFunction mod;
4245
private final int precomputedMonomialForHint;
4346
private final long bytesPerCrcHint;
4447
private final long stripeLength;
@@ -76,28 +79,26 @@ public static CrcComposer newCrcComposer(DataChecksum.Type type, long bytesPerCr
7679
* underlying data size which aligns with the specified stripe boundary.
7780
*/
7881
public static CrcComposer newStripedCrcComposer(DataChecksum.Type type, long bytesPerCrcHint, long stripeLength) {
79-
final int polynomial = CrcUtil.getCrcPolynomialForType(type);
80-
return new CrcComposer(
81-
polynomial,
82-
CrcUtil.getMonomial(bytesPerCrcHint, polynomial),
83-
bytesPerCrcHint,
84-
stripeLength);
82+
return new CrcComposer(type, bytesPerCrcHint, stripeLength);
8583
}
8684

87-
CrcComposer(
88-
int crcPolynomial,
89-
int precomputedMonomialForHint,
90-
long bytesPerCrcHint,
91-
long stripeLength) {
92-
LOG.debug(
93-
"crcPolynomial=0x{}, precomputedMonomialForHint=0x{}, "
94-
+ "bytesPerCrcHint={}, stripeLength={}",
95-
Integer.toString(crcPolynomial, 16),
96-
Integer.toString(precomputedMonomialForHint, 16),
97-
bytesPerCrcHint,
98-
stripeLength);
99-
this.crcPolynomial = crcPolynomial;
100-
this.precomputedMonomialForHint = precomputedMonomialForHint;
85+
/** @return the mod function for the given type. */
86+
static LongToIntFunction getModFunction(DataChecksum.Type type) {
87+
switch (type) {
88+
case CRC32:
89+
return PureJavaCrc32ByteBuffer::mod;
90+
case CRC32C:
91+
return PureJavaCrc32CByteBuffer::mod;
92+
default:
93+
throw new IllegalArgumentException("Unexpected type: " + type);
94+
}
95+
}
96+
97+
private CrcComposer(DataChecksum.Type type, long bytesPerCrcHint, long stripeLength) {
98+
LOG.debug("type={}, bytesPerCrcHint={}, stripeLength={}",
99+
type, bytesPerCrcHint, stripeLength);
100+
this.mod = getModFunction(type);
101+
this.precomputedMonomialForHint = CrcUtil.getMonomial(bytesPerCrcHint, mod);
101102
this.bytesPerCrcHint = bytesPerCrcHint;
102103
this.stripeLength = stripeLength;
103104
}
@@ -157,9 +158,9 @@ public void update(int crcB, long bytesPerCrc) {
157158
if (curCompositeCrc == 0) {
158159
curCompositeCrc = crcB;
159160
} else if (bytesPerCrc == bytesPerCrcHint) {
160-
curCompositeCrc = CrcUtil.composeWithMonomial(curCompositeCrc, crcB, precomputedMonomialForHint, crcPolynomial);
161+
curCompositeCrc = CrcUtil.composeWithMonomial(curCompositeCrc, crcB, precomputedMonomialForHint, mod);
161162
} else {
162-
curCompositeCrc = CrcUtil.compose(curCompositeCrc, crcB, bytesPerCrc, crcPolynomial);
163+
curCompositeCrc = CrcUtil.compose(curCompositeCrc, crcB, bytesPerCrc, mod);
163164
}
164165

165166
curPositionInStripe += bytesPerCrc;

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/client/checksum/CrcUtil.java

Lines changed: 52 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
package org.apache.hadoop.ozone.client.checksum;
1919

2020
import java.util.Arrays;
21+
import java.util.function.LongToIntFunction;
2122
import org.apache.hadoop.hdds.annotation.InterfaceAudience;
2223
import org.apache.hadoop.hdds.annotation.InterfaceStability;
23-
import org.apache.hadoop.util.DataChecksum;
2424

2525
/**
2626
* This class provides utilities for working with CRCs.
@@ -29,8 +29,7 @@
2929
@InterfaceStability.Unstable
3030
public final class CrcUtil {
3131
public static final int MULTIPLICATIVE_IDENTITY = 0x80000000;
32-
public static final int GZIP_POLYNOMIAL = 0xEDB88320;
33-
public static final int CASTAGNOLI_POLYNOMIAL = 0x82F63B78;
32+
private static final long UNIT = 0x8000_0000_0000_0000L;
3433

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

4140
/**
42-
* getCrcPolynomialForType.
43-
*
44-
* @param type type.
45-
* @return the int representation of the polynomial associated with the
46-
* CRC {@code type}, suitable for use with further CRC arithmetic.
41+
* @return a * b (mod p),
42+
* where mod p is computed by the given mod function.
4743
*/
48-
public static int getCrcPolynomialForType(DataChecksum.Type type) {
49-
switch (type) {
50-
case CRC32:
51-
return GZIP_POLYNOMIAL;
52-
case CRC32C:
53-
return CASTAGNOLI_POLYNOMIAL;
54-
default:
55-
throw new IllegalArgumentException(
56-
"No CRC polynomial could be associated with type: " + type);
57-
}
44+
static int multiplyMod(int a, int b, LongToIntFunction mod) {
45+
final long left = ((long)a) << 32;
46+
final long right = ((long)b) << 32;
47+
48+
final long product
49+
= ((((((left & (UNIT /* */)) == 0L ? 0L : right)
50+
^ ((left & (UNIT >>> 1)) == 0L ? 0L : right >>> 1))
51+
^ (((left & (UNIT >>> 2)) == 0L ? 0L : right >>> 2)
52+
^ ((left & (UNIT >>> 3)) == 0L ? 0L : right >>> 3)))
53+
^ ((((left & (UNIT >>> 4)) == 0L ? 0L : right >>> 4)
54+
^ ((left & (UNIT >>> 5)) == 0L ? 0L : right >>> 5))
55+
^ (((left & (UNIT >>> 6)) == 0L ? 0L : right >>> 6)
56+
^ ((left & (UNIT >>> 7)) == 0L ? 0L : right >>> 7))))
57+
58+
^ (((((left & (UNIT >>> 8)) == 0L ? 0L : right >>> 8)
59+
^ ((left & (UNIT >>> 9)) == 0L ? 0L : right >>> 9))
60+
^ (((left & (UNIT >>> 10)) == 0L ? 0L : right >>> 10)
61+
^ ((left & (UNIT >>> 11)) == 0L ? 0L : right >>> 11)))
62+
^ ((((left & (UNIT >>> 12)) == 0L ? 0L : right >>> 12)
63+
^ ((left & (UNIT >>> 13)) == 0L ? 0L : right >>> 13))
64+
^ (((left & (UNIT >>> 14)) == 0L ? 0L : right >>> 14)
65+
^ ((left & (UNIT >>> 15)) == 0L ? 0L : right >>> 15)))))
66+
67+
^ ((((((left & (UNIT >>> 16)) == 0L ? 0L : right >>> 16)
68+
^ ((left & (UNIT >>> 17)) == 0L ? 0L : right >>> 17))
69+
^ (((left & (UNIT >>> 18)) == 0L ? 0L : right >>> 18)
70+
^ ((left & (UNIT >>> 19)) == 0L ? 0L : right >>> 19)))
71+
^ ((((left & (UNIT >>> 20)) == 0L ? 0L : right >>> 20)
72+
^ ((left & (UNIT >>> 21)) == 0L ? 0L : right >>> 21))
73+
^ (((left & (UNIT >>> 22)) == 0L ? 0L : right >>> 22)
74+
^ ((left & (UNIT >>> 23)) == 0L ? 0L : right >>> 23))))
75+
76+
^ (((((left & (UNIT >>> 24)) == 0L ? 0L : right >>> 24)
77+
^ ((left & (UNIT >>> 25)) == 0L ? 0L : right >>> 25))
78+
^ (((left & (UNIT >>> 26)) == 0L ? 0L : right >>> 26)
79+
^ ((left & (UNIT >>> 27)) == 0L ? 0L : right >>> 27)))
80+
^ ((((left & (UNIT >>> 28)) == 0L ? 0L : right >>> 28)
81+
^ ((left & (UNIT >>> 29)) == 0L ? 0L : right >>> 29))
82+
^ (((left & (UNIT >>> 30)) == 0L ? 0L : right >>> 30)
83+
^ ((left & (UNIT >>> 31)) == 0L ? 0L : right >>> 31)))));
84+
85+
return mod.applyAsInt(product);
5886
}
5987

6088
/**
@@ -66,7 +94,7 @@ public static int getCrcPolynomialForType(DataChecksum.Type type) {
6694
* @param mod mod.
6795
* @return monomial.
6896
*/
69-
public static int getMonomial(long lengthBytes, int mod) {
97+
public static int getMonomial(long lengthBytes, LongToIntFunction mod) {
7098
if (lengthBytes == 0) {
7199
return MULTIPLICATIVE_IDENTITY;
72100
} else if (lengthBytes < 0) {
@@ -85,9 +113,9 @@ public static int getMonomial(long lengthBytes, int mod) {
85113
while (degree > 0) {
86114
if ((degree & 1) != 0) {
87115
product = (product == MULTIPLICATIVE_IDENTITY) ? multiplier :
88-
galoisFieldMultiply(product, multiplier, mod);
116+
multiplyMod(product, multiplier, mod);
89117
}
90-
multiplier = galoisFieldMultiply(multiplier, multiplier, mod);
118+
multiplier = multiplyMod(multiplier, multiplier, mod);
91119
degree >>= 1;
92120
}
93121
return product;
@@ -103,8 +131,8 @@ public static int getMonomial(long lengthBytes, int mod) {
103131
* @return compose with monomial.
104132
*/
105133
public static int composeWithMonomial(
106-
int crcA, int crcB, int monomial, int mod) {
107-
return galoisFieldMultiply(crcA, monomial, mod) ^ crcB;
134+
int crcA, int crcB, int monomial, LongToIntFunction mod) {
135+
return multiplyMod(crcA, monomial, mod) ^ crcB;
108136
}
109137

110138
/**
@@ -116,7 +144,7 @@ public static int composeWithMonomial(
116144
* @param mod mod.
117145
* @return compose result.
118146
*/
119-
public static int compose(int crcA, int crcB, long lengthB, int mod) {
147+
public static int compose(int crcA, int crcB, long lengthB, LongToIntFunction mod) {
120148
int monomial = getMonomial(lengthB, mod);
121149
return composeWithMonomial(crcA, crcB, monomial, mod);
122150
}
@@ -216,41 +244,4 @@ public static String toMultiCrcString(final byte[] bytes) {
216244
sb.append(']');
217245
return sb.toString();
218246
}
219-
220-
/**
221-
* Galois field multiplication of {@code p} and {@code q} with the
222-
* generator polynomial {@code m} as the modulus.
223-
*
224-
* @param m The little-endian polynomial to use as the modulus when
225-
* multiplying p and q, with implicit "1" bit beyond the bottom bit.
226-
*/
227-
private static int galoisFieldMultiply(int p, int q, int m) {
228-
int summation = 0;
229-
230-
// Top bit is the x^0 place; each right-shift increments the degree of the
231-
// current term.
232-
int curTerm = MULTIPLICATIVE_IDENTITY;
233-
234-
// Iteratively multiply p by x mod m as we go to represent the q[i] term
235-
// (of degree x^i) times p.
236-
int px = p;
237-
238-
while (curTerm != 0) {
239-
if ((q & curTerm) != 0) {
240-
summation ^= px;
241-
}
242-
243-
// Bottom bit represents highest degree since we're little-endian; before
244-
// we multiply by "x" for the next term, check bottom bit to know whether
245-
// the resulting px will thus have a term matching the implicit "1" term
246-
// of "m" and thus will need to subtract "m" after mutiplying by "x".
247-
boolean hasMaxDegree = ((px & 1) != 0);
248-
px >>>= 1;
249-
if (hasMaxDegree) {
250-
px ^= m;
251-
}
252-
curTerm >>>= 1;
253-
}
254-
return summation;
255-
}
256247
}

0 commit comments

Comments
 (0)