blob: 0d5bf8f0688a464b9da701647c71a18f405cf050 [file] [log] [blame]
/**
* 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.io.erasurecode;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Erasure coding schema to housekeeper relevant information.
*/
public final class ECSchema {
public static final String NUM_DATA_UNITS_KEY = "numDataUnits";
public static final String NUM_PARITY_UNITS_KEY = "numParityUnits";
public static final String CODEC_NAME_KEY = "codec";
/**
* The erasure codec name associated.
*/
private final String codecName;
/**
* Number of source data units coded
*/
private final int numDataUnits;
/**
* Number of parity units generated in a coding
*/
private final int numParityUnits;
/*
* An erasure code can have its own specific advanced parameters, subject to
* itself to interpret these key-value settings.
*/
private final Map<String, String> extraOptions;
/**
* Constructor with schema name and provided all options. Note the options may
* contain additional information for the erasure codec to interpret further.
* @param allOptions all schema options
*/
public ECSchema(Map<String, String> allOptions) {
if (allOptions == null || allOptions.isEmpty()) {
throw new IllegalArgumentException("No schema options are provided");
}
this.codecName = allOptions.get(CODEC_NAME_KEY);
if (codecName == null || codecName.isEmpty()) {
throw new IllegalArgumentException("No codec option is provided");
}
int tmpNumDataUnits = extractIntOption(NUM_DATA_UNITS_KEY, allOptions);
int tmpNumParityUnits = extractIntOption(NUM_PARITY_UNITS_KEY, allOptions);
if (tmpNumDataUnits < 0 || tmpNumParityUnits < 0) {
throw new IllegalArgumentException(
"No good option for numDataUnits or numParityUnits found ");
}
this.numDataUnits = tmpNumDataUnits;
this.numParityUnits = tmpNumParityUnits;
allOptions.remove(CODEC_NAME_KEY);
allOptions.remove(NUM_DATA_UNITS_KEY);
allOptions.remove(NUM_PARITY_UNITS_KEY);
// After some cleanup
this.extraOptions = Collections.unmodifiableMap(allOptions);
}
/**
* Constructor with key parameters provided.
* @param codecName codec name
* @param numDataUnits number of data units used in the schema
* @param numParityUnits number os parity units used in the schema
*/
public ECSchema(String codecName, int numDataUnits, int numParityUnits) {
this(codecName, numDataUnits, numParityUnits, null);
}
/**
* Constructor with key parameters provided. Note the extraOptions may contain
* additional information for the erasure codec to interpret further.
* @param codecName codec name
* @param numDataUnits number of data units used in the schema
* @param numParityUnits number os parity units used in the schema
* @param extraOptions extra options to configure the codec
*/
public ECSchema(String codecName, int numDataUnits, int numParityUnits,
Map<String, String> extraOptions) {
assert (codecName != null && ! codecName.isEmpty());
assert (numDataUnits > 0 && numParityUnits > 0);
this.codecName = codecName;
this.numDataUnits = numDataUnits;
this.numParityUnits = numParityUnits;
if (extraOptions == null) {
extraOptions = new HashMap<>();
}
// After some cleanup
this.extraOptions = Collections.unmodifiableMap(extraOptions);
}
private int extractIntOption(String optionKey, Map<String, String> options) {
int result = -1;
try {
if (options.containsKey(optionKey)) {
result = Integer.parseInt(options.get(optionKey));
if (result <= 0) {
throw new IllegalArgumentException("Bad option value " + result +
" found for " + optionKey);
}
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Option value " +
options.get(optionKey) + " for " + optionKey +
" is found. It should be an integer");
}
return result;
}
/**
* Get the codec name
* @return codec name
*/
public String getCodecName() {
return codecName;
}
/**
* Get extra options specific to a erasure code.
* @return extra options
*/
public Map<String, String> getExtraOptions() {
return extraOptions;
}
/**
* Get required data units count in a coding group
* @return count of data units
*/
public int getNumDataUnits() {
return numDataUnits;
}
/**
* Get required parity units count in a coding group
* @return count of parity units
*/
public int getNumParityUnits() {
return numParityUnits;
}
/**
* Make a meaningful string representation for log output.
* @return string representation
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("ECSchema=[");
sb.append("Codec=" + codecName + ", ");
sb.append(NUM_DATA_UNITS_KEY + "=" + numDataUnits + ", ");
sb.append(NUM_PARITY_UNITS_KEY + "=" + numParityUnits);
sb.append((extraOptions.isEmpty() ? "" : ", "));
int i = 0;
for (String opt : extraOptions.keySet()) {
sb.append(opt + "=" + extraOptions.get(opt) +
(++i < extraOptions.size() ? ", " : ""));
}
sb.append("]");
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ECSchema ecSchema = (ECSchema) o;
if (numDataUnits != ecSchema.numDataUnits) {
return false;
}
if (numParityUnits != ecSchema.numParityUnits) {
return false;
}
if (!codecName.equals(ecSchema.codecName)) {
return false;
}
return extraOptions.equals(ecSchema.extraOptions);
}
@Override
public int hashCode() {
int result = codecName.hashCode();
result = 31 * result + extraOptions.hashCode();
result = 31 * result + numDataUnits;
result = 31 * result + numParityUnits;
return result;
}
}