# HG changeset patch # User sherman # Date 1322600735 28800 # Node ID f7248a4db8db30e002be7921df4ec1c4fecb6f5b # Parent 6d340c7b6a328dfafb2bcc161ba82620564d7a6e 7109837: Provide a mechanism for computing an Adler32 checksum for the contents of a ByteBuffer Summary: added methods Adler32/CRC32.update(ByteBuffer) Reviewed-by: alanb diff -r 6d340c7b6a32 -r f7248a4db8db jdk/make/java/zip/mapfile-vers --- a/jdk/make/java/zip/mapfile-vers Tue Nov 29 11:39:59 2011 -0800 +++ b/jdk/make/java/zip/mapfile-vers Tue Nov 29 13:05:35 2011 -0800 @@ -30,8 +30,10 @@ Java_java_util_jar_JarFile_getMetaInfEntryNames; Java_java_util_zip_Adler32_update; Java_java_util_zip_Adler32_updateBytes; + Java_java_util_zip_Adler32_updateByteBuffer; Java_java_util_zip_CRC32_update; Java_java_util_zip_CRC32_updateBytes; + Java_java_util_zip_CRC32_updateByteBuffer; Java_java_util_zip_Deflater_deflateBytes; Java_java_util_zip_Deflater_end; Java_java_util_zip_Deflater_getAdler; diff -r 6d340c7b6a32 -r f7248a4db8db jdk/src/share/classes/java/util/zip/Adler32.java --- a/jdk/src/share/classes/java/util/zip/Adler32.java Tue Nov 29 11:39:59 2011 -0800 +++ b/jdk/src/share/classes/java/util/zip/Adler32.java Tue Nov 29 13:05:35 2011 -0800 @@ -25,16 +25,23 @@ package java.util.zip; +import java.nio.ByteBuffer; +import sun.nio.ch.DirectBuffer; + /** * A class that can be used to compute the Adler-32 checksum of a data * stream. An Adler-32 checksum is almost as reliable as a CRC-32 but * can be computed much faster. * + *

Passing a {@code null} argument to a method in this class will cause + * a {@link NullPointerException} to be thrown. + * * @see Checksum * @author David Connelly */ public class Adler32 implements Checksum { + private int adler = 1; /** @@ -75,6 +82,39 @@ adler = updateBytes(adler, b, 0, b.length); } + + /** + * Updates the checksum with the bytes from the specified buffer. + * + * The checksum is updated using + * buffer.{@link java.nio.Buffer#remaining() remaining()} + * bytes starting at + * buffer.{@link java.nio.Buffer#position() position()} + * Upon return, the buffer's position will be updated to its + * limit; its limit will not have been changed. + * + * @param buffer the ByteBuffer to update the checksum with + * @since 1.8 + */ + public void update(ByteBuffer buffer) { + int pos = buffer.position(); + int limit = buffer.limit(); + assert (pos <= limit); + int rem = limit - pos; + if (rem <= 0) + return; + if (buffer instanceof DirectBuffer) { + adler = updateByteBuffer(adler, ((DirectBuffer)buffer).address(), pos, rem); + } else if (buffer.hasArray()) { + adler = updateBytes(adler, buffer.array(), pos + buffer.arrayOffset(), rem); + } else { + byte[] b = new byte[rem]; + buffer.get(b); + adler = updateBytes(adler, b, 0, b.length); + } + buffer.position(limit); + } + /** * Resets the checksum to initial value. */ @@ -92,4 +132,6 @@ private native static int update(int adler, int b); private native static int updateBytes(int adler, byte[] b, int off, int len); + private native static int updateByteBuffer(int adler, long addr, + int off, int len); } diff -r 6d340c7b6a32 -r f7248a4db8db jdk/src/share/classes/java/util/zip/CRC32.java --- a/jdk/src/share/classes/java/util/zip/CRC32.java Tue Nov 29 11:39:59 2011 -0800 +++ b/jdk/src/share/classes/java/util/zip/CRC32.java Tue Nov 29 13:05:35 2011 -0800 @@ -25,9 +25,15 @@ package java.util.zip; +import java.nio.ByteBuffer; +import sun.nio.ch.DirectBuffer; + /** * A class that can be used to compute the CRC-32 of a data stream. * + *

Passing a {@code null} argument to a method in this class will cause + * a {@link NullPointerException} to be thrown. + * * @see Checksum * @author David Connelly */ @@ -75,6 +81,38 @@ } /** + * Updates the checksum with the bytes from the specified buffer. + * + * The checksum is updated using + * buffer.{@link java.nio.Buffer#remaining() remaining()} + * bytes starting at + * buffer.{@link java.nio.Buffer#position() position()} + * Upon return, the buffer's position will + * be updated to its limit; its limit will not have been changed. + * + * @param buffer the ByteBuffer to update the checksum with + * @since 1.8 + */ + public void update(ByteBuffer buffer) { + int pos = buffer.position(); + int limit = buffer.limit(); + assert (pos <= limit); + int rem = limit - pos; + if (rem <= 0) + return; + if (buffer instanceof DirectBuffer) { + crc = updateByteBuffer(crc, ((DirectBuffer)buffer).address(), pos, rem); + } else if (buffer.hasArray()) { + crc = updateBytes(crc, buffer.array(), pos + buffer.arrayOffset(), rem); + } else { + byte[] b = new byte[rem]; + buffer.get(b); + crc = updateBytes(crc, b, 0, b.length); + } + buffer.position(limit); + } + + /** * Resets CRC-32 to initial value. */ public void reset() { @@ -90,4 +128,7 @@ private native static int update(int crc, int b); private native static int updateBytes(int crc, byte[] b, int off, int len); + + private native static int updateByteBuffer(int adler, long addr, + int off, int len); } diff -r 6d340c7b6a32 -r f7248a4db8db jdk/src/share/native/java/util/zip/Adler32.c --- a/jdk/src/share/native/java/util/zip/Adler32.c Tue Nov 29 11:39:59 2011 -0800 +++ b/jdk/src/share/native/java/util/zip/Adler32.c Tue Nov 29 13:05:35 2011 -0800 @@ -30,6 +30,7 @@ #include "jni.h" #include "jni_util.h" #include "zlib.h" +#include "jlong.h" #include "java_util_zip_Adler32.h" @@ -53,3 +54,17 @@ } return adler; } + + +JNIEXPORT jint JNICALL +Java_java_util_zip_Adler32_updateByteBuffer(JNIEnv *env, jclass cls, jint adler, + jlong address, jint off, jint len) +{ + Bytef *buf = (Bytef *)jlong_to_ptr(address); + if (buf) { + adler = adler32(adler, buf + off, len); + } + return adler; +} + + diff -r 6d340c7b6a32 -r f7248a4db8db jdk/src/share/native/java/util/zip/CRC32.c --- a/jdk/src/share/native/java/util/zip/CRC32.c Tue Nov 29 11:39:59 2011 -0800 +++ b/jdk/src/share/native/java/util/zip/CRC32.c Tue Nov 29 13:05:35 2011 -0800 @@ -58,3 +58,14 @@ { return crc32(crc, (Bytef*)buf, len); } + +JNIEXPORT jint JNICALL +Java_java_util_zip_CRC32_updateByteBuffer(JNIEnv *env, jclass cls, jint crc, + jlong address, jint off, jint len) +{ + Bytef *buf = (Bytef *)jlong_to_ptr(address); + if (buf) { + crc = crc32(crc, buf + off, len); + } + return crc; +} diff -r 6d340c7b6a32 -r f7248a4db8db jdk/test/java/util/zip/TimeChecksum.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/zip/TimeChecksum.java Tue Nov 29 13:05:35 2011 -0800 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* @test + * @bug 7109837 + * @summary Test Adler32/CRC32.update(ByteBuffer) + */ + +import java.util.*; +import java.util.zip.*; +import java.nio.*; + +public class TimeChecksum { + + static long time(Adler32 adler32, byte[] data, int iters, int len) { + long start_t = System.nanoTime(); + for (int i = 0; i < iters; i++) { + adler32.reset(); + adler32.update(data, 0, len); + } + long t = System.nanoTime() - start_t; + System.out.printf("%,12d", t / len); + return t; + } + + static long time(Adler32 adler32, ByteBuffer buf, int iters) { + long start_t = System.nanoTime(); + for (int i = 0; i < iters; i++) { + adler32.reset(); + buf.mark(); + adler32.update(buf); + buf.reset(); + } + long t = System.nanoTime() - start_t; + System.out.printf("%,12d", t / buf.remaining()); + return t; + } + + static void testPosLimit(Adler32 adler32, ByteBuffer buf) { + int pos = buf.position(); + int limit = buf.limit(); + adler32.update(buf); + if (limit != buf.position() || limit != buf.limit()) { + System.out.printf("%nFAILED: pos,limit=(%d, %d), expected (%d, %d)%n", + buf.position(), buf.limit(), limit, limit); + throw new RuntimeException(); + } + buf.position(pos); + } + + static long time(CRC32 crc32, byte[] data, int iters, int len) { + long start_t = System.nanoTime(); + for (int i = 0; i < iters; i++) { + crc32.reset(); + crc32.update(data, 0, len); + } + long t = System.nanoTime() - start_t; + System.out.printf("%,12d", t / len); + return t; + } + + static long time(CRC32 crc32, ByteBuffer buf, int iters) { + long start_t = System.nanoTime(); + for (int i = 0; i < iters; i++) { + crc32.reset(); + buf.mark(); + crc32.update(buf); + buf.reset(); + } + long t = System.nanoTime() - start_t; + System.out.printf("%,12d", t / buf.remaining()); + return t; + } + + static void testPosLimit(CRC32 crc32, ByteBuffer buf) { + int pos = buf.position(); + int limit = buf.limit(); + crc32.update(buf); + if (limit != buf.position() || limit != buf.limit()) { + System.out.printf("%nFAILED: pos,limit=(%d, %d), expected (%d, %d)%n", + buf.position(), buf.limit(), limit, limit); + throw new RuntimeException(); + } + buf.position(pos); + } + + public static void main(String[] args) { + int len = 1024 * 32; + int iters = 1; + if (args.length != 0 && "-benchmark".equals(args[0])) + iters = 100000; + Adler32 adler32 = new Adler32(); + CRC32 crc32 = new CRC32(); + Random rdm = new Random(); + byte[] data = new byte[len]; + new Random().nextBytes(data); + ByteBuffer buf; + + System.out.println("---------- Adler32 ----------"); + System.out.print("Warmup..."); + time(adler32, data, iters, len); + time(adler32, ByteBuffer.wrap(data), iters); + buf = ByteBuffer.allocateDirect(len); + buf.put(data, 0, len); + buf.flip(); + time(adler32, buf, iters); + System.out.println("\n"); + + System.out.println("Length byte[](ns/len) ByteBuffer(direct) ByteBuffer"); + for (int testlen = 1; testlen < data.length; testlen <<= 1) { + System.out.print(testlen + "\t"); + long baT = time(adler32, data, iters, testlen); + long baV = adler32.getValue(); + System.out.print("\t"); + + buf = ByteBuffer.allocateDirect(testlen); + buf.put(data, 0, testlen); + buf.flip(); + long bbdT = time(adler32, buf, iters); + long bbdV = adler32.getValue(); + if (baV != bbdV) { + System.out.printf("%nFAILED: baV=%x,bbdV=%x%n", baV, bbdV); + throw new RuntimeException(); + } + System.out.printf(" (%.2f)", (float)bbdT/baT); + testPosLimit(adler32, buf); + + buf = ByteBuffer.allocate(testlen); + buf.put(data, 0, testlen); + buf.flip(); + long bbT = time(adler32, buf, iters); + long bbV = adler32.getValue(); + if (baV != bbV) { + System.out.printf("%nFAILED: baV=%x,bbV=%x%n", baV, bbV); + throw new RuntimeException(); + } + testPosLimit(adler32, buf); + System.out.printf(" (%.2f) checksum=%x%n", (float)bbT/baT, bbV); + } + + System.out.println("\n---------- CRC32 ----------"); + System.out.print("Warmup..."); + time(crc32, data, iters, len); + time(crc32, ByteBuffer.wrap(data), iters); + buf = ByteBuffer.allocateDirect(len); + buf.put(data, 0, len); + buf.flip(); + time(crc32, buf, iters); + System.out.println("\n"); + + + System.out.println("Length byte[](ns/len) ByteBuffer(direct) ByteBuffer"); + for (int testlen = 1; testlen < data.length; testlen <<= 1) { + System.out.print(testlen + "\t"); + long baT = time(crc32, data, iters, testlen); + long baV = crc32.getValue(); + System.out.print("\t"); + + buf = ByteBuffer.allocateDirect(testlen); + buf.put(data, 0, testlen); + buf.flip(); + long bbdT = time(crc32, buf, iters); + long bbdV = crc32.getValue(); + if (baV != bbdV) { + System.out.printf("%nFAILED: baV=%x,bbdV=%x%n", baV, bbdV); + throw new RuntimeException(); + } + System.out.printf(" (%.2f)", (float)bbdT/baT); + testPosLimit(crc32, buf); + + buf = ByteBuffer.allocate(testlen); + buf.put(data, 0, testlen); + buf.flip(); + long bbT = time(crc32, buf, iters); + long bbV = crc32.getValue(); + if (baV != bbV) { + System.out.printf("%nFAILED: baV=%x,bbV=%x%n", baV, bbV); + throw new RuntimeException(); + } + testPosLimit(crc32, buf); + System.out.printf(" (%.2f) checksum=%x%n", (float)bbT / baT, bbV); + } + } +}