001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: Adler32.java,v 1.10.2.2 2008/01/07 15:14:18 cwl Exp $
007: */
008:
009: package com.sleepycat.je.utilint;
010:
011: import java.util.zip.Checksum;
012:
013: import com.sleepycat.je.dbi.EnvironmentImpl;
014:
015: /**
016: * Adler32 checksum implementation.
017: *
018: * This class is used rather than the native java.util.zip.Adler32 class
019: * because we have seen a JIT problem when calling the Adler32 class using
020: * the Server JVM on Linux and Solaris. Specifically, we suspect this may
021: * be Bug Parade number 4965907. See SR [#9376]. We also believe that this
022: * bug is fixed in Java 5 and therefore only use this class conditionally
023: * if we find that we're in a 1.4 JVM. [#13354].
024: *
025: * The Adler32 checksum is discussed in RFC1950. The sample implementation
026: * from this RFC is shown below:
027: *
028: * <pre>
029: * #define BASE 65521 largest prime smaller than 65536
030: * unsigned long update_adler32(unsigned long adler,
031: * unsigned char *buf, int len)
032: * {
033: * unsigned long s1 = adler & 0xffff;
034: * unsigned long s2 = (adler >> 16) & 0xffff;
035: * int n;
036: *
037: * for (n = 0; n < len; n++) {
038: * s1 = (s1 + buf[n]) % BASE;
039: * s2 = (s2 + s1) % BASE;
040: * }
041: * return (s2 << 16) + s1;
042: * }
043: *
044: * unsigned long adler32(unsigned char *buf, int len)
045: * {
046: * return update_adler32(1L, buf, len);
047: * }
048: * </pre>
049: *
050: * The NMAX optimization is so that we don't have to do modulo calculations
051: * on every iteration. NMAX is the max number of additions to make
052: * before you have to perform the modulo calculation.
053: */
054: public class Adler32 implements Checksum {
055:
056: /* This class and the ctor are public for the unit tests. */
057: public static class ChunkingAdler32 extends java.util.zip.Adler32 {
058: int adler32ChunkSize = 0;
059:
060: public ChunkingAdler32(int adler32ChunkSize) {
061: this .adler32ChunkSize = adler32ChunkSize;
062: }
063:
064: public void update(byte[] b, int off, int len) {
065: if (len < adler32ChunkSize) {
066: super .update(b, off, len);
067: return;
068: }
069:
070: int i = 0;
071: while (i < len) {
072: int bytesRemaining = len - i;
073: int nBytesThisChunk = Math.min(bytesRemaining,
074: adler32ChunkSize);
075: super .update(b, off + i, nBytesThisChunk);
076: i += nBytesThisChunk;
077: }
078: }
079: }
080:
081: public static Checksum makeChecksum() {
082: if (EnvironmentImpl.JAVA5_AVAILABLE) {
083: int adler32ChunkSize = EnvironmentImpl
084: .getAdler32ChunkSize();
085: if (adler32ChunkSize > 0) {
086: return new ChunkingAdler32(adler32ChunkSize);
087: } else {
088: return new java.util.zip.Adler32();
089: }
090: } else {
091: return new Adler32();
092: }
093: }
094:
095: private long adler = 1;
096:
097: /*
098: * BASE is the largest prime number smaller than 65536
099: * NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
100: */
101: private static final int BASE = 65521;
102: private static final int NMAX = 5552;
103:
104: /**
105: * Update current Adler-32 checksum given the specified byte.
106: */
107: public void update(int b) {
108: long s1 = adler & 0xffff;
109: long s2 = (adler >> 16) & 0xffff;
110: s1 = (s1 + (b & 0xff)) % BASE;
111: s2 = (s1 + s2) % BASE;
112: adler = (s2 << 16) | s1;
113: }
114:
115: /**
116: * Update current Adler-32 checksum given the specified byte array.
117: */
118: public void update(byte[] b, int off, int len) {
119: long s1 = adler & 0xffff;
120: long s2 = (adler >> 16) & 0xffff;
121:
122: while (len > 0) {
123: int k = len < NMAX ? len : NMAX;
124: len -= k;
125:
126: /* This does not benefit from loop unrolling. */
127: while (k-- > 0) {
128: s1 += (b[off++] & 0xff);
129: s2 += s1;
130: }
131:
132: s1 %= BASE;
133: s2 %= BASE;
134: }
135: adler = (s2 << 16) | s1;
136: }
137:
138: /**
139: * Reset Adler-32 checksum to initial value.
140: */
141: public void reset() {
142: adler = 1;
143: }
144:
145: /**
146: * Returns current checksum value.
147: */
148: public long getValue() {
149: return adler;
150: }
151: }
|