@@ -168,6 +168,15 @@ public enum Counter {
168168 BYTES_COPIED
169169 }
170170
171+ /**
172+ * Indicates the checksum comparison result.
173+ */
174+ public enum ChecksumComparison {
175+ TRUE , // checksum comparison is compatible and true.
176+ FALSE , // checksum comparison is compatible and false.
177+ INCOMPATIBLE , // checksum comparison is not compatible.
178+ }
179+
171180 private static class ExportMapper
172181 extends Mapper <BytesWritable , NullWritable , NullWritable , NullWritable > {
173182 private static final Logger LOG = LoggerFactory .getLogger (ExportMapper .class );
@@ -539,6 +548,9 @@ private FileChecksum getFileChecksum(final FileSystem fs, final Path path) {
539548 }
540549 }
541550
551+ /**
552+ * Utility to compare the file length and checksums for the paths specified.
553+ */
542554 private void verifyCopyResult (final FileStatus inputStat , final FileStatus outputStat )
543555 throws IOException {
544556 long inputLen = inputStat .getLen ();
@@ -553,20 +565,64 @@ private void verifyCopyResult(final FileStatus inputStat, final FileStatus outpu
553565
554566 // If length==0, we will skip checksum
555567 if (inputLen != 0 && verifyChecksum ) {
556- FileChecksum inChecksum = getFileChecksum (inputFs , inputPath );
557- if (inChecksum == null ) {
558- LOG .warn ("Input file " + inputPath + " checksums are not available" );
559- }
560- FileChecksum outChecksum = getFileChecksum (outputFs , outputPath );
561- if (outChecksum == null ) {
562- LOG .warn ("Output file " + outputPath + " checksums are not available" );
563- }
564- if (inChecksum != null && outChecksum != null && !inChecksum .equals (outChecksum )) {
565- throw new IOException ("Checksum mismatch between " + inputPath + " and " + outputPath );
568+ FileChecksum inChecksum = getFileChecksum (inputFs , inputStat .getPath ());
569+ FileChecksum outChecksum = getFileChecksum (outputFs , outputStat .getPath ());
570+
571+ ChecksumComparison checksumComparison = verifyChecksum (inChecksum , outChecksum );
572+ if (!checksumComparison .equals (ChecksumComparison .TRUE )) {
573+ StringBuilder errMessage = new StringBuilder ("Checksum mismatch between " )
574+ .append (inputPath ).append (" and " ).append (outputPath ).append ("." );
575+
576+ boolean addSkipHint = false ;
577+ String inputScheme = inputFs .getScheme ();
578+ String outputScheme = outputFs .getScheme ();
579+ if (!inputScheme .equals (outputScheme )) {
580+ errMessage .append (" Input and output filesystems are of different types.\n " )
581+ .append ("Their checksum algorithms may be incompatible." );
582+ addSkipHint = true ;
583+ } else if (inputStat .getBlockSize () != outputStat .getBlockSize ()) {
584+ errMessage .append (" Input and output differ in block-size." );
585+ addSkipHint = true ;
586+ } else if (
587+ inChecksum != null && outChecksum != null
588+ && !inChecksum .getAlgorithmName ().equals (outChecksum .getAlgorithmName ())
589+ ) {
590+ errMessage .append (" Input and output checksum algorithms are of different types." );
591+ addSkipHint = true ;
592+ }
593+ if (addSkipHint ) {
594+ errMessage
595+ .append (" You can choose file-level checksum validation via "
596+ + "-Ddfs.checksum.combine.mode=COMPOSITE_CRC when block-sizes"
597+ + " or filesystems are different." )
598+ .append (" Or you can skip checksum-checks altogether with --no-checksum-verify.\n " )
599+ .append (" (NOTE: By skipping checksums, one runs the risk of "
600+ + "masking data-corruption during file-transfer.)\n " );
601+ }
602+ throw new IOException (errMessage .toString ());
566603 }
567604 }
568605 }
569606
607+ /**
608+ * Utility to compare checksums
609+ */
610+ private ChecksumComparison verifyChecksum (final FileChecksum inChecksum ,
611+ final FileChecksum outChecksum ) {
612+ // If the input or output checksum is null, or the algorithms of input and output are not
613+ // equal, that means there is no comparison
614+ // and return not compatible. else if matched, return compatible with the matched result.
615+ if (
616+ inChecksum == null || outChecksum == null
617+ || !inChecksum .getAlgorithmName ().equals (outChecksum .getAlgorithmName ())
618+ ) {
619+ return ChecksumComparison .INCOMPATIBLE ;
620+ } else if (inChecksum .equals (outChecksum )) {
621+ return ChecksumComparison .TRUE ;
622+ }
623+ return ChecksumComparison .FALSE ;
624+ }
625+
570626 /**
571627 * Check if the two files are equal by looking at the file length, and at the checksum (if user
572628 * has specified the verifyChecksum flag).
0 commit comments