blob: 9e5b6865e8ef674cef45f588a46162db9ec3abc2 [file]
/*
* 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.
*/
#ifndef ENCODING_CHIMP_ENCODER_H
#define ENCODING_CHIMP_ENCODER_H
#include <stdint.h>
#include <climits>
#include "bit_packing_utils.h"
#include "common/allocator/byte_stream.h"
#include "common/db_common.h"
#include "encode_utils.h"
#include "encoder.h"
#include "utils/errno_define.h"
#include "utils/util_define.h"
namespace storage {
static constexpr int8_t CHIMP_LEADING_REPRESENTATION[64] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5,
6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
static constexpr int8_t CHIMP_LEADING_ROUND[64] = {
0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 12, 12, 12, 12,
16, 16, 18, 18, 20, 20, 22, 22, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24};
static constexpr int32_t CHIMP_ENCODING_ENDING_INTEGER = INT32_MIN;
static constexpr int64_t CHIMP_ENCODING_ENDING_LONG = INT64_MIN;
static constexpr int32_t CHIMP_ENCODING_ENDING_FLOAT = 0x7fc00000;
static constexpr int64_t CHIMP_ENCODING_ENDING_DOUBLE =
static_cast<int64_t>(0x7ff8000000000000ULL);
template <typename T>
struct ChimpTraits;
template <>
struct ChimpTraits<int32_t> {
using Unsigned = uint32_t;
static constexpr int VALUE_BITS = 32;
static constexpr int PREVIOUS_VALUES = 64;
static constexpr int PREVIOUS_VALUES_LOG2 = 6;
static constexpr int THRESHOLD = 5 + PREVIOUS_VALUES_LOG2;
static constexpr int SET_LSB = (1 << (THRESHOLD + 1)) - 1;
static constexpr int CASE_ZERO_METADATA_LENGTH = PREVIOUS_VALUES_LOG2 + 2;
static constexpr int CASE_ONE_METADATA_LENGTH = PREVIOUS_VALUES_LOG2 + 10;
static constexpr int32_t ENDING = CHIMP_ENCODING_ENDING_INTEGER;
};
template <>
struct ChimpTraits<int64_t> {
using Unsigned = uint64_t;
static constexpr int VALUE_BITS = 64;
static constexpr int PREVIOUS_VALUES = 128;
static constexpr int PREVIOUS_VALUES_LOG2 = 7;
static constexpr int THRESHOLD = 6 + PREVIOUS_VALUES_LOG2;
static constexpr int SET_LSB = (1 << (THRESHOLD + 1)) - 1;
static constexpr int CASE_ZERO_METADATA_LENGTH = PREVIOUS_VALUES_LOG2 + 2;
static constexpr int CASE_ONE_METADATA_LENGTH = PREVIOUS_VALUES_LOG2 + 11;
static constexpr int64_t ENDING = CHIMP_ENCODING_ENDING_LONG;
};
template <typename T>
class ChimpEncoder : public Encoder {
public:
using Traits = ChimpTraits<T>;
using Unsigned = typename Traits::Unsigned;
ChimpEncoder() { reset(); }
~ChimpEncoder() override = default;
void destroy() override {}
void reset() override {
type_ = common::CHIMP;
first_value_was_written_ = false;
stored_leading_zeros_ = INT32_MAX;
writer_.reset();
index_ = 0;
current_ = 0;
for (int i = 0; i < Traits::PREVIOUS_VALUES; ++i) {
stored_values_[i] = 0;
}
for (int i = 0; i < (1 << (Traits::THRESHOLD + 1)); ++i) {
indices_[i] = 0;
}
}
int flush(common::ByteStream& out) override {
int ret = encode_value(Traits::ENDING, out);
if (RET_FAIL(ret)) {
return ret;
}
ret = writer_.flush_forced(out);
reset();
return ret;
}
int get_max_byte_size() override {
return (2 + (Traits::VALUE_BITS == 32 ? 5 : 6) +
(Traits::VALUE_BITS == 32 ? 5 : 6) + Traits::VALUE_BITS) /
8 +
1;
}
int encode(bool, common::ByteStream&) override {
return common::E_TYPE_NOT_MATCH;
}
int encode(int32_t, common::ByteStream&) override {
return common::E_TYPE_NOT_MATCH;
}
int encode(int64_t, common::ByteStream&) override {
return common::E_TYPE_NOT_MATCH;
}
int encode(float, common::ByteStream&) override {
return common::E_TYPE_NOT_MATCH;
}
int encode(double, common::ByteStream&) override {
return common::E_TYPE_NOT_MATCH;
}
int encode(common::String, common::ByteStream&) override {
return common::E_TYPE_NOT_MATCH;
}
protected:
int encode_value(T value, common::ByteStream& out) {
if (LIKELY(first_value_was_written_)) {
return compress_value(value, out);
}
int ret = write_first(value, out);
if (ret == common::E_OK) {
first_value_was_written_ = true;
}
return ret;
}
private:
int key_of(T value) const {
return static_cast<int>(static_cast<uint32_t>(value) & Traits::SET_LSB);
}
int write_first(T value, common::ByteStream& out) {
stored_values_[current_] = value;
indices_[key_of(value)] = index_;
return writer_.write_bits(static_cast<Unsigned>(value),
Traits::VALUE_BITS, out);
}
int compress_value(T value, common::ByteStream& out) {
int ret = common::E_OK;
int key = key_of(value);
T xor_value = 0;
int previous_index = 0;
int trailing_zeros = 0;
int curr_index = indices_[key];
if ((index_ - curr_index) < Traits::PREVIOUS_VALUES) {
T temp_xor =
value ^ stored_values_[curr_index % Traits::PREVIOUS_VALUES];
trailing_zeros = number_of_trailing_zeros(temp_xor);
if (trailing_zeros > Traits::THRESHOLD) {
previous_index = curr_index % Traits::PREVIOUS_VALUES;
xor_value = temp_xor;
} else {
previous_index = index_ % Traits::PREVIOUS_VALUES;
xor_value = stored_values_[previous_index] ^ value;
}
} else {
previous_index = index_ % Traits::PREVIOUS_VALUES;
xor_value = stored_values_[previous_index] ^ value;
}
if (xor_value == 0) {
ret = writer_.write_bits(static_cast<uint64_t>(previous_index),
Traits::CASE_ZERO_METADATA_LENGTH, out);
stored_leading_zeros_ = Traits::VALUE_BITS + 1;
} else {
int leading_zeros =
CHIMP_LEADING_ROUND[number_of_leading_zeros(xor_value)];
if (trailing_zeros > Traits::THRESHOLD) {
int significant_bits =
Traits::VALUE_BITS - leading_zeros - trailing_zeros;
uint64_t metadata =
(Traits::VALUE_BITS == 32
? 256ULL * (Traits::PREVIOUS_VALUES + previous_index)
: 512ULL *
(Traits::PREVIOUS_VALUES + previous_index)) +
(Traits::VALUE_BITS == 32
? 32ULL * CHIMP_LEADING_REPRESENTATION[leading_zeros]
: 64ULL *
CHIMP_LEADING_REPRESENTATION[leading_zeros]) +
static_cast<uint64_t>(significant_bits);
if (RET_FAIL(writer_.write_bits(
metadata, Traits::CASE_ONE_METADATA_LENGTH, out))) {
return ret;
}
Unsigned meaningful =
static_cast<Unsigned>(xor_value) >> trailing_zeros;
ret = writer_.write_bits(meaningful, significant_bits, out);
stored_leading_zeros_ = Traits::VALUE_BITS + 1;
} else if (leading_zeros == stored_leading_zeros_) {
if (RET_FAIL(writer_.write_bit(true, out))) {
return ret;
}
if (RET_FAIL(writer_.write_bit(false, out))) {
return ret;
}
int significant_bits = Traits::VALUE_BITS - leading_zeros;
ret = writer_.write_bits(static_cast<Unsigned>(xor_value),
significant_bits, out);
} else {
stored_leading_zeros_ = leading_zeros;
int significant_bits = Traits::VALUE_BITS - leading_zeros;
if (RET_FAIL(writer_.write_bits(
24ULL + CHIMP_LEADING_REPRESENTATION[leading_zeros], 5,
out))) {
return ret;
}
ret = writer_.write_bits(static_cast<Unsigned>(xor_value),
significant_bits, out);
}
}
if (ret == common::E_OK) {
current_ = (current_ + 1) % Traits::PREVIOUS_VALUES;
stored_values_[current_] = value;
++index_;
indices_[key] = index_;
}
return ret;
}
protected:
common::TSEncoding type_;
bool first_value_was_written_;
int stored_leading_zeros_;
MsbBitWriter writer_;
T stored_values_[Traits::PREVIOUS_VALUES];
int indices_[1 << (Traits::THRESHOLD + 1)];
int index_;
int current_;
};
class IntChimpEncoder : public ChimpEncoder<int32_t> {
public:
int encode(int32_t value, common::ByteStream& out) override {
return encode_value(value, out);
}
};
class LongChimpEncoder : public ChimpEncoder<int64_t> {
public:
int encode(int64_t value, common::ByteStream& out) override {
return encode_value(value, out);
}
};
class FloatChimpEncoder : public ChimpEncoder<int32_t> {
public:
int encode(float value, common::ByteStream& out) override {
return encode_value(common::float_to_int(value), out);
}
int flush(common::ByteStream& out) override {
int ret = encode_value(CHIMP_ENCODING_ENDING_FLOAT, out);
if (RET_FAIL(ret)) {
return ret;
}
ret = writer_.flush_forced(out);
reset();
return ret;
}
};
class DoubleChimpEncoder : public ChimpEncoder<int64_t> {
public:
int encode(double value, common::ByteStream& out) override {
return encode_value(common::double_to_long(value), out);
}
int flush(common::ByteStream& out) override {
int ret = encode_value(CHIMP_ENCODING_ENDING_DOUBLE, out);
if (RET_FAIL(ret)) {
return ret;
}
ret = writer_.flush_forced(out);
reset();
return ret;
}
};
} // namespace storage
#endif // ENCODING_CHIMP_ENCODER_H