/** * 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.raid; import java.io.IOException; import java.util.ArrayList; import java.util.List; public abstract class ErasureCode { /** * Encodes the given message. * * @param message * The data of the message. The data is present in the least * significant bits of each int. The number of data bits is * symbolSize(). The number of elements of message is stripeSize(). * @param parity * (out) The information is present in the least significant bits of * each int. The number of parity bits is symbolSize(). The number of * elements in the code is paritySize(). */ public abstract void encode(int[] message, int[] parity); /** * Generates missing portions of data. * * @param data * The message and parity. The parity should be placed in the first * part of the array. In each integer, the relevant portion is * present in the least significant bits of each int. The number of * elements in data is stripeSize() + paritySize(). * @param erasedLocations * The indexes in data which are not available. * @param erasedValues * (out)The decoded values corresponding to erasedLocations. */ public abstract void decode(int[] data, int[] erasedLocations, int[] erasedValues); /** * Figure out which locations need to be read to decode erased locations. The * locations are specified as integers in the range [ 0, stripeSize() + * paritySize() ). Values in the range [ 0, paritySize() ) represent parity * data. Values in the range [ paritySize(), paritySize() + stripeSize() ) * represent message data. * * @param erasedLocations * The erased locations. * @return The locations to read. */ public List<Integer> locationsToReadForDecode(List<Integer> erasedLocations) throws TooManyErasedLocations { List<Integer> locationsToRead = new ArrayList<Integer>(stripeSize()); int limit = stripeSize() + paritySize(); // Loop through all possible locations in the stripe. for (int loc = limit - 1; loc >= 0; loc--) { // Is the location good. if (erasedLocations.indexOf(loc) == -1) { locationsToRead.add(loc); if (stripeSize() == locationsToRead.size()) { break; } } } // If we are are not able to fill up the locationsToRead list, // we did not find enough good locations. Throw TooManyErasedLocations. if (locationsToRead.size() != stripeSize()) { String locationsStr = ""; for (Integer erasedLocation : erasedLocations) { locationsStr += " " + erasedLocation; } throw new TooManyErasedLocations("Locations " + locationsStr); } return locationsToRead; } public abstract void init(int stripeSize, int paritySize); /** * The number of elements in the message. */ public abstract int stripeSize(); /** * The number of elements in the code. */ public abstract int paritySize(); public abstract int symbolSize(); /** * This method would be overridden in the subclass, * so that the subclass will have its own encodeBulk behavior. */ public abstract void encodeBulk(byte[][] inputs, byte[][] outputs, boolean useNative) throws IOException; public void encodeBulk(byte[][] inputs, byte[][] outputs) throws IOException { final int stripeSize = stripeSize(); final int paritySize = paritySize(); assert (stripeSize == inputs.length); assert (paritySize == outputs.length); int[] data = new int[stripeSize]; int[] code = new int[paritySize]; for (int j = 0; j < outputs[0].length; j++) { for (int i = 0; i < paritySize; i++) { code[i] = 0; } for (int i = 0; i < stripeSize; i++) { data[i] = inputs[i][j] & 0x000000FF; } encode(data, code); for (int i = 0; i < paritySize; i++) { outputs[i][j] = (byte) code[i]; } } } /** * position decode. */ public abstract void decodeBulk(byte[][] readBufs, byte[][] writeBufs, int[] erasedLocation, int dataStart, int dataLen) throws IOException; public abstract void decodeOneBlock(byte[][] readBufs, byte[] decodeVec, int dataLen, int[] erasedLocation, int decodeLocation, int decodePos, int decodeLen, boolean useNative) throws IOException; /** * This method would be overridden in the subclass, * so that the subclass will have its own decodeBulk behavior. */ public void decodeBulk(byte[][] readBufs, byte[][] writeBufs, int[] erasedLocations) throws IOException { int[] tmpInput = new int[readBufs.length]; int[] tmpOutput = new int[erasedLocations.length]; int numBytes = readBufs[0].length; for (int idx = 0; idx < numBytes; idx++) { for (int i = 0; i < tmpOutput.length; i++) { tmpOutput[i] = 0; } for (int i = 0; i < tmpInput.length; i++) { tmpInput[i] = readBufs[i][idx] & 0x000000FF; } decode(tmpInput, erasedLocations, tmpOutput); for (int i = 0; i < tmpOutput.length; i++) { writeBufs[i][idx] = (byte) tmpOutput[i]; } } } }