blob: 453aadfed2db087ba8e919c85c08ce380f5b3554 [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.iotdb.tsfile.encoding.encoder;
import org.apache.iotdb.tsfile.common.conf.TSFileConfig;
import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
import org.apache.iotdb.tsfile.common.constant.JsonFormatConstant;
import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* Each subclass of TSEncodingBuilder responds a enumerate value in {@linkplain TSEncoding
* TSEncoding}, which stores several configuration related to responding encoding type to generate
* {@linkplain Encoder Encoder} instance.<br>
* Each TSEncoding has a responding TSEncodingBuilder. The design referring to visit pattern
* provides same outer interface for different TSEncodings and gets rid of the duplicate switch-case
* code.
*/
public abstract class TSEncodingBuilder {
private static final Logger logger = LoggerFactory.getLogger(TSEncodingBuilder.class);
protected final TSFileConfig conf;
protected TSEncodingBuilder() {
this.conf = TSFileDescriptor.getInstance().getConfig();
}
/**
* return responding TSEncodingBuilder from a TSEncoding.
*
* @param type - given encoding type
* @return - responding TSEncodingBuilder
*/
public static TSEncodingBuilder getEncodingBuilder(TSEncoding type) {
switch (type) {
case PLAIN:
return new Plain();
case RLE:
return new Rle();
case TS_2DIFF:
return new Ts2Diff();
case GORILLA_V1:
return new GorillaV1();
case REGULAR:
return new Regular();
case GORILLA:
return new GorillaV2();
case DICTIONARY:
return new Dictionary();
case ZIGZAG:
return new Zigzag();
case CHIMP:
return new Chimp();
case SPRINTZ:
return new Sprintz();
case RLBE:
return new RLBE();
default:
throw new UnsupportedOperationException(type.toString());
}
}
/**
* return a thread safe series's encoder with different types and parameters according to its
* measurement id and data type.
*
* @param type - given data type
* @return - return a {@linkplain Encoder Encoder}
*/
public abstract Encoder getEncoder(TSDataType type);
/**
* for TSEncoding, JSON is a kind of type for initialization. {@code InitFromJsonObject} gets
* values from JSON object which will be used latter.<br>
* if this type has extra parameters to construct, override it.
*
* @param props - properties of encoding
*/
public abstract void initFromProps(Map<String, String> props);
@Override
public String toString() {
return "";
}
/** for all TSDataType. */
public static class Plain extends TSEncodingBuilder {
private int maxStringLength = TSFileDescriptor.getInstance().getConfig().getMaxStringLength();
@Override
public Encoder getEncoder(TSDataType type) {
return new PlainEncoder(type, maxStringLength);
}
@Override
public void initFromProps(Map<String, String> props) {
// set max error from initialized map or default value if not set
if (props == null || !props.containsKey(Encoder.MAX_STRING_LENGTH)) {
maxStringLength = TSFileDescriptor.getInstance().getConfig().getMaxStringLength();
} else {
maxStringLength = Integer.valueOf(props.get(Encoder.MAX_STRING_LENGTH));
if (maxStringLength < 0) {
maxStringLength = TSFileDescriptor.getInstance().getConfig().getMaxStringLength();
logger.warn(
"cannot set max string length to negative value, replaced with default value:{}",
maxStringLength);
}
}
}
}
/** for ENUMS, INT32, BOOLEAN, INT64, FLOAT, DOUBLE. */
public static class Rle extends TSEncodingBuilder {
private int maxPointNumber = TSFileDescriptor.getInstance().getConfig().getFloatPrecision();
@Override
public Encoder getEncoder(TSDataType type) {
switch (type) {
case INT32:
case BOOLEAN:
return new IntRleEncoder();
case INT64:
return new LongRleEncoder();
case FLOAT:
case DOUBLE:
return new FloatEncoder(TSEncoding.RLE, type, maxPointNumber);
default:
throw new UnSupportedDataTypeException("RLE doesn't support data type: " + type);
}
}
/**
* RLE could specify <b>max_point_number</b> in given JSON Object, which means the maximum
* decimal digits for float or double data.
*/
@Override
public void initFromProps(Map<String, String> props) {
// set max error from initialized map or default value if not set
if (props == null || !props.containsKey(Encoder.MAX_POINT_NUMBER)) {
maxPointNumber = TSFileDescriptor.getInstance().getConfig().getFloatPrecision();
} else {
try {
this.maxPointNumber = Integer.parseInt(props.get(Encoder.MAX_POINT_NUMBER));
} catch (NumberFormatException e) {
logger.warn(
"The format of max point number {} is not correct."
+ " Using default float precision.",
props.get(Encoder.MAX_POINT_NUMBER));
}
if (maxPointNumber < 0) {
maxPointNumber = TSFileDescriptor.getInstance().getConfig().getFloatPrecision();
logger.warn(
"cannot set max point number to negative value, replaced with default value:{}",
maxPointNumber);
}
}
}
@Override
public String toString() {
return JsonFormatConstant.MAX_POINT_NUMBER + ":" + maxPointNumber;
}
}
/** for INT32, INT64, FLOAT, DOUBLE. */
public static class Ts2Diff extends TSEncodingBuilder {
private int maxPointNumber = 0;
@Override
public Encoder getEncoder(TSDataType type) {
switch (type) {
case INT32:
return new DeltaBinaryEncoder.IntDeltaEncoder();
case INT64:
return new DeltaBinaryEncoder.LongDeltaEncoder();
case FLOAT:
case DOUBLE:
return new FloatEncoder(TSEncoding.TS_2DIFF, type, maxPointNumber);
default:
throw new UnSupportedDataTypeException("TS_2DIFF doesn't support data type: " + type);
}
}
@Override
/**
* TS_2DIFF could specify <b>max_point_number</b> in given JSON Object, which means the maximum
* decimal digits for float or double data.
*/
public void initFromProps(Map<String, String> props) {
// set max error from initialized map or default value if not set
if (props == null || !props.containsKey(Encoder.MAX_POINT_NUMBER)) {
maxPointNumber = TSFileDescriptor.getInstance().getConfig().getFloatPrecision();
} else {
try {
this.maxPointNumber = Integer.parseInt(props.get(Encoder.MAX_POINT_NUMBER));
} catch (NumberFormatException e) {
logger.warn(
"The format of max point number {} is not correct."
+ " Using default float precision.",
props.get(Encoder.MAX_POINT_NUMBER));
}
if (maxPointNumber < 0) {
maxPointNumber = TSFileDescriptor.getInstance().getConfig().getFloatPrecision();
logger.warn(
"cannot set max point number to negative value, replaced with default value:{}",
maxPointNumber);
}
}
}
@Override
public String toString() {
return JsonFormatConstant.MAX_POINT_NUMBER + ":" + maxPointNumber;
}
}
/** for FLOAT, DOUBLE. */
public static class GorillaV1 extends TSEncodingBuilder {
@Override
public Encoder getEncoder(TSDataType type) {
switch (type) {
case FLOAT:
return new SinglePrecisionEncoderV1();
case DOUBLE:
return new DoublePrecisionEncoderV1();
default:
throw new UnSupportedDataTypeException("GORILLA_V1 doesn't support data type: " + type);
}
}
@Override
public void initFromProps(Map<String, String> props) {
// allowed do nothing
}
}
/** for INT32, INT64. */
public static class Regular extends TSEncodingBuilder {
@Override
public Encoder getEncoder(TSDataType type) {
switch (type) {
case INT32:
return new RegularDataEncoder.IntRegularEncoder();
case INT64:
return new RegularDataEncoder.LongRegularEncoder();
default:
throw new UnSupportedDataTypeException("REGULAR doesn't support data type: " + type);
}
}
@Override
public void initFromProps(Map<String, String> props) {
// allowed do nothing
}
}
/** for FLOAT, DOUBLE, INT, LONG. */
public static class GorillaV2 extends TSEncodingBuilder {
@Override
public Encoder getEncoder(TSDataType type) {
switch (type) {
case FLOAT:
return new SinglePrecisionEncoderV2();
case DOUBLE:
return new DoublePrecisionEncoderV2();
case INT32:
return new IntGorillaEncoder();
case INT64:
return new LongGorillaEncoder();
default:
throw new UnSupportedDataTypeException("GORILLA doesn't support data type: " + type);
}
}
@Override
public void initFromProps(Map<String, String> props) {
// allowed do nothing
}
}
public static class Sprintz extends TSEncodingBuilder {
@Override
public Encoder getEncoder(TSDataType type) {
switch (type) {
case INT32:
return new IntSprintzEncoder();
case INT64:
return new LongSprintzEncoder();
case FLOAT:
return new FloatSprintzEncoder();
case DOUBLE:
return new DoubleSprintzEncoder();
default:
throw new UnSupportedDataTypeException("Sprintz doesn't support data type: " + type);
}
}
@Override
public void initFromProps(Map<String, String> props) {
// do nothing
}
}
public static class RLBE extends TSEncodingBuilder {
@Override
public Encoder getEncoder(TSDataType type) {
switch (type) {
case INT32:
return new IntRLBE();
case INT64:
return new LongRLBE();
case FLOAT:
return new FloatRLBE();
case DOUBLE:
return new DoubleRLBE();
default:
throw new UnSupportedDataTypeException("RLBE doesn't support data type: " + type);
}
}
@Override
public void initFromProps(Map<String, String> props) {
// do nothing
}
}
public static class Dictionary extends TSEncodingBuilder {
@Override
public Encoder getEncoder(TSDataType type) {
if (type == TSDataType.TEXT) {
return new DictionaryEncoder();
}
throw new UnSupportedDataTypeException("DICTIONARY doesn't support data type: " + type);
}
@Override
public void initFromProps(Map<String, String> props) {
// do nothing
}
}
public static class Zigzag extends TSEncodingBuilder {
@Override
public Encoder getEncoder(TSDataType type) {
switch (type) {
case INT32:
return new IntZigzagEncoder();
case INT64:
return new LongZigzagEncoder();
default:
throw new UnSupportedDataTypeException("ZIGZAG doesn't support data type: " + type);
}
}
@Override
public void initFromProps(Map<String, String> props) {
// do nothing
}
}
/** for FLOAT, DOUBLE, INT, LONG. */
public static class Chimp extends TSEncodingBuilder {
@Override
public Encoder getEncoder(TSDataType type) {
switch (type) {
case FLOAT:
return new SinglePrecisionChimpEncoder();
case DOUBLE:
return new DoublePrecisionChimpEncoder();
case INT32:
return new IntChimpEncoder();
case INT64:
return new LongChimpEncoder();
default:
throw new UnSupportedDataTypeException("CHIMP doesn't support data type: " + type);
}
}
@Override
public void initFromProps(Map<String, String> props) {
// allowed do nothing
}
}
}