1 /*** 2 * 3 * Copyright 2004 Hiram Chirino 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 **/ 18 package org.codehaus.activemq.journal.impl; 19 20 import java.io.DataInput; 21 import java.io.DataOutput; 22 import java.io.IOException; 23 import java.nio.ByteBuffer; 24 import java.util.zip.CRC32; 25 26 /*** 27 * Serializes/Deserializes record header information. 28 * 29 * @version $Revision: 1.1 $ 30 */ 31 public class RecordFooter { 32 33 static final public int SELECTED_CHECKSUM_ALGORITHIM; 34 static final public int NO_CHECKSUM_ALGORITHIM=0; 35 static final public int HASH_CHECKSUM_ALGORITHIM=1; 36 static final public int CRC32_CHECKSUM_ALGORITHIM=2; 37 38 static { 39 String type = System.getProperty("org.codehaus.activemq.journal.impl.SELECTED_CHECKSUM_ALGORITHIM", "hash"); 40 if( "none".equals(type) ) { 41 SELECTED_CHECKSUM_ALGORITHIM = NO_CHECKSUM_ALGORITHIM; 42 } else if( "crc32".equals(type) ) { 43 SELECTED_CHECKSUM_ALGORITHIM = CRC32_CHECKSUM_ALGORITHIM; 44 } else if( "hash".equals(type) ) { 45 SELECTED_CHECKSUM_ALGORITHIM = HASH_CHECKSUM_ALGORITHIM; 46 } else { 47 System.err.println("System property 'org.codehaus.activemq.journal.impl.SELECTED_CHECKSUM_ALGORITHIM' not set properly. Valid values are: 'none', 'hash', or 'crc32'"); 48 SELECTED_CHECKSUM_ALGORITHIM = NO_CHECKSUM_ALGORITHIM; 49 } 50 } 51 52 static final public int RECORD_FOOTER_SIZE=19; 53 static final public byte[] END_OF_RECORD = new byte[] { 'E', 'o', 'R' }; 54 55 public long checksum; 56 public long sequenceId; 57 58 /*** 59 * @return 60 */ 61 public ByteBuffer toByteBuffer() { 62 ByteBuffer buff = ByteBuffer.allocate(RECORD_FOOTER_SIZE); 63 buff.putLong(checksum) 64 .putLong(sequenceId) 65 .put(END_OF_RECORD) 66 .flip(); 67 return buff; 68 } 69 70 void writeRecordFooter( DataOutput out ) throws IOException { 71 out.writeLong(checksum); 72 out.writeLong(sequenceId); 73 out.write(END_OF_RECORD); 74 } 75 76 void readRecordFooter( DataInput in ) throws IOException { 77 checksum = in.readLong(); 78 sequenceId = in.readLong(); 79 for (int i = 0; i < END_OF_RECORD.length; i++) { 80 byte checkByte = END_OF_RECORD[i]; 81 if( in.readByte()!= checkByte ) { 82 throw new IOException("Not a valid record header."); 83 } 84 } 85 } 86 87 /*** 88 * 89 */ 90 public void invalidate() { 91 checksum=-1; 92 sequenceId=-1; 93 } 94 95 public boolean matches(RecordHeader header) { 96 return header.sequenceId==sequenceId; 97 } 98 99 static public boolean isChecksumingEnabled() { 100 return SELECTED_CHECKSUM_ALGORITHIM!=NO_CHECKSUM_ALGORITHIM; 101 } 102 103 public boolean matches(byte data[]) { 104 return buildChecksum(data)==checksum; 105 } 106 107 static public long buildChecksum(byte[] data) { 108 if( SELECTED_CHECKSUM_ALGORITHIM==HASH_CHECKSUM_ALGORITHIM ) { 109 byte rc[] = new byte[8]; 110 for (int i = 0; i < data.length; i++) { 111 rc[i%8] ^= data[i]; 112 } 113 return (rc[0])|(rc[1]<<1)|(rc[2]<<2)|(rc[3]<<3)|(rc[4]<<4)|(rc[5]<<5)|(rc[6]<<6)|(rc[7]<<7) ; 114 } else if( SELECTED_CHECKSUM_ALGORITHIM==CRC32_CHECKSUM_ALGORITHIM ) { 115 CRC32 crc32 = new CRC32(); 116 crc32.update(data); 117 return crc32.getValue(); 118 } else { 119 return 0L; 120 } 121 } 122 123 /*** 124 * @param header 125 * @param data 126 */ 127 public void bulkSet(RecordHeader header, byte[] data) { 128 this.sequenceId = header.sequenceId; 129 this.checksum = buildChecksum(data); 130 } 131 132 }