blob: eb4d05b993376f747331cafa9de0899a3a16837b [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.file.header;
import org.apache.iotdb.tsfile.common.conf.TSFileConfig;
import org.apache.iotdb.tsfile.file.MetaMarker;
import org.apache.iotdb.tsfile.file.metadata.TimeseriesMetadata;
import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.apache.iotdb.tsfile.read.TsFileSequenceReader;
import org.apache.iotdb.tsfile.read.reader.TsFileInput;
import org.apache.iotdb.tsfile.utils.Pair;
import org.apache.iotdb.tsfile.utils.RamUsageEstimator;
import org.apache.iotdb.tsfile.utils.ReadWriteForEncodingUtils;
import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
public class ChunkHeader {
public static final long INSTANCE_SIZE =
RamUsageEstimator.shallowSizeOfInstance(ChunkHeader.class)
+ RamUsageEstimator.shallowSizeOfInstance(TSDataType.class)
+ RamUsageEstimator.shallowSizeOfInstance(CompressionType.class)
+ RamUsageEstimator.shallowSizeOfInstance(TSEncoding.class);
/**
* 1 means this chunk has more than one page, so each page has its own page statistic. 5 means
* this chunk has only one page, and this page has no page statistic.
*
* <p>if the 8th bit of this byte is 1 means this chunk is a time chunk of one vector if the 7th
* bit of this byte is 1 means this chunk is a value chunk of one vector
*/
private byte chunkType;
private String measurementID;
private int dataSize;
private final TSDataType dataType;
private final CompressionType compressionType;
private final TSEncoding encodingType;
// the following fields do not need to be serialized.
private int numOfPages;
private final int serializedSize;
public ChunkHeader(
String measurementID,
int dataSize,
TSDataType dataType,
CompressionType compressionType,
TSEncoding encoding,
int numOfPages) {
this(measurementID, dataSize, dataType, compressionType, encoding, numOfPages, 0);
}
public ChunkHeader(
String measurementID,
int dataSize,
TSDataType dataType,
CompressionType compressionType,
TSEncoding encoding,
int numOfPages,
int mask) {
this(
(byte)
((numOfPages <= 1 ? MetaMarker.ONLY_ONE_PAGE_CHUNK_HEADER : MetaMarker.CHUNK_HEADER)
| (byte) mask),
measurementID,
dataSize,
getSerializedSize(measurementID, dataSize),
dataType,
compressionType,
encoding);
this.numOfPages = numOfPages;
}
public ChunkHeader(
byte chunkType,
String measurementID,
int dataSize,
TSDataType dataType,
CompressionType compressionType,
TSEncoding encoding) {
this(
chunkType,
measurementID,
dataSize,
getSerializedSize(measurementID, dataSize),
dataType,
compressionType,
encoding);
}
public ChunkHeader(
byte chunkType,
String measurementID,
int dataSize,
int headerSize,
TSDataType dataType,
CompressionType compressionType,
TSEncoding encoding) {
this.chunkType = chunkType;
this.measurementID = measurementID;
this.dataSize = dataSize;
this.dataType = dataType;
this.compressionType = compressionType;
this.encodingType = encoding;
this.serializedSize = headerSize;
}
/** the exact serialized size of chunk header. */
public static int getSerializedSize(String measurementID, int dataSize) {
int measurementIdLength =
measurementID == null ? 0 : measurementID.getBytes(TSFileConfig.STRING_CHARSET).length;
return Byte.BYTES // chunkType
+ ReadWriteForEncodingUtils.varIntSize(measurementIdLength) // measurementID length
+ measurementIdLength // measurementID
+ ReadWriteForEncodingUtils.uVarIntSize(dataSize) // dataSize
+ TSDataType.getSerializedSize() // dataTypex
+ CompressionType.getSerializedSize() // compressionType
+ TSEncoding.getSerializedSize(); // encodingType
}
/**
* The estimated serialized size of chunk header. Only used when we don't know the actual dataSize
* attribute
*/
public static int getSerializedSize(String measurementID) {
int measurementIdLength = measurementID.getBytes(TSFileConfig.STRING_CHARSET).length;
return Byte.BYTES // chunkType
+ ReadWriteForEncodingUtils.varIntSize(measurementIdLength) // measurementID length
+ measurementIdLength // measurementID
+ Integer.BYTES
+ 1 // uVarInt dataSize
+ TSDataType.getSerializedSize() // dataType
+ CompressionType.getSerializedSize() // compressionType
+ TSEncoding.getSerializedSize(); // encodingType
}
public int getSerializedSize() {
return serializedSize;
}
/**
* deserialize from inputStream, the marker has already been read.
*
* @return ChunkHeader the ChunkHeader read from inputStream
* @throws IOException exception when reading stream
*/
public static ChunkHeader deserializeFrom(InputStream inputStream, byte chunkType)
throws IOException {
// read measurementID
String measurementID = ReadWriteIOUtils.readVarIntString(inputStream);
int dataSize = ReadWriteForEncodingUtils.readUnsignedVarInt(inputStream);
TSDataType dataType = ReadWriteIOUtils.readDataType(inputStream);
CompressionType type = ReadWriteIOUtils.readCompressionType(inputStream);
TSEncoding encoding = ReadWriteIOUtils.readEncoding(inputStream);
return new ChunkHeader(chunkType, measurementID, dataSize, dataType, type, encoding);
}
/**
* deserialize from TsFileInput, the marker has not been read.
*
* @param input TsFileInput
* @param offset offset
* @return CHUNK_HEADER object
* @throws IOException IOException
*/
public static ChunkHeader deserializeFrom(TsFileInput input, long offset) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(Byte.BYTES + Integer.BYTES + 1);
input.read(buffer, offset);
buffer.flip();
// read chunk header from input to buffer
byte chunkType = buffer.get();
int strLength = ReadWriteForEncodingUtils.readVarInt(buffer);
int alreadyReadLength = buffer.position();
int remainingBytes =
strLength
+ Integer.BYTES
+ 1 // uVarInt dataSize
+ TSDataType.getSerializedSize() // dataType
+ CompressionType.getSerializedSize() // compressionType
+ TSEncoding.getSerializedSize();
buffer = ByteBuffer.allocate(remainingBytes);
input.read(buffer, offset + alreadyReadLength);
buffer.flip();
// read measurementID
String measurementID = ReadWriteIOUtils.readStringWithLength(buffer, strLength);
int dataSize = ReadWriteForEncodingUtils.readUnsignedVarInt(buffer);
TSDataType dataType = ReadWriteIOUtils.readDataType(buffer);
CompressionType type = ReadWriteIOUtils.readCompressionType(buffer);
TSEncoding encoding = ReadWriteIOUtils.readEncoding(buffer);
int chunkHeaderSize = alreadyReadLength + buffer.position();
return new ChunkHeader(
chunkType, measurementID, dataSize, chunkHeaderSize, dataType, type, encoding);
}
/**
* Used by {@link
* TsFileSequenceReader#readTimeseriesCompressionTypeAndEncoding(TimeseriesMetadata)} to only
* decode data size, {@link CompressionType} and {@link TSEncoding}.
*
* @param inputStream input stream
* @return - Compression type and encoding.
* @throws IOException - If an I/O error occurs.
*/
public static Pair<CompressionType, TSEncoding> deserializeCompressionTypeAndEncoding(
InputStream inputStream) throws IOException {
ReadWriteForEncodingUtils.readUnsignedVarInt(inputStream);
ReadWriteIOUtils.skip(inputStream, Byte.BYTES); // skip Data type
CompressionType type = ReadWriteIOUtils.readCompressionType(inputStream);
TSEncoding encoding = ReadWriteIOUtils.readEncoding(inputStream);
return new Pair<>(type, encoding);
}
public String getMeasurementID() {
return measurementID;
}
public void setMeasurementID(String measurementID) {
this.measurementID = measurementID;
}
public int getDataSize() {
return dataSize;
}
public TSDataType getDataType() {
return dataType;
}
/**
* serialize to outputStream.
*
* @param outputStream outputStream
* @return length
* @throws IOException IOException
*/
public int serializeTo(OutputStream outputStream) throws IOException {
int length = 0;
length += ReadWriteIOUtils.write(chunkType, outputStream);
length += ReadWriteIOUtils.writeVar(measurementID, outputStream);
length += ReadWriteForEncodingUtils.writeUnsignedVarInt(dataSize, outputStream);
length += ReadWriteIOUtils.write(dataType, outputStream);
length += ReadWriteIOUtils.write(compressionType, outputStream);
length += ReadWriteIOUtils.write(encodingType, outputStream);
return length;
}
/**
* serialize to ByteBuffer.
*
* @param buffer ByteBuffer
* @return length
*/
public int serializeTo(ByteBuffer buffer) {
int length = 0;
length += ReadWriteIOUtils.write(chunkType, buffer);
length += ReadWriteIOUtils.writeVar(measurementID, buffer);
length += ReadWriteForEncodingUtils.writeUnsignedVarInt(dataSize, buffer);
length += ReadWriteIOUtils.write(dataType, buffer);
length += ReadWriteIOUtils.write(compressionType, buffer);
length += ReadWriteIOUtils.write(encodingType, buffer);
return length;
}
public int getNumOfPages() {
return numOfPages;
}
public CompressionType getCompressionType() {
return compressionType;
}
public TSEncoding getEncodingType() {
return encodingType;
}
@Override
public String toString() {
return "CHUNK_HEADER{"
+ "measurementID='"
+ measurementID
+ '\''
+ ", dataSize="
+ dataSize
+ ", dataType="
+ dataType
+ ", compressionType="
+ compressionType
+ ", encodingType="
+ encodingType
+ ", numOfPages="
+ numOfPages
+ ", serializedSize="
+ serializedSize
+ '}';
}
public void mergeChunkHeader(ChunkHeader chunkHeader) {
this.dataSize += chunkHeader.getDataSize();
this.numOfPages += chunkHeader.getNumOfPages();
}
public void setDataSize(int dataSize) {
this.dataSize = dataSize;
}
public byte getChunkType() {
return chunkType;
}
public void setChunkType(byte chunkType) {
this.chunkType = chunkType;
}
public void increasePageNums(int i) {
numOfPages += i;
}
}