/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hdfs.server.datanode; import java.io.DataInput; import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Class to read block CRC file from disk. * * Format of the file: * * +--------------------+ * | FORMAT_VERSION | * +--------------------+ * | NUMBER OF BUCKETS | * +--------------------+ ------------- * | numRecords bucket 0| * +--------------------+ * | bucket 0 record 0 | * | | * +--------------------+ Bucket 0 * | bucket 0 record 1 | * | | * +--------------------+ * | ...... | * | | * +--------------------+ ------------- * | numRecords bucket 1| * +--------------------+ * | bucket 1 record 0 | * | | Bucket 1 * | ...... | * | | * +--------------------+ ------------- * | ...... | * | | Other buckets * +--------------------+ ------------- * * Every record is encoded as BlockCrcInfoWriteable. * * If a bucket has no record, 0 is filled in number of records field * without any data for actual records. * */ class BlockCrcFileReader { public static final Log LOG = LogFactory.getLog(BlockCrcFileReader.class); final private DataInput in; private int numBuckets; private int currentBucket; private int numRecordsInBucket; private int numRecordsReadInBucket; BlockCrcFileReader(DataInput in) { this.in = in; } int getNumBuckets() { return numBuckets; } /** * Read header of the file * @throws IOException */ void readHeader() throws IOException { int version = in.readInt(); if (version != BlockCrcInfoWritable.LATEST_BLOCK_CRC_FILE_VERSION) { throw new IOException("Version " + version + " is not supported."); } numBuckets = in.readInt(); currentBucket = -1; numRecordsReadInBucket = 0; numRecordsInBucket = 0; } /** * Find the bucket ID for the next record. If current bucket hasn't yet been * finished, then the current bucket ID will be returned. Otherwise, it will * keep reading the input file until it finds the next non-empty bucket and * return this bucket's ID. * * After the call, the position of the input stream will be just before the * next record. * * @return bucket ID for next record. -1 if no more record left. * @throws IOException */ int moveToNextRecordAndGetItsBucketId() throws IOException { while (numRecordsReadInBucket >= numRecordsInBucket) { if (currentBucket + 1>= numBuckets) { // We've finished all the records. return -1; } else { numRecordsInBucket = in.readInt(); currentBucket++; numRecordsReadInBucket = 0; } } return currentBucket; } /** * Get information for the next blockCRC record. NULL if not more left. * @return * @throws IOException */ BlockCrcInfoWritable getNextRecord() throws IOException { // By calling getBucketIdForNextRecord(), we make sure the next field // to read is the next record (if there is any record left in the file) // Also, by checking the return value, we know whether we've finished // the file. if (moveToNextRecordAndGetItsBucketId() == -1) { return null; } BlockCrcInfoWritable crcInfo = new BlockCrcInfoWritable(); crcInfo.readFields(in); numRecordsReadInBucket++; return crcInfo; } }