|
@@ -28,6 +28,12 @@ import java.util.zip.Checksum;
|
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
|
import org.apache.hadoop.classification.InterfaceStability;
|
|
|
import org.apache.hadoop.fs.ChecksumException;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+
|
|
|
+import java.lang.invoke.MethodHandle;
|
|
|
+import java.lang.invoke.MethodHandles;
|
|
|
+import java.lang.invoke.MethodType;
|
|
|
|
|
|
/**
|
|
|
* This class provides interface and utilities for processing checksums for
|
|
@@ -43,6 +49,9 @@ public class DataChecksum implements Checksum {
|
|
|
public static final int CHECKSUM_CRC32C = 2;
|
|
|
public static final int CHECKSUM_DEFAULT = 3;
|
|
|
public static final int CHECKSUM_MIXED = 4;
|
|
|
+
|
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(DataChecksum.class);
|
|
|
+ private static volatile boolean useJava9Crc32C = Shell.isJavaVersionAtLeast(9);
|
|
|
|
|
|
/** The checksum types */
|
|
|
public enum Type {
|
|
@@ -78,6 +87,23 @@ public class DataChecksum implements Checksum {
|
|
|
return new CRC32();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The flag is volatile to avoid synchronization here.
|
|
|
+ * Re-entrancy is unlikely except in failure mode (and inexpensive).
|
|
|
+ */
|
|
|
+ static Checksum newCrc32C() {
|
|
|
+ try {
|
|
|
+ return useJava9Crc32C ? Java9Crc32CFactory.createChecksum()
|
|
|
+ : new PureJavaCrc32C();
|
|
|
+ } catch (ExceptionInInitializerError | RuntimeException e) {
|
|
|
+ // should not happen
|
|
|
+ LOG.error("CRC32C creation failed, switching to PureJavaCrc32C", e);
|
|
|
+ useJava9Crc32C = false;
|
|
|
+ return new PureJavaCrc32C();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public static DataChecksum newDataChecksum(Type type, int bytesPerChecksum ) {
|
|
|
if ( bytesPerChecksum <= 0 ) {
|
|
|
return null;
|
|
@@ -89,7 +115,7 @@ public class DataChecksum implements Checksum {
|
|
|
case CRC32 :
|
|
|
return new DataChecksum(type, newCrc32(), bytesPerChecksum );
|
|
|
case CRC32C:
|
|
|
- return new DataChecksum(type, new PureJavaCrc32C(), bytesPerChecksum);
|
|
|
+ return new DataChecksum(type, newCrc32C(), bytesPerChecksum);
|
|
|
default:
|
|
|
return null;
|
|
|
}
|
|
@@ -528,4 +554,36 @@ public class DataChecksum implements Checksum {
|
|
|
@Override
|
|
|
public void update(int b) {}
|
|
|
};
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Holds constructor handle to let it be initialized on demand.
|
|
|
+ */
|
|
|
+ private static class Java9Crc32CFactory {
|
|
|
+ private static final MethodHandle NEW_CRC32C_MH;
|
|
|
+
|
|
|
+ static {
|
|
|
+ MethodHandle newCRC32C = null;
|
|
|
+ try {
|
|
|
+ newCRC32C = MethodHandles.publicLookup()
|
|
|
+ .findConstructor(
|
|
|
+ Class.forName("java.util.zip.CRC32C"),
|
|
|
+ MethodType.methodType(void.class)
|
|
|
+ );
|
|
|
+ } catch (ReflectiveOperationException e) {
|
|
|
+ // Should not reach here.
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ NEW_CRC32C_MH = newCRC32C;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Checksum createChecksum() {
|
|
|
+ try {
|
|
|
+ // Should throw nothing
|
|
|
+ return (Checksum) NEW_CRC32C_MH.invoke();
|
|
|
+ } catch (Throwable t) {
|
|
|
+ throw (t instanceof RuntimeException) ? (RuntimeException) t
|
|
|
+ : new RuntimeException(t);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
}
|