You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tsfile.apache.org by ja...@apache.org on 2024/06/17 08:41:14 UTC
(tsfile) 09/20: init tsfile for cpp.
This is an automated email from the ASF dual-hosted git repository.
jackietien pushed a commit to branch iotdb
in repository https://gitbox.apache.org/repos/asf/tsfile.git
commit ca2f942b8ccbb1aa85cd5a8c1cba6be6cdb97ab4
Author: RkGrit <G1...@gmail.com>
AuthorDate: Thu May 23 15:17:38 2024 +0800
init tsfile for cpp.
---
cpp/examples/src/demo_read.cpp | 92 +
cpp/tsfile/src/CMakeLists.txt | 4 +
cpp/tsfile/src/common/CMakeLists.txt | 20 +
cpp/tsfile/src/common/allocator/CMakeLists.txt.bak | 16 +
cpp/tsfile/src/common/allocator/alloc_base.h | 128 +
cpp/tsfile/src/common/allocator/byte_stream.h | 1111 ++++++++
cpp/tsfile/src/common/allocator/mem_alloc.cc | 236 ++
cpp/tsfile/src/common/allocator/my_string.h | 143 +
cpp/tsfile/src/common/allocator/object_pool.h | 104 +
cpp/tsfile/src/common/allocator/page_arena.cc | 52 +
cpp/tsfile/src/common/allocator/page_arena.h | 90 +
cpp/tsfile/src/common/allocator/stl_allocator.h | 68 +
cpp/tsfile/src/common/allocator/util_define.h | 136 +
cpp/tsfile/src/common/config/CMakeLists.txt | 2 +
cpp/tsfile/src/common/config/config.h | 52 +
cpp/tsfile/src/common/container/CMakeLists.txt | 12 +
cpp/tsfile/src/common/container/array.h | 312 +++
cpp/tsfile/src/common/container/bit_map.cc | 32 +
cpp/tsfile/src/common/container/bit_map.h | 71 +
cpp/tsfile/src/common/container/blocking_queue.cc | 47 +
cpp/tsfile/src/common/container/blocking_queue.h | 32 +
cpp/tsfile/src/common/container/byte_buffer.h | 114 +
cpp/tsfile/src/common/container/hash_func.h | 102 +
cpp/tsfile/src/common/container/hash_node.h | 90 +
cpp/tsfile/src/common/container/hash_segm.h | 41 +
cpp/tsfile/src/common/container/hash_table.h | 685 +++++
cpp/tsfile/src/common/container/list.h | 147 ++
cpp/tsfile/src/common/container/murmur_hash3.cc | 126 +
cpp/tsfile/src/common/container/murmur_hash3.h | 67 +
cpp/tsfile/src/common/container/simple_vector.h | 48 +
cpp/tsfile/src/common/container/slice.h | 142 +
cpp/tsfile/src/common/container/sorted_array.h | 333 +++
cpp/tsfile/src/common/datatype/CMakeLists.txt | 13 +
cpp/tsfile/src/common/datatype/value.h | 216 ++
cpp/tsfile/src/common/db_common.h | 168 ++
cpp/tsfile/src/common/db_utils.h | 457 ++++
cpp/tsfile/src/common/errno_define.h | 64 +
cpp/tsfile/src/common/global.cc | 201 ++
cpp/tsfile/src/common/global.h | 28 +
cpp/tsfile/src/common/injection.h | 53 +
cpp/tsfile/src/common/mutex/CMakeLists.txt | 2 +
cpp/tsfile/src/common/mutex/mutex.h | 64 +
cpp/tsfile/src/common/tsblock/CMakeLists.txt | 11 +
cpp/tsfile/src/common/tsblock/tsblock.cc | 293 +++
cpp/tsfile/src/common/tsblock/tsblock.h | 291 +++
cpp/tsfile/src/common/tsblock/tuple_desc.cc | 76 +
cpp/tsfile/src/common/tsblock/tuple_desc.h | 116 +
.../common/tsblock/vector/fixed_length_vector.h | 76 +
.../common/tsblock/vector/variable_length_vector.h | 77 +
cpp/tsfile/src/common/tsblock/vector/vector.h | 75 +
cpp/tsfile/src/common/util_define.h | 133 +
cpp/tsfile/src/tsfile.cpp | 29 -
cpp/tsfile/src/tsfile/CMakeLists.txt | 118 +
cpp/tsfile/src/tsfile/Makefile | 1281 +++++++++
cpp/tsfile/src/tsfile/bloom_filter.cc | 254 ++
cpp/tsfile/src/tsfile/bloom_filter.h | 120 +
cpp/tsfile/src/tsfile/chunk_reader | 0
cpp/tsfile/src/tsfile/chunk_reader.cc | 425 +++
cpp/tsfile/src/tsfile/chunk_reader.h | 128 +
cpp/tsfile/src/tsfile/chunk_writer.cc | 140 +
cpp/tsfile/src/tsfile/chunk_writer.h | 116 +
cpp/tsfile/src/tsfile/compress/CMakeLists.txt | 14 +
cpp/tsfile/src/tsfile/compress/Makefile | 285 ++
cpp/tsfile/src/tsfile/compress/compressor.c | 0
cpp/tsfile/src/tsfile/compress/compressor.h | 42 +
.../src/tsfile/compress/compressor_factory.h | 62 +
cpp/tsfile/src/tsfile/compress/gzip_compressor.cc | 271 ++
cpp/tsfile/src/tsfile/compress/gzip_compressor.h | 137 +
cpp/tsfile/src/tsfile/compress/lz4.c | 2751 ++++++++++++++++++++
cpp/tsfile/src/tsfile/compress/lz4.h | 861 ++++++
cpp/tsfile/src/tsfile/compress/lz4_compressor.cc | 132 +
cpp/tsfile/src/tsfile/compress/lz4_compressor.h | 59 +
.../src/tsfile/compress/uncompressed_compressor.h | 56 +
.../tsfile/data_dir/smoke_test.write_record.dat | Bin 0 -> 1273 bytes
cpp/tsfile/src/tsfile/encode/CMakeLists.txt | 14 +
cpp/tsfile/src/tsfile/encode/Makefile | 189 ++
cpp/tsfile/src/tsfile/encode/bitpack_decoder.h | 164 ++
cpp/tsfile/src/tsfile/encode/bitpack_encoder.h | 170 ++
cpp/tsfile/src/tsfile/encode/decoder.h | 30 +
cpp/tsfile/src/tsfile/encode/decoder_factory.h | 89 +
cpp/tsfile/src/tsfile/encode/dictionary_decoder.h | 69 +
cpp/tsfile/src/tsfile/encode/dictionary_encoder.h | 96 +
cpp/tsfile/src/tsfile/encode/encode_utils.h | 138 +
cpp/tsfile/src/tsfile/encode/encoder.h | 33 +
cpp/tsfile/src/tsfile/encode/encoder_factory.h | 105 +
cpp/tsfile/src/tsfile/encode/gorilla_decoder.h | 311 +++
cpp/tsfile/src/tsfile/encode/gorilla_encoder.h | 388 +++
cpp/tsfile/src/tsfile/encode/intpacker.h | 144 +
cpp/tsfile/src/tsfile/encode/plain_decoder.h | 45 +
cpp/tsfile/src/tsfile/encode/plain_encoder.h | 56 +
cpp/tsfile/src/tsfile/encode/ts2diff_decoder.h | 214 ++
cpp/tsfile/src/tsfile/encode/ts2diff_encoder.h | 273 ++
cpp/tsfile/src/tsfile/encode/zigzag_decoder.h | 206 ++
cpp/tsfile/src/tsfile/encode/zigzag_encoder.h | 172 ++
cpp/tsfile/src/tsfile/expression.cc | 180 ++
cpp/tsfile/src/tsfile/expression.h | 132 +
cpp/tsfile/src/tsfile/filter/and_filter.h | 79 +
cpp/tsfile/src/tsfile/filter/between.h | 107 +
cpp/tsfile/src/tsfile/filter/binary_filter.h | 31 +
cpp/tsfile/src/tsfile/filter/eq.h | 63 +
cpp/tsfile/src/tsfile/filter/filter.h | 32 +
cpp/tsfile/src/tsfile/filter/filter_type.h | 42 +
cpp/tsfile/src/tsfile/filter/gt.h | 59 +
cpp/tsfile/src/tsfile/filter/gt_eq.h | 60 +
cpp/tsfile/src/tsfile/filter/in.h | 42 +
cpp/tsfile/src/tsfile/filter/lt.h | 59 +
cpp/tsfile/src/tsfile/filter/lt_eq.h | 60 +
cpp/tsfile/src/tsfile/filter/not_eq.h | 60 +
cpp/tsfile/src/tsfile/filter/object.h | 78 +
cpp/tsfile/src/tsfile/filter/or_filter.h | 81 +
cpp/tsfile/src/tsfile/filter/time_filter.cc | 30 +
cpp/tsfile/src/tsfile/filter/time_filter.h | 39 +
cpp/tsfile/src/tsfile/filter/time_operator.cc | 295 +++
cpp/tsfile/src/tsfile/filter/time_operator.h | 207 ++
cpp/tsfile/src/tsfile/filter/unary_filter.h | 42 +
cpp/tsfile/src/tsfile/open_file.cc | 99 +
cpp/tsfile/src/tsfile/open_file.h | 123 +
cpp/tsfile/src/tsfile/page_writer.cc | 191 ++
cpp/tsfile/src/tsfile/page_writer.h | 156 ++
cpp/tsfile/src/tsfile/path.h | 37 +
cpp/tsfile/src/tsfile/qds_with_timegenerator.cc | 377 +++
cpp/tsfile/src/tsfile/qds_with_timegenerator.h | 127 +
cpp/tsfile/src/tsfile/qds_without_timegenerator.cc | 149 ++
cpp/tsfile/src/tsfile/qds_without_timegenerator.h | 52 +
cpp/tsfile/src/tsfile/query_data_set.h | 23 +
cpp/tsfile/src/tsfile/query_executor.h | 50 +
cpp/tsfile/src/tsfile/read_file.cc | 106 +
cpp/tsfile/src/tsfile/read_file.h | 51 +
cpp/tsfile/src/tsfile/record.h | 144 +
cpp/tsfile/src/tsfile/row_record.h | 194 ++
cpp/tsfile/src/tsfile/scan_iterator.cc | 238 ++
cpp/tsfile/src/tsfile/scan_iterator.h | 190 ++
cpp/tsfile/src/tsfile/schema.h | 63 +
cpp/tsfile/src/tsfile/seq_tvlist.h | 176 ++
cpp/tsfile/src/tsfile/seq_tvlist.inc | 159 ++
cpp/tsfile/src/tsfile/statistic.h | 792 ++++++
cpp/tsfile/src/tsfile/storage_utils.h | 80 +
cpp/tsfile/src/tsfile/tablet.cc | 154 ++
cpp/tsfile/src/tsfile/tablet.h | 82 +
cpp/tsfile/src/tsfile/tablet_iterator.h | 59 +
cpp/tsfile/src/tsfile/tsfile_common.cc | 230 ++
cpp/tsfile/src/tsfile/tsfile_common.h | 812 ++++++
cpp/tsfile/src/tsfile/tsfile_executor.cc | 107 +
cpp/tsfile/src/tsfile/tsfile_executor.h | 42 +
cpp/tsfile/src/tsfile/tsfile_io_reader.cc | 495 ++++
cpp/tsfile/src/tsfile/tsfile_io_reader.h | 158 ++
cpp/tsfile/src/tsfile/tsfile_io_writer.cc | 716 +++++
cpp/tsfile/src/tsfile/tsfile_io_writer.h | 190 ++
cpp/tsfile/src/tsfile/tsfile_mgr.cc | 130 +
cpp/tsfile/src/tsfile/tsfile_mgr.h | 89 +
cpp/tsfile/src/tsfile/tsfile_reader.cc | 53 +
cpp/tsfile/src/tsfile/tsfile_reader.h | 45 +
.../src/tsfile/tsfile_series_scan_iterator.cc | 102 +
.../src/tsfile/tsfile_series_scan_iterator.h | 93 +
cpp/tsfile/src/tsfile/tsfile_writer.cc | 438 ++++
cpp/tsfile/src/tsfile/tsfile_writer.h | 120 +
cpp/tsfile/src/tsfile/write_file.cc | 116 +
cpp/tsfile/src/tsfile/write_file.h | 49 +
158 files changed, 26862 insertions(+), 29 deletions(-)
diff --git a/cpp/examples/src/demo_read.cpp b/cpp/examples/src/demo_read.cpp
new file mode 100644
index 00000000..a80ff801
--- /dev/null
+++ b/cpp/examples/src/demo_read.cpp
@@ -0,0 +1,92 @@
+#include <iostream>
+#include <vector>
+#include <string>
+#include "tsfile/path.h"
+#include "tsfile/filter/filter.h"
+#include "tsfile/expression.h"
+#include "tsfile/tsfile_reader.h"
+#include "tsfile/qds_with_timegenerator.h"
+#include "tsfile/qds_without_timegenerator.h"
+#include "tsfile/row_record.h"
+
+using namespace std;
+
+std::string field_to_string(timecho::storage::Field *value)
+{
+ if (value->type_ == timecho::common::TEXT) {
+ return std::string(value->value_.sval_);
+ } else {
+ std::stringstream ss;
+ switch (value->type_) {
+ case timecho::common::BOOLEAN:
+ ss << (value->value_.bval_ ? "true" : "false");
+ break;
+ case timecho::common::INT32:
+ ss << value->value_.ival_;
+ break;
+ case timecho::common::INT64:
+ ss << value->value_.lval_;
+ break;
+ case timecho::common::FLOAT:
+ ss << value->value_.fval_;
+ break;
+ case timecho::common::DOUBLE:
+ ss << value->value_.dval_;
+ break;
+ case timecho::common::NULL_TYPE:
+ ss << "NULL";
+ break;
+ default:
+ ASSERT(false);
+ break;
+ }
+ return ss.str();
+ }
+}
+
+int main (int argc, char **argv)
+{
+ std::cout<<"begin to read tsfile from /tmp/t1" << std::endl;
+ std::string device_name = "root.db001.dev001";
+ std::string measurement_name = "m001";
+ timecho::storage::Path p1(device_name, measurement_name);
+ std::vector<timecho::storage::Path> select_list;
+ select_list.push_back(p1);
+ timecho::storage::QueryExpression *query_expr =
+ timecho::storage::QueryExpression::create(select_list, nullptr);
+
+ timecho::common::init_config_value();
+ timecho::storage::TsFileReader reader;
+ int ret = reader.open("/tmp/t1");
+ std::cout <<"open file return " << ret<< std::endl;
+
+ std::cout << "begin to query expr" << std::endl;
+ ASSERT(ret == 0);
+ timecho::storage::QueryDataSet *qds = nullptr;
+ ret = reader.query(query_expr, qds);
+
+
+ timecho::storage::RowRecord *record;
+ std::cout << "begin to dump data from tsfile ---" << std::endl;
+ int row_cout = 0;
+ do {
+ record = qds->get_next();
+ if (record) {
+ std::cout<< "dump QDS : " << record->get_timestamp() << ",";
+ if (record) {
+ int size = record->get_fields()->size();
+ for (int i = 0; i < size; ++i) {
+ std::cout << field_to_string(record->get_field(i)) << ",";
+ }
+ std::cout<< std::endl;
+ row_cout++;
+ }
+ } else {
+ break;
+ }
+ } while (true);
+ std::cout << "dump tsfile finish" << std::endl;
+ std::cout << "total row count = " << row_cout<<std::endl;
+
+ return (0);
+}
diff --git a/cpp/tsfile/src/CMakeLists.txt b/cpp/tsfile/src/CMakeLists.txt
new file mode 100644
index 00000000..78ad85c6
--- /dev/null
+++ b/cpp/tsfile/src/CMakeLists.txt
@@ -0,0 +1,4 @@
+message("Running in src diectory")
+include(${PROJECT_SOURCE_DIR}/cmake/build_function.cmake)
+add_subdirectory(tsfile)
+add_subdirectory(common)
\ No newline at end of file
diff --git a/cpp/tsfile/src/common/CMakeLists.txt b/cpp/tsfile/src/common/CMakeLists.txt
new file mode 100644
index 00000000..20249ab5
--- /dev/null
+++ b/cpp/tsfile/src/common/CMakeLists.txt
@@ -0,0 +1,20 @@
+message("Running in src/common directory")
+
+add_subdirectory(allocator)
+add_subdirectory(config)
+add_subdirectory(container)
+add_subdirectory(mutex)
+add_subdirectory(tsblock)
+add_subdirectory(datatype)
+
+aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} common_SRC_LIST)
+set(common_INC_LIST )
+set(common_DEFINE_OPTIONS )
+set(common_COMPILE_OPTIONS )
+set(common_LINK_OPTIONS )
+
+add_statis_objtarget(common common_SRC_LIST common_INC_LIST
+ "${common_DEFINE_OPTIONS}"
+ "${common_COMPILE_OPTIONS}"
+ "${common_LINK_OPTIONS}")
+
diff --git a/cpp/tsfile/src/common/allocator/CMakeLists.txt.bak b/cpp/tsfile/src/common/allocator/CMakeLists.txt.bak
new file mode 100644
index 00000000..94b845f4
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/CMakeLists.txt.bak
@@ -0,0 +1,16 @@
+
+message("Running in src/common/allocator directory")
+
+message("CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}")
+
+aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} common_allocator_SRC_LIST)
+set(common_allocator_INC_LIST)
+set(common_allocator_DEFINE_OPTIONS)
+set(common_allocator_COMPILE_OPTIONS)
+set(common_allocator_LINK_OPTIONS)
+
+add_statis_objtarget(common_allocator common_allocator_SRC_LIST common_allocator_INC_LIST
+ "${common_allocator_DEFINE_OPTIONS}"
+ "${common_allocator_COMPILE_OPTIONS}"
+ "${common_allocator_LINK_OPTIONS}")
+
diff --git a/cpp/tsfile/src/common/allocator/alloc_base.h b/cpp/tsfile/src/common/allocator/alloc_base.h
new file mode 100644
index 00000000..953a34a9
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/alloc_base.h
@@ -0,0 +1,128 @@
+
+#ifndef COMMON_ALLOCATOR_ALLOC_BASE_H
+#define COMMON_ALLOCATOR_ALLOC_BASE_H
+
+#include <cstring>
+#include <stddef.h>
+#include "../util_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+enum AllocModID
+{
+ __FIRST_MOD_ID = 0,
+ // if you are sure you will not consume too much memory, you can use MOD_DEFAULT.
+ MOD_DEFAULT = 0,
+ MOD_MEMTABLE = 1,
+ MOD_SCHEMA = 2,
+ MOD_SQL = 3,
+ MOD_NET = 4,
+ MOD_NET_DATA = 5,
+ MOD_TVLIST_DATA = 6,
+ MOD_TVLIST_OBJ = 7,
+ MOD_TSBLOCK = 8,
+ MOD_CONTAINER = 9,
+ MOD_TSSTORE_OBJ = 10,
+ MOD_FLUSH_TASK_OBJ = 11,
+ MOD_PAGE_WRITER_OUTPUT_STREAM = 12,
+ MOD_CW_PAGES_DATA = 13,
+ MOD_CHUNK_WRITER_OBJ = 14,
+ MOD_STATISTIC_OBJ = 15,
+ MOD_ENCODER_OBJ = 16,
+ MOD_DECODER_OBJ = 17,
+ MOD_TSFILE_WRITER_META = 18,
+ MOD_TSFILE_WRITE_STREAM = 19,
+ MOD_TIMESERIES_INDEX_OBJ = 20,
+ MOD_BLOOM_FILTER = 21,
+ MOD_OPEN_FILE_OBJ = 22,
+ MOD_TSFILE_READER = 23,
+ MOD_CHUNK_READER = 24,
+ MOD_COMPRESSOR_OBJ = 25,
+ MOD_ARRAY = 26,
+ MOD_HASH_TABLE = 27,
+ MOD_WRITER_INDEX_NODE = 28,
+ MOD_TS2DIFF_OBJ = 29,
+ MOD_BITENCODE_OBJ = 30,
+ MOD_DICENCODE_OBJ = 31,
+ MOD_ZIGZAG_OBJ = 32,
+ __LAST_MOD_ID = 33, // prev + 1,
+ __MAX_MOD_ID = 127, // leave 1 bit to detect header size
+};
+
+extern const char *g_mod_names[__LAST_MOD_ID];
+
+/* very basic alloc/free interface in C style */
+void *mem_alloc(uint32_t size, AllocModID mid);
+void mem_free(void *ptr);
+void *mem_realloc(void *ptr, uint32_t size);
+
+class ModStat
+{
+public:
+ ModStat() : stat_arr_(NULL) {}
+
+ static ModStat &get_instance()
+ {
+ /*
+ * This is the singleton of Mod Memory Statistic.
+ * gms is short for Global Mod Statistic
+ */
+ static ModStat gms;
+ return gms;
+ }
+ void init();
+ void destroy();
+ INLINE void update_alloc(AllocModID mid, int32_t size)
+ {
+// ASSERT(mid < __LAST_MOD_ID);
+// ATOMIC_FAA(get_item(mid), size);
+ }
+ void update_free(AllocModID mid, uint32_t size)
+ {
+// ASSERT(mid < __LAST_MOD_ID);
+// ATOMIC_FAA(get_item(mid), 0 - size);
+ }
+ void print_stat();
+
+#ifdef ENABLE_TEST
+ int32_t TEST_get_stat(int8_t mid) { return ATOMIC_FAA(get_item(mid), 0); }
+#endif
+
+private:
+ INLINE int32_t *get_item(int8_t mid)
+ {
+ return &(stat_arr_[mid * (ITEM_SIZE/sizeof(int32_t))]);
+ }
+
+private:
+ static const int32_t ITEM_SIZE = CACHE_LINE_SIZE;
+ static const int32_t ITEM_COUNT = __LAST_MOD_ID;
+ int32_t *stat_arr_;
+
+ STATIC_ASSERT((ITEM_SIZE % sizeof(int32_t) == 0), ModStat_ITEM_SIZE_ERROR);
+};
+
+/* base allocator */
+class BaseAllocator
+{
+public:
+ void *alloc(uint32_t size, AllocModID mid)
+ {
+ return mem_alloc(size, mid);
+ }
+ void free(void *ptr)
+ {
+ mem_free(ptr);
+ }
+};
+
+extern BaseAllocator g_base_allocator;
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_ALLOCATOR_ALLOC_BASE_H
+
diff --git a/cpp/tsfile/src/common/allocator/byte_stream.h b/cpp/tsfile/src/common/allocator/byte_stream.h
new file mode 100644
index 00000000..5dd56ebc
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/byte_stream.h
@@ -0,0 +1,1111 @@
+
+#ifndef COMMON_ALLOCATOR_BYTE_STREAM_H
+#define COMMON_ALLOCATOR_BYTE_STREAM_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+#include <iostream>
+
+#include "common/allocator/alloc_base.h"
+#include "common/allocator/my_string.h"
+#include "common/errno_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+template<typename T>
+class OptionalAtomic
+{
+public:
+ OptionalAtomic(T t, bool enable_atomic = false)
+ : val_(t), enable_atomic_(enable_atomic) {}
+
+ FORCE_INLINE T load() const
+ {
+ if (UNLIKELY(enable_atomic_)) {
+ return ATOMIC_LOAD(&val_);
+ } else {
+ return val_;
+ }
+ }
+
+ FORCE_INLINE void store(const T t)
+ {
+ if (UNLIKELY(enable_atomic_)) {
+ ATOMIC_STORE(&val_, t);
+ } else {
+ val_ = t;
+ }
+ }
+
+ FORCE_INLINE T atomic_faa(const T increament)
+ {
+ if (UNLIKELY(enable_atomic_)) {
+ return ATOMIC_FAA(&val_, increament);
+ } else {
+ T old_val = val_;
+ val_ = val_ + increament;
+ return old_val;
+ }
+ }
+
+ FORCE_INLINE T atomic_aaf(const T increament)
+ {
+ if (UNLIKELY(enable_atomic_)) {
+ return ATOMIC_AAF(&val_, increament);
+ } else {
+ val_ = val_ + increament;
+ return val_;
+ }
+ }
+
+ FORCE_INLINE bool enable_atomic() const { return enable_atomic_; }
+
+private:
+ T val_;
+ bool enable_atomic_;
+};
+
+FORCE_INLINE int32_t float_to_int(float f)
+{
+ // return *((int32_t*)(&f));
+ // return *(reinterpret_cast<int32_t*>(&f));
+ union fi
+ {
+ int i_;
+ float f_;
+ };
+
+ fi my_fi;
+ my_fi.f_ = f;
+ return my_fi.i_; // By mimicking the java jdk's implementation, it's essentially the same as line 75.
+}
+
+FORCE_INLINE float int_to_float(int32_t i)
+{
+ // return *((float *)(&i));
+ union fi
+ {
+ int i_;
+ float f_;
+ };
+
+ fi my_fi;
+ my_fi.i_ = i;
+ return my_fi.f_;
+}
+
+FORCE_INLINE void float_to_bytes(float f, uint8_t bytes[4])
+{
+ /*
+ * See:
+ * floatToBytes in BytesUtils.java of IoTDB project and
+ * Java_java_lang_Float_intBitsToFloat in JDK project
+ */
+ if (UNLIKELY(f != f)) { // this is NaN
+ // IEEE754: 0x7FC00000 for NanN
+ bytes[0] = 0x7F;
+ bytes[1] = 0xC0;
+ bytes[2] = 0x00;
+ bytes[3] = 0x00;
+ return;
+ }
+
+ // follow jdk implementation style.
+ union {
+ int i;
+ float f;
+ } u;
+
+ u.f = f;
+
+ bytes[3] = (uint8_t)(u.i);
+ bytes[2] = (uint8_t)(u.i >> 8);
+ bytes[1] = (uint8_t)(u.i >> 16);
+ bytes[0] = (uint8_t)(u.i >> 24);
+}
+
+FORCE_INLINE float bytes_to_float(uint8_t bytes[4])
+{
+ int32_t i = bytes[3];
+ i &= 0xFF;
+ i |= bytes[2] << 8;
+ i &= 0xFFFF;
+ i |= bytes[1] << 16;
+ i &= 0xFFFFFF;
+ i |= bytes[0] << 24;
+
+ union {
+ int i;
+ float f;
+ } u;
+
+ u.i = i;
+ return u.f;
+}
+
+FORCE_INLINE int64_t double_to_long(double d)
+{
+ // return *((int64_t*)(&d));
+ union dl
+ {
+ double d_;
+ int64_t l_;
+ };
+ dl my_dl;
+ my_dl.d_ = d;
+ return my_dl.l_;
+}
+
+FORCE_INLINE double long_to_double(int64_t l)
+{
+ // return *((double *)(&l));
+ union dl
+ {
+ double d_;
+ int64_t l_;
+ };
+ dl my_dl;
+ my_dl.l_ = l;
+ return my_dl.d_;
+}
+
+FORCE_INLINE void double_to_bytes(double d, uint8_t bytes[8])
+{
+ if (UNLIKELY(d != d)) {
+ // NaN, 0x7FF8000000000000L
+ memset(bytes, 0, 8);
+ bytes[0] = 0x7F;
+ bytes[1] = 0xF8;
+ return;
+ }
+ // follow jdk implementation style.
+ union {
+ long long l;
+ double d;
+ } u;
+
+ u.d = d;
+
+ bytes[7] = (uint8_t)u.l;
+ bytes[6] = (uint8_t)(u.l >> 8);
+ bytes[5] = (uint8_t)(u.l >> 16);
+ bytes[4] = (uint8_t)(u.l >> 24);
+ bytes[3] = (uint8_t)(u.l >> 32);
+ bytes[2] = (uint8_t)(u.l >> 40);
+ bytes[1] = (uint8_t)(u.l >> 48);
+ bytes[0] = (uint8_t)(u.l >> 56);
+}
+
+FORCE_INLINE double bytes_to_double(uint8_t bytes[8])
+{
+ int64_t value = bytes[7];
+ value &= 0xFFl;
+ value |= ((int64_t)bytes[6]) << 8;
+ value &= 0xFFFFl;
+ value |= ((int64_t)bytes[5]) << 16;
+ value &= 0xFFFFFFl;
+ value |= ((int64_t)bytes[4]) << 24;
+ value &= 0xFFFFFFFFl;
+ value |= ((int64_t)bytes[3]) << 32;
+ value &= 0xFFFFFFFFFFl;
+ value |= ((int64_t)bytes[2]) << 40;
+ value &= 0xFFFFFFFFFFFFl;
+ value |= ((int64_t)bytes[1]) << 48;
+ value &= 0xFFFFFFFFFFFFFFl;
+ value |= ((int64_t)bytes[0]) << 56;
+
+ // follow jdk implementation style.
+ union {
+ long l;
+ double d;
+ } u;
+
+ u.l = value;
+ return u.d;
+}
+
+// TODO define a WrappedByteStream class
+
+// auto extend buffer for serialization
+class ByteStream
+{
+private:
+ struct Page
+ {
+ OptionalAtomic<Page*> next_; // 9 bytes
+ uint8_t *buf_; // 8 bytes
+
+ explicit Page(bool enable_atomic) : next_(nullptr, enable_atomic)
+ {
+ buf_ = (uint8_t*)(this + 1); // I think it should add 17, because the Page class is 9+8=17 bytes. No, adding one to a pointer is not adding a byte, but adding the length of the byte corresponding to the type pointed to by the pointer, and adding one here is actually adding 17 bytes. No problem.
+ }
+ Page(bool enable_atomic, uint8_t *wrapped_buf)
+ : next_(nullptr, enable_atomic),
+ buf_(wrapped_buf) {}
+ };
+
+public:
+ ByteStream(uint32_t page_size,
+ AllocModID mid,
+ bool enable_atomic = false,
+ BaseAllocator &allocator = g_base_allocator)
+ : allocator_(allocator),
+ head_(nullptr, enable_atomic),
+ tail_(nullptr, enable_atomic),
+ read_page_(nullptr),
+ total_size_(0, enable_atomic),
+ read_pos_(0),
+ marked_read_pos_(0),
+ page_size_(page_size),
+ mid_(mid),
+ wrapped_page_(false, nullptr)
+ {
+ // assert(page_size >= 16); // commented out by gxh on 2023.03.09
+ std::cout<<"page size when created is " << page_size << std::endl;
+ }
+
+ // TODO use a specific construct function to mark it as wrapped use.
+ // for wrap plain buffer to ByteStream
+ ByteStream() : allocator_(g_base_allocator),
+ head_(nullptr, false),
+ tail_(nullptr, false),
+ read_page_(nullptr),
+ total_size_(0, false),
+ read_pos_(0),
+ marked_read_pos_(0),
+ page_size_(0),
+ mid_(MOD_DEFAULT),
+ wrapped_page_(false, nullptr) {}
+
+ ~ByteStream() { destroy(); }
+
+ /* ================ Part 0: wrap from outside buffer ================ */
+ // if you wrap a buffer as a ByteStream, you should
+ // manage the outside buffer yourself.
+ void wrap_from(const char *buf, int32_t buf_len)
+ {
+ wrapped_page_.next_.store(nullptr);
+ wrapped_page_.buf_ = (uint8_t*)buf;
+
+ page_size_ = buf_len;
+ std::cout<<"page_size when wrap from" << page_size_ << std::endl;
+ head_.store(&wrapped_page_);
+ tail_.store(&wrapped_page_);
+ total_size_.store(buf_len);
+ marked_read_pos_ = 0;
+ read_pos_ = 0;
+ read_page_ = nullptr;
+ }
+ FORCE_INLINE bool is_wrapped() const { return head_.load() == &wrapped_page_; }
+ char* get_wrapped_buf() { return (char*)wrapped_page_.buf_; }
+ void clear_wrapped_buf() { wrapped_page_.buf_ = nullptr; }
+
+ /* ================ Part 1: basic ================ */
+ FORCE_INLINE uint32_t remaining_size() const
+ {
+ ASSERT(total_size_.load() >= read_pos_);
+ return total_size_.load() - read_pos_;
+ }
+ FORCE_INLINE bool has_remaining() const { return remaining_size() > 0; }
+
+ FORCE_INLINE void mark_read_pos() { marked_read_pos_ = read_pos_; }
+ FORCE_INLINE uint32_t get_mark_len() const
+ {
+ ASSERT(marked_read_pos_ <= read_pos_);
+ return read_pos_ - marked_read_pos_;
+ }
+
+ void destroy() { reset(); }
+ void reset()
+ {
+ // if this ByteStream is wrapped from a plain buffer
+ // do not free the outside buffer.
+ if (!is_wrapped()) {
+ Page *p = head_.load();
+ while (p) {
+ p = head_.load()->next_.load();
+ allocator_.free(head_.load());
+ head_.store(p);
+ }
+ }
+ head_.store(nullptr);
+ tail_.store(nullptr);
+ read_page_ = nullptr;
+ total_size_.store(0);
+ read_pos_ = 0;
+ }
+
+ // never used TODO
+ void shallow_clone_from(ByteStream &other)
+ {
+ this->page_size_ = other.page_size_ ;
+ std::cout << "page size after clone" << this->page_size_ << std::endl;
+ this->mid_ = other.mid_ ;
+ this->head_.store(other.head_.load());
+ this->tail_.store(other.tail_.load());
+ this->total_size_.store(other.total_size_.load());
+ }
+
+ FORCE_INLINE uint32_t total_size() const { return total_size_.load(); }
+ FORCE_INLINE uint32_t read_pos() const { return read_pos_; };
+ FORCE_INLINE void wrapped_buf_advance_read_pos(uint32_t size)
+ {
+ if (size + read_pos_ > total_size_.load()) {
+ read_pos_ = total_size_.load();
+ } else {
+ read_pos_ += size;
+ }
+ }
+
+ /* ================ Part 2: write_xxx and read_xxx ================ */
+ // write @buf with length @len into this bytestream
+ int write_buf(const uint8_t *buf, const uint32_t len)
+ {
+ int ret = common::E_OK;
+ uint32_t write_len = 0;
+ while (write_len < len) {
+ if (RET_FAIL(prepare_space())) {
+ std::cout<<"write_buf error "<< ret <<std::endl;
+ return ret;
+ }
+ uint32_t remainder = page_size_ - (total_size_.load() % page_size_);
+ uint32_t copy_len = remainder < (len - write_len) ? remainder : (len - write_len);
+ memcpy(tail_.load()->buf_ + total_size_.load() % page_size_, buf + write_len, copy_len);
+ total_size_.atomic_aaf(copy_len);
+ write_len += copy_len;
+ }
+ return ret;
+ }
+
+ // read @want_len bytes to @buf, @read_len indicates real len we read.
+ // if ByteStream do not have so many bytes, it will return E_PARTIAL_READ if
+ // no other error occure.
+ int read_buf(uint8_t *buf, const uint32_t want_len, uint32_t &read_len)
+ {
+ int ret = common::E_OK;
+ bool partial_read = (read_pos_ + want_len > total_size_.load());
+ uint32_t want_len_limited = partial_read ? (total_size_.load() - read_pos_) : want_len;
+ read_len = 0;
+ while (read_len < want_len_limited) {
+ if (RET_FAIL(check_space())) {
+ return ret;
+ }
+ uint32_t remainder = page_size_ - (read_pos_ % page_size_);
+ uint32_t copy_len = remainder < want_len_limited - read_len ? remainder : want_len_limited - read_len;
+ memcpy(buf + read_len, read_page_->buf_ + (read_pos_ % page_size_), copy_len);
+ read_len += copy_len;
+ read_pos_ += copy_len;
+ }
+ return partial_read ? common::E_PARTIAL_READ : common::E_OK;
+ }
+
+ FORCE_INLINE int write_buf(const char *buf, const uint32_t len)
+ {
+ return write_buf((const uint8_t*)buf, len);
+ }
+ FORCE_INLINE int read_buf(char *buf, const uint32_t want_len, uint32_t &read_len)
+ {
+ return read_buf((uint8_t*)buf, want_len, read_len);
+ }
+ FORCE_INLINE int read_buf(char *buf, const int32_t want_len, int32_t &read_len)
+ {
+ return read_buf((uint8_t*)buf, (uint32_t&)want_len, (uint32_t&)read_len);
+ }
+
+ void purge_prev_pages(int purge_page_count = INT32_MAX)
+ {
+ Page *cur = head_.load();
+ while (cur != tail_.load() && purge_page_count-- > 0) {
+ Page *next = cur->next_.load();
+ allocator_.free(cur);
+ cur = next;
+ }
+ head_.store(cur);
+ }
+
+ /* ================ Part 3: writing internal buffers ================ */
+ /*
+ * use @acquire_buf function to get a buf, caller will fill the buf, and
+ * after filling, caller use @buffer_used to notice ByteStream to update
+ * internal variables.
+ *
+ * Note: it should be used in single thread.
+ */
+ struct Buffer
+ {
+ char *buf_;
+ uint32_t len_;
+
+ Buffer() : buf_(nullptr), len_(0) {}
+ };
+
+ Buffer acquire_buf()
+ {
+ Buffer b;
+ if (common::E_OK != prepare_space()) {
+ return b;
+ }
+ b.buf_ = (char*)(tail_.load()->buf_ + (total_size_.load() % page_size_));
+ b.len_ = page_size_ - (total_size_.load() % page_size_);
+ return b;
+ }
+
+ void buffer_used(uint32_t used_bytes)
+ {
+ ASSERT(used_bytes >= 1);
+ // would not span page
+ ASSERT((total_size_.load() / page_size_) == ((total_size_.load() + used_bytes - 1) / page_size_));
+ total_size_.atomic_aaf(used_bytes);
+ }
+
+ /* ================ Part 4: reading internal buffers ================ */
+ /*
+ * one-shot read iterator
+ * Do not use it if the host_ is still writing
+ */
+ struct BufferIterator
+ {
+ const ByteStream &host_;
+ Page *cur_;
+ Page *end_;
+ int64_t total_size_;
+ BufferIterator(const ByteStream &bs) : host_(bs)
+ {
+ cur_ = bs.head_.load();
+ end_ = bs.tail_.load();
+ total_size_ = bs.total_size_.load();
+ }
+
+ Buffer get_next_buf()
+ {
+ Buffer b;
+ if (cur_ != nullptr) {
+ b.buf_ = (char*)cur_->buf_;
+ if (cur_ == end_ && host_.total_size_.load() % host_.page_size_ != 0) {
+ b.len_ = host_.total_size_.load() % host_.page_size_;
+ } else {
+ b.len_ = host_.page_size_;
+ }
+ ASSERT(b.len_ > 0);
+ cur_ = cur_->next_.load();
+ }
+ return b;
+ }
+ };
+ BufferIterator init_buffer_iterator() const { return BufferIterator(*this); }
+
+ /*
+ * producer-consumer mode read iterator
+ * Note:
+ * the host ByteStream should be configured as atomically.
+ */
+ struct Consumer
+ {
+ const ByteStream &host_;
+ Page *cur_;
+ uint32_t read_offset_within_cur_page_;
+ int64_t total_end_offset_; // for DEBUG
+
+ Consumer(const ByteStream &bs) : host_(bs)
+ {
+ ASSERT(bs.head_.enable_atomic());
+ cur_ = nullptr;
+ read_offset_within_cur_page_ = 0;
+ total_end_offset_ = 0;
+ }
+
+ Buffer get_next_buf(ByteStream &host)
+ {
+ Buffer b;
+ if (UNLIKELY(host.head_.load() == nullptr)) {
+ // host is empty, return empty buffer.
+ return b;
+ }
+ if (UNLIKELY(cur_ == nullptr)) {
+ // this consumer did not initialiazed.
+ cur_ = host_.head_.load();
+ read_offset_within_cur_page_ = 0;
+ }
+
+ // get tail position <tail_, total_size_> atomically
+ Page *host_end = nullptr;
+ uint32_t host_total_size = 0;
+ while (true) {
+ host_end = host_.tail_.load();
+ host_total_size = host_.total_size_.load();
+ if (host_end == host_.tail_.load()) {
+ break;
+ }
+ }
+
+ while (true) {
+ if (cur_ == host_end) {
+ if (host_total_size % host_.page_size_ == 0) {
+ if (read_offset_within_cur_page_ == host_.page_size_) {
+ return b;
+ } else {
+ b.buf_ = ((char*)(cur_->buf_)) + read_offset_within_cur_page_;
+ b.len_ = host_.page_size_ - read_offset_within_cur_page_;
+ read_offset_within_cur_page_ = host_.page_size_;
+ total_end_offset_ += b.len_;
+ return b;
+ }
+ } else {
+ if (read_offset_within_cur_page_ == (host_total_size % host_.page_size_)) {
+ return b;
+ } else {
+ b.buf_ = ((char*)(cur_->buf_)) + read_offset_within_cur_page_;
+ b.len_ = (host_total_size % host_.page_size_) - read_offset_within_cur_page_;
+ read_offset_within_cur_page_ = (host_total_size % host_.page_size_);
+ total_end_offset_ += b.len_;
+ return b;
+ }
+ }
+ } else {
+ if (read_offset_within_cur_page_ == host_.page_size_) {
+ cur_ = cur_->next_.load();
+ read_offset_within_cur_page_ = 0;
+ } else {
+ b.buf_ = ((char*)(cur_->buf_)) + read_offset_within_cur_page_;
+ b.len_ = host_.page_size_ - read_offset_within_cur_page_;
+ cur_ = cur_->next_.load();
+ read_offset_within_cur_page_ = 0;
+ total_end_offset_ += b.len_;
+ return b;
+ }
+ }
+ }
+ ASSERT(b.len_ < (1<<30));
+ return b;
+ }
+ };
+
+private:
+ FORCE_INLINE int prepare_space()
+ {
+ int ret = common::E_OK;
+ if (UNLIKELY(tail_.load() == nullptr || total_size_.load() % page_size_ == 0)) {
+ Page *p = nullptr;
+ if (RET_FAIL(alloc_page(p))) {
+ return ret;
+ }
+ } else {
+ // do nothing
+ }
+ return ret;
+ }
+
+ FORCE_INLINE int check_space()
+ {
+ if (UNLIKELY(read_pos_ >= total_size_.load())) {
+ return common::E_OUT_OF_RANGE;
+ }
+ if (UNLIKELY(read_page_ == nullptr)) {
+ read_page_ = head_.load();
+ } else if (UNLIKELY(read_pos_ % page_size_ == 0)) {
+ read_page_ = read_page_->next_.load();
+ }
+ if (UNLIKELY(read_page_ == nullptr)) {
+ return common::E_OUT_OF_RANGE;
+ }
+ return common::E_OK;
+ }
+
+ FORCE_INLINE int alloc_page(Page *&p)
+ {
+ int ret = common::E_OK;
+ char *buf = (char*)allocator_.alloc(page_size_ + sizeof(Page), mid_);
+ if (UNLIKELY(buf == nullptr)) {
+ ret = common::E_OOM;
+ } else {
+ p = new (buf) Page(head_.enable_atomic());
+ p->next_.store(nullptr);
+ if (head_.load()) {
+ tail_.load()->next_.store(p);
+ tail_.store(p);
+ } else {
+ head_.store(p);
+ tail_.store(p);
+ }
+ }
+ // printf("\nByteStream alloc_page, this=%p, new_page=%p\n", this, p);
+ return ret;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ByteStream);
+private:
+ BaseAllocator &allocator_;
+ OptionalAtomic<Page*> head_;
+ OptionalAtomic<Page*> tail_;
+ Page* read_page_; // only one thread is allow to read this ByteStream
+ OptionalAtomic<uint32_t> total_size_; // total size in byte
+ uint32_t read_pos_; // current read position
+ uint32_t marked_read_pos_; // current read position
+ uint32_t page_size_;
+ AllocModID mid_;
+ Page wrapped_page_;
+};
+
+FORCE_INLINE int merge_byte_stream(ByteStream &sea, ByteStream &river, bool purge_river = false)
+{
+ int ret = common::E_OK;
+ ByteStream::BufferIterator buf_iter = river.init_buffer_iterator();
+ while (true) {
+ ByteStream::Buffer buf = buf_iter.get_next_buf();
+ if (buf.buf_ == nullptr) {
+ break;
+ } else {
+ if (RET_FAIL(sea.write_buf(buf.buf_, buf.len_))) {
+ break;
+ }
+ }
+ if (purge_river) {
+ river.purge_prev_pages(1);
+ }
+ }
+ return ret;
+}
+
+FORCE_INLINE uint32_t get_var_uint_size(uint32_t ui32) // return: the length of usigned number after varint encoding.
+{
+ uint32_t bytes = 0;
+ while ((ui32 & 0xFFFFFF80) != 0) {
+ bytes++;
+ ui32 = ui32 >> 7;
+ }
+ return ++bytes;
+}
+
+#if DEBUG_SE
+FORCE_INLINE void DEBUG_print_byte_stream(const char *print_tag, ByteStream &b)
+{
+ const int32_t WRAP_COUNT = 16;
+ int32_t print_char_count = 0;
+ ByteStream::BufferIterator buf_iter = b.init_buffer_iterator();
+ while (true) {
+ ByteStream::Buffer buf = buf_iter.get_next_buf();
+ if (buf.buf_ == nullptr) {
+ break;
+ } else {
+ // print_hex(buf.buf_, buf.len_);
+ printf("\n %s: buf.buf_=%p, buf.len_=%u\n", print_tag, buf.buf_, buf.len_);
+ for (uint32_t i = 0; i < buf.len_; i++) {
+ if (print_char_count++ % WRAP_COUNT == 0) {
+ printf("\n %s offset=0x%05x : ", print_tag, print_char_count - 1);
+ }
+ printf("%02x ", (uint8_t)buf.buf_[i]);
+ }
+ }
+ }
+ printf("\n\n");
+}
+
+FORCE_INLINE void DEBUG_hex_dump_buf(const char *print_tag, const char *buf, int32_t len)
+{
+ const int32_t WRAP_COUNT = 16;
+ for (int i = 0; i < len; i++) {
+ if (i % WRAP_COUNT == 0) {
+ printf("\n%s", print_tag);
+ }
+ printf("%02x ", (uint8_t)(buf[i]));
+ }
+ printf("\n");
+}
+#endif // ifndef NDEBUG
+
+class SerializationUtil
+{
+public:
+ FORCE_INLINE static int write_ui8(uint8_t ui8, ByteStream &out)
+ {
+ return out.write_buf(&ui8, 1);
+ }
+ FORCE_INLINE static int write_ui16(uint16_t ui16, ByteStream &out)
+ {
+ uint8_t buf[2];
+ buf[0] = (uint8_t)((ui16 >> 8) & 0xFF);
+ buf[1] = (uint8_t)((ui16 ) & 0xFF);
+ return out.write_buf(buf, 2);
+ }
+ FORCE_INLINE static int write_ui32(uint32_t ui32, ByteStream &out)
+ {
+ uint8_t buf[4];
+ buf[0] = (uint8_t)((ui32 >> 24) & 0xFF);
+ buf[1] = (uint8_t)((ui32 >> 16) & 0xFF);
+ buf[2] = (uint8_t)((ui32 >> 8) & 0xFF);
+ buf[3] = (uint8_t)((ui32 ) & 0xFF);
+ return out.write_buf(buf, 4);
+ }
+ FORCE_INLINE static int write_ui64(uint64_t ui64, ByteStream &out)
+ {
+ // big-endian: most signification byte at smaller address
+ // refer to tsfile.utils.BytesUtil
+ uint8_t buf[8];
+ buf[0] = (uint8_t)((ui64 >> 56) & 0xFF);
+ buf[1] = (uint8_t)((ui64 >> 48) & 0xFF);
+ buf[2] = (uint8_t)((ui64 >> 40) & 0xFF);
+ buf[3] = (uint8_t)((ui64 >> 32) & 0xFF);
+ buf[4] = (uint8_t)((ui64 >> 24) & 0xFF);
+ buf[5] = (uint8_t)((ui64 >> 16) & 0xFF);
+ buf[6] = (uint8_t)((ui64 >> 8) & 0xFF);
+ buf[7] = (uint8_t)((ui64 ) & 0xFF);
+ return out.write_buf(buf, 8);
+ }
+
+ FORCE_INLINE static int read_ui8(uint8_t &ui8, ByteStream &in)
+ {
+ int ret = common::E_OK;
+ char buf[1];
+ uint32_t read_len = 0;
+ ret = in.read_buf(buf, 1, read_len);
+ ui8 = (uint8_t)buf[0];
+ return ret;
+ }
+ FORCE_INLINE static int read_ui16(uint16_t &ui16, ByteStream &in)
+ {
+ int ret = common::E_OK;
+ uint8_t buf[2];
+ uint32_t read_len = 0;
+ if (RET_FAIL(in.read_buf(buf, 2, read_len))) {
+ return ret;
+ }
+ ui16 = buf[0];
+ ui16 = (ui16 << 8) | buf[1];
+ return ret;
+ }
+ FORCE_INLINE static int read_ui32(uint32_t &ui32, ByteStream &in)
+ {
+ int ret = common::E_OK;
+ uint8_t buf[4];
+ uint32_t read_len = 0;
+ if (RET_FAIL(in.read_buf(buf, 4, read_len))) {
+ return ret;
+ }
+ ui32 = buf[0];
+ ui32 = (ui32 << 8) | (buf[1] & 0xFF);
+ ui32 = (ui32 << 8) | (buf[2] & 0xFF);
+ ui32 = (ui32 << 8) | (buf[3] & 0xFF);
+ return ret;
+ }
+ FORCE_INLINE static int read_ui64(uint64_t &ui64, ByteStream &in)
+ {
+ int ret = common::E_OK;
+ uint8_t buf[8];
+ uint32_t read_len = 0;
+ if (RET_FAIL(in.read_buf(buf, 8, read_len))) {
+ return ret;
+ }
+ ui64 = buf[0];
+ ui64 = (ui64 << 8) | (buf[1] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[2] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[3] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[4] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[5] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[6] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[7] & 0xFF);
+ return ret;
+ }
+ // caller guarantee buffer has at least 1 byte
+ FORCE_INLINE static uint8_t read_ui8(char *buffer)
+ {
+ return *(uint8_t*)buffer;
+ }
+
+ // caller guarantee buffer has at least 2 bytes
+ FORCE_INLINE static uint16_t read_ui16(char *buffer)
+ {
+ uint8_t *buf = (uint8_t*)buffer;
+ uint16_t ui16 = buf[0];
+ ui16 = (ui16 << 8) | (buf[1] & 0xFF);
+ return ui16;
+ }
+ // caller guarantee buffer has at least 4 bytes
+ FORCE_INLINE static uint32_t read_ui32(char *buffer)
+ {
+ uint8_t *buf = (uint8_t*)buffer;
+ uint32_t ui32 = buf[0];
+ ui32 = (ui32 << 8) | (buf[1] & 0xFF);
+ ui32 = (ui32 << 8) | (buf[2] & 0xFF);
+ ui32 = (ui32 << 8) | (buf[3] & 0xFF);
+ return ui32;
+ }
+ // caller guarantee buffer has at least 8 bytes
+ FORCE_INLINE static uint64_t read_ui64(char *buffer)
+ {
+ uint8_t *buf = (uint8_t*)buffer;
+ uint64_t ui64 = buf[0];
+ ui64 = (ui64 << 8) | (buf[1] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[2] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[3] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[4] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[5] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[6] & 0xFF);
+ ui64 = (ui64 << 8) | (buf[7] & 0xFF);
+ return ui64;
+ }
+
+ FORCE_INLINE static int write_float(float f, ByteStream &out)
+ {
+ uint8_t bytes[4];
+ float_to_bytes(f, bytes);
+ return out.write_buf(bytes, 4);
+ }
+ FORCE_INLINE static int read_float(float &f, ByteStream &in)
+ {
+ int ret = common::E_OK;
+ uint8_t bytes[4];
+ uint32_t read_len = 0;
+ if (RET_FAIL(in.read_buf(bytes, 4, read_len))) {
+ } else if (read_len != 4) {
+ ret = common::E_BUF_NOT_ENOUGH;
+ } else {
+ f = bytes_to_float(bytes);
+ }
+ return ret;
+ }
+ FORCE_INLINE static float read_float(char *buffer)
+ {
+ uint8_t *buf = (uint8_t*)buffer;
+ return bytes_to_float(buf);
+ }
+ FORCE_INLINE static int write_double(double d, ByteStream &out)
+ {
+ uint8_t bytes[8];
+ double_to_bytes(d, bytes);
+ return out.write_buf(bytes, 8);
+ }
+ FORCE_INLINE static int read_double(double &d, ByteStream &in)
+ {
+ int ret = common::E_OK;
+ uint32_t read_len = 0;
+ uint8_t bytes[8];
+ if (RET_FAIL(in.read_buf(bytes, 8, read_len))) {
+ } else if (read_len != 8) {
+ ret = common::E_BUF_NOT_ENOUGH;
+ } else {
+ d = bytes_to_double(bytes);
+ }
+ return ret;
+ }
+ FORCE_INLINE static double read_double(char *buffer)
+ {
+ uint8_t *buf = (uint8_t*)buffer;
+ return bytes_to_double(buf);
+ }
+
+ FORCE_INLINE static int write_i8(int8_t i8, ByteStream &out) { return write_ui8((uint8_t)i8, out); }
+ FORCE_INLINE static int write_i16(int16_t i16, ByteStream &out) { return write_ui16((uint16_t)i16, out); }
+ FORCE_INLINE static int write_i32(int32_t i32, ByteStream &out) { return write_ui32((uint32_t)i32, out); }
+ FORCE_INLINE static int write_i64(int64_t i64, ByteStream &out) { return write_ui64((uint64_t)i64, out); }
+
+ FORCE_INLINE static int read_i8(int8_t &i8, ByteStream &in) { return read_ui8((uint8_t&)i8, in); }
+ FORCE_INLINE static int read_i16(int16_t &i16, ByteStream &in) { return read_ui16((uint16_t&)i16, in); }
+ FORCE_INLINE static int read_i32(int32_t &i32, ByteStream &in) { return read_ui32((uint32_t&)i32, in); }
+ FORCE_INLINE static int read_i64(int64_t &i64, ByteStream &in) { return read_ui64((uint64_t&)i64, in); }
+
+ // TODO more test on var_xxx
+ FORCE_INLINE static int do_write_var_uint(uint32_t ui32, ByteStream &out)
+ {
+ int ret = common::E_OK;
+ while ((ui32 & 0xFFFFFF80) != 0) {
+ if (RET_FAIL(write_ui8((ui32 & 0x7F) | 0x80, out))) {
+ return ret;
+ }
+ ui32 = ui32 >> 7;
+ }
+ return write_ui8(ui32 & 0x7F, out);
+ }
+ FORCE_INLINE static int do_write_var_uint(uint32_t ui32, char *out_buf, const uint32_t out_buf_len)
+ {
+ uint32_t offset = 0;
+ while ((ui32 & 0xFFFFFF80) != 0) {
+ if (offset >= out_buf_len) {
+ return common::E_BUF_NOT_ENOUGH;
+ }
+ *(out_buf + offset) = (ui32 & 0x7F) | 0x80;
+ ui32 = ui32 >> 7;
+ offset++;
+ }
+ if (offset >= out_buf_len) {
+ return common::E_BUF_NOT_ENOUGH;
+ }
+ *(out_buf + offset) = (ui32 & 0x7F);
+ return common::E_OK;
+ }
+ FORCE_INLINE static int do_read_var_uint(uint32_t &ui32, ByteStream &in)
+ {
+ // Follow readUnsignedVarInt in ReadWriteForEncodingUtils.java
+ int ret = common::E_OK;
+ ui32 = 0;
+ int i = 0;
+ uint8_t ui8 = 0;
+ if (RET_FAIL(read_ui8(ui8, in))) {
+ return ret;
+ }
+ while (ui8 != 0xF && (ui8 & 0x80) != 0) {
+ ui32 = ui32 | ((ui8 &0x7F) << i);
+ i = i + 7;
+ if (RET_FAIL(read_ui8(ui8, in))) {
+ return ret;
+ }
+ }
+ ui32 = ui32 | (ui8 << i);
+ return ret;
+ }
+ FORCE_INLINE static int do_read_var_uint(uint32_t &ui32, char *in_buf, int in_buf_len, int *ret_offset)
+ {
+ ui32 = 0;
+ int i = 0;
+ uint8_t ui8 = 0;
+ int offset = 0;
+ if (offset < in_buf_len) {
+ ui8 = *(uint8_t*)(in_buf + offset);
+ offset++;
+ } else {
+ return common::E_BUF_NOT_ENOUGH;
+ }
+ while (ui8 != 0xF && (ui8 & 0x80) != 0) {
+ ui32 = ui32 | ((ui8 &0x7F) << i);
+ i = i + 7;
+ if (offset < in_buf_len) {
+ ui8 = *(uint8_t*)(in_buf + offset);
+ offset++;
+ } else {
+ return common::E_BUF_NOT_ENOUGH;
+ }
+ }
+ ui32 = ui32 | (ui8 << i);
+ if (ret_offset != nullptr) {
+ *ret_offset = offset;
+ }
+ return common::E_OK;
+ }
+ FORCE_INLINE static int write_var_int(int32_t i32, ByteStream &out)
+ {
+ // TODO 8byte to 4byte.
+ // but in IoTDB java, it has only write_var_uint(i32)
+ i32 = i32 << 1;
+ return do_write_var_uint((uint32_t)i32, out);
+ }
+ FORCE_INLINE static int read_var_int(int32_t &i32, ByteStream &in)
+ {
+ int ret = common::E_OK;
+ uint32_t ui32;
+ if (RET_FAIL(do_read_var_uint(ui32, in))) {
+ } else {
+ i32 = (int32_t)(ui32 >> 1);
+ }
+ return ret;
+ }
+ FORCE_INLINE static int write_var_uint(uint32_t ui32, ByteStream &out) { return do_write_var_uint(ui32, out); }
+ FORCE_INLINE static int write_var_uint(uint32_t ui32, char *out_buf, const uint32_t out_buf_len)
+ {
+ return do_write_var_uint(ui32, out_buf, out_buf_len);
+ }
+ FORCE_INLINE static int read_var_uint(uint32_t &ui32, ByteStream &in) { return do_read_var_uint(ui32, in); }
+ FORCE_INLINE static int read_var_uint(uint32_t &ui32, char *in_buf, int in_buf_len, int *ret_offset = nullptr)
+ {
+ return do_read_var_uint(ui32, in_buf, in_buf_len, ret_offset);
+ }
+
+ FORCE_INLINE static int write_str(const std::string &str, ByteStream &out)
+ {
+ int ret = common::E_OK;
+ if (RET_FAIL(write_var_int(((int32_t)str.size()), out))) {
+ } else if (RET_FAIL(out.write_buf(str.c_str(), str.size()))) {
+ }
+ return ret;
+ }
+ FORCE_INLINE static int read_str(std::string &str, ByteStream &in)
+ {
+ int ret = common::E_OK;
+ int32_t len = 0;
+ int32_t read_len = 0;
+ if (RET_FAIL(read_var_int(len, in))) {
+ } else {
+ char *tmp_buf = (char*)malloc(len + 1);
+ tmp_buf[len] = '\0';
+ if (RET_FAIL(in.read_buf(tmp_buf, len, read_len))) {
+ } else if (len != read_len) {
+ ret = E_BUF_NOT_ENOUGH;
+ } else {
+ str = std::string(tmp_buf);
+ }
+ free(tmp_buf);
+ }
+ return ret;
+ }
+ FORCE_INLINE static int write_mystring(const String &str, ByteStream &out)
+ {
+ int ret = common::E_OK;
+ if (RET_FAIL(write_var_int(str.len_, out))) {
+ } else if (RET_FAIL(out.write_buf(str.buf_, str.len_))) {
+ }
+ return ret;
+ }
+ FORCE_INLINE static int read_mystring(String &str, common::PageArena *pa, ByteStream &in)
+ {
+ int ret = common::E_OK;
+ int32_t len = 0;
+ int32_t read_len = 0;
+ if (RET_FAIL(read_var_int(len, in))) {
+ } else {
+ char *buf = (char*)pa->alloc(len);
+ if (IS_NULL(buf)) {
+ ret = common::E_OOM;
+ } else {
+ if (RET_FAIL(in.read_buf(buf, len, read_len))) {
+ } else if (len != read_len) {
+ ret = E_BUF_NOT_ENOUGH;
+ } else {
+ str.buf_ = buf;
+ str.len_ = len;
+ }
+ }
+ }
+ return ret;
+ }
+ FORCE_INLINE static int write_char(char ch, ByteStream &out) { return write_ui8(ch, out); }
+ FORCE_INLINE static int read_char(char &ch, ByteStream &in) { return read_ui8((uint8_t&)ch, in); }
+};
+
+FORCE_INLINE bool deserialize_buf_not_enough(int ret)
+{
+ return ret == E_OUT_OF_RANGE || ret == E_PARTIAL_READ;
+}
+FORCE_INLINE char *get_bytes_from_bytestream(ByteStream &bs)
+{
+ if (bs.total_size() == 0) {
+ return nullptr;
+ }
+ uint32_t size = bs.total_size();
+ char *ret_buf = (char*)malloc(size);
+ if (ret_buf == nullptr) {
+ return nullptr;
+ }
+
+ ByteStream::BufferIterator buf_iter = bs.init_buffer_iterator();
+ uint32_t offset = 0;
+ while (true) {
+ ByteStream::Buffer buf = buf_iter.get_next_buf();
+ if (buf.buf_ == nullptr) {
+ break;
+ } else {
+ assert(offset + buf.len_ <= size);
+ memcpy(ret_buf + offset, buf.buf_, buf.len_);
+ offset += buf.len_;
+ }
+ }
+ assert(offset == size);
+ return ret_buf;
+}
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_ALLOCATOR_BYTE_STREAM_H
+
diff --git a/cpp/tsfile/src/common/allocator/mem_alloc.cc b/cpp/tsfile/src/common/allocator/mem_alloc.cc
new file mode 100644
index 00000000..5f1a16e2
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/mem_alloc.cc
@@ -0,0 +1,236 @@
+
+#include <iostream>
+#include <string.h>
+#include <execinfo.h>
+
+
+#include "stdlib.h"
+#include "stdio.h"
+#include "alloc_base.h"
+#include "../util_define.h"
+#include "../logger/elog.h"
+
+namespace timecho
+{
+namespace common
+{
+
+const char *g_mod_names[__LAST_MOD_ID] = {
+ /* 0 */ "DEFAULT",
+ /* 1 */ "MEMTABLE",
+ /* 2 */ "SCHEMA",
+ /* 3 */ "SQL",
+ /* 4 */ "NET",
+ /* 5 */ "NET_DATA",
+ /* 6 */ "TVLIST_DATA",
+ /* 7 */ "TVLIST_OBJ",
+ /* 8 */ "TSBLOCK",
+ /* 9 */ "CONTAINER",
+ /* 10 */ "TSSTORE_OBJ",
+ /* 11 */ "FLUSH_TASK_OBJ",
+ /* 12 */ "PAGE_WRITER_OUTPUT_STREAM",
+ /* 13 */ "CW_PAGES_DATA",
+ /* 14 */ "CHUNK_WRITER_OBJ",
+ /* 15 */ "STATISTIC_OBJ",
+ /* 16 */ "ENCODER_OBJ",
+ /* 17 */ "DECODER_OBJ",
+ /* 18 */ "TSFILE_WRITER_META",
+ /* 19 */ "TSFILE_WRITE_STREAM",
+ /* 20 */ "TIMESERIES_INDEX_OBJ",
+ /* 21 */ "BLOOM_FILTER",
+ /* 22 */ "OPEN_FILE_OBJ",
+ /* 23 */ "TSFILE_READER",
+ /* 24 */ "CHUNK_READER",
+ /* 25 */ "COMPRESSOR_OBJ",
+ /* 26 */ "ARRAY",
+ /* 27 */ "HASH_TABLE",
+};
+
+const uint32_t HEADER_SIZE_4B = 4;
+const uint32_t HEADER_SIZE_8B = 8;
+
+void *mem_alloc(uint32_t size, AllocModID mid)
+{
+ // use 7bit at most
+ ASSERT(mid <= 127);
+
+ if (size <= 0xFFFFFF) {
+ // use 3B size + 1B mod
+ char *p = (char*)malloc(size + HEADER_SIZE_4B);
+ if (UNLIKELY(p == nullptr)) {
+ std::cout<<"alloc filed for size " << size + HEADER_SIZE_4B << std::endl;
+ return nullptr;
+ } else {
+ uint32_t header = (size << 8) | ((uint32_t)mid);
+ *((uint32_t*)p) = header;
+ ModStat::get_instance().update_alloc(mid, size);
+ // cppcheck-suppress memleak
+ // cppcheck-suppress unmatchedSuppression
+ return p + HEADER_SIZE_4B;
+ }
+ } else {
+ char *p = (char*)malloc(size + HEADER_SIZE_8B);
+ if (UNLIKELY(p == nullptr)) {
+ std::cout<<"alloc big filed for size " << size + HEADER_SIZE_4B << std::endl;
+ return nullptr;
+ } else {
+ uint64_t large_size = size;
+ uint64_t header = ((large_size) << 8) | (((uint32_t)mid) | (0x80));
+ uint32_t low4b = (uint32_t)(header & 0xFFFFFFFF);
+ uint32_t high4b = (uint32_t)(header >> 32);
+ *(uint32_t*)p = high4b;
+ *(uint32_t*)(p + 4) = low4b;
+ ModStat::get_instance().update_alloc(mid, size);
+ // cppcheck-suppress unmatchedSuppression
+ // cppcheck-suppress memleak
+ return p + HEADER_SIZE_8B;
+ }
+ }
+}
+
+void printCallers()
+{
+ int layers = 0, i = 0;
+ char **symbols = NULL;
+
+ const int64_t MAX_FRAMES = 32;
+
+ void *frames[MAX_FRAMES];
+ memset(frames, 0, sizeof(frames));
+ layers = backtrace(frames, MAX_FRAMES);
+ for (i = 0; i < layers; i++) {
+ printf("Layer %d: %p\n", i, frames[i]);
+ }
+ printf("------------------\n");
+
+ symbols = backtrace_symbols(frames, layers);
+ if (symbols) {
+ for (i = 0; i < layers; i++) {
+ printf("SYMBOL layer %d: %s\n", i, symbols[i]);
+ }
+ free(symbols);
+ } else {
+ printf("Failed to parse function names\n");
+ }
+}
+
+void mem_free(void *ptr)
+{
+ // try as 4Byte header
+ char *p = (char*)ptr;
+ uint32_t header = *(uint32_t*)(p - HEADER_SIZE_4B);
+ if ((header & 0x80) == 0) {
+ // 4Byte header
+ uint32_t size = header >> 8;
+ AllocModID mid = (AllocModID)(header & 0x7F);
+ ModStat::get_instance().update_free(mid, size);
+ ::free(p - HEADER_SIZE_4B);
+ } else {
+ // 8Byte header
+ uint64_t header8b = ((uint64_t)(*(uint32_t*)(p - 4))) | ((uint64_t)(*(uint32_t*)(p - 8)) << 32);
+ AllocModID mid = (AllocModID)(header8b & 0x7F);
+ uint32_t size = (uint32_t)(header8b >> 8);
+ ModStat::get_instance().update_free(mid, size);
+ ::free(p - HEADER_SIZE_8B);
+ }
+}
+
+void *mem_realloc(void *ptr, uint32_t size)
+{
+ AllocModID mid_org;
+ uint32_t size_org;
+ char *p = (char*)ptr;
+ uint32_t header_org = *(uint32_t*)(p - HEADER_SIZE_4B);// try as 4Byte header
+ if ((header_org & 0x80) == 0) {
+ // header_org is 4byte
+ size_org = header_org >> 8;
+ mid_org = (AllocModID)(header_org & 0x7F);
+ if (size <= 0xFFFFFF) {
+ p = (char *) realloc(p - HEADER_SIZE_4B, size + HEADER_SIZE_4B);
+ if (UNLIKELY(p == nullptr)) {
+ return nullptr;
+ } else {
+ uint32_t header = (size << 8) | ((uint32_t)mid_org); //size changed
+ *((uint32_t*)p) = header;
+ ModStat::get_instance().update_alloc(mid_org, int32_t(size) - int32_t(size_org));
+ return p + HEADER_SIZE_4B;
+ }
+ } else { // size > 0xFFFFFF, realloc(os_p, size + header_len)
+ p = (char *) realloc(p - HEADER_SIZE_4B, size + HEADER_SIZE_8B);
+ if (UNLIKELY(p == nullptr)) {
+ return nullptr;
+ } else {
+ std::memmove(p + HEADER_SIZE_8B, p + HEADER_SIZE_4B, size_org);
+ // reconstruct 8-byte header
+ uint64_t large_size = size;
+ uint64_t header = ((large_size) << 8) | (((uint32_t)mid_org) | (0x80));
+ uint32_t low4b = (uint32_t)(header & 0xFFFFFFFF);
+ uint32_t high4b = (uint32_t)(header >> 32);
+ *(uint32_t*)p = high4b;
+ *(uint32_t*)(p + 4) = low4b;
+ ModStat::get_instance().update_alloc(mid_org, int32_t(size) - int32_t(size_org));
+ return p + HEADER_SIZE_8B;
+ }
+ }
+ } else { // header_org is 8byte
+ uint64_t header = ((uint64_t)(*(uint32_t*)(p - 4))) | ((uint64_t)(*(uint32_t*)(p - 8)) << 32); // 8Byte header
+ mid_org = (AllocModID)(header & 0x7F);
+ size_org = (uint32_t)(header >> 8);
+ if (size <= 0xFFFFFF) {
+ uint32_t save_data = *(uint32_t*)(p - HEADER_SIZE_8B + HEADER_SIZE_4B + size);
+ p = (char *) realloc(p - HEADER_SIZE_8B, size + HEADER_SIZE_4B);
+ if (UNLIKELY(p == nullptr)) {
+ return nullptr;
+ } else {
+ std::memmove(p + HEADER_SIZE_4B, p + HEADER_SIZE_8B, size - HEADER_SIZE_4B);
+ // reconstruct 4-byte header
+ uint32_t header4b = (size << 8) | (((uint32_t)mid_org));
+ *((uint32_t*)p) = header4b;
+ // reconstruct data
+ *(uint32_t*)((char*)p + size - 4) = save_data;
+ ModStat::get_instance().update_alloc(mid_org, int32_t(size) - int32_t(size_org));
+ return p + HEADER_SIZE_4B;
+ }
+ } else {
+ p = (char *) realloc(p - HEADER_SIZE_8B, size + HEADER_SIZE_8B);
+ if (UNLIKELY(p == nullptr)) {
+ return nullptr;
+ } else {
+ uint64_t large_size = size;
+ uint64_t header8b = ((large_size) << 8) | (((uint32_t)mid_org) | (0x80));
+ uint32_t low4b = (uint32_t)(header8b & 0xFFFFFFFF);
+ uint32_t high4b = (uint32_t)(header8b >> 32);
+ *(uint32_t*)p = high4b;
+ *(uint32_t*)(p + 4) = low4b;
+ ModStat::get_instance().update_alloc(mid_org, int32_t(size) - int32_t(size_org));
+ return p + HEADER_SIZE_8B;
+ }
+ }
+ }
+}
+
+void ModStat::init()
+{
+ stat_arr_ = (int32_t*)(::malloc(ITEM_SIZE * ITEM_COUNT));
+ for (int8_t i = 0; i < __LAST_MOD_ID; i++) {
+ int32_t *item = get_item(i);
+ *item = 0;
+ }
+}
+
+void ModStat::destroy()
+{
+ ::free(stat_arr_);
+}
+
+// TODO return to SQL
+void ModStat::print_stat()
+{
+ //
+}
+
+BaseAllocator g_base_allocator;
+
+} // end namespace common
+} // end namespace timecho
+
diff --git a/cpp/tsfile/src/common/allocator/my_string.h b/cpp/tsfile/src/common/allocator/my_string.h
new file mode 100644
index 00000000..4deaafd2
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/my_string.h
@@ -0,0 +1,143 @@
+#ifndef COMMON_ALLOCATOR_MY_STRING_H
+#define COMMON_ALLOCATOR_MY_STRING_H
+
+#include <string.h>
+#include <iostream>
+
+#include "common/allocator/page_arena.h"
+#include "common/errno_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+// String that use PageArena
+struct String
+{
+ char *buf_;
+ uint32_t len_;
+
+ String() : buf_(nullptr), len_(0) {}
+ String(char *buf, uint32_t len) : buf_(buf), len_(len) {}
+ FORCE_INLINE bool is_null() const
+ {
+ return buf_ == nullptr && len_ == 0;
+ }
+ FORCE_INLINE void reset()
+ {
+ len_ = 0;
+ buf_ = nullptr;
+ }
+ FORCE_INLINE int dup_from(const std::string &str, common::PageArena &pa)
+ {
+ len_ = str.size();
+ if (UNLIKELY(len_ == 0)) {
+ return common::E_OK;
+ }
+ buf_ = pa.alloc(len_);
+ if (IS_NULL(buf_)) {
+ return common::E_OOM;
+ }
+ memcpy(buf_, str.c_str(), len_);
+ return common::E_OK;
+ }
+ FORCE_INLINE int dup_from(const String &str, common::PageArena &pa)
+ {
+ len_ = str.len_;
+ if (UNLIKELY(len_ == 0)) {
+ return common::E_OK;
+ }
+ buf_ = pa.alloc(len_);
+ if (IS_NULL(buf_)) {
+ return common::E_OOM;
+ }
+ memcpy(buf_, str.buf_, len_);
+ return common::E_OK;
+ }
+ FORCE_INLINE int build_from(const String &s1, const String &s2, common::PageArena &pa)
+ {
+ len_ = s1.len_ + s2.len_;
+ buf_ = pa.alloc(len_);
+ if (IS_NULL(buf_)) {
+ return common::E_OOM;
+ }
+ memcpy(buf_, s1.buf_, s1.len_);
+ memcpy(buf_ + s1.len_, s2.buf_, s2.len_);
+ return common::E_OK;
+ }
+ FORCE_INLINE void shallow_copy_from(const String &src)
+ {
+ buf_ = src.buf_;
+ len_ = src.len_;
+ }
+ FORCE_INLINE bool equal_to(const String &that) const
+ {
+ return (len_ == 0 && that.len_ == 0)
+ || ((len_ == that.len_) && (0 == memcmp(buf_, that.buf_, len_)));
+ }
+
+ // FORCE_INLINE bool equal_to(const std::string &that)
+ // {
+ // return (len_ == 0 && that.size() == 0)
+ // || ((len_ == that.len_) && (0 == memcmp(buf_, that.c_str(), len_)));
+ // }
+
+ // strict less than. If @this equals to @that, return false.
+ FORCE_INLINE bool less_than(const String &that) const
+ {
+ if (len_ == 0 || that.len_ == 0) {
+ return false;
+ }
+ uint32_t min_len = std::min(len_, that.len_);
+ int cmp_res = memcmp(buf_, that.buf_, min_len);
+ if (cmp_res < 0) {
+ return true;
+ } else if (cmp_res > 0) {
+ return false;
+ } else {
+ return len_ < that.len_;
+ }
+ }
+
+ // return = 0, if this = that
+ // return < 0, if this < that
+ // return > 0, if this > that
+ FORCE_INLINE int compare(const String &that) const
+ {
+ if (len_ == 0 || that.len_ == 0) {
+ return 0;
+ }
+ uint32_t min_len = std::min(len_, that.len_);
+ int cmp_res = memcmp(buf_, that.buf_, min_len);
+ if (cmp_res == 0) {
+ return len_ - that.len_;
+ } else {
+ return cmp_res;
+ }
+ }
+
+#ifndef NDEBUG
+ friend std::ostream& operator << (std::ostream &os, const String &s)
+ {
+ os << s.len_ << "@";
+ for (uint32_t i = 0; i < s.len_; i++) {
+ os << s.buf_[i];
+ }
+ return os;
+ }
+#endif // ifndef NDEBUG
+};
+
+struct StringLessThan
+{
+ FORCE_INLINE bool operator()(const String &s1, const String &s2) const
+ {
+ return s1.less_than(s2);
+ }
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_ALLOCATOR_MY_STRING_H
diff --git a/cpp/tsfile/src/common/allocator/object_pool.h b/cpp/tsfile/src/common/allocator/object_pool.h
new file mode 100644
index 00000000..c60ae558
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/object_pool.h
@@ -0,0 +1,104 @@
+
+#ifndef COMMON_ALLOCTOR_OBJECT_POOL_H
+#define COMMON_ALLOCTOR_OBJECT_POOL_H
+
+#include "common/allocator/alloc_base.h"
+#include "common/mutex/mutex.h"
+
+namespace timecho
+{
+namespace common
+{
+
+template<class T>
+class ObjectPool
+{
+private:
+ struct ObjectPoolNode
+ {
+ T data_;
+ ObjectPoolNode *next_;
+
+ ObjectPoolNode() : data_(), next_(nullptr) {}
+ };
+
+public:
+ /*
+ * max_cache_count is a soft limitation:
+ */
+ ObjectPool(const uint32_t max_cache_count,
+ const AllocModID mid,
+ BaseAllocator &allocator = g_base_allocator)
+ : max_cache_count_(max_cache_count),
+ cur_alloc_count_(0),
+ mid_(mid),
+ allocator_(allocator),
+ mutex_(),
+ head_(nullptr)
+ {
+ assert(max_cache_count > 1);
+ }
+
+ ~ObjectPool() { destroy(); }
+
+ void destroy()
+ {
+ ObjectPoolNode *cur = head_;
+ while (cur) {
+ head_ = cur->next_;
+ allocator_.free(cur);
+ cur = head_;
+ cur_alloc_count_--;
+ }
+ ASSERT(cur_alloc_count_ == 0);
+ }
+
+ T *alloc()
+ {
+ T *ret_obj = nullptr;
+ common::MutexGuard g(mutex_);
+ if (head_) {
+ ret_obj = &(head_->data_);
+ head_ = head_->next_;
+ return ret_obj;
+ } else {
+ void *buf = allocator_.alloc(sizeof(ObjectPoolNode), mid_);
+ if (UNLIKELY(buf == nullptr)) {
+ return nullptr;
+ }
+ cur_alloc_count_++;
+ ret_obj = &(new (buf) ObjectPoolNode)->data_;
+ return ret_obj;
+ }
+ }
+
+ void free(T* obj)
+ {
+ ASSERT(obj != nullptr);
+ common::MutexGuard g(mutex_);
+ if (cur_alloc_count_ > max_cache_count_) {
+ allocator_.free(obj);
+ cur_alloc_count_--;
+ ASSERT(cur_alloc_count_ >= 0);
+ } else {
+ ObjectPoolNode *n = (ObjectPoolNode*)obj;
+ n->next_ = head_;
+ head_ = n;
+ }
+ }
+
+ uint32_t get_cur_alloc_count() const { return cur_alloc_count_; }
+private:
+ uint32_t max_cache_count_;
+ uint32_t cur_alloc_count_;
+ AllocModID mid_;
+ BaseAllocator allocator_;
+ common::Mutex mutex_;
+ ObjectPoolNode *head_; // freelist head
+};
+
+} // end namspace common
+} // end namespace timecho
+
+#endif // COMMON_ALLOCTOR_OBJECT_POOL_H
+
diff --git a/cpp/tsfile/src/common/allocator/page_arena.cc b/cpp/tsfile/src/common/allocator/page_arena.cc
new file mode 100644
index 00000000..b43bc790
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/page_arena.cc
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include "page_arena.h"
+#include <new>
+
+namespace timecho
+{
+namespace common
+{
+
+char *PageArena::alloc(uint32_t size)
+{
+ if (LIKELY(size <= page_size_)) {
+ Page *cur_page = dummy_head_.next_;
+ if (LIKELY(cur_page != nullptr)) {
+ char *ret_ptr = cur_page->alloc(size);
+ if (LIKELY(ret_ptr != nullptr)) {
+ return ret_ptr;
+ }
+ }
+
+ /*
+ * cur_page is null OR can not alloc @size from cur_page,
+ * then alloc new page
+ */
+ void *ptr = base_allocator_.alloc(page_size_ + sizeof(Page), mid_);
+ if (UNLIKELY(ptr == nullptr)) {
+ return nullptr;
+ }
+ Page *new_page = new(ptr) Page(page_size_, cur_page);
+ dummy_head_.next_ = new_page;
+ return new_page->alloc(size);
+ } else {
+ void *ptr = base_allocator_.alloc(size + sizeof(Page), mid_);
+ Page *new_page = new(ptr) Page(dummy_head_.next_);
+ dummy_head_.next_ = new_page;
+ return reinterpret_cast<char*>(new_page) + sizeof(Page);
+ }
+}
+
+void PageArena::reset()
+{
+ Page *p = dummy_head_.next_;
+ while (p) {
+ dummy_head_.next_ = p->next_;
+ base_allocator_.free(p);
+ p = dummy_head_.next_;
+ }
+}
+
+} // end namespace common
+} // end namespace timecho
+
diff --git a/cpp/tsfile/src/common/allocator/page_arena.h b/cpp/tsfile/src/common/allocator/page_arena.h
new file mode 100644
index 00000000..d2115411
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/page_arena.h
@@ -0,0 +1,90 @@
+
+#ifndef COMMON_ALLOCATOR_PAGE_ARENA_H
+#define COMMON_ALLOCATOR_PAGE_ARENA_H
+
+#include "alloc_base.h"
+
+namespace timecho
+{
+namespace common
+{
+
+/*
+ * Not Thread Safe
+ */
+class PageArena
+{
+public:
+ explicit PageArena(BaseAllocator &base_allocator = g_base_allocator)
+ : page_size_(0),
+ mid_(__FIRST_MOD_ID),
+ base_allocator_(base_allocator),
+ dummy_head_() {}
+ ~PageArena() { destroy(); }
+ void init(uint32_t page_size, AllocModID mid)
+ {
+ page_size_ = page_size;
+ mid_ = mid;
+ }
+
+ char *alloc(uint32_t size);
+ FORCE_INLINE void destroy() { reset(); }
+ void reset();
+
+#ifdef ENABLE_TEST
+ int TEST_get_page_count() const
+ {
+ int count = 0;
+ Page *p = dummy_head_.next_;
+ while (p) {
+ p = p->next_;
+ count++;
+ }
+ return count;
+ }
+#endif
+
+private:
+ class Page
+ {
+ public:
+ Page() : next_(nullptr), page_end_(nullptr), cur_alloc_(nullptr) {}
+ explicit Page(Page *next_page) : next_(next_page), page_end_(nullptr), cur_alloc_(nullptr) {}
+ Page(uint32_t page_size, Page *next_page)
+ {
+ next_ = next_page;
+ cur_alloc_ = (char*)this + sizeof(Page); // equals to (char*)(this+1)
+ page_end_ = cur_alloc_ + page_size;
+ }
+ INLINE char *alloc(uint32_t size)
+ {
+ if (cur_alloc_ + size > page_end_) {
+ return nullptr;
+ } else {
+ char *ret = cur_alloc_;
+ cur_alloc_ += size;
+ int address = reinterpret_cast<uintptr_t>(cur_alloc_);
+ int new_addr = (address + 3) & (~3);
+ cur_alloc_ = reinterpret_cast<char *>(new_addr);
+ return ret;
+ }
+ }
+
+ public:
+ Page *next_;
+ char *page_end_;
+ char *cur_alloc_; // buf_'s current offset
+ };
+
+private:
+ uint32_t page_size_;
+ AllocModID mid_;
+ BaseAllocator &base_allocator_;
+ Page dummy_head_;
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_ALLOCATOR_PAGE_ARENA_H
+
diff --git a/cpp/tsfile/src/common/allocator/stl_allocator.h b/cpp/tsfile/src/common/allocator/stl_allocator.h
new file mode 100644
index 00000000..5be4cb59
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/stl_allocator.h
@@ -0,0 +1,68 @@
+
+#ifndef COMMON_ALLOCATOR_STL_ALLOCATOR_H
+#define COMMON_ALLOCATOR_STL_ALLOCATOR_H
+
+#include "alloc_base.h"
+
+namespace timecho
+{
+namespace common
+{
+
+template<class T, AllocModID Mid, class TAllocator=BaseAllocator>
+class StlAllocator
+{
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ /*
+ * rebind provides a way to obtain an allocator for a different type.
+ * For example, std::list will alloc object Node<T> beside alloc object T.
+ */
+ template<class U>
+ struct rebind { typedef StlAllocator<U, Mid, TAllocator> other; };
+
+ StlAllocator() {}
+ StlAllocator(const StlAllocator&) {}
+
+ template<class T2, AllocModID Mid2>
+ StlAllocator(const StlAllocator<T2, Mid2, TAllocator>&) {}
+
+ StlAllocator(TAllocator base_allocator) : base_allocator_(base_allocator) {}
+
+ pointer address(reference x) const { return &x; }
+ const_pointer address(const_reference x) { return &x; }
+
+ pointer allocate(size_type n, const void *hint = 0) { return (pointer)base_allocator_.alloc(n * sizeof(T), Mid); };
+ void deallocate(void *p, size_type) { base_allocator_.free(p); }
+ size_type max_size() const { return uint32_t(-1); }
+
+ void construct(pointer p, const T& val) { new ((T*)p) T(val); }
+ void destroy(pointer p) { p->~T(); }
+
+private:
+ TAllocator base_allocator_;
+};
+
+/*
+ * According to the manual, allocator is stateless.
+ * Although we define a base_allocator_ here, but base_allocator_ is also stateless.
+ * so '==' is always true and '!=' is always false.
+ * refer to https://en.cppreference.com/w/cpp/memory/allocator/operator_cmp.
+ */
+template<class T1, AllocModID Mid1, class T2, AllocModID Mid2>
+bool operator==(const StlAllocator<T1, Mid1> &a1, const StlAllocator<T2, Mid2> &a2) { return true; }
+
+template<class T1, AllocModID Mid1, class T2, AllocModID Mid2>
+bool operator!=(const StlAllocator<T1, Mid1> &a1, const StlAllocator<T2, Mid2> &a2) { return false; }
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_ALLOCATOR_STL_ALLOCATOR_H
diff --git a/cpp/tsfile/src/common/allocator/util_define.h b/cpp/tsfile/src/common/allocator/util_define.h
new file mode 100644
index 00000000..4d85ef52
--- /dev/null
+++ b/cpp/tsfile/src/common/allocator/util_define.h
@@ -0,0 +1,136 @@
+
+/*
+ * This file defines some basic macros
+ */
+
+#ifndef COMMON_UTIL_DEFINE_H
+#define COMMON_UTIL_DEFINE_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+
+/* ======== cmake config define ======== */
+
+/* ======== unsued ======== */
+#define UNUSED(v) ((void)(v))
+
+
+/* ======== inline ======== */
+#ifdef __GNUC__
+#define FORCE_INLINE inline __attribute__((always_inline))
+#else
+#define FORCE_INLINE inline
+#endif // __GNUC__
+
+#ifdef BUILD_FOR_SMALL_BINARY
+#define INLINE FORCE_INLINE
+#else
+#define INLINE
+#endif // BUILD_FOR_SMALL_BINARY
+
+
+/* ======== likely ======== */
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define LIKELY(x) (__builtin_expect((x), 1))
+#define UNLIKELY(x) (__builtin_expect((x), 0))
+#else
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#endif // __GNUC__ >= 4
+
+
+/* ======== nullptr ======== */
+#if __cplusplus < 201103L
+#ifndef nullptr
+#define nullptr NULL
+#endif
+#define OVERRIDE
+#else
+#define OVERRIDE override
+#endif // __cplusplus < 201103L
+
+
+/* ======== cache line ======== */
+#ifndef CACHE_LINE_SIZE
+#define CACHE_LINE_SIZE 64
+#endif // CACHE_LINE_SIZE
+
+
+/* ======== assert ======== */
+#ifdef NDEBUG
+#define ASSERT(condition) ((void)0)
+#else
+#define ASSERT(condition) assert((condition))
+#endif // NDEBUG
+
+/* ======== statis assert ======== */
+/*
+ * To be compatible with C++ before C++11,
+ * @msg should be a single word (use -/_ to concat)
+ * such as This_should_be_TRUE
+ */
+#if __cplusplus < 201103L
+// TODO only define this when DEBUG
+#define STATIC_ASSERT(cond, msg) typedef char static_assertion_##msg[(cond) ? 1 : -1] __attribute__((unused))
+#else
+#define STATIC_ASSERT(cond, msg) static_assert((cond), #msg)
+#endif // __cplusplus < 201103L
+
+
+/* ======== atomic operation ======== */
+#define ATOMIC_FAA(val_addr, addv) __atomic_fetch_add((val_addr), (addv), __ATOMIC_SEQ_CST)
+#define ATOMIC_AAF(val_addr, addv) __atomic_add_fetch((val_addr), (addv), __ATOMIC_SEQ_CST)
+/*
+ * It implements an atomic compare and exchange operation.
+ * This compares the contents of *ptr with the contents of *expected.
+ * - If equal, the operation is a read-modify-write operation that writes desired into *ptr.
+ * - If they are not equal, the operation is a read and the current contents of *ptr are written into *expected
+ */
+#define ATOMIC_CAS(val_addr, expected, desired) \
+ __atomic_compare_exchange_n((val_addr), (expected),(desired), \
+ /* weak = */ false, \
+ /* success_memorder = */ __ATOMIC_SEQ_CST, \
+ /* failure_memorder = */ __ATOMIC_SEQ_CST)
+#define ATOMIC_LOAD(val_addr) __atomic_load_n((val_addr), __ATOMIC_SEQ_CST)
+#define ATOMIC_STORE(val_addr, val) __atomic_store_n((val_addr), (val), __ATOMIC_SEQ_CST)
+
+/* ======== align ======== */
+#define ALIGNED(a) __attribute__((aligned(a)))
+#define ALIGNED_4 ALIGNED(4)
+#define ALIGNED_8 ALIGNED(8)
+
+/* ======== disallow copy and assign ======== */
+#if __cplusplus < 201103L
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+#else
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ TypeName& operator=(const TypeName&) = delete;
+#endif
+
+/* ======== return value check ======== */
+#define RET_FAIL(expr) UNLIKELY(common::E_OK != (ret = (expr)))
+#define RFAIL(expr) UNLIKELY(common::E_OK != (ret = (expr)))
+#define RET_SUCC(expr) LIKELY(common::E_OK != (ret = (exprt)))
+#define RSUCC(expr) LIKELY(common::E_OK != (ret = (exprt)))
+#define IS_SUCC(ret) LIKELY(common::E_OK == (ret))
+#define IS_FAIL(ret) UNLIKELY(common::E_OK != (ret))
+
+#define IS_NULL(ptr) UNLIKELY((ptr) == nullptr)
+
+/* ======== min/max ======== */
+#define UTIL_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define UTIL_MIN(a, b) ((a) > (b) ? (b) : (a))
+
+/*
+ * int64_max < 10^20
+ * consider +/- and the '\0' tail. 24 is enough
+ */
+#define INT64_TO_BASE10_MAX_LEN 24
+
+#endif // COMMON_UTIL_DEFINE_H
+
diff --git a/cpp/tsfile/src/common/config/CMakeLists.txt b/cpp/tsfile/src/common/config/CMakeLists.txt
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/cpp/tsfile/src/common/config/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+
diff --git a/cpp/tsfile/src/common/config/config.h b/cpp/tsfile/src/common/config/config.h
new file mode 100644
index 00000000..5c4754e9
--- /dev/null
+++ b/cpp/tsfile/src/common/config/config.h
@@ -0,0 +1,52 @@
+#ifndef COMMON_CONFIG_CONFIG_H
+#define COMMON_CONFIG_CONFIG_H
+
+#include <stdint.h>
+
+#include "common/util_define.h"
+#include "common/mutex/mutex.h"
+#include "common/db_utils.h"
+
+namespace timecho
+{
+namespace common
+{
+enum ConfigLevel
+{
+ INIT, // Unchangeable, initialized during database init
+ RESTART, // Can be changed, but the database must be restarted to take effect
+ USERSET // Session level update
+};
+
+typedef struct ConfigValue
+{
+ uint32_t tsblock_mem_inc_step_size_; // tsblock memory self-increment step size
+ uint32_t tsblock_max_memory_; // the maximum memory of a single tsblock
+ const char *rest_service_ip_;
+ int32_t rest_service_port_;
+ WALFlushPolicy wal_flush_policy_;
+ uint32_t seqtvlist_primary_array_size_;
+ uint32_t seqtvlist_max_record_count_;
+ uint32_t page_writer_max_point_num_;
+ uint32_t page_writer_max_memory_bytes_;
+ uint32_t max_degree_of_index_node_;
+ double tsfile_index_bloom_filter_error_percent_;
+ const char *tsfile_prefix_path_;
+ TSEncoding time_encoding_type_;
+ uint32_t memtable_flusher_poll_interval_seconds_;
+} ConfigValue;
+
+extern void init_config_value();
+
+// In the future, configuration items need to be dynamically adjusted according to the level
+extern void set_config_value();
+extern void config_set_page_max_point_count(uint32_t page_max_ponint_count);
+extern void config_set_max_degree_of_index_node(uint32_t max_degree_of_index_node);
+
+// FORCE_INLINE bool wal_cfg_enabled() { return g_config_value_.wal_flush_policy_ != WAL_DISABLED; }
+// FORCE_INLINE bool wal_cfg_should_wait_persisted() { return g_config_value_.wal_flush_policy_ >= WAL_FLUSH; }
+
+} // common
+} // timecho
+
+#endif // COMMON_CONFIG_CONFIG_H
diff --git a/cpp/tsfile/src/common/container/CMakeLists.txt b/cpp/tsfile/src/common/container/CMakeLists.txt
new file mode 100644
index 00000000..c3d4b867
--- /dev/null
+++ b/cpp/tsfile/src/common/container/CMakeLists.txt
@@ -0,0 +1,12 @@
+message("Running in src/common/container directory")
+
+aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} common_container_SRC_LIST)
+set(common_container_INC_LIST)
+set(common_container_DEFINE_OPTIONS)
+set(common_container_COMPILE_OPTIONS)
+set(common_container_LINK_OPTIONS)
+
+add_statis_objtarget(common_container common_container_SRC_LIST common_container_INC_LIST
+ "${common_container_DEFINE_OPTIONS}"
+ "${common_container_COMPILE_OPTIONS}"
+ "${common_container_LINK_OPTIONS}")
diff --git a/cpp/tsfile/src/common/container/array.h b/cpp/tsfile/src/common/container/array.h
new file mode 100644
index 00000000..70e7a891
--- /dev/null
+++ b/cpp/tsfile/src/common/container/array.h
@@ -0,0 +1,312 @@
+#ifndef COMMON_CONTAINER_ARRAY_H
+#define COMMON_CONTAINER_ARRAY_H
+
+#include <cstdlib>
+#include <cstdio>
+#include <stdint.h>
+#include <cstring>
+#include <iostream>
+#include "common/allocator/alloc_base.h"
+#include "common/logger/elog.h"
+#include "common/errno_define.h"
+#include "common/util_define.h"
+
+#define ARRAY_INIT_CAPACITY 1000 // TODO: configurable mode
+#define ARRAY_GROWTH_THRESHOLD 50 // TODO: configurable mode
+#define ARRAY_SHRINK_THRESHOLD 50 // TODO: configurable mode
+
+namespace timecho
+{
+namespace common
+{
+
+template <class ValueType>
+class Array
+{
+public:
+
+#ifndef NDEBUG
+ friend std::ostream & operator << (std::ostream &out, Array<ValueType> &sa)
+ {
+ for (size_t idx = 0; idx < sa.size(); idx++) {
+ if (idx > 0) {
+ out << ' ';
+ }
+ out << sa[idx];
+ }
+ out << std::endl;
+ return out;
+ }
+#endif // NDEBUG
+
+ Array()
+ {
+ capacity_ = ARRAY_INIT_CAPACITY;
+ size_ = 0;
+ is_inited_ = false;
+ array_ = nullptr;
+ }
+
+ Array(size_t capacity)
+ {
+ capacity_ = capacity;
+ size_ = 0;
+ is_inited_ = false;
+ array_ = nullptr;
+ }
+
+ ~Array()
+ {
+ if(is_inited_){
+ destroy();
+ }
+ capacity_ = 0;
+ size_ = 0;
+ }
+
+ // int deep_copy(const Array &other)
+ // {
+ // this->capacity_ = other.capacity_;
+ // this->size_ = other.size_;
+ // if (init() == E_OK) {
+ // memcpy(this->array_, other.array_, this->capacity_ * sizeof(*(this->array_)));
+ // return E_OK;
+ // }
+ // return E_OOM;
+ // }
+
+ int init()
+ {
+ if(is_inited_) {
+ log_error("init repeated.");
+ ASSERT(!is_inited_);
+ }
+ array_ = (ValueType *)mem_alloc(capacity_ * sizeof(*(array_)), MOD_ARRAY);
+ if (UNLIKELY(nullptr == array_)) {
+ is_inited_ = false;
+ log_error("malloc failed.");
+ return E_OOM;
+ }
+ is_inited_ = true;
+ return E_OK;
+ }
+
+ void destroy()
+ {
+ capacity_ = 0;
+ size_ = 0;
+ if (is_inited_) {
+ mem_free(array_);
+ array_ = nullptr;
+ }
+ is_inited_ = false;
+ }
+
+private:
+ static size_t linear_calc(size_t input)
+ {
+ if (input < ARRAY_GROWTH_THRESHOLD) {
+ return input;
+ }
+ size_t res = 1;
+ input /= 10;
+ while (input) {
+ input /= 10;
+ res *= 10;
+ }
+ return res;
+ }
+
+public:
+ int extend()
+ {
+ // Check for a potential overflow
+ uint64_t tmp = (uint64_t) (linear_calc(capacity_) + capacity_);
+ if (tmp > SIZE_MAX) {
+ log_error("size overflow.");
+ return E_OVERFLOW;
+ }
+
+ size_t new_capacity = (size_t) tmp;
+ array_ = (ValueType *)mem_realloc(array_, new_capacity * sizeof(*(array_)));
+ if (UNLIKELY(nullptr == array_)) {
+ log_error("realloc failed.");
+ return E_OOM;
+ }
+ capacity_ = new_capacity;
+ return E_OK;
+ }
+
+ int shrink()
+ {
+ size_t new_capacity = (size_t)(capacity_ / 2);
+ // if the size passed to realloc is smaller than before, OS will automatically release the rest memory
+ array_ = (ValueType *)mem_realloc(array_, new_capacity * sizeof(*(array_)));
+ if (UNLIKELY(nullptr == array_)) {
+ log_error("malloc failed.");
+ return E_OOM;
+ }
+ capacity_ = new_capacity;
+ return E_OK;
+ }
+
+ int insert(size_t idx, const ValueType &value)
+ {
+ if (idx > size_) {
+ log_error("index %lu is out of range, because size is %lu.", idx, size_);
+ return E_OUT_OF_RANGE;
+ }
+ if (size_ >= capacity_) {
+ int ret = extend();
+ if(ret != E_OK) {
+ return ret;
+ }
+ }
+ ASSERT(idx <= size_);
+ ASSERT(size_ < capacity_);
+ if (idx == size_) {
+ array_[idx] = value;
+ size_++;
+ return E_OK;
+ }
+
+ memmove(array_ + (idx + 1), array_ + idx, (size_ - idx) * sizeof(*(array_)));
+ array_[idx] = value;
+ size_++;
+ return E_OK;
+ }
+
+ // int update(size_t idx, const ValueType &value)
+ // {
+ // if (idx >= size_) {
+ // log_error("index %lu is out of range, because size is %lu.", idx, size_);
+ // return E_OUT_OF_RANGE;
+ // }
+ // array_[idx] = value;
+ // return E_OK;
+ // }
+
+ int append(const ValueType &value)
+ {
+ if (size_ >= capacity_) {
+ int ret = extend();
+ if(ret != E_OK) {
+ return ret;
+ }
+ }
+ array_[size_] = value;
+ size_++;
+ return E_OK;
+ }
+
+ FORCE_INLINE ValueType & at(size_t idx)
+ {
+ if (idx >= size_) {
+ log_error("index %lu is out of range, because size is %lu.", idx, size_);
+ ASSERT(idx < size_);
+ return dummy_;
+ }
+ return array_[idx];
+ }
+
+ FORCE_INLINE ValueType & operator [] (size_t idx)
+ {
+ if (idx >= size_) {
+ log_error("index %lu is out of range, because size is %lu.", idx, size_);
+ ASSERT(idx < size_);
+ return dummy_;
+ }
+ return array_[idx];
+ }
+
+ bool contain(const ValueType& value)
+ {
+ for(int i = 0; i < size_; i++){
+ if(array_[i] == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * if the value is not found, then set 'found' is false.
+ */
+ size_t find(const ValueType& target_val, bool &found)
+ {
+ for (size_t i = 0; i < size_; i++) {
+ if (array_[i] == target_val) {
+ found = true;
+ return i;
+ }
+ }
+ found = false;
+ return 0;
+ }
+
+ ValueType remove(size_t idx)
+ {
+ if (idx >= size_) {
+ log_error("index %lu is out of range, because size is %lu.", idx, size_);
+ ASSERT(idx < size_);
+ return dummy_;
+ }
+ if (capacity_ > ARRAY_SHRINK_THRESHOLD && size_ <= capacity_ / 4) {
+ shrink();
+ }
+ ValueType ret = array_[idx];
+ memmove(array_ + idx, array_ + idx + 1, (size_ - idx - 1) * sizeof(*(array_)));
+ size_--;
+
+ return ret;
+ }
+
+ int remove_value(const ValueType &value)
+ {
+ bool found = false;
+ size_t pos = find(value, found);
+ if (!found) {
+ log_warn("the value is not exist in the array.");
+ return E_NOT_EXIST;
+ }
+ while (found) {
+ remove(pos);
+ pos = find(value, found);
+ }
+
+ return E_OK;
+ }
+
+ FORCE_INLINE void clear()
+ {
+ size_ = 0;
+ }
+
+ FORCE_INLINE bool empty() const
+ {
+ return ATOMIC_LOAD(&size_) == 0;
+ }
+
+ FORCE_INLINE size_t size() const
+ {
+ return ATOMIC_LOAD(&size_);
+ }
+
+ FORCE_INLINE size_t capacity() const
+ {
+ return ATOMIC_LOAD(&capacity_);
+ }
+
+private:
+ size_t capacity_;
+ size_t size_;
+ ValueType *array_;
+ ValueType dummy_;
+ bool is_inited_;
+};
+
+} // end namespace common
+} // end namespace timecho
+
+
+#endif // COMMON_CONTAINER_ARRAY_H
diff --git a/cpp/tsfile/src/common/container/bit_map.cc b/cpp/tsfile/src/common/container/bit_map.cc
new file mode 100644
index 00000000..88d9515a
--- /dev/null
+++ b/cpp/tsfile/src/common/container/bit_map.cc
@@ -0,0 +1,32 @@
+
+#include "bit_map.h"
+#include "common/allocator/alloc_base.h"
+
+namespace timecho
+{
+namespace common
+{
+
+BitMap::~BitMap()
+{
+ if (bitmap_ && (size_ > 0)) {
+ mem_free(bitmap_);
+ bitmap_ = nullptr;
+ size_ = 0;
+ }
+}
+
+int BitMap::init(uint32_t item_size, bool init_as_zero)
+{
+ uint32_t size = (item_size + 7) / 8;
+ bitmap_ = static_cast<char*>(mem_alloc(size, MOD_TSBLOCK));
+ // need set to 0, otherwise there will be wrong data
+ const char initial_char = init_as_zero ? 0x00 : 0xFF;
+ memset(bitmap_, initial_char, size);
+ size_ = size;
+ init_as_zero_ = init_as_zero;
+ return common::E_OK;
+}
+
+}
+}
diff --git a/cpp/tsfile/src/common/container/bit_map.h b/cpp/tsfile/src/common/container/bit_map.h
new file mode 100644
index 00000000..5bde42f1
--- /dev/null
+++ b/cpp/tsfile/src/common/container/bit_map.h
@@ -0,0 +1,71 @@
+#ifndef COMMON_CONTAINER_BIT_MAP_H
+#define COMMON_CONTAINER_BIT_MAP_H
+
+#include <string.h>
+#include "common/errno_define.h"
+#include "common/util_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+class BitMap
+{
+public:
+ BitMap() : bitmap_(nullptr), size_(0), init_as_zero_(true) { }
+ ~BitMap();
+ int init(uint32_t item_size, bool init_as_zero = true);
+
+ FORCE_INLINE void reset()
+ {
+ const char initial_char = init_as_zero_ ? 0x00 : 0xFF;
+ memset(bitmap_, initial_char, size_);
+ }
+
+ FORCE_INLINE void set(uint32_t index)
+ {
+ uint32_t offset = index >> 3;
+ ASSERT(offset < size_);
+
+ char *start_addr = bitmap_ + offset;
+ uint8_t bit_mask = get_bit_mask(index);
+ *start_addr = (*start_addr) | (bit_mask);
+ }
+
+ FORCE_INLINE void clear(uint32_t index)
+ {
+ uint32_t offset = index >> 3;
+ ASSERT(offset < size_);
+
+ char *start_addr = bitmap_ + offset;
+ uint8_t bit_mask = get_bit_mask(index);
+ *start_addr = (*start_addr) ^ (~bit_mask);
+ }
+
+ FORCE_INLINE bool test(uint32_t index)
+ {
+ uint32_t offset = index >> 3;
+ ASSERT(offset < size_);
+
+ char *start_addr = bitmap_ + offset;
+ uint8_t bit_mask = get_bit_mask(index);
+ return (*start_addr & bit_mask);
+ }
+
+ FORCE_INLINE uint32_t get_size() { return size_; }
+
+ FORCE_INLINE char* get_bitmap() { return bitmap_; } // for debug
+
+private:
+ FORCE_INLINE uint8_t get_bit_mask(uint32_t index) { return 1 << (index & 7); }
+
+private:
+ char *bitmap_;
+ uint32_t size_;
+ bool init_as_zero_;
+};
+} // common
+} // timecho
+
+#endif // COMMON_CONTAINER_BIT_MAP_H
diff --git a/cpp/tsfile/src/common/container/blocking_queue.cc b/cpp/tsfile/src/common/container/blocking_queue.cc
new file mode 100644
index 00000000..9da55d23
--- /dev/null
+++ b/cpp/tsfile/src/common/container/blocking_queue.cc
@@ -0,0 +1,47 @@
+
+#include "blocking_queue.h"
+
+namespace timecho
+{
+namespace common
+{
+
+BlockingQueue::BlockingQueue() : queue_(), mutex_(), cond_()
+{
+ pthread_mutex_init(&mutex_, NULL);
+ pthread_cond_init(&cond_, NULL);
+}
+
+BlockingQueue::~BlockingQueue()
+{
+ pthread_mutex_destroy(&mutex_);
+ pthread_cond_destroy(&cond_);
+}
+
+void BlockingQueue::push(void *data)
+{
+ pthread_mutex_lock(&mutex_);
+ queue_.push(data);
+ pthread_mutex_unlock(&mutex_);
+ /*
+ * it is safe to signal after unlock.
+ * since pthread_cond_wait is guarantee to unlock and sleep atomically.
+ */
+ pthread_cond_signal(&cond_);
+}
+
+void* BlockingQueue::pop()
+{
+ void *ret_data = NULL;
+ pthread_mutex_lock(&mutex_);
+ while (queue_.empty()) {
+ pthread_cond_wait(&cond_, &mutex_);
+ }
+ ret_data = queue_.front();
+ queue_.pop();
+ pthread_mutex_unlock(&mutex_);
+ return ret_data;
+}
+
+} // end namespace common
+} // end namespace timecho
diff --git a/cpp/tsfile/src/common/container/blocking_queue.h b/cpp/tsfile/src/common/container/blocking_queue.h
new file mode 100644
index 00000000..84d2ee3c
--- /dev/null
+++ b/cpp/tsfile/src/common/container/blocking_queue.h
@@ -0,0 +1,32 @@
+#ifndef COMMON_CONTAINER_BLOCKING_QUEUE_H
+#define COMMON_CONTAINER_BLOCKING_QUEUE_H
+
+#include <queue>
+#include <pthread.h>
+
+namespace timecho
+{
+namespace common
+{
+
+class BlockingQueue
+{
+public:
+ BlockingQueue();
+ ~BlockingQueue();
+
+ void push(void *data);
+ // if empty, blocking
+ void* pop();
+
+private:
+ std::queue<void*> queue_;
+ pthread_mutex_t mutex_;
+ pthread_cond_t cond_;
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_CONTAINER_BLOCKING_QUEUE_H
+
diff --git a/cpp/tsfile/src/common/container/byte_buffer.h b/cpp/tsfile/src/common/container/byte_buffer.h
new file mode 100644
index 00000000..9843770b
--- /dev/null
+++ b/cpp/tsfile/src/common/container/byte_buffer.h
@@ -0,0 +1,114 @@
+#ifndef COMMON_CONTAINER_BYTE_BUFFER_H
+#define COMMON_CONTAINER_BYTE_BUFFER_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/allocator/alloc_base.h"
+#include "common/global.h"
+#include "common/util_define.h"
+
+namespace timecho
+{
+namespace common
+{
+class ByteBuffer
+{
+public:
+ ByteBuffer() : data_(nullptr), variable_type_len_(sizeof(uint32_t)), real_data_size_(0), reserved_size_(0) {}
+
+ ~ByteBuffer()
+ {
+ if (data_ && (reserved_size_ > 0)) {
+ mem_free(data_);
+ data_ = nullptr;
+ real_data_size_ = 0;
+ reserved_size_ = 0;
+ }
+ }
+
+ FORCE_INLINE void init(uint32_t size)
+ {
+ data_ = static_cast<char*>(mem_alloc(size, MOD_TSBLOCK));
+ reserved_size_ = size;
+ }
+
+ FORCE_INLINE void reset()
+ {
+ real_data_size_ = 0;
+ }
+
+ FORCE_INLINE void extend_memory(uint32_t new_size)
+ {
+ ASSERT(new_size > reserved_size_);
+ data_ = static_cast<char*>(mem_realloc(data_, new_size));
+ reserved_size_ = new_size;
+ }
+
+ FORCE_INLINE void append_variable_value(const char *value, uint32_t len)
+ {
+ // dynamic growth
+ if (UNLIKELY((real_data_size_ + len + variable_type_len_) > reserved_size_)) {
+ // extreme scenarios, when encountering very long string
+ uint32_t growth_size = g_config_value_.tsblock_mem_inc_step_size_ > len ?
+ g_config_value_.tsblock_mem_inc_step_size_ : (len + 1);
+ extend_memory(reserved_size_ + growth_size);
+ }
+
+ ASSERT(data_);
+ // append len
+ memcpy(&data_[real_data_size_], reinterpret_cast<char*>(&len), variable_type_len_);
+ real_data_size_ += variable_type_len_;
+ if (len > 0) {
+ // append data
+ memcpy(&data_[real_data_size_], value, len);
+ real_data_size_ += len;
+ }
+ }
+
+ FORCE_INLINE void append_fixed_value(const char *value, uint32_t len)
+ {
+ // dynamic growth
+ if (UNLIKELY(real_data_size_ + len > reserved_size_)) {
+ // extreme scenarios, when encountering very long string
+ uint32_t growth_size = g_config_value_.tsblock_mem_inc_step_size_ > len ?
+ g_config_value_.tsblock_mem_inc_step_size_ : (len + 1);
+ extend_memory(reserved_size_ + growth_size);
+ }
+
+ ASSERT(data_);
+ memcpy(&data_[real_data_size_], value, len);
+ real_data_size_ += len;
+ }
+
+ // for fixed len value
+ FORCE_INLINE char* read(uint32_t offset, uint32_t len)
+ {
+ ASSERT((offset + len) <= real_data_size_);
+ char *p = &data_[offset];
+ return p;
+ }
+
+ // for variable len value
+ FORCE_INLINE char* read(uint32_t offset, uint32_t *len)
+ {
+ // get len
+ *len = *reinterpret_cast<uint32_t*>(&data_[offset]);
+ // get value
+ char *p = &data_[offset + variable_type_len_];
+ return p;
+ }
+
+ FORCE_INLINE char* get_data() { return data_; }
+
+private:
+ char *data_;
+ uint8_t variable_type_len_;
+ uint32_t real_data_size_;
+ uint32_t reserved_size_; // malloc memory size from system
+};
+
+} // common
+} // timecho
+#endif // COMMON_CONTAINER_BYTE_BUFFER_H
\ No newline at end of file
diff --git a/cpp/tsfile/src/common/container/hash_func.h b/cpp/tsfile/src/common/container/hash_func.h
new file mode 100644
index 00000000..d8522eaa
--- /dev/null
+++ b/cpp/tsfile/src/common/container/hash_func.h
@@ -0,0 +1,102 @@
+#ifndef COMMON_CONTAINER_HASH_FUNC_H
+#define COMMON_CONTAINER_HASH_FUNC_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "common/db_utils.h"
+#include "common/container/slice.h"
+#include "common/container/hash_table.h"
+#include "common/container/murmur_hash3.h"
+
+#define TSID_MAX_LEN 20
+
+namespace timecho
+{
+namespace common
+{
+
+/*
+ * using djb2 hash algorithm
+ */
+struct StringHashFunc
+{
+ uint32_t hash_fmix32(uint32_t h)
+ {
+ h ^= h >> 16;
+ h *= 0x3243f6a9U;
+ h ^= h >> 16;
+ return h;
+ }
+
+ uint32_t operator()(const void *data)
+ {
+ uint32_t hash_ = (const uint32_t)5381;
+ const char *str = (const char*)data;
+ char c;
+ while((c = *str++)) {
+ hash_ = ((hash_ << 5) + hash_) + c;
+ }
+ return hash_fmix32(hash_);
+ }
+};
+
+/*
+ * using djb2 hash algorithm
+ */
+struct SliceHashFunc
+{
+ uint32_t hash_fmix32(uint32_t h)
+ {
+ h ^= h >> 16;
+ h *= 0x3243f6a9U;
+ h ^= h >> 16;
+ return h;
+ }
+
+ uint32_t operator()(const Slice &slice)
+ {
+ uint32_t hash_ = (const uint32_t)5381;
+ const char *str = (const char*)slice.data();
+ char c;
+ while((c = *str++)) {
+ hash_ = ((hash_ << 5) + hash_) + c;
+ }
+ return hash_fmix32(hash_);
+ }
+};
+
+/*
+ * using murmur_hash hash algorithm
+ */
+struct TsIDHashFunc
+{
+ uint32_t hash_fmix32(uint32_t h)
+ {
+ h ^= h >> 16;
+ h *= 0x3243f6a9U;
+ h ^= h >> 16;
+ return h;
+ }
+
+ uint32_t operator()(const TsID &data)
+ {
+ int32_t tmp = data.db_nid_ * 10000 + data.device_nid_ * 100 + data.measurement_nid_;
+ return Murmur128Hash::hash(tmp, 0);
+ }
+};
+
+/*
+ * using murmur_hash hash algorithm
+ */
+struct NodeIDHashFunc
+{
+ uint32_t operator()(const NodeID &data)
+ {
+ return Murmur128Hash::hash(static_cast<int32_t>(data), 0);
+ }
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_CONTAINER_HASH_FUNC_H
diff --git a/cpp/tsfile/src/common/container/hash_node.h b/cpp/tsfile/src/common/container/hash_node.h
new file mode 100644
index 00000000..6a2ffe10
--- /dev/null
+++ b/cpp/tsfile/src/common/container/hash_node.h
@@ -0,0 +1,90 @@
+#ifndef COMMON_CONTAINER_HASH_NODE_H
+#define COMMON_CONTAINER_HASH_NODE_H
+
+#include "common/util_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+template <class KeyType, class ValueType>
+class HashNode {
+public:
+ HashNode()
+ {
+ is_valid_ = false;
+ rehash_ = 0;
+ next_ = nullptr;
+ }
+
+ HashNode(const KeyType &key, const ValueType &value) : key_(key), value_(value),
+ is_valid_(true), rehash_(0), next_(nullptr) {}
+
+ ~HashNode()
+ {
+ is_valid_ = false;
+ }
+
+ FORCE_INLINE KeyType get_key() const
+ {
+ return key_;
+ }
+
+ FORCE_INLINE ValueType get_value() const
+ {
+ return value_;
+ }
+
+ FORCE_INLINE void set_key(const KeyType &key)
+ {
+ key_ = key;
+ }
+
+ FORCE_INLINE void set_value(const ValueType &value)
+ {
+ value_ = value;
+ }
+
+ FORCE_INLINE HashNode* get_next() const
+ {
+ return next_;
+ }
+
+ FORCE_INLINE void set_next(HashNode *next)
+ {
+ next_ = next;
+ }
+
+ FORCE_INLINE bool get_valid() const
+ {
+ return is_valid_;
+ }
+
+ FORCE_INLINE void set_valid(bool vd)
+ {
+ is_valid_ = vd;
+ }
+
+ FORCE_INLINE uint64_t get_rehashid() const
+ {
+ return rehash_;
+ }
+
+ FORCE_INLINE void set_rehashid(uint64_t id)
+ {
+ rehash_ = id;
+ }
+
+public:
+ bool is_valid_;
+ uint64_t rehash_;
+ KeyType key_;
+ ValueType value_;
+ HashNode *next_; // pointer to the next node (same bucket)
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_CONTAINER_HASH_NODE_H
\ No newline at end of file
diff --git a/cpp/tsfile/src/common/container/hash_segm.h b/cpp/tsfile/src/common/container/hash_segm.h
new file mode 100644
index 00000000..40746311
--- /dev/null
+++ b/cpp/tsfile/src/common/container/hash_segm.h
@@ -0,0 +1,41 @@
+#ifndef COMMON_CONTAINER_HASH_SEGM_H
+#define COMMON_CONTAINER_HASH_SEGM_H
+
+#include <stddef.h>
+#include "common/container/hash_node.h"
+#include "common/errno_define.h"
+#include "common/util_define.h"
+#include "common/mutex/mutex.h"
+
+#define SEGMENT_CAPACITY 100
+
+namespace timecho
+{
+namespace common
+{
+
+template <class KeyType, class ValueType>
+class HashSegm {
+public:
+ HashSegm() {}
+ ~HashSegm() {}
+
+ FORCE_INLINE HashNode<KeyType, ValueType> & operator [] (size_t idx)
+ {
+ if (idx >= SEGMENT_CAPACITY) {
+ log_error("index %lu is out of range.", idx);
+ ASSERT(idx < SEGMENT_CAPACITY);
+ }
+ return segm_pointer_[idx];
+ }
+
+public:
+ Mutex mutexes_[SEGMENT_CAPACITY];
+ HashNode<KeyType, ValueType> segm_pointer_[SEGMENT_CAPACITY];
+};
+
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_CONTAINER_HASH_SEGM_H
\ No newline at end of file
diff --git a/cpp/tsfile/src/common/container/hash_table.h b/cpp/tsfile/src/common/container/hash_table.h
new file mode 100644
index 00000000..d72e2167
--- /dev/null
+++ b/cpp/tsfile/src/common/container/hash_table.h
@@ -0,0 +1,685 @@
+#ifndef COMMON_CONTAINER_HASH_TABLE_H
+#define COMMON_CONTAINER_HASH_TABLE_H
+
+#include "common/allocator/alloc_base.h"
+#include "common/container/array.h"
+#include "common/container/hash_func.h"
+#include "common/container/hash_node.h"
+#include "common/container/hash_segm.h"
+
+#define TABLE_CAPACITY 100
+#define TABLE_GROWTH 2
+
+namespace timecho
+{
+namespace common
+{
+
+template < typename KeyType, typename ValueType, typename F >
+class HashTable {
+public:
+ HashTable() : table_(TABLE_CAPACITY)
+ {
+ new_table_capacity_ = TABLE_CAPACITY;
+ old_table_capacity_ = TABLE_CAPACITY;
+ size_ = 0;
+ is_inited_ = false;
+ hash_version_ = 0;
+ is_extending_ = 0;
+ }
+
+ HashTable(size_t total_capacity) : table_(total_capacity / SEGMENT_CAPACITY)
+ {
+ new_table_capacity_ = total_capacity / SEGMENT_CAPACITY;
+ old_table_capacity_ = new_table_capacity_;
+ size_ = 0;
+ is_inited_ = false;
+ hash_version_ = 0;
+ is_extending_ = 0;
+ }
+ ~HashTable()
+ {
+ new_table_capacity_ = 0;
+ size_ = 0;
+ is_inited_ = false;
+ hash_version_ = 0;
+ is_extending_ = 0;
+ }
+
+ int init()
+ {
+ if (is_inited_) {
+ log_error("init repeated.");
+ ASSERT(!is_inited_);
+ }
+
+ int ret = E_OK;
+ ret = table_.init();
+ if (ret != E_OK) {
+ return E_OOM;
+ }
+ for (size_t i = 0; i < new_table_capacity_; i++) {
+ void *buf = mem_alloc(sizeof(HashSegm<KeyType, ValueType>), MOD_HASH_TABLE);
+ if (UNLIKELY(nullptr == buf)) {
+ log_error("malloc() failed.");
+ return E_OOM;
+ }
+ HashSegm<KeyType, ValueType> *tmp_segm = new (buf) HashSegm<KeyType, ValueType>;
+ table_.append(tmp_segm);
+ }
+ is_inited_ = true;
+ return E_OK;
+ }
+
+ void destroy()
+ {
+ if (is_inited_) {
+ for (size_t i = 0; i < new_table_capacity_; i++) {
+ for (size_t j = 0; j < SEGMENT_CAPACITY; j++) {
+ if ((*table_[i])[j].get_valid()) {
+ HashNode<KeyType, ValueType>* prev = nullptr;
+ HashNode<KeyType, ValueType>* entry = (*table_[i])[j].get_next();
+ while (entry != nullptr) {
+ prev = entry;
+ entry = entry->get_next();
+ prev->~HashNode();
+ mem_free(prev);
+ prev = nullptr;
+ }
+ (*table_[i])[j].set_valid(false);
+ }
+ }
+ table_[i]->~HashSegm();
+ mem_free(table_[i]);
+ table_[i] = nullptr;
+ }
+ table_.destroy();
+ }
+ is_inited_ = false;
+ }
+
+ int table_extend()
+ {
+ int ret = table_.extend();
+ if ( ret != E_OK) {
+ return ret;
+ }
+ for (size_t i = ATOMIC_LOAD(&new_table_capacity_); i < table_.capacity(); i++) {
+ void *buf = mem_alloc(sizeof(HashSegm<KeyType, ValueType>), MOD_HASH_TABLE);
+ if (UNLIKELY(nullptr == buf)) {
+ log_error("malloc() failed.");
+ return E_OOM;
+ }
+ HashSegm<KeyType, ValueType> *tmp_segm = new (buf) HashSegm<KeyType, ValueType>;
+ table_.append(tmp_segm);
+ }
+ return E_OK;
+ }
+
+ int move_bucket_head(size_t from_segment_idx, size_t from_bucket_idx)
+ {
+ HashNode<KeyType, ValueType>* prev = &((*table_[from_segment_idx])[from_bucket_idx]);
+ HashNode<KeyType, ValueType>* entry = ((*table_[from_segment_idx])[from_bucket_idx]).get_next();
+
+ while ((*table_[from_segment_idx])[from_bucket_idx].get_rehashid() != ATOMIC_LOAD(&hash_version_)) { // if the hashnode hasn't rehashed
+ uint32_t hash_value = hashfunc_((*table_[from_segment_idx])[from_bucket_idx].get_key());
+ size_t to_segment_idx = hash_value % ATOMIC_LOAD(&new_table_capacity_);
+ size_t to_bucket_idx = hash_value % SEGMENT_CAPACITY;
+ if (from_segment_idx == to_segment_idx && from_bucket_idx == to_bucket_idx) {
+ ((*table_[to_segment_idx])[to_bucket_idx]).set_rehashid(ATOMIC_LOAD(&hash_version_)); // only update rehashid
+ } else {
+ // put
+ table_[to_segment_idx]->mutexes_[to_bucket_idx].lock();
+ int ret = put_nolock((*table_[from_segment_idx])[from_bucket_idx].get_key(), (*table_[from_segment_idx])[from_bucket_idx].get_value(), to_segment_idx, to_bucket_idx);
+ table_[to_segment_idx]->mutexes_[to_bucket_idx].unlock();
+ if (ret != E_OK) {
+ return ret;
+ }
+ // remove
+ if (entry != nullptr) {
+ ((*table_[from_segment_idx])[from_bucket_idx]).set_key(entry->get_key());
+ ((*table_[from_segment_idx])[from_bucket_idx]).set_value(entry->get_value());
+ ((*table_[from_segment_idx])[from_bucket_idx]).set_next(entry->get_next());
+ ((*table_[from_segment_idx])[from_bucket_idx]).set_valid(true);
+ ((*table_[from_segment_idx])[from_bucket_idx]).set_rehashid(entry->get_rehashid());
+ ATOMIC_AAF(&size_, -1);
+ entry->~HashNode();
+ mem_free(entry);
+ entry = prev->get_next();
+ } else {
+ ((*table_[from_segment_idx])[from_bucket_idx]).set_valid(false);
+ ATOMIC_AAF(&size_, -1);
+ break;
+ }
+ }
+ }
+
+ return E_OK;
+ }
+
+ int move_bucket_chain(size_t from_segment_idx, size_t from_bucket_idx)
+ {
+ HashNode<KeyType, ValueType>* prev = &((*table_[from_segment_idx])[from_bucket_idx]);
+ HashNode<KeyType, ValueType>* entry = ((*table_[from_segment_idx])[from_bucket_idx]).get_next();
+
+ while (entry != nullptr) {
+ if (entry->get_rehashid() != ATOMIC_LOAD(&hash_version_)) {
+ uint32_t hash_value = hashfunc_(entry->get_key());
+ size_t to_segment_idx = hash_value % ATOMIC_LOAD(&new_table_capacity_);
+ size_t to_bucket_idx = hash_value % SEGMENT_CAPACITY;
+ if (from_segment_idx == to_segment_idx && from_bucket_idx == to_bucket_idx) {
+ entry->set_rehashid(ATOMIC_LOAD(&hash_version_));
+ prev = entry;
+ entry = entry->get_next();
+ } else {
+ table_[to_segment_idx]->mutexes_[to_bucket_idx].lock();
+ if ((*table_[to_segment_idx])[to_bucket_idx].get_valid() == false) {
+ ((*table_[to_segment_idx])[to_bucket_idx]).set_key(entry->get_key());
+ ((*table_[to_segment_idx])[to_bucket_idx]).set_value(entry->get_value());
+ ((*table_[to_segment_idx])[to_bucket_idx]).set_next(nullptr);
+ ((*table_[to_segment_idx])[to_bucket_idx]).set_valid(true);
+ ((*table_[to_segment_idx])[to_bucket_idx]).set_rehashid(ATOMIC_LOAD(&hash_version_));
+ prev->set_next(entry->get_next());
+ entry->~HashNode();
+ mem_free(entry);
+ entry = prev->get_next();
+ // entry = entry->get_next();
+ } else {
+ entry->set_rehashid(ATOMIC_LOAD(&hash_version_));
+ prev->set_next(entry->get_next());
+ entry->set_next((*table_[to_segment_idx])[to_bucket_idx].get_next());
+ (*table_[to_segment_idx])[to_bucket_idx].set_next(entry);
+ entry = prev->get_next();
+ }
+ table_[to_segment_idx]->mutexes_[to_bucket_idx].unlock();
+ }
+ } else {
+ prev = prev->get_next();
+ entry = entry->get_next();
+ }
+ }
+ return E_OK;
+ }
+
+ int extend()
+ {
+ int ret = table_extend();
+ if (ret != E_OK) {
+ return ret;
+ }
+ ATOMIC_STORE(&old_table_capacity_, ATOMIC_LOAD(&new_table_capacity_));
+ ATOMIC_STORE(&new_table_capacity_, table_.capacity());
+ // ATOMIC_STORE(&hash_total_capacity_, table_.capacity() * SEGMENT_CAPACITY);
+
+ int64_t next_hash_version = ATOMIC_LOAD(&hash_version_) + 1; // the highest position of next_hash_version is 0
+ ATOMIC_STORE(&hash_version_, next_hash_version | (1UL<<63)); // set the highest position to 1 which means 'extend' is beginning.
+
+ // rehash
+ for (size_t from_segment_idx = 0; from_segment_idx < ATOMIC_LOAD(&old_table_capacity_); from_segment_idx++) {
+ for (size_t from_bucket_idx = 0; from_bucket_idx < SEGMENT_CAPACITY; from_bucket_idx++) {
+ table_[from_segment_idx]->mutexes_[from_bucket_idx].lock();
+ if ((*table_[from_segment_idx])[from_bucket_idx].get_valid()) {
+ ret = move_bucket_head(from_segment_idx,from_bucket_idx);
+ if (ret != E_OK) {
+ table_[from_segment_idx]->mutexes_[from_bucket_idx].unlock();
+ return ret;
+ }
+ ret = move_bucket_chain(from_segment_idx,from_bucket_idx);
+ if (ret != E_OK) {
+ table_[from_segment_idx]->mutexes_[from_bucket_idx].unlock();
+ return ret;
+ }
+ }
+ table_[from_segment_idx]->mutexes_[from_bucket_idx].unlock();
+ }
+ }
+
+ ATOMIC_STORE(&hash_version_, next_hash_version & (~(1UL<<63))); // set extending flag is false
+
+ return E_OK;
+ }
+
+ /*
+ * when the key already exists, just update old value to new value;
+ */
+ int put(const KeyType& key, const ValueType& value)
+ {
+ int ret;
+ uint32_t hash_value = hashfunc_(key);
+
+ while (true) {
+ uint8_t cur_table_capacity = ATOMIC_LOAD(&new_table_capacity_);
+ size_t segment_idx = hash_value % cur_table_capacity;
+ size_t bucket_idx = hash_value % SEGMENT_CAPACITY;
+
+ table_[segment_idx]->mutexes_[bucket_idx].lock();
+ ret = put_nolock(key, value, segment_idx, bucket_idx);
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ if (ret != E_OK) {
+ return ret;
+ }
+
+ if (UNLIKELY(cur_table_capacity != ATOMIC_LOAD(&new_table_capacity_))) { // resolve the problem of insert into old position
+ ret = remove_from_wrong_bucket(key, segment_idx, bucket_idx);
+ // if (ret != E_OK) {
+ // return ret;
+ // }
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (ATOMIC_LOAD(&size_) > ATOMIC_LOAD(&new_table_capacity_) * SEGMENT_CAPACITY * TABLE_GROWTH) {
+ int tmp = 0;
+ if (ATOMIC_CAS(&is_extending_, &tmp, 1)) {
+ ret = extend();
+ if (ret != E_OK) {
+ ATOMIC_AAF(&is_extending_, -1);
+ return ret;
+ }
+ ATOMIC_AAF(&is_extending_, -1);
+ }
+ }
+
+ return ret;
+ }
+
+ /*
+ * when the key already exists, just update old value to new value;
+ */
+ int put_nolock(const KeyType& key, const ValueType& value, size_t segment_idx, size_t bucket_idx)
+ {
+ if (((*table_[segment_idx])[bucket_idx]).get_valid() == false) { // if current segment has no valid node
+ ((*table_[segment_idx])[bucket_idx]).set_key(key);
+ ((*table_[segment_idx])[bucket_idx]).set_value(value);
+ ((*table_[segment_idx])[bucket_idx]).set_next(nullptr);
+ ((*table_[segment_idx])[bucket_idx]).set_valid(true);
+ ((*table_[segment_idx])[bucket_idx]).set_rehashid(ATOMIC_LOAD(&hash_version_));
+ ATOMIC_AAF(&size_, 1);
+ } else if (((*table_[segment_idx])[bucket_idx]).get_key() == key) { // if current segment's first node's key is same as the target key
+ ((*table_[segment_idx])[bucket_idx]).set_value(value); // update value of existing node
+ ((*table_[segment_idx])[bucket_idx]).set_rehashid(ATOMIC_LOAD(&hash_version_));
+ } else { // follow the link list
+ HashNode<KeyType, ValueType>* prev = &((*table_[segment_idx])[bucket_idx]);
+ HashNode<KeyType, ValueType>* entry = ((*table_[segment_idx])[bucket_idx]).get_next();
+ while (entry != nullptr && entry->get_key() != key) {
+ prev = entry;
+ entry = entry->get_next();
+ }
+ if (LIKELY(entry == nullptr)) {
+ void *buf = mem_alloc(sizeof(HashNode<KeyType, ValueType>), MOD_HASH_TABLE);
+ if (UNLIKELY(nullptr == buf)) {
+ log_error("malloc() failed.");
+ return E_OOM;
+ }
+ entry = new (buf) HashNode<KeyType, ValueType>;
+ entry->set_key(key);
+ entry->set_value(value);
+ entry->set_valid(true);
+ entry->set_rehashid(ATOMIC_LOAD(&hash_version_));
+ prev->set_next(entry);
+ ATOMIC_AAF(&size_, 1);
+ } else {
+ entry->set_value(value); // update value of existing node
+ entry->set_rehashid(ATOMIC_LOAD(&hash_version_));
+ }
+ }
+ return E_OK;
+ }
+
+ /*
+ * when the key already exists, then remain the old value and return the old value and set 'exist' to true
+ */
+ int put_no_update(const KeyType& key, ValueType& value, bool &exist)
+ {
+ int ret;
+ uint32_t hash_value = hashfunc_(key);
+
+ while (true) {
+ uint8_t cur_table_capacity = ATOMIC_LOAD(&new_table_capacity_);
+ size_t segment_idx = hash_value % cur_table_capacity;
+ size_t bucket_idx = hash_value % SEGMENT_CAPACITY;
+
+ table_[segment_idx]->mutexes_[bucket_idx].lock();
+ ret = put_nolock_no_update(key, value, segment_idx, bucket_idx, exist);
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ if (ret != E_OK) {
+ return ret;
+ }
+
+ if (UNLIKELY(cur_table_capacity != ATOMIC_LOAD(&new_table_capacity_))) { // resolve the problem of insert into old position
+ ret = remove_from_wrong_bucket(key, segment_idx, bucket_idx);
+ // if (ret != E_OK) {
+ // return ret;
+ // }
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (ATOMIC_LOAD(&size_) > ATOMIC_LOAD(&new_table_capacity_) * SEGMENT_CAPACITY * TABLE_GROWTH) {
+ int tmp = 0;
+ if (ATOMIC_CAS(&is_extending_, &tmp, 1)) {
+ ret = extend();
+ if (ret != E_OK) {
+ return ret;
+ }
+ ATOMIC_AAF(&is_extending_, -1);
+ }
+ }
+
+ return ret;
+ }
+
+
+ /*
+ * when the key already exists, then remain the old value and return the old value and set 'exist' to true
+ */
+ int put_nolock_no_update(const KeyType& key, ValueType& value, size_t segment_idx, size_t bucket_idx, bool &exist)
+ {
+ if (((*table_[segment_idx])[bucket_idx]).get_valid() == false) { // if current segment has no valid node
+ ((*table_[segment_idx])[bucket_idx]).set_key(key);
+ ((*table_[segment_idx])[bucket_idx]).set_value(value);
+ ((*table_[segment_idx])[bucket_idx]).set_next(nullptr);
+ ((*table_[segment_idx])[bucket_idx]).set_valid(true);
+ ((*table_[segment_idx])[bucket_idx]).set_rehashid(ATOMIC_LOAD(&hash_version_));
+ ATOMIC_AAF(&size_, 1);
+ } else if (((*table_[segment_idx])[bucket_idx]).get_key() == key) { // if current segment's first node's key is same as the target key
+ exist = true;
+ value = ((*table_[segment_idx])[bucket_idx]).get_value();
+ ((*table_[segment_idx])[bucket_idx]).set_rehashid(ATOMIC_LOAD(&hash_version_));
+ } else { // follow the link list
+ HashNode<KeyType, ValueType>* prev = &((*table_[segment_idx])[bucket_idx]);
+ HashNode<KeyType, ValueType>* entry = ((*table_[segment_idx])[bucket_idx]).get_next();
+ while (entry != nullptr && entry->get_key() != key) {
+ prev = entry;
+ entry = entry->get_next();
+ }
+ if (LIKELY(entry == nullptr)) {
+ void *buf = mem_alloc(sizeof(HashNode<KeyType, ValueType>), MOD_HASH_TABLE);
+ if (UNLIKELY(nullptr == buf)) {
+ log_error("malloc() failed.");
+ return E_OOM;
+ }
+ entry = new (buf) HashNode<KeyType, ValueType>;
+ entry->set_key(key);
+ entry->set_value(value);
+ entry->set_valid(true);
+ entry->set_rehashid(ATOMIC_LOAD(&hash_version_));
+ prev->set_next(entry);
+ ATOMIC_AAF(&size_, 1);
+ } else {
+ exist = true;
+ value = entry->get_value();
+ entry->set_rehashid(ATOMIC_LOAD(&hash_version_));
+ }
+ }
+ return E_OK;
+ }
+
+ int get(const KeyType &key, ValueType &result_value)
+ {
+ if (!ATOMIC_LOAD(&size_)){
+ return E_NOT_EXIST;
+ }
+ int ret;
+ ValueType result1;
+ ValueType result2;
+ ValueType result3;
+ while (true) {
+ uint64_t hv1 = ATOMIC_LOAD(&hash_version_);
+
+ if ((hv1 & (1UL<<63))) {
+ ret = get_by_bucket(key, result1, ATOMIC_LOAD(&old_table_capacity_));
+ if (ret == E_OK) {
+ result_value = result1;
+ return ret;
+ }
+ ret = get_by_bucket(key, result2, ATOMIC_LOAD(&new_table_capacity_));
+ if (ret == E_OK) {
+ result_value = result2;
+ return ret;
+ }
+ } else { //
+ ret = get_by_bucket(key, result3, ATOMIC_LOAD(&new_table_capacity_));
+ if (ret == E_OK) {
+ result_value = result3;
+ return ret;
+ }
+ }
+
+ uint64_t hv2 = ATOMIC_LOAD(&hash_version_);
+ if ((hv1 & (~(1UL<<63))) != (hv2 & (~(1UL<<63)))) {
+ continue;
+ } else if (ATOMIC_LOAD(&is_extending_)) {
+ continue;
+ } else {
+ return E_NOT_EXIST;
+ }
+ }
+ }
+
+ int get_by_bucket(const KeyType &key, ValueType &result_value, size_t table_capacity)
+ {
+ uint32_t hash_value = hashfunc_(key);
+ size_t segment_idx = hash_value % table_capacity;
+ size_t bucket_idx = hash_value % SEGMENT_CAPACITY;
+
+ table_[segment_idx]->mutexes_[bucket_idx].lock();
+
+ if (!((*table_[segment_idx])[bucket_idx]).get_valid()) { // if current segment has no node
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_NOT_EXIST;
+ } else if (((*table_[segment_idx])[bucket_idx]).get_key() == key) {
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ result_value = ((*table_[segment_idx])[bucket_idx]).get_value();
+ return E_OK;
+ } else {
+ HashNode<KeyType, ValueType>* entry = ((*table_[segment_idx])[bucket_idx]).get_next();
+ while (entry != nullptr) {
+ if (entry->get_key() == key) {
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ result_value = entry->get_value();
+ return E_OK;
+ }
+ entry = entry->get_next();
+ }
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_NOT_EXIST;
+ }
+ }
+
+ int remove(const KeyType& key)
+ {
+ if (!ATOMIC_LOAD(&size_)){
+ return E_NOT_EXIST;
+ }
+ int ret;
+ while (true) {
+ uint64_t hv1 = ATOMIC_LOAD(&hash_version_);
+
+ if ((hv1 & (1UL<<63))) {
+ ret = remove_by_bucket(key, ATOMIC_LOAD(&old_table_capacity_));
+ if (ret == E_OK) {
+ return ret;
+ }
+ ret = remove_by_bucket(key, ATOMIC_LOAD(&new_table_capacity_));
+ if (ret == E_OK) {
+ return ret;
+ }
+ } else {
+ ret = remove_by_bucket(key, ATOMIC_LOAD(&new_table_capacity_));
+ if (ret == E_OK) {
+ return ret;
+ }
+ }
+
+ uint64_t hv2 = ATOMIC_LOAD(&hash_version_);
+ if ((hv1 & (~(1UL<<63))) != (hv2 & (~(1UL<<63)))) {
+ continue;
+ } else if (ATOMIC_LOAD(&is_extending_)) {
+ continue;
+ } else {
+ return E_NOT_EXIST;
+ }
+ }
+ }
+
+ int remove_by_bucket(const KeyType& key, size_t table_capacity)
+ {
+ uint32_t hash_value = hashfunc_(key);
+ size_t segment_idx = hash_value % table_capacity;
+ size_t bucket_idx = hash_value % SEGMENT_CAPACITY;
+
+ table_[segment_idx]->mutexes_[bucket_idx].lock();
+
+ if (!((*table_[segment_idx])[bucket_idx]).get_valid()) { // if current segment has no node
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_NOT_EXIST;
+ } else if (((*table_[segment_idx])[bucket_idx]).get_key() == key) {
+ HashNode<KeyType, ValueType>* entry = ((*table_[segment_idx])[bucket_idx]).get_next();
+ if (entry != nullptr) {
+ ((*table_[segment_idx])[bucket_idx]).set_key(entry->get_key());
+ ((*table_[segment_idx])[bucket_idx]).set_value(entry->get_value());
+ ((*table_[segment_idx])[bucket_idx]).set_next(entry->get_next());
+ ((*table_[segment_idx])[bucket_idx]).set_valid(true);
+ ((*table_[segment_idx])[bucket_idx]).set_rehashid(entry->get_rehashid());
+ entry->~HashNode();
+ mem_free(entry);
+ entry = nullptr;
+ } else {
+ ((*table_[segment_idx])[bucket_idx]).set_valid(false);
+ }
+ ATOMIC_AAF(&size_, -1);
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_OK;
+ } else {
+ HashNode<KeyType, ValueType>* prev = &((*table_[segment_idx])[bucket_idx]);
+ HashNode<KeyType, ValueType>* entry = ((*table_[segment_idx])[bucket_idx]).get_next();
+ while (entry != nullptr) {
+ if (entry->get_key() == key) {
+ prev->set_next(entry->get_next()); // remove node and reconnect
+ entry->~HashNode();
+ mem_free(entry);
+ entry = nullptr;
+ ATOMIC_AAF(&size_, -1);
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_OK;
+ }
+ prev = entry;
+ entry = entry->get_next();
+ }
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_NOT_EXIST;
+ }
+ }
+
+ int remove_from_wrong_bucket(const KeyType& key, size_t segment_idx, size_t bucket_idx)
+ {
+ if (!ATOMIC_LOAD(&size_)){
+ return E_NO_MORE_DATA;
+ }
+
+ table_[segment_idx]->mutexes_[bucket_idx].lock();
+
+ if (!((*table_[segment_idx])[bucket_idx]).get_valid()) { // if current segment has no node
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_NOT_EXIST;
+ } else if (((*table_[segment_idx])[bucket_idx]).get_key() == key) {
+ HashNode<KeyType, ValueType>* entry = ((*table_[segment_idx])[bucket_idx]).get_next();
+ if (entry != nullptr) {
+ ((*table_[segment_idx])[bucket_idx]).set_key(entry->get_key());
+ ((*table_[segment_idx])[bucket_idx]).set_value(entry->get_value());
+ ((*table_[segment_idx])[bucket_idx]).set_next(entry->get_next());
+ ((*table_[segment_idx])[bucket_idx]).set_valid(true);
+ ((*table_[segment_idx])[bucket_idx]).set_rehashid(entry->get_rehashid());
+ entry->~HashNode();
+ mem_free(entry);
+ entry = nullptr;
+ } else {
+ ((*table_[segment_idx])[bucket_idx]).set_valid(false);
+ }
+ ATOMIC_AAF(&size_, -1);
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_OK;
+ } else {
+ HashNode<KeyType, ValueType>* prev = &((*table_[segment_idx])[bucket_idx]);
+ HashNode<KeyType, ValueType>* entry = ((*table_[segment_idx])[bucket_idx]).get_next();
+ while (entry != nullptr) {
+ if (entry->get_key() == key) {
+ prev->set_next(entry->get_next()); // remove node and reconnect
+ entry->~HashNode();
+ mem_free(entry);
+ entry = nullptr;
+ ATOMIC_AAF(&size_, -1);
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_OK;
+ }
+ prev = entry;
+ entry = entry->get_next();
+ }
+ table_[segment_idx]->mutexes_[bucket_idx].unlock();
+ return E_NOT_EXIST;
+ }
+ }
+
+#ifndef NDEBUG
+ void print()
+ {
+ printf("<< The Hash Table >>\n");
+ if (!ATOMIC_AAF(&size_, 0)){
+ printf(" Empty now!\n");
+ return;
+ }
+ size_t bucket_num = 0;
+ for (size_t i = 0; i < ATOMIC_AAF(&new_table_capacity_, 0); i++) {
+ for (size_t j = 0; j < SEGMENT_CAPACITY; j++) {
+ // printf("----(%ld)segment id is %ld, bucket id is %ld----\n", bucket_num++, i, j);
+ if ((*table_[i])[j].get_valid()) {
+ printf("----(%ld)segment id is %ld, bucket id is %ld----\n", bucket_num++, i, j);
+ std::cout << "| " << "key is " << (*table_[i])[j].get_key() << ", value is " << (*table_[i])[j].get_value() << ", rehashid is " << (int)(*table_[i])[j].get_rehashid() << std::endl;
+ HashNode<KeyType, ValueType>* entry = ((*table_[i])[j]).get_next();
+ while (entry != nullptr) {
+ std::cout << "| " << "key is " << entry->get_key() << ", value is " << entry->get_value() << ", rehashid is " << (int)entry->get_rehashid() << std::endl;
+ entry = entry->get_next();
+ }
+ } else {
+ bucket_num++;
+ }
+ }
+ }
+ }
+#endif // #ifndef NDEBUG
+
+ FORCE_INLINE bool empty() const
+ {
+ return ATOMIC_LOAD(&size_) == 0;
+ }
+
+ FORCE_INLINE size_t size()
+ {
+ return ATOMIC_LOAD(&size_);
+ }
+
+ FORCE_INLINE size_t total_capacity()
+ {
+ return ATOMIC_LOAD(&new_table_capacity_) * SEGMENT_CAPACITY;
+ }
+
+private:
+ size_t new_table_capacity_;
+ size_t old_table_capacity_;
+ size_t size_;
+ uint64_t hash_version_;
+ Array< HashSegm<KeyType, ValueType>* > table_; // the element in Array is pointer.
+ bool is_inited_;
+ uint8_t is_extending_;
+ F hashfunc_;
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_CONTAINER_HASH_TABLE_H
diff --git a/cpp/tsfile/src/common/container/list.h b/cpp/tsfile/src/common/container/list.h
new file mode 100644
index 00000000..151f5feb
--- /dev/null
+++ b/cpp/tsfile/src/common/container/list.h
@@ -0,0 +1,147 @@
+
+#ifndef COMMON_CONTAINER_LIST_H
+#define COMMON_CONTAINER_LIST_H
+
+#include "common/allocator/page_arena.h"
+#include "common/errno_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+#define INVALID_NODE_PTR ((SimpleListNode*)0xABCDEF)
+
+/*
+ * A very simple list.
+ * There are such scenarios:
+ * We prepare all data in the list, and pass the list as immutable
+ * parameters to other module or caller. We never do delete or complex
+ * push operations.
+ * for example:
+ * SchemaMgr::get_timeseries_by_tsid(TsID, list<ColumnDesc>&)
+ * SchemaMgr::create_aligned_timeseries(..., const list<char*> &measurement_list, ...)
+ *
+ * Note: not thread safe!
+ */
+template<class T>
+class SimpleList
+{
+private:
+ struct SimpleListNode
+ {
+ T data_;
+ SimpleListNode *next_;
+
+ SimpleListNode() : next_(nullptr) {}
+ SimpleListNode(const T &data) : data_(data), next_(nullptr) {}
+ };
+
+public:
+ class Iterator
+ {
+ public:
+ Iterator(SimpleListNode *node) : cur_(node) {}
+ Iterator() : cur_(INVALID_NODE_PTR) {}
+ T &get() { return cur_->data_; }
+ FORCE_INLINE bool is_inited() const
+ {
+ return cur_ != INVALID_NODE_PTR;
+ }
+ FORCE_INLINE Iterator& operator++(int n)
+ {
+ if (LIKELY(cur_ != nullptr)) {
+ cur_ = cur_->next_;
+ }
+ return *this;
+ }
+ FORCE_INLINE bool operator!=(const Iterator &other) const
+ {
+ return this->cur_ != other.cur_;
+ }
+ FORCE_INLINE bool operator==(const Iterator &other) const
+ {
+ return this->cur_ == other.cur_;
+ }
+ private:
+ SimpleListNode *cur_;
+ };
+
+public:
+ SimpleList(const uint32_t page_size, AllocModID mid) : head_(nullptr), tail_(nullptr), size_(0)
+ {
+ own_page_arena_.init(page_size, mid);
+ page_arena_ = &own_page_arena_;
+ }
+
+ SimpleList(PageArena *page_arena) : page_arena_(page_arena), head_(nullptr), tail_(nullptr), size_(0)
+ {
+ // page_arena_ should be destroy outside by caller
+ }
+
+ int push_back(const T &data)
+ {
+ void *buf = page_arena_->alloc(sizeof(SimpleListNode));
+ if (UNLIKELY(buf == nullptr)) {
+ return common::E_OOM;
+ }
+ SimpleListNode *node = new(buf) SimpleListNode(data);
+ if (head_ == nullptr) {
+ head_ = node;
+ tail_ = node;
+ } else {
+ assert(tail_ != nullptr);
+ tail_->next_ = node;
+ tail_ = node;
+ }
+ size_++;
+ return common::E_OK;
+ }
+
+ FORCE_INLINE T& front()
+ {
+ ASSERT(size_ > 0 && head_ != nullptr);
+ return head_->data_;
+ }
+
+ int remove(T target)
+ {
+ if (head_ == nullptr) {
+ return common::E_NOT_EXIST;
+ }
+ SimpleListNode *prev = head_;
+ SimpleListNode *cur = head_->next_;
+ while (cur && cur->data_ != target) {
+ cur = cur->next_;
+ }
+ if (cur) {
+ return common::E_NOT_EXIST;
+ }
+ prev->next_ = cur->next_;
+ // cur is allocated from PageArena, it should not reclaim now
+ return common::E_OK;
+ }
+
+ FORCE_INLINE Iterator begin() const { return Iterator(head_); }
+ FORCE_INLINE Iterator end() const { return Iterator(nullptr); }
+ FORCE_INLINE uint32_t size() const { return size_; }
+ FORCE_INLINE void clear()
+ {
+ head_ = nullptr;
+ tail_ = nullptr;
+ size_ = 0;
+ own_page_arena_.destroy();
+ }
+private:
+ PageArena *page_arena_;
+ PageArena own_page_arena_;
+ SimpleListNode *head_;
+ SimpleListNode *tail_;
+ uint32_t size_;
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_CONTAINER_LIST_H
+
diff --git a/cpp/tsfile/src/common/container/murmur_hash3.cc b/cpp/tsfile/src/common/container/murmur_hash3.cc
new file mode 100644
index 00000000..2604a00f
--- /dev/null
+++ b/cpp/tsfile/src/common/container/murmur_hash3.cc
@@ -0,0 +1,126 @@
+#include "murmur_hash3.h"
+
+namespace timecho
+{
+namespace common
+{
+
+/* ================ Murmur128Hash ================ */
+// follow Java IoTDB exactly.
+int64_t Murmur128Hash::inner_hash(const char *buf, int32_t len, int64_t seed)
+{
+ const int block_count = len >> 4; // as 128-bit blocks
+ int64_t h1 = seed;
+ int64_t h2 = seed;
+ int64_t c1 = 0x87c37b91114253d5L;
+ int64_t c2 = 0x4cf5ad432745937fL;
+
+ for (int i = 0; i < block_count; i++) {
+ int64_t k1 = get_block(buf, i * 2);
+ int64_t k2 = get_block(buf, i * 2 + 1);
+ k1 *= c1;
+ k1 = rotl64(k1, 31);
+ k1 *= c2;
+ h1 ^= k1;
+ h1 = rotl64(h1, 27);
+ h1 += h2;
+ h1 = h1 * 5 + 0x52dce729;
+ k2 *= c2;
+ k2 = rotl64(k2, 33);
+ k2 *= c1;
+ h2 ^= k2;
+ h2 = rotl64(h2, 31);
+ h2 += h1;
+ h2 = h2 * 5 + 0x38495ab5;
+ }
+
+ int offset = block_count * 16;
+ int64_t k1 = 0;
+ int64_t k2 = 0;
+ switch (len & 15) {
+ case 15:
+ k2 ^= ((int64_t)(buf[offset + 14])) << 48;
+ // fallthrough
+ case 14:
+ k2 ^= ((int64_t)(buf[offset + 13])) << 40;
+ // fallthrough
+ case 13:
+ k2 ^= ((int64_t)(buf[offset + 12])) << 32;
+ // fallthrough
+ case 12:
+ k2 ^= ((int64_t)(buf[offset + 11])) << 24;
+ // fallthrough
+ case 11:
+ k2 ^= ((int64_t)(buf[offset + 10])) << 16;
+ // fallthrough
+ case 10:
+ k2 ^= ((int64_t)(buf[offset + 9])) << 8;
+ // fallthrough
+ case 9:
+ k2 ^= buf[offset + 8];
+ k2 *= c2;
+ k2 = rotl64(k2, 33);
+ k2 *= c1;
+ h2 ^= k2;
+ // fallthrough
+ case 8:
+ k1 ^= ((int64_t)buf[offset + 7]) << 56;
+ // fallthrough
+ case 7:
+ k1 ^= ((int64_t)buf[offset + 6]) << 48;
+ // fallthrough
+ case 6:
+ k1 ^= ((int64_t)buf[offset + 5]) << 40;
+ // fallthrough
+ case 5:
+ k1 ^= ((int64_t)buf[offset + 4]) << 32;
+ // fallthrough
+ case 4:
+ k1 ^= ((int64_t)buf[offset + 3]) << 24;
+ // fallthrough
+ case 3:
+ k1 ^= ((int64_t)buf[offset + 2]) << 16;
+ // fallthrough
+ case 2:
+ k1 ^= ((int64_t)buf[offset + 1]) << 8;
+ // fallthrough
+ case 1:
+ k1 ^= buf[offset];
+ k1 *= c1;
+ k1 = rotl64(k1, 31);
+ k1 *= c2;
+ h1 ^= k1;
+ break;
+ default: // 0
+ // do nothing
+ break;
+ }
+
+ h1 ^= len;
+ h2 ^= len;
+ h1 += h2;
+ h2 += h1;
+ h1 = fmix(h1);
+ h2 = fmix(h2);
+ h1 += h2;
+ h2 += h1;
+ return h1 + h2;
+}
+
+int64_t Murmur128Hash::get_block(const char *buf, int32_t index)
+{
+ int block_offset = index << 3;
+ int64_t res = 0;
+ res += ((int64_t)(buf[block_offset + 0] & 0xFF));
+ res += (((int64_t)(buf[block_offset + 1] & 0xFF)) << 8);
+ res += (((int64_t)(buf[block_offset + 2] & 0xFF)) << 16);
+ res += (((int64_t)(buf[block_offset + 3] & 0xFF)) << 24);
+ res += (((int64_t)(buf[block_offset + 4] & 0xFF)) << 32);
+ res += (((int64_t)(buf[block_offset + 5] & 0xFF)) << 40);
+ res += (((int64_t)(buf[block_offset + 6] & 0xFF)) << 48);
+ res += (((int64_t)(buf[block_offset + 7] & 0xFF)) << 56);
+ return res;
+}
+
+} // end namespace common
+} // end namespace timecho
diff --git a/cpp/tsfile/src/common/container/murmur_hash3.h b/cpp/tsfile/src/common/container/murmur_hash3.h
new file mode 100644
index 00000000..e0d69600
--- /dev/null
+++ b/cpp/tsfile/src/common/container/murmur_hash3.h
@@ -0,0 +1,67 @@
+#ifndef COMMON_CONTAINER_MURMUR3_MURMUR_HASH3_H
+#define COMMON_CONTAINER_MURMUR3_MURMUR_HASH3_H
+
+#include <string>
+#include "common/db_utils.h"
+#include "common/allocator/my_string.h"
+
+namespace timecho
+{
+namespace common
+{
+
+/*
+ * Murmur128Hash has to follow the logic in Java IoTDB,
+ * since the bitmap buffer will be serialized to tsfile.
+ */
+class Murmur128Hash
+{
+public:
+ FORCE_INLINE static int32_t hash(int32_t value, uint32_t seed)
+ {
+ return inner_hash(reinterpret_cast<const char *>(&value), 4, seed);
+ }
+
+ FORCE_INLINE static int32_t hash(int64_t value, uint32_t seed)
+ {
+ return inner_hash(reinterpret_cast<const char *>(&value), 8, seed);
+ }
+
+ FORCE_INLINE static int32_t hash(double value, uint32_t seed)
+ {
+ return inner_hash(reinterpret_cast<const char *>(&value), 8, seed);
+ }
+
+ FORCE_INLINE static int32_t hash(std::string &value, uint32_t seed)
+ {
+ return inner_hash(value.data(), static_cast<uint32_t >(value.size()), seed);
+ }
+
+ FORCE_INLINE static int32_t hash(const common::String &buf, int32_t seed)
+ {
+ return inner_hash(buf.buf_, buf.len_ - 1, seed);
+ }
+private:
+ FORCE_INLINE static int64_t rotl64(int64_t v, int n)
+ {
+ uint64_t uv = (uint64_t)v;
+ return ((uv << n) | (uv >> (64 - n)));
+ }
+ FORCE_INLINE static int64_t fmix(int64_t k)
+ {
+ uint64_t uk = (uint64_t)k;
+ uk ^= uk >> 33;
+ uk *= 0xff51afd7ed558ccdL;
+ uk ^= uk >> 33;
+ uk *= 0xc4ceb9fe1a85ec53L;
+ uk ^= uk >> 33;
+ return (int64_t)uk;
+ }
+ static int64_t get_block(const char *buf, int32_t index);
+ static int64_t inner_hash(const char *buf, int32_t len, int64_t seed);
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_CONTAINER_MURMUR3_MURMUR_HASH3_H
diff --git a/cpp/tsfile/src/common/container/simple_vector.h b/cpp/tsfile/src/common/container/simple_vector.h
new file mode 100644
index 00000000..67c69749
--- /dev/null
+++ b/cpp/tsfile/src/common/container/simple_vector.h
@@ -0,0 +1,48 @@
+#ifndef COMMON_CONTAINER_VECTOR_H
+#define COMMON_CONTAINER_VECTOR_H
+
+#include "common/util_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+template<typename T>
+class SimpleVector
+{
+public:
+ SimpleVector() : std_vec_(), size_(0) {}
+ void push_back(T t)
+ {
+ if (LIKELY(size_ < STACKED_ITEM_COUNT)) {
+ stacked_items_[size_] = t;
+ } else {
+ std_vec_.push_back(t);
+ }
+ size_++;
+ }
+ size_t size() { return size_; }
+ T operator[](int index)
+ {
+ if (UNLIKELY((size_t)index > size_)) {
+ abort();
+ }
+ if (index < STACKED_ITEM_COUNT) {
+ return stacked_items_[index];
+ } else {
+ return std_vec_[index - STACKED_ITEM_COUNT];
+ }
+ }
+private:
+ static const int STACKED_ITEM_COUNT = 16;
+ T stacked_items_[STACKED_ITEM_COUNT];
+ std::vector<T> std_vec_;
+ size_t size_;
+};
+
+} // end namespace common
+} // end namespace timecho
+
+
+#endif
diff --git a/cpp/tsfile/src/common/container/slice.h b/cpp/tsfile/src/common/container/slice.h
new file mode 100644
index 00000000..b2e44247
--- /dev/null
+++ b/cpp/tsfile/src/common/container/slice.h
@@ -0,0 +1,142 @@
+#ifndef COMMON_CONTAINER_SLICE_H
+#define COMMON_CONTAINER_SLICE_H
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <string>
+#include "common/allocator/alloc_base.h"
+#include "common/logger/elog.h"
+#include "common/errno_define.h"
+#include "common/util_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+class Slice
+{
+ public:
+ // Create an empty slice.
+ // Slice() : data_(""), size_(0) {}
+ Slice()
+ {
+ data_ = nullptr;
+ size_ = 0;
+ }
+
+ // Create a slice that refers to the contents of "s"
+ // Slice(const std::string& s) : data_(s.data()), size_(s.size()) {}
+ Slice(const std::string &s)
+ {
+ int len = s.size();
+ data_ = (char *)malloc(len + 1); // TODO: user ourself's mem_alloc()
+ if (UNLIKELY(nullptr == data_)) {
+ log_error("malloc() failed.");
+ }
+ strcpy(data_, s.c_str());
+ size_ = len;
+ }
+
+ // Create a slice that refers to s[0,strlen(s)-1]
+ // Slice(const char* s) : data_(s), size_(strlen(s)) {}
+ Slice(const char *s)
+ {
+ int len = strlen(s);
+ data_ = (char *)malloc(len + 1); // TODO: user ourself's mem_alloc()
+ if (UNLIKELY(nullptr == data_)) {
+ log_error("malloc() failed.");
+ }
+ strcpy(data_, s);
+ size_ = len;
+ }
+
+ ~Slice()
+ {
+ free(data_); // TODO: user ourself's mem_free()
+ data_ = nullptr;
+ size_ = 0;
+ }
+
+ // Intentionally copyable.
+ // Slice(const Slice&) = default;
+ // Slice& operator=(const Slice&) = default;
+ Slice(const Slice &other)
+ {
+ int len = other.size_;
+ data_ = (char *)malloc(len + 1); // TODO: user ourself's mem_alloc()
+ if (UNLIKELY(nullptr == data_)) {
+ log_error("malloc() failed.");
+ }
+ strcpy(data_, other.data_);
+ size_ = len;
+ }
+ Slice& operator=(const Slice &other)
+ {
+ if (this->data_ != nullptr) {
+ free(data_); // TODO: user ourself's mem_free()
+ data_ = nullptr;
+ }
+ int len = other.size_;
+ this->data_ = (char *)malloc(len + 1); // TODO: user ourself's mem_alloc()
+ if (UNLIKELY(nullptr == data_)) {
+ log_error("malloc() failed.");
+ }
+ strcpy(this->data_, other.data_);
+ this->size_ = len;
+ return *this;
+ }
+
+ // Return a pointer to the beginning of the referenced data
+ char* data() const { return data_; }
+
+ // Return the length (in bytes) of the referenced data
+ size_t size() const { return size_; }
+
+ // Return true iff the length of the referenced data is zero
+ bool empty() const { return size_ == 0; }
+
+ // Return the ith byte in the referenced data.
+ char operator[](size_t n) const {
+ ASSERT(n < size());
+ return data_[n];
+ }
+
+ // Return a string that contains the copy of the referenced data.
+ std::string to_string() const { return std::string(data_, size_); }
+
+ friend bool operator==(const Slice &x, const Slice &y) {
+ return ((x.size() == y.size()) &&
+ (memcmp(x.data(), y.data(), x.size()) == 0));
+ }
+
+ friend bool operator!=(const Slice &x, const Slice &y) { return !(x == y); }
+
+ // Three-way comparison. Returns value:
+ // < 0 iff "*this" < "b",
+ // == 0 iff "*this" == "b",
+ // > 0 iff "*this" > "b"
+ int compare(const Slice &b) const
+ {
+ const size_t min_len = (size_ < b.size_) ? size_ : b.size_;
+ int r = memcmp(data_, b.data_, min_len);
+ if (r == 0) {
+ if (size_ < b.size_)
+ r = -1;
+ else if (size_ > b.size_)
+ r = +1;
+ }
+ return r;
+ }
+
+
+private:
+ char *data_;
+ size_t size_;
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_CONTAINER_SLICE_H
diff --git a/cpp/tsfile/src/common/container/sorted_array.h b/cpp/tsfile/src/common/container/sorted_array.h
new file mode 100644
index 00000000..dfcae3b2
--- /dev/null
+++ b/cpp/tsfile/src/common/container/sorted_array.h
@@ -0,0 +1,333 @@
+/*
+* no duplicated elements
+*/
+#ifndef COMMON_CONTAINER_SORTEDARRAY_H
+#define COMMON_CONTAINER_SORTEDARRAY_H
+
+#include <cstdlib>
+#include <cstdio>
+#include <stdint.h>
+#include <cstring>
+#include <iostream>
+#include "common/allocator/alloc_base.h"
+#include "common/logger/elog.h"
+#include "common/errno_define.h"
+#include "common/util_define.h"
+
+#define SORTED_ARRAY_INIT_CAPACITY 1000 // TODO: configurable mode
+#define SORTED_ARRAY_GROWTH_THRESHOLD 50 // TODO: configurable mode
+#define SORTED_ARRAY_SHRINK_THRESHOLD 50 // TODO: configurable mode
+
+namespace timecho
+{
+namespace common
+{
+
+template <class ValueType>
+class SortedArray
+{
+public:
+
+#ifndef NDEBUG
+ friend std::ostream& operator << (std::ostream &out, SortedArray<ValueType> &sa)
+ {
+ for (size_t idx = 0; idx < sa.size(); idx++) {
+ if (idx > 0) {
+ out << ' ';
+ }
+ out << sa.at(idx);
+ }
+ out << std::endl;
+ return out;
+ }
+#endif // NDEBUG
+
+ SortedArray()
+ {
+ capacity_ = SORTED_ARRAY_INIT_CAPACITY;
+ size_ = 0;
+ is_inited_ = false;
+ array_ = nullptr;
+ }
+
+ SortedArray(size_t capacity)
+ {
+ capacity_ = capacity;
+ size_ = 0;
+ is_inited_ = false;
+ array_ = nullptr;
+ }
+
+ ~SortedArray()
+ {
+ if (is_inited_) {
+ destroy();
+ }
+ capacity_ = 0;
+ size_ = 0;
+ }
+
+ // int deep_copy(const SortedArray &other)
+ // {
+ // this->capacity_ = other.capacity_;
+ // this->size_ = other.size_;
+ // if (init() == E_OK) {
+ // memcpy(this->array_, other.array_, this->capacity_ * sizeof(*(this->array_)));
+ // return E_OK;
+ // }
+ // return E_OOM;
+ // }
+
+ int init()
+ {
+ if (is_inited_) {
+ log_error("init repeated.");
+ ASSERT(!is_inited_);
+ }
+ array_ = (ValueType *)mem_alloc(capacity_ * sizeof(*(array_)), MOD_ARRAY);
+ if (UNLIKELY(nullptr == array_)) {
+ is_inited_ = false;
+ log_error("malloc failed.");
+ return E_OOM;
+ }
+ is_inited_ = true;
+ return E_OK;
+ }
+
+ void destroy()
+ {
+ capacity_ = 0;
+ size_ = 0;
+ if (is_inited_) {
+ mem_free(array_);
+ array_ = nullptr;
+ }
+ is_inited_ = false;
+ }
+
+private:
+ static size_t linear_calc(size_t input)
+ {
+ if (input < SORTED_ARRAY_GROWTH_THRESHOLD) {
+ return input;
+ }
+ size_t res = 1;
+ input /= 10;
+ while (input) {
+ input /= 10;
+ res *= 10;
+ }
+ return res;
+ }
+
+ int extend()
+ {
+ // Check for a potential overflow
+ uint64_t tmp = (uint64_t) (linear_calc(capacity_) + capacity_);
+ if (tmp > SIZE_MAX) {
+ log_error("size overflow.");
+ return E_OVERFLOW;
+ }
+
+ size_t new_capacity = (size_t) tmp;
+ array_ = (ValueType *)mem_realloc(array_, new_capacity * sizeof(*(array_)));
+ if (UNLIKELY(nullptr == array_)) {
+ log_error("realloc failed.");
+ return E_OOM;
+ }
+ capacity_ = new_capacity;
+ return E_OK;
+ }
+
+ int shrink()
+ {
+ size_t new_capacity = (size_t)(capacity_ / 2);
+ // if the size passed to realloc is smaller than before, OS will automatically release the rest memory
+ array_ = (ValueType *)mem_realloc(array_, new_capacity * sizeof(*(array_))); // TODO: user ourself's mem_alloc()
+ if (UNLIKELY(nullptr == array_)) {
+ log_error("malloc failed.");
+ return E_OOM;
+ }
+ capacity_ = new_capacity;
+ return E_OK;
+ }
+
+public:
+ int insert(const ValueType &value)
+ {
+ if (size_ >= capacity_) {
+ int ret = extend();
+ if(ret != E_OK) {
+ return ret;
+ }
+ }
+
+ bool found = false;
+ size_t pos = find(value, found);
+ if (found) {
+ log_warn("the new value has already in the sorted array.");
+ return E_ALREADY_EXIST;
+ }
+
+ if (pos == size_) {
+ array_[pos] = value;
+ size_++;
+ return E_OK;
+ }
+
+ memmove(array_ + (pos + 1), array_ + pos, (size_ - pos) * sizeof(*(array_)));
+ array_[pos] = value;
+ size_++;
+ return E_OK;
+ }
+
+ FORCE_INLINE ValueType at(size_t idx)
+ {
+ if (idx >= size_) {
+ log_error("index %lu is out of range, because size is %lu.", idx, size_);
+ ASSERT(idx < size_);
+ return dummy_;
+ }
+ return array_[idx];
+ }
+
+ FORCE_INLINE ValueType operator [] (size_t idx)
+ {
+ if (idx >= size_) {
+ log_error("index %lu is out of range, because size is %lu.", idx, size_);
+ ASSERT(idx < size_);
+ return dummy_;
+ }
+ return array_[idx];
+ }
+
+ bool contain(const ValueType &target_val)
+ {
+ if (size_ == 0) {
+ return false;
+ }
+ int64_t left = 0;
+ int64_t right = size_ - 1;
+ while (left <= right) {
+ size_t mid = (left + right) / 2;
+ ValueType mid_val = array_[mid];
+ if (mid_val == target_val) {
+ return true;
+ } else if (mid_val < target_val) {
+ left = mid + 1;
+ } else if (mid_val > target_val) {
+ right = mid - 1;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * if the value is not found, then set 'found' is false ant return the first bigger one's location
+ */
+ size_t find(const ValueType &target_val, bool &found)
+ {
+ if (size_ == 0) {
+ found = false;
+ return 0;
+ }
+ int64_t left = 0;
+ int64_t right = size_ - 1;
+ while (left <= right) {
+ size_t mid = (left + right) / 2;
+ ValueType mid_val = array_[mid];
+ if (mid_val == target_val) {
+ found = true;
+ return mid;
+ } else if (mid_val < target_val) {
+ left = mid + 1;
+ } else if (mid_val > target_val) {
+ right = mid - 1;
+ }
+ }
+ found = false;
+ return (size_t)left;
+ }
+
+ ValueType remove(size_t idx)
+ {
+ if (idx >= size_) {
+ log_error("index %lu is out of range, because size is %lu.", idx, size_);
+ ASSERT(idx < size_);
+ }
+ if (capacity_ > SORTED_ARRAY_SHRINK_THRESHOLD && size_ <= capacity_ / 4) {
+ shrink();
+ }
+ ValueType ret = array_[idx];
+ memmove(array_ + idx, array_ + idx + 1, (size_ - idx - 1) * sizeof(*(array_)));
+ size_--;
+
+ return ret;
+ }
+
+ int remove_value(const ValueType &value)
+ {
+ bool found = false;
+ size_t pos = find(value, found);
+ if(found) {
+ remove(pos);
+ } else {
+ log_warn("the value is not exist in the array.");
+ return E_NOT_EXIST;
+ }
+ return E_OK;
+ }
+
+ FORCE_INLINE void clear()
+ {
+ size_ = 0;
+ }
+
+ ValueType get_min()
+ {
+ if (size_ == 0) {
+ log_warn("The array is empty now.");
+ ASSERT(size_ > 0);
+ return dummy_;
+ }
+ return array_[0];
+ }
+
+ ValueType& get_max()
+ {
+ if (size_ == 0) {
+ log_warn("The array is empty now.");
+ ASSERT(size_ > 0);
+ return dummy_;
+ }
+ return array_[size_ - 1];
+ }
+
+ FORCE_INLINE bool empty() const
+ {
+ return ATOMIC_LOAD(&size_) == 0;
+ }
+
+ FORCE_INLINE size_t size() const
+ {
+ return ATOMIC_LOAD(&size_);
+ }
+
+ FORCE_INLINE size_t capacity() const
+ {
+ return ATOMIC_LOAD(&capacity_);
+ }
+
+private:
+ size_t capacity_;
+ size_t size_;
+ ValueType *array_;
+ ValueType dummy_;
+ bool is_inited_;
+};
+
+} // end namespace common
+} // end namespace timecho
+
+
+#endif // COMMON_CONTAINER_SORTEDARRAY_H
diff --git a/cpp/tsfile/src/common/datatype/CMakeLists.txt b/cpp/tsfile/src/common/datatype/CMakeLists.txt
new file mode 100644
index 00000000..9beefbae
--- /dev/null
+++ b/cpp/tsfile/src/common/datatype/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+# message("Running in src/common/datatype directory")
+#
+# aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} common_datatype_SRC_LIST)
+# set(common_datatype_INC_LIST)
+# set(common_datatype_DEFINE_OPTIONS)
+# set(common_datatype_COMPILE_OPTIONS)
+# set(common_datatype_LINK_OPTIONS)
+#
+# add_statis_objtarget(common_datatype common_datatype_SRC_LIST common_datatype_INC_LIST
+# "${common_datatype_DEFINE_OPTIONS}"
+# "${common_datatype_COMPILE_OPTIONS}"
+# "${common_datatype_LINK_OPTIONS}")
diff --git a/cpp/tsfile/src/common/datatype/value.h b/cpp/tsfile/src/common/datatype/value.h
new file mode 100644
index 00000000..bc73cb71
--- /dev/null
+++ b/cpp/tsfile/src/common/datatype/value.h
@@ -0,0 +1,216 @@
+#ifndef COMMON_DATATYPE_VALUE_H
+#define COMMON_DATATYPE_VALUE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <float.h>
+#include <vector>
+#include <utility>
+
+#include "common/db_utils.h"
+#include "common/logger/elog.h"
+
+namespace timecho
+{
+namespace common
+{
+
+struct Value
+{
+ Value(TSDataType type) : type_(type) {}
+
+ ~Value()
+ {
+ if (value_.sval_) {
+ free(value_.sval_);
+ }
+ }
+
+ FORCE_INLINE void free_memory()
+ {
+ if (value_.sval_) {
+ free(value_.sval_);
+ value_.sval_ = nullptr;
+ }
+ }
+
+ FORCE_INLINE bool is_type(TSDataType type) const
+ {
+ return type == type_;
+ }
+
+ FORCE_INLINE bool is_literal() const
+ {
+ return is_type(BOOLEAN) || is_type(DOUBLE) ||
+ is_type(TEXT) || is_type(INT64) || is_type(NULL_TYPE);
+ }
+
+ template<class T>
+ FORCE_INLINE void set_value(TSDataType type, T val)
+ {
+ type_ = type;
+ switch (type) {
+ case common::BOOLEAN: {
+ value_.bval_ = *(bool*)val;
+ break;
+ }
+ case common::INT32: {
+ value_.ival_ = *(int32_t*)val;
+ break;
+ }
+ case common::INT64: {
+ value_.lval_ = *(int64_t*)val;
+ break;
+ }
+ case common::FLOAT: {
+ value_.fval_ = *(float*)val;
+ break;
+ }
+ case common::DOUBLE: {
+ value_.dval_ = *(double*)val;
+ break;
+ }
+ case common::TEXT: {
+ value_.sval_ = strdup(val);
+ break;
+ }
+ default: {
+ common::log_error("unknown data type");
+ }
+ }
+ }
+
+public:
+ TSDataType type_;
+
+ union {
+ bool bval_;
+ int64_t lval_;
+ int32_t ival_;
+ float fval_;
+ double dval_;
+ char *sval_;
+ } value_;
+};
+
+FORCE_INLINE Value* make(TSDataType type)
+{
+ Value *value = new Value(type);
+ return value;
+}
+
+FORCE_INLINE Value* make_literal(int64_t val)
+{
+ Value *value = new Value(INT64);
+ value->value_.lval_ = val;
+ return value;
+}
+
+FORCE_INLINE Value* make_literal(double val)
+{
+ Value *value = new Value(DOUBLE);
+ value->value_.dval_ = val;
+ return value;
+}
+
+FORCE_INLINE Value* make_literal(char *string)
+{
+ Value *value = new Value(TEXT);
+ value->value_.sval_ = string;
+ return value;
+}
+
+FORCE_INLINE Value* make_literal(bool val)
+{
+ Value *value = new Value(BOOLEAN);
+ value->value_.bval_ = val;
+ return value;
+}
+
+FORCE_INLINE Value* make_null_literal()
+{
+ Value *value = new Value(NULL_TYPE);
+ return value;
+}
+
+FORCE_INLINE std::string value_to_string(Value *value)
+{
+ if (value->type_ == timecho::common::TEXT) {
+ return std::string(value->value_.sval_);
+ } else {
+ std::stringstream ss;
+ switch (value->type_) {
+ case timecho::common::BOOLEAN:
+ ss << (value->value_.bval_ ? "true" : "false");
+ break;
+ case timecho::common::INT32:
+ case timecho::common::INT64:
+ ss << value->value_.lval_;
+ break;
+ case timecho::common::FLOAT:
+ case timecho::common::DOUBLE:
+ ss << value->value_.dval_;
+ break;
+ case timecho::common::NULL_TYPE:
+ ss << "NULL";
+ default:
+ ASSERT(false);
+ break;
+ }
+ return ss.str();
+ }
+}
+
+// return true if cast succ.
+template<typename T>
+FORCE_INLINE int get_typed_data_from_value(Value *value, T &ret_data) { return E_OK; }
+
+template<> FORCE_INLINE int get_typed_data_from_value<bool>(Value *value, bool &ret_data)
+{
+ ret_data = value->value_.bval_;
+ return (value->type_ == BOOLEAN) ? E_OK : E_TYPE_NOT_MATCH;
+}
+
+template<> FORCE_INLINE int get_typed_data_from_value<int32_t>(Value *value, int32_t &ret_data)
+{
+ if (value->value_.lval_ > INT32_MAX || value->value_.lval_ < INT32_MIN) {
+ return E_OVERFLOW;
+ }
+ ret_data = (int32_t)value->value_.lval_;
+ // number value will be parsed as INT64
+ return (value->type_ == INT64) ? E_OK : E_TYPE_NOT_MATCH;
+}
+
+template<> FORCE_INLINE int get_typed_data_from_value<int64_t>(Value *value, int64_t &ret_data)
+{
+ ret_data = value->value_.lval_;
+ return (value->type_ == INT64) ? E_OK : E_TYPE_NOT_MATCH;
+}
+
+template<> FORCE_INLINE int get_typed_data_from_value<float>(Value *value, float &ret_data)
+{
+ if (value->value_.dval_ > FLT_MAX || value->value_.dval_ < FLT_MIN) {
+ return E_OVERFLOW;
+ }
+ ret_data = (float)value->value_.dval_;
+ return (value->type_ == DOUBLE) ? E_OK : E_TYPE_NOT_MATCH;
+}
+
+template<> FORCE_INLINE int get_typed_data_from_value<double>(Value *value, double &ret_data)
+{
+ ret_data = value->value_.dval_;
+ return (value->type_ == DOUBLE) ? E_OK : E_TYPE_NOT_MATCH;
+}
+
+// template<> FORCE_INLINE int get_typed_data_from_value<Text>(Value *value, Text &ret_data)
+// {
+// ret_data.buf_ = value->value_.sval_;
+// ret_data.len_ = strlen(ret_data.buf_);
+// return value->type_ == TEXT;
+// }
+
+} // common
+} // timecho
+
+#endif // COMMON_DATATYPE_VALUE_H
diff --git a/cpp/tsfile/src/common/db_common.h b/cpp/tsfile/src/common/db_common.h
new file mode 100644
index 00000000..9ab5b2ad
--- /dev/null
+++ b/cpp/tsfile/src/common/db_common.h
@@ -0,0 +1,168 @@
+
+#ifndef COMMON_DB_COMMON_H
+#define COMMON_DB_COMMON_H
+
+#include <iostream>
+#include "common/util_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+enum TSDataType
+{
+ BOOLEAN = 0,
+ INT32 = 1,
+ INT64 = 2,
+ FLOAT = 3,
+ DOUBLE = 4,
+ TEXT = 5,
+ VECTOR = 6,
+ NULL_TYPE = 254,
+ INVALID_DATATYPE = 255
+};
+
+enum TSEncoding
+{
+ PLAIN = 0,
+ DICTIONARY = 1,
+ RLE = 2,
+ DIFF = 3,
+ TS_2DIFF = 4,
+ BITMAP = 5,
+ GORILLA_V1 = 6,
+ REGULAR = 7,
+ GORILLA = 8,
+ ZIGZAG = 9,
+ FREQ = 10,
+ INVALID_ENCODING = 255
+};
+
+enum CompressionType
+{
+ UNCOMPRESSED = 0,
+ SNAPPY = 1,
+ GZIP = 2,
+ LZO = 3,
+ SDT = 4,
+ PAA = 5,
+ PLA = 6,
+ LZ4 = 7,
+ INVALID_COMPRESSION = 255
+};
+
+extern const char* s_data_type_names[7];
+extern const char* s_encoding_names[12];
+extern const char* s_compression_names[8];
+
+FORCE_INLINE const char* get_data_type_name(TSDataType type)
+{
+ ASSERT(type >= BOOLEAN && type <= VECTOR);
+ return s_data_type_names[type];
+}
+
+FORCE_INLINE const char* get_encoding_name(TSEncoding encoding)
+{
+ ASSERT(encoding >= PLAIN && encoding <= FREQ);
+ return s_encoding_names[encoding];
+}
+
+FORCE_INLINE const char* get_compression_name(CompressionType type)
+{
+ return s_compression_names[type];
+}
+
+FORCE_INLINE TSEncoding get_default_encoding_for_type(TSDataType type)
+{
+ if (type == timecho::common::BOOLEAN) {
+ return PLAIN;
+ } else if (type == timecho::common::INT32) {
+ return PLAIN;
+ } else if (type == timecho::common::INT64) {
+ return PLAIN;
+ } else if (type == timecho::common::FLOAT) {
+ return PLAIN;
+ } else if (type == timecho::common::DOUBLE) {
+ return PLAIN;
+ } else if (type == timecho::common::TEXT) {
+ return PLAIN;
+ } else {
+ ASSERT(false);
+ }
+ return INVALID_ENCODING;
+}
+
+FORCE_INLINE CompressionType get_default_compression_for_type(TSDataType type)
+{
+ if (type == timecho::common::BOOLEAN) {
+ return UNCOMPRESSED;
+ } else if (type == timecho::common::INT32) {
+ return UNCOMPRESSED;
+ } else if (type == timecho::common::INT64) {
+ return UNCOMPRESSED;
+ } else if (type == timecho::common::FLOAT) {
+ return UNCOMPRESSED;
+ } else if (type == timecho::common::DOUBLE) {
+ return UNCOMPRESSED;
+ } else if (type == timecho::common::TEXT) {
+ return UNCOMPRESSED;
+ } else {
+ ASSERT(false);
+ }
+ return INVALID_COMPRESSION;
+}
+
+enum Ordering
+{
+ DESC,
+ ASC
+};
+
+template<typename T>
+FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType() { return common::INVALID_DATATYPE; }
+
+template<> FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<bool>() { return common::BOOLEAN; }
+template<> FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<int32_t>() { return common::INT32; }
+template<> FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<int64_t>() { return common::INT64; }
+template<> FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<float>() { return common::FLOAT; }
+template<> FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<double>() { return common::DOUBLE; }
+
+FORCE_INLINE size_t get_data_type_size(TSDataType data_type)
+{
+ switch (data_type) {
+ case timecho::common::BOOLEAN:
+ return 1;
+ case timecho::common::INT32:
+ case timecho::common::FLOAT:
+ return 4;
+ case timecho::common::INT64:
+ case timecho::common::DOUBLE:
+ return 8;
+ default:
+ ASSERT(false);
+ return 8;
+ }
+}
+
+} // end namespace common
+
+namespace storage
+{
+
+struct TimeRange
+{
+ TimeRange() : start_time_(INT64_MAX),
+ end_time_(INT64_MIN) {}
+ TimeRange(int64_t start_time, int64_t end_time) : start_time_(start_time), end_time_(end_time) {}
+
+ int64_t start_time_;
+ int64_t end_time_;
+};
+
+}
+
+} // end namespace timecho
+
+#endif
+
diff --git a/cpp/tsfile/src/common/db_utils.h b/cpp/tsfile/src/common/db_utils.h
new file mode 100644
index 00000000..96358b53
--- /dev/null
+++ b/cpp/tsfile/src/common/db_utils.h
@@ -0,0 +1,457 @@
+
+#ifndef COMMON_UTILS_H
+#define COMMON_UTILS_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sstream>
+#include <string>
+#include <string.h> // memcpy
+#include <sys/time.h>
+#include <iostream>
+#include "common/util_define.h"
+#include "common/db_common.h"
+#include "common/allocator/my_string.h"
+
+namespace timecho
+{
+namespace common
+{
+
+typedef struct FileID
+{
+ int64_t seq_; // timestamp when create
+ int32_t version_;
+ int32_t merge_;
+
+ FileID() : seq_(0), version_(0), merge_(0) {}
+ void reset()
+ {
+ seq_ = 0;
+ version_ = 0;
+ merge_ = 0;
+ }
+ FORCE_INLINE bool is_valid() const { return seq_ != 0; }
+ FORCE_INLINE bool operator < (const FileID &that) const
+ {
+ return this->seq_ < that.seq_;
+ }
+ FORCE_INLINE bool operator == (const FileID &that) const
+ {
+ return this->seq_ == that.seq_;
+ }
+#ifndef NDEBUG
+ friend std::ostream& operator << (std::ostream& out, const FileID &file_id)
+ {
+ out << "{seq_=" << file_id.seq_ << ", version_=" << file_id.version_ << ", merge_=" << file_id.merge_ << "}";
+ return out;
+ }
+#endif
+} FileID;
+
+typedef uint16_t NodeID;
+struct TsID
+{
+ NodeID db_nid_;
+ NodeID device_nid_;
+ NodeID measurement_nid_;
+
+ TsID() : db_nid_(0),
+ device_nid_(0),
+ measurement_nid_(0) {};
+
+ TsID(NodeID db_nid,
+ NodeID device_nid,
+ NodeID measurement_nid)
+ : db_nid_(db_nid),
+ device_nid_(device_nid),
+ measurement_nid_(measurement_nid) {}
+
+ /*
+ * To make TsID to be a trival copyable struct.
+ */
+#if 0
+ TsID(const TsID &other) : db_nid_(other.db_nid_),
+ device_nid_(other.device_nid_),
+ measurement_nid_(other.measurement_nid_) {}
+
+ TsID & operator = (const TsID &other)
+ {
+ db_nid_ = other.db_nid_;
+ device_nid_ = other.device_nid_;
+ measurement_nid_ = other.measurement_nid_;
+ return *this;
+ }
+#endif
+
+ void reset()
+ {
+ db_nid_ = 0;
+ device_nid_ = 0;
+ measurement_nid_ = 0;
+ }
+
+ bool is_valid() const
+ {
+ // TODO
+ return true;
+ }
+
+ FORCE_INLINE bool operator == (const TsID &other) const
+ {
+ return db_nid_ == other.db_nid_
+ && device_nid_ == other.device_nid_
+ && measurement_nid_ == other.measurement_nid_;
+ }
+ FORCE_INLINE bool operator != (const TsID &other) const
+ {
+ return db_nid_ != other.db_nid_
+ || device_nid_ != other.device_nid_
+ || measurement_nid_ != other.measurement_nid_;
+ }
+
+ FORCE_INLINE int64_t to_int64() const
+ {
+ int64_t res = db_nid_;
+ res = (res << 16) | device_nid_;
+ res = (res << 16) | measurement_nid_;
+ return res;
+ }
+
+ FORCE_INLINE bool operator < (const TsID &that) const
+ {
+ return to_int64() < that.to_int64();
+ }
+
+ FORCE_INLINE bool operator > (const TsID &other)
+ {
+ return to_int64() > other.to_int64();
+ }
+
+ friend std::ostream& operator << (std::ostream& out, TsID& ti)
+ {
+ out << "(" << ti.db_nid_ << ", " << ti.device_nid_ << ", " << ti.measurement_nid_ << ") ";
+ return out;
+ }
+
+ FORCE_INLINE void to_string(char *print_buf, int len) const
+ {
+ snprintf(print_buf, len, "<%d,%d,%d>", db_nid_, device_nid_, measurement_nid_);
+ }
+ FORCE_INLINE std::string to_string() const
+ {
+ const int buf_len = 32;
+ char buf[buf_len];
+ snprintf(buf, buf_len, "<%d,%d,%d>", db_nid_, device_nid_, measurement_nid_);
+ // construct std::string will invoke memory allocation and copy.
+ // try to use first to_string instead.
+ return std::string(buf);
+ }
+};
+
+struct DeviceID
+{
+ NodeID db_nid_;
+ NodeID device_nid_;
+
+ DeviceID() : db_nid_(0),
+ device_nid_(0) {}
+ DeviceID(const NodeID db_nid, const NodeID device_nid)
+ : db_nid_(db_nid),
+ device_nid_(device_nid) {}
+ explicit DeviceID(const TsID &ts_id)
+ : db_nid_(ts_id.db_nid_),
+ device_nid_(ts_id.device_nid_) {}
+
+ FORCE_INLINE bool operator == (const DeviceID &other) const
+ {
+ return db_nid_ == other.db_nid_
+ && device_nid_ == other.device_nid_;
+ }
+ FORCE_INLINE bool operator != (const DeviceID &other) const
+ {
+ return db_nid_ != other.db_nid_
+ || device_nid_ != other.device_nid_;
+ }
+ FORCE_INLINE void from(const TsID &ts_id)
+ {
+ db_nid_ = ts_id.db_nid_;
+ device_nid_ = ts_id.device_nid_;
+ }
+ FORCE_INLINE bool operator < (const DeviceID &that) const
+ {
+ int32_t this_i32 = (((int32_t)db_nid_) << 16) | (device_nid_);
+ int32_t that_i32 = (((int32_t)that.db_nid_) << 16) | (that.device_nid_);
+ return this_i32 < that_i32;
+ }
+};
+
+#define INVALID_TTL (-1)
+
+// describe single database
+struct DatabaseDesc
+{
+ int64_t ttl_;
+ std::string db_name_;
+ TsID ts_id_;
+
+ DatabaseDesc() : ttl_(INVALID_TTL), db_name_(""), ts_id_() {}
+ DatabaseDesc(uint64_t ttl, const std::string &name, const TsID &ts_id) :
+ ttl_(ttl), db_name_(name), ts_id_(ts_id) {}
+};
+
+// Describe single timeseries
+struct ColumnDesc
+{
+ TSDataType type_;
+ TSEncoding encoding_;
+ CompressionType compression_;
+ int64_t ttl_; // obtained from the metadata and passed to the storage
+ std::string column_name_; // measurement name or Time
+ TsID ts_id_; // id of timeseries
+
+ ColumnDesc() :
+ type_(INVALID_DATATYPE),
+ encoding_(PLAIN),
+ compression_(UNCOMPRESSED),
+ ttl_(INVALID_TTL),
+ column_name_(""),
+ ts_id_() {}
+
+ ColumnDesc(TSDataType type,
+ TSEncoding encoding,
+ CompressionType compression,
+ uint64_t ttl,
+ const std::string &name,
+ const TsID &ts_id)
+ : type_(type),
+ encoding_(encoding),
+ compression_(compression),
+ ttl_(ttl),
+ column_name_(name),
+ ts_id_(ts_id) {}
+
+ ~ColumnDesc() {}
+
+ bool operator == (const ColumnDesc &other) const
+ {
+ return (type_ == other.type_
+ && encoding_ == other.encoding_
+ && compression_ == other.compression_
+ && column_name_ == other.column_name_
+ && ts_id_ == other.ts_id_);
+ }
+
+ bool operator != (const ColumnDesc &other) const
+ {
+ return (type_ != other.type_
+ || encoding_ != other.encoding_
+ || compression_ != other.compression_
+ || column_name_ != other.column_name_
+ || ts_id_ != other.ts_id_);
+ }
+
+ bool is_valid() const
+ {
+ return type_ != INVALID_DATATYPE
+ && encoding_ != INVALID_ENCODING
+ && compression_ != INVALID_COMPRESSION
+ && ts_id_.is_valid();
+ }
+
+ void reset()
+ {
+ // TODO
+ }
+
+ void get_device_name(char *ret_device_name_buf,
+ const int buf_len,
+ uint32_t &ret_len) const
+ {
+ int pos = column_name_.find_last_of('.');
+ ASSERT(pos > 0 && pos < buf_len);
+ memcpy(ret_device_name_buf, column_name_.c_str(), pos);
+ ret_device_name_buf[pos] = '\0';
+ ret_len = pos;
+ }
+ std::string get_device_name_str() const
+ {
+ int pos = column_name_.find_last_of('.');
+ ASSERT(pos > 0);
+ return column_name_.substr(0, pos);
+ }
+ void get_device_name(String &device_name) const
+ {
+ int pos = column_name_.find_last_of('.');
+ ASSERT(pos > 0);
+ const char *c_string = column_name_.c_str();
+ device_name.buf_ = (char*)c_string;
+ device_name.len_ = pos;
+ }
+ void get_measurement_name(char *ret_measurement_name_buf,
+ const int buf_len,
+ uint32_t &ret_len) const
+ {
+ int pos = column_name_.find_last_of('.');
+ ASSERT(pos > 0 && pos < buf_len);
+ ret_len = column_name_.size() - pos - 1;
+ memcpy(ret_measurement_name_buf, column_name_.c_str() + pos + 1, ret_len);
+ ret_measurement_name_buf[ret_len] = '\0';
+ }
+ std::string get_measurement_name_str() const
+ {
+ int pos = column_name_.find_last_of('.');
+ ASSERT(pos > 0);
+ return column_name_.substr(pos + 1, column_name_.size() - pos);
+ }
+ // TODO remove
+ void get_measurement_name(String &measurement_name) const
+ {
+ int pos = column_name_.find_last_of('.');
+ ASSERT(pos > 0);
+ const char *c_string = column_name_.c_str();
+ measurement_name.buf_ = (char*)c_string + pos + 1;
+ measurement_name.len_ = column_name_.size() - pos - 1;
+ }
+ String get_measurement_name()
+ {
+ int pos = column_name_.find_last_of('.');
+ ASSERT(pos > 0);
+ const char *c_string = column_name_.c_str();
+ String res;
+ res.buf_ = (char*)c_string + pos + 1;
+ res.len_ = column_name_.size() - pos - 1;
+ return res;
+ }
+
+ std::string debug_string() // for debug
+ {
+ std::stringstream out;
+ out << "print ColumnDesc: " << this << std::endl
+ << "name: " << column_name_.c_str() << std::endl
+ << "datatype: " << type_ << std::endl
+ << "encoding: " << encoding_ << std::endl
+ << "compression:" << compression_ << std::endl
+ << "ttl:" << ttl_ << std::endl
+ << "tsid:" << ts_id_.to_string().c_str() << std::endl;
+ return out.str();
+ }
+};
+
+enum WALFlushPolicy
+{
+ WAL_DISABLED = 0,
+ WAL_ASYNC = 1,
+ WAL_FLUSH = 2,
+ WAL_SYNC = 3,
+};
+
+template<typename T>
+std::string to_string(const T &val)
+{
+ // todo: There may be a better way to avoid the memory problem of ostringstream
+ std::ostringstream oss;
+ oss << val;
+ return oss.str();
+}
+
+// TODO rename to DatabaseIdTTL
+struct DatabaseIdTTL
+{
+ NodeID db_nid_;
+ int64_t ttl_;
+ DatabaseIdTTL() {}
+ DatabaseIdTTL(NodeID db_nid, int64_t ttl) : db_nid_(db_nid), ttl_(ttl) {}
+ DatabaseIdTTL(const DatabaseIdTTL &other) : db_nid_(other.db_nid_), ttl_(other.ttl_) {}
+ DatabaseIdTTL & operator = (const DatabaseIdTTL &other)
+ {
+ this->db_nid_ = other.db_nid_;
+ this->ttl_ = other.ttl_;
+ return *this;
+ }
+ bool operator == (const DatabaseIdTTL &other)
+ {
+ if (db_nid_ != other.db_nid_ || ttl_ != other.ttl_) {
+ return false;
+ }
+ return true;
+ }
+ friend std::ostream& operator << (std::ostream& out, DatabaseIdTTL& di)
+ {
+ out << "(" << di.db_nid_ << ", " << di.ttl_ << ") ";
+ return out;
+ }
+};
+
+FORCE_INLINE int64_t get_cur_timestamp()
+{
+ int64_t timestamp = 0;
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) >= 0) {
+ timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ }
+ return timestamp;
+}
+
+#if 0
+struct DatabaseIdTTL
+{
+ NodeID db_nid_;
+ int64_t ttl_;
+ int16_t counter_; // suppose we at most support 64k timeseries.
+ DatabaseIdTTL() {}
+ DatabaseIdTTL(NodeID db_nid, int64_t ttl, int16_t counter) : db_nid_(db_nid), ttl_(ttl), counter_(counter) {}
+ DatabaseIdTTL(const DatabaseIdTTL &other) : db_nid_(other.db_nid_), ttl_(other.ttl_), counter_(other.counter_) {}
+ DatabaseIdTTL & operator = (const DatabaseIdTTL &other)
+ {
+ this->db_nid_ = other.db_nid_;
+ this->ttl_ = other.ttl_;
+ this->counter_ = other.counter_;
+ return *this;
+ }
+ bool operator == (const DatabaseIdTTL &other)
+ {
+ if (db_nid_ != other.db_nid_ || ttl_ != other.ttl_ || counter_ != other.counter_) {
+ return false;
+ }
+ return true;
+ }
+ friend std::ostream& operator << (std::ostream& out, DatabaseIdTTL& di)
+ {
+
+ return out;
+ }
+};
+
+struct DeviceIDWithCounter
+{
+ NodeID device_nid_;
+ int16_t counter_; // suppose we at most support 64k timeseries.
+ DeviceIDWithCounter() {}
+ DeviceIDWithCounter(NodeID device_nid, int16_t counter) : device_nid_(device_nid), counter_(counter) {}
+ DeviceIDWithCounter(const DeviceIDWithCounter &other) : device_nid_(other.device_nid_), counter_(other.counter_) {}
+ DeviceIDWithCounter& operator = (const DeviceIDWithCounter &other)
+ {
+ this->device_nid_ = other.device_nid_;
+ this->counter_ = other.counter_;
+ return *this;
+ }
+ bool operator == (const DeviceID &other)
+ {
+ if (device_nid_ != other.device_nid_ || counter_ != other.counter_) {
+ return false;
+ }
+ return true;
+ }
+ friend std::ostream& operator << (std::ostream& out, DeviceID& di)
+ {
+ out << "(" << di.device_nid_ << ", " << di.counter_ << ") ";
+ return out;
+ }
+};
+#endif
+
+} // end namespace common
+} // end namespace timecho
+
+#endif
diff --git a/cpp/tsfile/src/common/errno_define.h b/cpp/tsfile/src/common/errno_define.h
new file mode 100644
index 00000000..eef043cc
--- /dev/null
+++ b/cpp/tsfile/src/common/errno_define.h
@@ -0,0 +1,64 @@
+
+#ifndef COMMON_ERRNO_DEFINE_H
+#define COMMON_ERRNO_DEFINE_H
+
+namespace timecho
+{
+namespace common
+{
+
+const int E_OK = 0;
+const int E_OOM = 1;
+const int E_NOT_EXIST = 2;
+const int E_ALREADY_EXIST = 3;
+const int E_INVALID_ARG = 4;
+const int E_OUT_OF_RANGE = 5;
+const int E_PARTIAL_READ = 6;
+const int E_NET_BIND_ERR = 7;
+const int E_NET_SOCKET_ERR = 8;
+const int E_NET_EPOLL_ERR = 9;
+const int E_NET_EPOLL_WAIT_ERR = 10;
+const int E_NET_RECV_ERR = 11;
+const int E_NET_ACCEPT_ERR = 12;
+const int E_NET_FCNTL_ERR = 13;
+const int E_NET_LISTEN_ERR = 14;
+const int E_NET_SEND_ERR = 15;
+const int E_PIPE_ERR = 16;
+const int E_THREAD_CREATE_ERR = 17;
+const int E_MUTEX_ERR = 18;
+const int E_COND_ERR = 19;
+const int E_OVERFLOW = 20;
+const int E_NO_MORE_DATA = 21;
+const int E_OUT_OF_ORDER = 22;
+const int E_TSBLOCK_TYPE_NOT_SUPPORTED = 23;
+const int E_TSBLOCK_DATA_INCONSISTENCY = 24;
+const int E_DDL_UNKNOWN_TYPE = 25;
+const int E_TYPE_NOT_SUPPORTED = 26;
+const int E_TYPE_NOT_MATCH = 27;
+const int E_FILE_OPEN_ERR = 28;
+const int E_FILE_CLOSE_ERR = 29;
+const int E_FILE_WRITE_ERR = 30;
+const int E_FILE_READ_ERR = 31;
+const int E_FILE_SYNC_ERR = 32;
+const int E_TSFILE_WRITER_META_ERR = 33;
+const int E_FILE_STAT_ERR = 34;
+const int E_TSFILE_CORRUPTED = 35;
+const int E_BUF_NOT_ENOUGH = 36;
+const int E_INVALID_PATH = 37;
+const int E_NOT_MATCH = 38;
+const int E_JSON_INVALID = 39;
+const int E_NOT_SUPPORT = 40;
+const int E_PARSER_ERR = 41;
+const int E_ANALYZE_ERR = 42;
+const int E_INVALID_DATA_POINT = 43;
+const int E_DEVICE_NOT_EXIST = 44;
+const int E_MEASUREMENT_NOT_EXIST = 45;
+const int E_INVALID_QUERY = 46;
+const int E_SDK_QUERY_OPTIMIZE_ERR = 47;
+const int E_COMPRESS_ERR = 48;
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_ERRNO_DEFINE_H
+
diff --git a/cpp/tsfile/src/common/global.cc b/cpp/tsfile/src/common/global.cc
new file mode 100644
index 00000000..d8b96399
--- /dev/null
+++ b/cpp/tsfile/src/common/global.cc
@@ -0,0 +1,201 @@
+
+#include "global.h"
+#include <stdlib.h>
+#include <execinfo.h>
+#include "injection.h"
+
+namespace timecho
+{
+namespace common
+{
+
+ColumnDesc g_time_column_desc;
+ConfigValue g_config_value_;
+
+// TODO move to server.cc ?
+void init_config_value()
+{
+ g_config_value_.tsblock_mem_inc_step_size_ = 8000; // 8k
+ g_config_value_.tsblock_max_memory_ = 64000; // 64k
+ // g_config_value_.tsblock_max_memory_ = 32;
+ g_config_value_.rest_service_ip_ = "0.0.0.0";
+
+ char *timechodb_port = getenv("TIMECHODB_PORT");
+ if (nullptr == timechodb_port) {
+ g_config_value_.rest_service_port_ = 8899;
+ } else {
+ g_config_value_.rest_service_port_ = atoi(timechodb_port);
+ }
+
+ g_config_value_.wal_flush_policy_ = WAL_DISABLED;
+ g_config_value_.seqtvlist_primary_array_size_ = 32; // 32;
+ g_config_value_.seqtvlist_max_record_count_ = 1024; // 64;
+ g_config_value_.page_writer_max_point_num_ = 5;
+ g_config_value_.page_writer_max_memory_bytes_ = 128 * 1024; // 128 k
+ g_config_value_.max_degree_of_index_node_ = 256;
+ g_config_value_.tsfile_index_bloom_filter_error_percent_ = 0.05;
+ // g_config_value_.tsfile_prefix_path_ = "./data";
+ g_config_value_.tsfile_prefix_path_ = "";
+ //g_config_value_.time_encoding_type_ = TS_2DIFF;
+ g_config_value_.time_encoding_type_ = PLAIN;
+ g_config_value_.memtable_flusher_poll_interval_seconds_ = 1;
+}
+
+void config_set_page_max_point_count(uint32_t page_max_ponint_count)
+{
+ g_config_value_.page_writer_max_point_num_ = page_max_ponint_count;
+}
+
+void config_set_max_degree_of_index_node(uint32_t max_degree_of_index_node)
+{
+ g_config_value_.max_degree_of_index_node_ = max_degree_of_index_node;
+}
+
+void set_config_value() {}
+
+const char* s_data_type_names[7] = {
+ "BOOLEAN",
+ "INT32",
+ "INT64",
+ "FLOAT",
+ "DOUBLE",
+ "TEXT",
+ "VECTOR"
+};
+
+const char* s_encoding_names[12] = {
+ "PLAIN",
+ "DICTIONARY",
+ "RLE",
+ "DIFF",
+ "TS_2DIFF",
+ "BITMAP",
+ "GORILLA_V1",
+ "REGULAR",
+ "GORILLA",
+ "ZIGZAG",
+ "FREQ"
+};
+
+const char* s_compression_names[8] = {
+ "UNCOMPRESSED",
+ "SNAPPY",
+ "GZIP",
+ "LZO",
+ "SDT",
+ "PAA",
+ "PLA",
+ "LZ4",
+};
+
+int init_common()
+{
+ int ret = E_OK;
+ common::init_config_value();
+ g_time_column_desc.type_ = INT64;
+ g_time_column_desc.encoding_ = PLAIN;
+ g_time_column_desc.compression_ = UNCOMPRESSED;
+ g_time_column_desc.ttl_ = INT64_MAX; // TODO
+ g_time_column_desc.column_name_ = std::string("time");
+ g_time_column_desc.ts_id_ = TsID(0, 0, 0);
+ return ret;
+}
+
+bool is_timestamp_column_name(const char *time_col_name)
+{
+ // both "time" and "timestamp" refer to timestmap column.
+ int32_t len = strlen(time_col_name);
+ if (len == 4) {
+ return strncasecmp(time_col_name, "time", 4) == 0;
+ } else if (len == 9) {
+ return strncasecmp(time_col_name, "timestamp", 9) == 0;
+ } else {
+ return false;
+ }
+}
+
+void cols_to_json(ByteStream *byte_stream, std::vector<common::ColumnDesc> &ret_ts_list)
+{
+ // 1. append start tag
+ byte_stream->write_buf("{\n", 2);
+
+ size_t ts_count = ret_ts_list.size();
+ for (size_t i = 0; i < ts_count; ++i) {
+ // 2. append timeseries name
+ std::string name = ret_ts_list[i].column_name_;
+ byte_stream->write_buf(" \"", 3);
+ byte_stream->write_buf(name.c_str(), name.length());
+ byte_stream->write_buf("\" : {\n", 6);
+
+ // 3. append DataType
+ const char* data_type = get_data_type_name(ret_ts_list[i].type_);
+ byte_stream->write_buf(" \"DataType\" : \"", 18);
+ byte_stream->write_buf(data_type, strlen(data_type));
+ byte_stream->write_buf("\",\n", 3);
+
+ // 4. append Encoding
+ const char* encoding = get_encoding_name(ret_ts_list[i].encoding_);
+ byte_stream->write_buf(" \"Encoding\" : \"", 18);
+ byte_stream->write_buf(encoding, strlen(encoding));
+ byte_stream->write_buf("\",\n", 3);
+
+ // 5. append CompressionType
+ const char* compression = get_compression_name(ret_ts_list[i].compression_);
+ byte_stream->write_buf(" \"Compression\" : \"", 21);
+ byte_stream->write_buf(compression, strlen(compression));
+ byte_stream->write_buf("\",\n", 3);
+
+ // 6. append TTL
+ std::string ttl_str = to_string(ret_ts_list[i].ttl_);
+ if (ret_ts_list[i].ttl_ == INVALID_TTL) {
+ byte_stream->write_buf(" \"TTL\" : \"INVALID\",\n", 23); // if it is the end, delete ','
+ } else {
+ byte_stream->write_buf(" \"TTL\" : \"", 13);
+ byte_stream->write_buf(ttl_str.c_str(), ttl_str.length());
+ byte_stream->write_buf("\",\n", 3); // if it is the end, delete ','
+ }
+
+ // TODO : this is used for Debug
+ // 7. append TsId
+ std::string tsid_str = ret_ts_list[i].ts_id_.to_string();
+ byte_stream->write_buf(" \"TsID\" : \"", 14);
+ byte_stream->write_buf(tsid_str.c_str(), tsid_str.length());
+ byte_stream->write_buf("\"\n", 2);
+
+ // 8. append footer
+ if (i == ts_count - 1) {
+ byte_stream->write_buf(" }\n", 4);
+ } else {
+ byte_stream->write_buf(" },\n", 5);
+ }
+ }
+
+ // 9. end
+ byte_stream->write_buf("}\n", 2);
+
+ // DEBUG_print_byte_stream(*byte_stream); // for debug
+}
+
+void print_backtrace()
+{
+ const int MAX_FRAMES = 32;
+ int layers = 0;
+ char **symbols = NULL;
+ void *frames[MAX_FRAMES];
+
+ memset(frames, 0, sizeof(frames));
+ layers = backtrace(frames, MAX_FRAMES);
+ symbols = backtrace_symbols(frames, layers);
+ if (symbols) {
+ for (int i = 0; i < layers; i++) {
+ printf("SYMBOL layer %d: %s\n", i, symbols[i]);
+ }
+ free(symbols);
+ }
+}
+
+Mutex g_all_inject_points_mutex;
+std::map<std::string, InjectPoint> g_all_inject_points;
+
+} // common
+} // timecho
diff --git a/cpp/tsfile/src/common/global.h b/cpp/tsfile/src/common/global.h
new file mode 100644
index 00000000..3fc3e64a
--- /dev/null
+++ b/cpp/tsfile/src/common/global.h
@@ -0,0 +1,28 @@
+#ifndef COMMON_GLOBAL_H
+#define COMMON_GLOBAL_H
+
+#include <string>
+#include <vector>
+#include "common/config/config.h"
+#include "common/allocator/byte_stream.h"
+
+namespace timecho
+{
+namespace common
+{
+
+extern ConfigValue g_config_value_;
+
+FORCE_INLINE bool wal_cfg_enabled() { return g_config_value_.wal_flush_policy_ != WAL_DISABLED; }
+FORCE_INLINE bool wal_cfg_should_wait_persisted() { return g_config_value_.wal_flush_policy_ >= WAL_FLUSH; }
+
+extern ColumnDesc g_time_column_desc;
+extern int init_common();
+extern bool is_timestamp_column_name(const char *time_col_name);
+extern void cols_to_json(ByteStream *byte_stream, std::vector<common::ColumnDesc> &ret_ts_list);
+extern void print_backtrace();
+
+}
+}
+
+#endif // COMMON_GLOBAL_H
diff --git a/cpp/tsfile/src/common/injection.h b/cpp/tsfile/src/common/injection.h
new file mode 100644
index 00000000..16d02cb6
--- /dev/null
+++ b/cpp/tsfile/src/common/injection.h
@@ -0,0 +1,53 @@
+#ifndef COMMON_INJECTION_H
+#define COMMON_INJECTION_H
+
+#include <iostream>
+#include <string>
+#include <map>
+
+namespace timecho
+{
+namespace common
+{
+
+// define struct
+struct InjectPoint
+{
+ int count_down_; // left count
+};
+
+// define DBUG_EXECUTE_IF
+#define DBUG_EXECUTE_IF(inject_point_name, code) \
+ do { \
+ common::MutexGuard mg(g_all_inject_points_mutex); \
+ if (g_all_inject_points.find(inject_point_name) != g_all_inject_points.end()) { \
+ InjectPoint& inject_point = g_all_inject_points[inject_point_name]; \
+ if (inject_point.count_down_ <= 0) { \
+ code; \
+ } \
+ inject_point.count_down_--; \
+ } \
+ } while(0)
+
+// open injection
+#define ENABLE_INJECTION(inject_point_name, count) \
+ do { \
+ common::MutexGuard mg(g_all_inject_points_mutex); \
+ g_all_inject_points[inject_point_name] = {count}; \
+ } while(0)
+
+// close injection
+#define DISABLE_INJECTION(inject_point_name) \
+ do { \
+ common::MutexGuard mg(g_all_inject_points_mutex); \
+ g_all_inject_points.erase(inject_point_name); \
+ } while(0)
+
+// the map save all inject points
+extern Mutex g_all_inject_points_mutex;
+extern std::map<std::string, InjectPoint> g_all_inject_points;
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_INJECTION_H
diff --git a/cpp/tsfile/src/common/mutex/CMakeLists.txt b/cpp/tsfile/src/common/mutex/CMakeLists.txt
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/cpp/tsfile/src/common/mutex/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+
diff --git a/cpp/tsfile/src/common/mutex/mutex.h b/cpp/tsfile/src/common/mutex/mutex.h
new file mode 100644
index 00000000..e5d7da72
--- /dev/null
+++ b/cpp/tsfile/src/common/mutex/mutex.h
@@ -0,0 +1,64 @@
+
+#ifndef COMMON_MUTEX_MUTEX_H
+#define COMMON_MUTEX_MUTEX_H
+
+#include <errno.h>
+#include <pthread.h>
+#include "common/util_define.h"
+
+namespace timecho
+{
+namespace common
+{
+
+class Mutex
+{
+public:
+ Mutex() : mutex_() { pthread_mutex_init(&mutex_, NULL); }
+ ~Mutex() { pthread_mutex_destroy(&mutex_); }
+
+ void lock()
+ {
+ int ret = EBUSY;
+ do {
+ ret = pthread_mutex_lock(&mutex_);
+ } while (UNLIKELY(ret == EBUSY || ret == EAGAIN));
+ ASSERT(ret == 0);
+ }
+
+ void unlock()
+ {
+ int ret = pthread_mutex_unlock(&mutex_);
+ ASSERT(ret == 0);
+ }
+
+ bool try_lock()
+ {
+ int ret = pthread_mutex_trylock(&mutex_);
+ if (ret == 0) {
+ return true;
+ } else if (ret == EBUSY || ret == EAGAIN) {
+ return false;
+ } else {
+ ASSERT(false);
+ return false;
+ }
+ }
+
+private:
+ pthread_mutex_t mutex_;
+};
+
+class MutexGuard
+{
+public:
+ MutexGuard(Mutex &m) : m_(m) { m_.lock(); }
+ ~MutexGuard() { m_.unlock(); }
+private:
+ Mutex &m_;
+};
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_MUTEX_MUTEX_H
diff --git a/cpp/tsfile/src/common/tsblock/CMakeLists.txt b/cpp/tsfile/src/common/tsblock/CMakeLists.txt
new file mode 100644
index 00000000..e498c112
--- /dev/null
+++ b/cpp/tsfile/src/common/tsblock/CMakeLists.txt
@@ -0,0 +1,11 @@
+message("Running in src/common/tsblock directory")
+
+aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} common_tsblock_SRC_LIST)
+set(common_tsblock_INC_LIST)
+set(common_tsblock_DEFINE_OPTIONS)
+set(common_tsblock_COMPILE_OPTIONS)
+set(common_tsblock_LINK_OPTIONS)
+add_statis_objtarget(common_tsblock common_tsblock_SRC_LIST common_tsblock_INC_LIST
+ "${common_tsblock_DEFINE_OPTIONS}"
+ "${common_tsblock_COMPILE_OPTIONS}"
+ "${common_tsblock_LINK_OPTIONS}")
diff --git a/cpp/tsfile/src/common/tsblock/tsblock.cc b/cpp/tsfile/src/common/tsblock/tsblock.cc
new file mode 100644
index 00000000..e60b1077
--- /dev/null
+++ b/cpp/tsfile/src/common/tsblock/tsblock.cc
@@ -0,0 +1,293 @@
+#include "tsblock.h"
+
+#include <string>
+
+namespace timecho
+{
+namespace common
+{
+
+int TsBlock::init()
+{
+ // todo: The current version select_list_ is useless, so it is not initialized
+ int ret = 0;
+ uint32_t row_size = tuple_desc_->get_single_row_len(&ret);
+ if (ret != 0) {
+ return ret;
+ }
+
+ // No maximum number of rows given, calculated with capacity_
+ if (LIKELY(max_row_count_ == 0)) {
+ max_row_count_ = capacity_ / row_size;
+ } else {
+ // max_row_count_ given, calculated with max_row_count_
+ capacity_ = row_size * max_row_count_;
+ }
+ int colnum = tuple_desc_->get_column_count();
+ for (int i = 0; i < colnum; ++i) {
+ ret = build_vector(tuple_desc_->get_column_type(i), max_row_count_);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+ return ret;
+}
+
+int TsBlock::build_vector(common::TSDataType type, uint32_t row_count)
+{
+ Vector *vec;
+ int ret = 0;
+ if (LIKELY(type != common::TEXT)) {
+ vec = new FixedLengthVector(type, row_count, get_len(type), this);
+ } else if (type == common::TEXT) {
+ vec = new VariableLengthVector(type, row_count, DEFAULT_RESERVED_SIZE_OF_TEXT + TEXT_LEN, this);
+ } else {
+ log_error("TsBlock::BuildVector failed because of unknown type %d", static_cast<int>(type));
+ ret = E_TYPE_NOT_SUPPORTED;
+ }
+ vectors_.push_back(vec);
+ return ret;
+}
+
+void TsBlock::write_data(ByteStream* __restrict byte_stream, char* __restrict val, uint32_t len,
+ bool has_null, TSDataType type)
+{
+ std::string strval;
+ switch (type) {
+ case timecho::common::INT64: {
+ int64_t ival = *reinterpret_cast<int64_t*>(val);
+ strval = to_string(ival);
+ break;
+ }
+ case timecho::common::INT32: {
+ int32_t ival = *reinterpret_cast<int32_t*>(val);
+ strval = to_string(ival);
+ break;
+ }
+ case timecho::common::FLOAT: {
+ float ival = *reinterpret_cast<float*>(val); // cppcheck-suppress invalidPointerCast
+ strval = to_string(ival);
+ break;
+ }
+ case timecho::common::DOUBLE: {
+ double ival = *reinterpret_cast<double*>(val); // cppcheck-suppress invalidPointerCast
+ strval = to_string(ival);
+ break;
+ }
+ case timecho::common::BOOLEAN: {
+ bool ival = *reinterpret_cast<bool*>(val);
+ if (ival) {
+ strval = "true";
+ } else {
+ strval = "false";
+ }
+ break;
+ }
+ case timecho::common::TEXT:{
+ if (LIKELY(!has_null)) {
+ byte_stream->write_buf(val, len);
+ } else {
+ byte_stream->write_buf("null", 4);
+ }
+ byte_stream->write_buf(",\n", 2);
+ return;
+ }
+ default: {
+ log_error("write_data unknown type");
+ }
+ }
+ if (LIKELY(!has_null)) {
+ byte_stream->write_buf(const_cast<char*>(strval.c_str()), strval.length());
+ } else {
+ byte_stream->write_buf("null", 4);
+ }
+}
+
+void TsBlock::tsblock_to_json(ByteStream *byte_stream)
+{
+ // 1. append start tag
+ byte_stream->write_buf("{\n", 2);
+
+ // 2. append output columns to bytestream
+ int column_count = tuple_desc_->get_column_count();
+ // 2.1 append header
+ byte_stream->write_buf(" \"expressions\": [\n", 19);
+ // 2.2 append column names
+ for (int i = 1; i < column_count; ++i) {
+ std::string name = tuple_desc_->get_column_name(i);
+ byte_stream->write_buf(" ", 4);
+ byte_stream->write_buf("\"", 1);
+ byte_stream->write_buf(name.c_str(), name.length());
+ byte_stream->write_buf("\"", 1);
+ if (i == column_count - 1) {
+ byte_stream->write_buf("\n", 1);
+ } else {
+ byte_stream->write_buf(",\n", 2);
+ }
+ }
+ byte_stream->write_buf(" ],\n", 5);
+
+ // 3. append column_names
+ byte_stream->write_buf(" \"column_names\": null,\n", 24);
+
+ // 4. append time value
+ byte_stream->write_buf(" \"timestamps\": [\n", 18);
+ ColIterator time_iter(0, this);
+ bool is_first = true;
+ while (!time_iter.end()) {
+ uint32_t ilen;
+ byte_stream->write_buf(" ", 4);
+ char *val = time_iter.read(&ilen);
+ if (!is_first) {
+ byte_stream->write_buf(",\n", 2);
+ }
+ is_first = false;
+ write_data(byte_stream, val, ilen, false, INT64);
+ time_iter.next();
+ }
+ byte_stream->write_buf(" ],\n", 5);
+
+ // 5. append user values
+ byte_stream->write_buf(" \"values\": [\n", 14);
+ for (int i = 1; i < column_count; ++i) {
+ byte_stream->write_buf(" [\n", 6);
+
+ ColIterator value_iter(i, this);
+ bool has_null = value_iter.has_null();
+ if (LIKELY(!has_null)) {
+ bool is_first = true; // cppcheck-suppress shadowVariable
+ while (!value_iter.end()) {
+ uint32_t ilen = 0;
+ byte_stream->write_buf(" ", 6);
+ char *val = value_iter.read(&ilen);
+ if (!is_first) {
+ byte_stream->write_buf(",\n", 2);
+ }
+ is_first = false;
+ write_data(byte_stream, val, ilen, false, tuple_desc_->get_column_type(i));
+ value_iter.next();
+ }
+ } else {
+ while (!value_iter.end()) {
+ bool inull;
+ uint32_t ilen = 0;
+ byte_stream->write_buf(" ", 6);
+ char *val = value_iter.read(&ilen, &inull);
+ if (!is_first) {
+ byte_stream->write_buf(",\n", 2);
+ }
+ is_first = false;
+ write_data(byte_stream, val, ilen, inull, tuple_desc_->get_column_type(i));
+ value_iter.next();
+ }
+ }
+ if (i == column_count - 1) {
+ byte_stream->write_buf(" ]\n", 6);
+ } else {
+ byte_stream->write_buf(" ],\n", 7);
+ }
+ }
+ byte_stream->write_buf(" ]\n", 4);
+
+ // 6. end
+ byte_stream->write_buf("}\n", 2);
+}
+
+std::string TsBlock::debug_string()
+{
+ std::stringstream out;
+ out << "print TsBlock: " << this << std::endl
+ << "capacity_: " << capacity_ << std::endl
+ << "row_count_: " << row_count_ << std::endl
+ << "max_row_count_: " << max_row_count_ << std::endl;
+
+ out << "------ tuple desc ------" << std::endl << std::endl;
+ out << tuple_desc_->debug_string() << std::endl;
+
+ out << "------ real data area ------" << std::endl;
+
+ RowIterator iter(this);
+ while (!iter.end()) {
+ out << iter.debug_string() << std::endl;
+ iter.next();
+ }
+ return out.str();
+}
+
+std::string RowIterator::debug_string()
+{
+ std::stringstream out;
+ out.precision(20); // Default precision is 6, set precision, otherwise double precision will be lost
+
+ for (uint32_t i = 0; i < column_count_; ++i) {
+ bool is_null = false;
+ uint32_t len = 0;
+ void *value = read(i, &len, &is_null);
+ if (is_null) {
+ out << "NULL";
+ } else {
+ ColumnDesc &col_desc = tsblock_->tuple_desc_->get_column_desc(i);
+ switch (col_desc.type_) {
+ case timecho::common::BOOLEAN: {
+ out << *static_cast<bool*>(value);
+ break;
+ }
+ case timecho::common::INT32: {
+ out << *static_cast<int32_t*>(value);
+ break;
+ }
+ case timecho::common::INT64: {
+ out << *static_cast<int64_t*>(value);
+ break;
+ }
+ case timecho::common::FLOAT: {
+ out << *static_cast<float*>(value);
+ break;
+ }
+ case timecho::common::DOUBLE: {
+ out << *static_cast<double*>(value);
+ break;
+ }
+ case timecho::common::TEXT: {
+ out << std::string(static_cast<char*>(value), len);
+ break;
+ }
+ default: {
+ out << "ERR";
+ }
+ }
+ }
+ if (i + 1 < tsblock_->tuple_desc_->get_column_count()) {
+ out << ", ";
+ }
+ }
+ return out.str();
+}
+
+// TODO use memcpy in vector instead of using iter/appender
+int merge_tsblock_by_row(TsBlock *sea, TsBlock *river)
+{
+ int ret = E_OK;
+ TupleDesc *sea_tuple_desc = sea->get_tuple_desc();
+ TupleDesc *river_tupe_desc = river->get_tuple_desc();
+ if (!sea_tuple_desc->equal_to(*river_tupe_desc)) {
+ ret = E_NOT_MATCH;
+ } else {
+ RowAppender sea_appender(sea);
+ RowIterator river_iter(river);
+ while (!river_iter.end()) {
+ sea_appender.add_row();
+ for (uint32_t c = 0; c < sea_tuple_desc->get_column_count(); c++) {
+ uint32_t len = 0;
+ bool null = false;
+ char *val = river_iter.read(c, &len, &null);
+ sea_appender.append(c, val, len);
+ }
+ river_iter.next();
+ }
+ }
+ return ret;
+}
+
+} // common
+} // timecho
diff --git a/cpp/tsfile/src/common/tsblock/tsblock.h b/cpp/tsfile/src/common/tsblock/tsblock.h
new file mode 100644
index 00000000..a38f6e8d
--- /dev/null
+++ b/cpp/tsfile/src/common/tsblock/tsblock.h
@@ -0,0 +1,291 @@
+#ifndef COMMON_TSBLOCK_TSBLOCK_H
+#define COMMON_TSBLOCK_TSBLOCK_H
+
+#include <stdint.h>
+
+#include "common/allocator/byte_stream.h"
+#include "common/container/byte_buffer.h"
+#include "common/global.h"
+
+#include "tuple_desc.h"
+#include "vector/fixed_length_vector.h"
+#include "vector/variable_length_vector.h"
+#include "vector/vector.h"
+
+namespace timecho
+{
+namespace common
+{
+class TsBlock
+{
+public:
+ friend class RowIterator;
+ friend class ColIterator;
+
+ friend class RowAppender;
+ friend class ColAppender;
+ /*
+ * row_count: If we can clearly estimate the number of tsblock rows,
+ * such as limit scenarios, such as based on statistical information,
+ * such as insert scenarios, etc.
+ * Then we will use the given number of rows
+ */
+ explicit TsBlock(TupleDesc *tupledesc, uint32_t max_row_count = 0) :
+ capacity_(g_config_value_.tsblock_max_memory_),
+ row_count_(0), max_row_count_(max_row_count), tuple_desc_(tupledesc) { }
+
+ virtual ~TsBlock()
+ {
+ int size = vectors_.size();
+ for (int i = 0; i < size; ++i) {
+ delete vectors_[i];
+ }
+ }
+
+ FORCE_INLINE uint32_t get_row_count() const { return row_count_; }
+
+ FORCE_INLINE TupleDesc* get_tuple_desc() const { return tuple_desc_; }
+
+ FORCE_INLINE Vector* get_vector(uint32_t index) { return vectors_[index]; }
+
+ FORCE_INLINE uint32_t get_column_count() const { return tuple_desc_->get_column_count(); }
+
+ FORCE_INLINE uint32_t get_max_row_count() const { return max_row_count_; }
+
+ FORCE_INLINE uint32_t get_capacity() const { return capacity_; }
+
+ FORCE_INLINE void update_capacity(uint32_t extend_size) { capacity_ += extend_size; }
+
+ // need to call flush_row_count after using colappender
+ FORCE_INLINE int flush_row_count(uint32_t row_count)
+ {
+ int errnum = E_OK;
+ if (row_count_ == 0) {
+ row_count_ = row_count;
+ } else if (row_count_ != row_count) {
+ log_error("Inconsistent number of rows in two columns");
+ errnum = E_TSBLOCK_DATA_INCONSISTENCY;
+ }
+ return errnum;
+ }
+
+ FORCE_INLINE void reset()
+ {
+ int size = vectors_.size();
+ for (int i = 0; i < size; ++i) {
+ vectors_[i]->reset();
+ }
+ row_count_ = 0;
+ }
+
+ int init();
+ void tsblock_to_json(ByteStream *byte_stream);
+
+ std::string debug_string();
+
+private:
+ int build_vector(common::TSDataType type, uint32_t row_count);
+ void write_data(ByteStream* __restrict byte_stream,
+ char* __restrict val,
+ uint32_t len,
+ bool has_null,
+ TSDataType type);
+
+private:
+ uint32_t capacity_; // maximum memory capacity
+ uint32_t row_count_; // real row count
+ uint32_t max_row_count_;
+
+ common::BitMap select_list_;
+ TupleDesc *tuple_desc_;
+ std::vector<Vector*> vectors_;
+};
+
+class RowAppender
+{
+public:
+ explicit RowAppender(TsBlock *tsblock) :tsblock_(tsblock) {}
+ ~RowAppender() {}
+
+ // todo:(yanghao) maybe need to consider select-list
+ FORCE_INLINE bool add_row()
+ {
+ if (LIKELY(tsblock_->row_count_ < tsblock_->max_row_count_)) {
+ ++tsblock_->row_count_;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ FORCE_INLINE void backoff_add_row()
+ {
+ ASSERT(tsblock_->row_count_ > 0);
+ tsblock_->row_count_--;
+ }
+
+ FORCE_INLINE void append(uint32_t slot_index, const char *value, uint32_t len)
+ {
+ ASSERT(slot_index < tsblock_->tuple_desc_->get_column_count());
+ Vector *vec = tsblock_->vectors_[slot_index];
+ vec->append(value, len);
+ }
+
+ FORCE_INLINE void append_null(uint32_t slot_index)
+ {
+ Vector *vec = tsblock_->vectors_[slot_index];
+ vec->set_null(tsblock_->row_count_ - 1);
+ }
+
+private:
+ TsBlock *tsblock_;
+};
+
+class ColAppender
+{
+public:
+ ColAppender(uint32_t column_index, TsBlock *tsblock) :
+ column_index_(column_index), column_row_count_(0), tsblock_(tsblock)
+ {
+ ASSERT(column_index < tsblock_->tuple_desc_->get_column_count());
+ vec_ = tsblock_->vectors_[column_index];
+ }
+
+ ~ColAppender() {}
+
+ // todo:(yanghao) maybe need to consider select-list
+ FORCE_INLINE bool add_row()
+ {
+ if (LIKELY(column_row_count_ < tsblock_->max_row_count_)) {
+ ++column_row_count_;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ FORCE_INLINE void append(const char *value, uint32_t len)
+ {
+ vec_->append(value, len);
+ }
+
+ FORCE_INLINE void append_null()
+ {
+ vec_->set_null(column_row_count_ - 1);
+ }
+
+ FORCE_INLINE uint32_t get_col_row_count() { return column_row_count_; }
+ FORCE_INLINE uint32_t get_column_index() { return column_index_; }
+
+private:
+ uint32_t column_index_;
+ uint32_t column_row_count_;
+ TsBlock *tsblock_;
+ Vector *vec_;
+};
+
+// todo:(yanghao) need to deal with select-list
+class RowIterator
+{
+public:
+ explicit RowIterator(TsBlock *tsblock) : tsblock_(tsblock), row_id_(0)
+ {
+ column_count_ = tsblock_->tuple_desc_->get_column_count();
+ }
+
+ ~RowIterator()
+ {
+ /*
+ * if use RowIterator and ColIterator at the same time,
+ * need to reset the offset after one is used,
+ * otherwise it will cause the offset to be wrong
+ */
+ for (uint32_t i = 0; i < column_count_; ++i) {
+ tsblock_->vectors_[i]->reset_offset();
+ }
+ }
+
+ FORCE_INLINE bool end()
+ {
+ return row_id_ >= tsblock_->row_count_;
+ }
+
+ FORCE_INLINE void next()
+ {
+ ASSERT(row_id_ < tsblock_->row_count_);
+ ++row_id_;
+ for (uint32_t i = 0; i < column_count_; ++i) {
+ tsblock_->vectors_[i]->update_offset();
+ }
+ }
+
+ FORCE_INLINE char* read(uint32_t slot_index, uint32_t* __restrict len, bool* __restrict null)
+ {
+ ASSERT(slot_index < column_count_);
+ Vector *vec = tsblock_->vectors_[slot_index];
+ return vec->read(len, null, row_id_);
+ }
+
+ std::string debug_string(); // for debug
+
+private:
+ TsBlock *tsblock_;
+ uint32_t row_id_; // The line number currently being read
+ uint32_t column_count_;
+};
+
+// todo:(yanghao) need to deal with select-list
+class ColIterator
+{
+public:
+ ColIterator(uint32_t column_index, const TsBlock *tsblock) :
+ column_index_(column_index), row_id_(0), tsblock_(tsblock)
+ {
+ ASSERT(column_index < tsblock_->tuple_desc_->get_column_count());
+ vec_ = tsblock_->vectors_[column_index];
+ }
+
+ ~ColIterator()
+ {
+ vec_->reset_offset();
+ }
+
+ FORCE_INLINE bool end() const
+ {
+ return row_id_ >= tsblock_->row_count_;
+ }
+
+ FORCE_INLINE void next()
+ {
+ ++row_id_;
+ vec_->update_offset();
+ }
+
+ FORCE_INLINE bool has_null() { return vec_->has_null(); }
+
+ FORCE_INLINE TSDataType get_data_type() { return vec_->get_vector_type(); }
+
+ FORCE_INLINE char* read(uint32_t* __restrict len, bool* __restrict null)
+ {
+ return vec_->read(len, null, row_id_);
+ }
+
+ FORCE_INLINE char* read(uint32_t *len)
+ {
+ return vec_->read(len);
+ }
+
+ FORCE_INLINE uint32_t get_column_index() { return column_index_; }
+
+private:
+ uint32_t column_index_;
+ uint32_t row_id_;
+ const TsBlock *tsblock_;
+ Vector *vec_;
+};
+
+int merge_tsblock_by_row(TsBlock *sea, TsBlock *river);
+
+} // end namespace common
+} // end namespace timecho
+
+#endif // COMMON_TSBLOCK_TSBLOCK_H
diff --git a/cpp/tsfile/src/common/tsblock/tuple_desc.cc b/cpp/tsfile/src/common/tsblock/tuple_desc.cc
new file mode 100644
index 00000000..802b32d7
--- /dev/null
+++ b/cpp/tsfile/src/common/tsblock/tuple_desc.cc
@@ -0,0 +1,76 @@
+#include "tuple_desc.h"
+
+namespace timecho
+{
+namespace common
+{
+ uint32_t TupleDesc::get_single_row_len(int *erro_code)
+ {
+ int size = get_column_count();
+ int totol_len = 0;
+ for (int i = 0; i < size; ++i) {
+ switch (column_list_[i].type_) {
+ case timecho::common::BOOLEAN: {
+ totol_len += sizeof(bool);
+ break;
+ }
+ case timecho::common::INT32: {
+ totol_len += sizeof(int32_t);
+ break;
+ }
+ case timecho::common::INT64: {
+ totol_len += sizeof(int64_t);
+ break;
+ }
+ case timecho::common::FLOAT: {
+ totol_len += sizeof(float);
+ break;
+ }
+ case timecho::common::DOUBLE: {
+ totol_len += sizeof(double);
+ break;
+ }
+ case timecho::common::TEXT: {
+ totol_len += DEFAULT_RESERVED_SIZE_OF_TEXT + TEXT_LEN;
+ break;
+ }
+ default: {
+ log_error("TsBlock::BuildVector unknown type %d", static_cast<int>(column_list_[i].type_));
+ *erro_code = E_TYPE_NOT_SUPPORTED;
+ break;
+ }
+ }
+ }
+ return totol_len;
+ }
+
+ uint32_t get_len(TSDataType type)
+ {
+ switch (type)
+ {
+ case timecho::common::BOOLEAN: {
+ return sizeof(bool);
+ }
+ case timecho::common::INT32: {
+ return sizeof(int32_t);
+ }
+ case timecho::common::INT64: {
+ return sizeof(int64_t);
+ }
+ case timecho::common::FLOAT: {
+ return sizeof(float);
+ }
+ case timecho::common::DOUBLE: {
+ return sizeof(double);
+ }
+ case timecho::common::TEXT: {
+ return DEFAULT_RESERVED_SIZE_OF_TEXT + TEXT_LEN;
+ }
+ default: {
+ // todo: log error
+ }
+ }
+ return 0;
+ }
+} // common
+} // timecho
diff --git a/cpp/tsfile/src/common/tsblock/tuple_desc.h b/cpp/tsfile/src/common/tsblock/tuple_desc.h
new file mode 100644
index 00000000..f9c04f93
--- /dev/null
+++ b/cpp/tsfile/src/common/tsblock/tuple_desc.h
@@ -0,0 +1,116 @@
+#ifndef COMMON_TSBLOCK_TUPLE_DESC_H
+#define COMMON_TSBLOCK_TUPLE_DESC_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "common/db_utils.h"
+#include "common/errno_define.h"
+#include "common/logger/elog.h"
+
+namespace timecho
+{
+namespace common
+{
+
+/*
+ * Anyway, a default length of text type is needed for easy calculation,
+ * and it will be changed to a configurable item later
+ */
+#define DEFAULT_RESERVED_SIZE_OF_TEXT 16
+#define TEXT_LEN 4
+
+extern uint32_t get_len(TSDataType type);
+
+// Describe merged information of multiple timeseries
+class TupleDesc
+{
+public:
+ TupleDesc() {}
+ virtual ~TupleDesc() {}
+
+ FORCE_INLINE void reset()
+ {
+ column_list_.clear();
+ }
+
+ FORCE_INLINE void push_back(ColumnDesc &desc)
+ {
+ column_list_.push_back(desc);
+ }
+
+ FORCE_INLINE uint32_t get_column_count() const
+ {
+ return column_list_.size();
+ }
+
+ FORCE_INLINE ColumnDesc& operator[](uint32_t index)
+ {
+ ASSERT(index < column_list_.size());
+ return column_list_[index];
+ }
+
+ FORCE_INLINE ColumnDesc& get_column_desc(uint32_t index)
+ {
+ ASSERT(index < column_list_.size());
+ return column_list_[index];
+ }
+
+ FORCE_INLINE common::TSDataType get_column_type(uint32_t index)
+ {
+ return column_list_[index].type_;
+ }
+
+ FORCE_INLINE std::string get_column_name(uint32_t index)
+ {
+ return column_list_[index].column_name_;
+ }
+
+ FORCE_INLINE void remove_column(uint32_t idx)
+ {
+ column_list_.erase(column_list_.begin() + idx);
+ }
+
+ // get the single row len, ignore nulls and select-list memory for the moment
+ uint32_t get_single_row_len(int *erro_code);
+
+ bool equal_to(const TupleDesc &that) const
+ {
+ if (column_list_.size() != that.column_list_.size()) {
+ return false;
+ }
+ for (uint32_t i = 0; i < column_list_.size(); i++) {
+ const ColumnDesc &this_col_desc = column_list_[i];
+ const ColumnDesc &that_col_desc = that.column_list_[i];
+ if (this_col_desc != that_col_desc) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void clone_from(TupleDesc *that)
+ {
+ ASSERT(column_list_.size() == 0);
+ column_list_ = that->column_list_; // deep copy
+ }
+
+ std::string debug_string() // for debug
+ {
+ std::stringstream out;
+ for (size_t i = 0; i < column_list_.size(); ++i) {
+ out << column_list_[i].debug_string() << std::endl;
+ }
+ return out.str();
+ }
+
+private:
+ std::vector<ColumnDesc> column_list_;
+};
+
+} // common
+} // timecho
+
+#endif // COMMON_TSBLOCK_TUPLE_DESC_H
diff --git a/cpp/tsfile/src/common/tsblock/vector/fixed_length_vector.h b/cpp/tsfile/src/common/tsblock/vector/fixed_length_vector.h
new file mode 100644
index 00000000..8b0ec674
--- /dev/null
+++ b/cpp/tsfile/src/common/tsblock/vector/fixed_length_vector.h
@@ -0,0 +1,76 @@
+#ifndef COMMON_TSBLOCK_VECTOR_FIX_LENGTH_VECTOR_H
+#define COMMON_TSBLOCK_VECTOR_FIX_LENGTH_VECTOR_H
+
+#include "vector.h"
+
+namespace timecho
+{
+namespace common
+{
+class FixedLengthVector : public Vector
+{
+public:
+ FixedLengthVector(common::TSDataType type, uint32_t max_row_num,
+ uint32_t type_size, common::TsBlock *tsblock) :
+ Vector(type, max_row_num, tsblock), type_len_(type_size)
+ {
+ values_.init(type_size * max_row_num);
+ }
+
+ ~FixedLengthVector() { }
+
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE void reset() OVERRIDE
+ {
+ has_null_ = false;
+ row_num_ = 0;
+ offset_ = 0;
+ nulls_.reset();
+ values_.reset();
+ }
+
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE void update_offset() OVERRIDE
+ {
+ offset_ += type_len_;
+ }
+
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE void append(const char *value, uint32_t len) OVERRIDE
+ {
+ values_.append_fixed_value(value, len);
+ }
+
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE char* read(uint32_t* __restrict len, bool* __restrict null, uint32_t rowid) OVERRIDE
+ {
+ *len = type_len_;
+ if (UNLIKELY(has_null_)) {
+ *null = nulls_.test(rowid);
+ } else {
+ *null = false;
+ }
+ if (LIKELY(!(*null))) {
+ char *result = values_.read(offset_, type_len_);
+ return result;
+ } else {
+ return nullptr;
+ }
+ }
+
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE char* read(uint32_t *len) OVERRIDE
+ {
+ *len = type_len_;
+ char *result = values_.read(offset_, type_len_);
+ return result;
+ }
+
+private:
+ uint32_t type_len_;
+};
+
+} // common
+} // timecho
+
+#endif // COMMON_TSBLOCK_VECTOR_FIX_LENGTH_VECTOR_H
diff --git a/cpp/tsfile/src/common/tsblock/vector/variable_length_vector.h b/cpp/tsfile/src/common/tsblock/vector/variable_length_vector.h
new file mode 100644
index 00000000..b1fe97e5
--- /dev/null
+++ b/cpp/tsfile/src/common/tsblock/vector/variable_length_vector.h
@@ -0,0 +1,77 @@
+#ifndef COMMON_TSBLOCK_VECTOR_VARIABLE_LENGTH_VECTOR_H
+#define COMMON_TSBLOCK_VECTOR_VARIABLE_LENGTH_VECTOR_H
+
+#include "vector.h"
+
+namespace timecho
+{
+namespace common
+{
+class VariableLengthVector : public Vector
+{
+public:
+ VariableLengthVector(common::TSDataType type, uint32_t max_row_num,
+ uint32_t type_size, common::TsBlock *tsblock) : Vector(type, max_row_num, tsblock),
+ variable_type_len_(sizeof(uint32_t)), last_value_len_(0)
+ {
+ values_.init(type_size * max_row_num);
+ }
+
+ ~VariableLengthVector() {}
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE void reset() OVERRIDE
+ {
+ last_value_len_ = 0;
+ has_null_ = false;
+ row_num_ = 0;
+ offset_ = 0;
+ nulls_.reset();
+ values_.reset();
+ }
+
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE void update_offset() OVERRIDE
+ {
+ offset_ += variable_type_len_;
+ offset_ += last_value_len_;
+ }
+
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE void append(const char *value, uint32_t len) OVERRIDE
+ {
+ values_.append_variable_value(value, len);
+ }
+
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE char* read(uint32_t* __restrict len, bool* __restrict null, uint32_t rowid) OVERRIDE
+ {
+ if (UNLIKELY(has_null_)) {
+ *null = nulls_.test(rowid);
+ } else {
+ *null = false;
+ }
+ if (LIKELY(!(*null))) {
+ char *result = values_.read(offset_, len);
+ last_value_len_ = *len;
+ return result;
+ } else {
+ return nullptr;
+ }
+ }
+
+ // cppcheck-suppress missingOverride
+ FORCE_INLINE char* read(uint32_t *len) OVERRIDE
+ {
+ char *result = values_.read(offset_, len);
+ last_value_len_ = *len;
+ return result;
+ }
+
+private:
+ uint8_t variable_type_len_;
+ uint32_t last_value_len_;
+};
+}
+}
+
+#endif // COMMON_TSBLOCK_VECTOR_VARIABLE_LENGTH_VECTOR_H
diff --git a/cpp/tsfile/src/common/tsblock/vector/vector.h b/cpp/tsfile/src/common/tsblock/vector/vector.h
new file mode 100644
index 00000000..a300472e
--- /dev/null
+++ b/cpp/tsfile/src/common/tsblock/vector/vector.h
@@ -0,0 +1,75 @@
+#ifndef COMMON_TSBLOCK_VECTOR_VECTOR_H
+#define COMMON_TSBLOCK_VECTOR_VECTOR_H
+
+#include "common/container/bit_map.h"
+#include "common/container/byte_buffer.h"
+#include "common/db_utils.h"
+#include "common/util_define.h"
+#include "common/allocator/page_arena.h"
+
+namespace timecho
+{
+namespace common
+{
+
+class TsBlock;
+
+class Vector
+{
+public:
+ Vector(common::TSDataType type, uint32_t max_row_num, common::TsBlock *tsblock)
+ : has_null_(false), type_(type), max_row_num_(max_row_num), row_num_(0), offset_(0), tsblock_(tsblock)
+ {
+ nulls_.init(max_row_num, true);
+ }
+
+ virtual ~Vector() { }
+
+ // len == 0 is '' or ""
+ virtual void append(const char *value, uint32_t len) = 0;
+
+ virtual char* read(uint32_t* __restrict len, bool* __restrict null, uint32_t rowid) = 0;
+
+ // For ColIterator, it is known that no null value exists in this column
+ virtual char* read(uint32_t *len) = 0;
+
+ virtual void reset() = 0;
+
+ virtual void update_offset() = 0;
+
+ FORCE_INLINE void reset_offset() { offset_ = 0; }
+
+ FORCE_INLINE bool is_null(uint32_t row_id) { return nulls_.test(row_id); }
+
+ FORCE_INLINE void set_null(uint32_t row_id)
+ {
+ nulls_.set(row_id);
+ has_null_ = true;
+ }
+
+ FORCE_INLINE void set_vector_type(common::TSDataType type) { type_ = type; }
+
+ FORCE_INLINE common::TSDataType get_vector_type() { return type_; }
+
+ FORCE_INLINE uint32_t get_row_num() { return row_num_; }
+
+ FORCE_INLINE common::TsBlock* get_tsblock() { return tsblock_; }
+
+ FORCE_INLINE bool has_null() { return has_null_; }
+
+// We want derived class to have access to base class members, so it is defined as protected
+protected:
+ bool has_null_; // mark whether there is a null value
+ common::TSDataType type_;
+ uint32_t max_row_num_; // max row num
+ uint32_t row_num_; // real row num
+ uint32_t offset_;
+
+ common::TsBlock *tsblock_; // parent tsblock
+ common::BitMap nulls_; // null bit value
+ common::ByteBuffer values_; // real user data
+};
+} // common
+} // timecho
+
+#endif // COMMON_TSBLOCK_VECTOR_VECTOR_H
diff --git a/cpp/tsfile/src/common/util_define.h b/cpp/tsfile/src/common/util_define.h
new file mode 100644
index 00000000..377590d3
--- /dev/null
+++ b/cpp/tsfile/src/common/util_define.h
@@ -0,0 +1,133 @@
+
+/*
+ * This file defines some basic macros
+ */
+
+#ifndef COMMON_UTIL_DEFINE_H
+#define COMMON_UTIL_DEFINE_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/* ======== unsued ======== */
+#define UNUSED(v) ((void)(v))
+
+
+/* ======== inline ======== */
+#ifdef __GNUC__
+#define FORCE_INLINE inline __attribute__((always_inline))
+#else
+#define FORCE_INLINE inline
+#endif // __GNUC__
+
+#ifdef BUILD_FOR_SMALL_BINARY
+#define INLINE FORCE_INLINE
+#else
+#define INLINE
+#endif // BUILD_FOR_SMALL_BINARY
+
+
+/* ======== likely ======== */
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define LIKELY(x) (__builtin_expect((x), 1))
+#define UNLIKELY(x) (__builtin_expect((x), 0))
+#else
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#endif // __GNUC__ >= 4
+
+
+/* ======== nullptr ======== */
+#if __cplusplus < 201103L
+#ifndef nullptr
+#define nullptr NULL
+#endif
+#define OVERRIDE
+#else
+#define OVERRIDE override
+#endif // __cplusplus < 201103L
+
+
+/* ======== cache line ======== */
+#ifndef CACHE_LINE_SIZE
+#define CACHE_LINE_SIZE 64
+#endif // CACHE_LINE_SIZE
+
+
+/* ======== assert ======== */
+#ifdef NDEBUG
+#define ASSERT(condition) ((void)0)
+#else
+#define ASSERT(condition) assert((condition))
+#endif // NDEBUG
+
+/* ======== statis assert ======== */
+/*
+ * To be compatible with C++ before C++11,
+ * @msg should be a single word (use -/_ to concat)
+ * such as This_should_be_TRUE
+ */
+#if __cplusplus < 201103L
+// TODO only define this when DEBUG
+#define STATIC_ASSERT(cond, msg) typedef char static_assertion_##msg[(cond) ? 1 : -1] __attribute__((unused))
+#else
+#define STATIC_ASSERT(cond, msg) static_assert((cond), #msg)
+#endif // __cplusplus < 201103L
+
+
+/* ======== atomic operation ======== */
+#define ATOMIC_FAA(val_addr, addv) __atomic_fetch_add((val_addr), (addv), __ATOMIC_SEQ_CST)
+#define ATOMIC_AAF(val_addr, addv) __atomic_add_fetch((val_addr), (addv), __ATOMIC_SEQ_CST)
+/*
+ * It implements an atomic compare and exchange operation.
+ * This compares the contents of *ptr with the contents of *expected.
+ * - If equal, the operation is a read-modify-write operation that writes desired into *ptr.
+ * - If they are not equal, the operation is a read and the current contents of *ptr are written into *expected
+ */
+#define ATOMIC_CAS(val_addr, expected, desired) \
+ __atomic_compare_exchange_n((val_addr), (expected),(desired), \
+ /* weak = */ false, \
+ /* success_memorder = */ __ATOMIC_SEQ_CST, \
+ /* failure_memorder = */ __ATOMIC_SEQ_CST)
+#define ATOMIC_LOAD(val_addr) __atomic_load_n((val_addr), __ATOMIC_SEQ_CST)
+#define ATOMIC_STORE(val_addr, val) __atomic_store_n((val_addr), (val), __ATOMIC_SEQ_CST)
+
+/* ======== align ======== */
+#define ALIGNED(a) __attribute__((aligned(a)))
+#define ALIGNED_4 ALIGNED(4)
+#define ALIGNED_8 ALIGNED(8)
+
+/* ======== disallow copy and assign ======== */
+#if __cplusplus < 201103L
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+#else
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ TypeName& operator=(const TypeName&) = delete;
+#endif
+
+/* ======== return value check ======== */
+#define RET_FAIL(expr) UNLIKELY(common::E_OK != (ret = (expr)))
+#define RFAIL(expr) UNLIKELY(common::E_OK != (ret = (expr)))
+#define RET_SUCC(expr) LIKELY(common::E_OK != (ret = (exprt)))
+#define RSUCC(expr) LIKELY(common::E_OK != (ret = (exprt)))
+#define IS_SUCC(ret) LIKELY(common::E_OK == (ret))
+#define IS_FAIL(ret) UNLIKELY(common::E_OK != (ret))
+
+#define IS_NULL(ptr) UNLIKELY((ptr) == nullptr)
+
+/* ======== min/max ======== */
+#define UTIL_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define UTIL_MIN(a, b) ((a) > (b) ? (b) : (a))
+
+/*
+ * int64_max < 10^20
+ * consider +/- and the '\0' tail. 24 is enough
+ */
+#define INT64_TO_BASE10_MAX_LEN 24
+
+#endif // COMMON_UTIL_DEFINE_H
+
diff --git a/cpp/tsfile/src/tsfile.cpp b/cpp/tsfile/src/tsfile.cpp
deleted file mode 100644
index 7683a289..00000000
--- a/cpp/tsfile/src/tsfile.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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
- *
- * https://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.
- */
-#include "common.hpp"
-#include "tsfile.hpp"
-
-TsFile::TsFile() {
- // Not really doing anything here ...
-}
-
-int TsFile::doSomethingElse(int a, int b, int c) const {
- Common* common = new Common();
- return common->doSomething(a, b - c);
-}
\ No newline at end of file
diff --git a/cpp/tsfile/src/tsfile/CMakeLists.txt b/cpp/tsfile/src/tsfile/CMakeLists.txt
new file mode 100644
index 00000000..92beda98
--- /dev/null
+++ b/cpp/tsfile/src/tsfile/CMakeLists.txt
@@ -0,0 +1,118 @@
+
+message("Running in src/storage/tsfile directory")
+
+aux_source_directory(. storage_tsfile_SRC_LIST)
+aux_source_directory(filter storage_tsfile_filter_SRC_LIST)
+set(storage_tsfile_INC_LIST )
+set(storage_tsfile_DEFINE_OPTIONS )
+set(storage_tsfile_COMPILE_OPTIONS )
+set(storage_tsfile_LINK_OPTIONS )
+set(storage_tsfile_for_server_SRC_LIST ${storage_tsfile_SRC_LIST}
+ ${storage_tsfile_filter_SRC_LIST})
+
+add_statis_objtarget(storage_tsfile storage_tsfile_for_server_SRC_LIST
+ storage_tsfile_INC_LIST
+ "${storage_tsfile_DEFINE_OPTIONS}"
+ "${storage_tsfile_COMPILE_OPTIONS}"
+ "${storage_tsfile_LINK_OPTIONS}")
+
+add_subdirectory(compress)
+add_subdirectory(encode)
+
+# for libtsfile SDK
+# FIXME remove elog
+aux_source_directory(. libtsfile_SRC_LIST)
+aux_source_directory(../common common_SRC_LIST)
+aux_source_directory(../common/allocator common_allocator_SRC_LIST)
+aux_source_directory(../common/container common_container_SRC_LIST)
+aux_source_directory(../common/tsblock common_tsblock_SRC_LIST)
+aux_source_directory(../common/logger common_logger_SRC_LIST)
+aux_source_directory(. storage_tsfile_SRC_LIST)
+aux_source_directory(compress storage_tsfile_compress_SRC_LIST)
+set(libtsfile_tsfile_SRC_LIST tsfile_writer.cc
+ qds_with_timegenerator.cc
+ qds_without_timegenerator.cc
+ tablet.cc
+ qds_with_timegenerator.cc
+ qds_without_timegenerator.cc
+ tablet.cc
+ tsfile_executor.cc
+ tsfile_reader.cc)
+set(libtsfile_DEP_SRC_LIST ${common_SRC_LIST}
+ ${common_allocator_SRC_LIST}
+ ${common_logger_SRC_LIST}
+ ${common_container_SRC_LIST}
+ ${common_tsblock_SRC_LIST}
+ ${storage_tsfile_SRC_LIST}
+ ${libtsfile_tsfile_SRC_LIST}
+ ${storage_tsfile_filter_SRC_LIST}
+ ${storage_tsfile_compress_SRC_LIST})
+
+add_library(tsfile SHARED ${libtsfile_SRC_LIST} ${libtsfile_DEP_SRC_LIST})
+
+# set(CMAKE_PREFIX_PATH ../../third-party/zlib-1.2.13/install/lib)
+# set(ZLIB_LIB_DIR ../../third-party/zlib-1.2.13/install/lib)
+# # find_library(my_z_lib NAMES z PATHS ${ZLIB_LIB_DIR} NO_DEFAULT_PATH REQUIRED)
+# # target_link_libraries(tsfile ${my_z_lib})
+
+# set(CMAKE_PREFIX_PATH ../../third-party/lz4-dev/lib)
+# set(LZ4_LIB_DIR ../../third-party/lz4-dev/lib)
+# find_library(my_lz4_lib NAMES lz4 PATHS ${LZ4_LIB_DIR} NO_DEFAULT_PATH REQUIRED)
+# link_directories(${LZ4_LIB_DIR})
+# target_link_libraries(tsfile ${my_lz4_lib})
+
+set(LIBTSFILE_PROJECT_VERSION 1.0)
+set(LIBTSFILE_SO_VERSION 1.0)
+set_target_properties(tsfile PROPERTIES VERSION ${LIBTSFILE_PROJECT_VERSION})
+set_target_properties(tsfile PROPERTIES SOVERSION ${LIBTSFILE_SO_VERSION})
+
+set(LIBTSFILE_SDK_DIR ${EXECUTABLE_OUTPUT_PATH}/libtsfile_sdk/)
+install(TARGETS tsfile LIBRARY DESTINATION ${LIBTSFILE_SDK_DIR}/lib)
+
+set(libtsfile_tsfile_HEADER_FILES tsfile_reader.h
+ schema.h
+ record.h
+ tsfile_writer.h
+ tablet.h
+ write_file.h
+ read_file.h
+ row_record.h
+ path.h
+ query_data_set.h
+ expression.h)
+install(FILES ${libtsfile_tsfile_HEADER_FILES} DESTINATION ${LIBTSFILE_SDK_DIR}/include/storage/tsfile)
+
+set(libtsfile_common_HEADER_FILES ../common/db_common.h
+ ../common/util_define.h
+ ../common/errno_define.h
+ ../../cmake/cmake_config.h)
+install(FILES ${libtsfile_common_HEADER_FILES} DESTINATION ${LIBTSFILE_SDK_DIR}/include/common)
+
+set(libtsfile_common_container_HEADER_FILES ../common/container/bit_map.h
+ ../common/container/simple_vector.h)
+install(FILES ${libtsfile_common_container_HEADER_FILES} DESTINATION ${LIBTSFILE_SDK_DIR}/include/common/container)
+
+set(libtsfile_tsfile_filter_HEADER_FILES filter/time_filter.h
+ filter/time_operator.h
+ filter/and_filter.h
+ filter/binary_filter.h
+ filter/between.h
+ filter/eq.h
+ filter/filter.h
+ filter/filter_type.h
+ filter/gt_eq.h
+ filter/gt.h
+ filter/in.h
+ filter/lt_eq.h
+ filter/lt.h
+ filter/not_eq.h
+ filter/or_filter.h
+ filter/time_filter.h
+ filter/time_operator.h)
+
+install(FILES ${libtsfile_tsfile_filter_HEADER_FILES} DESTINATION ${LIBTSFILE_SDK_DIR}/include/storage/tsfile/filter)
+
+if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ add_custom_command(TARGET tsfile POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change `otool -L ${LIBRARY_OUTPUT_PATH}/libtsfile.dylib | grep liblz4 | sed 's/dylib.*/dylib/g'` ${my_lz4_lib} ${LIBRARY_OUTPUT_PATH}/libtsfile.dylib)
+ add_custom_command(TARGET tsfile POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change `otool -L ${LIBRARY_OUTPUT_PATH}/libtsfile.dylib | grep libz | sed 's/dylib.*/dylib/g'` ${my_z_lib} ${LIBRARY_OUTPUT_PATH}/libtsfile.dylib)
+endif()
diff --git a/cpp/tsfile/src/tsfile/Makefile b/cpp/tsfile/src/tsfile/Makefile
new file mode 100644
index 00000000..de7837ad
--- /dev/null
+++ b/cpp/tsfile/src/tsfile/Makefile
@@ -0,0 +1,1281 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 3.24
+
+# Default target executed when no arguments are given to make.
+default_target: all
+.PHONY : default_target
+
+# Allow only one "make -f Makefile2" at a time, but pass parallelism.
+.NOTPARALLEL:
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canonical targets will work.
+.SUFFIXES:
+
+# Disable VCS-based implicit rules.
+% : %,v
+
+# Disable VCS-based implicit rules.
+% : RCS/%
+
+# Disable VCS-based implicit rules.
+% : RCS/%,v
+
+# Disable VCS-based implicit rules.
+% : SCCS/s.%
+
+# Disable VCS-based implicit rules.
+% : s.%
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+# Command-line flag to silence nested $(MAKE).
+$(VERBOSE)MAKESILENT = -s
+
+#Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+# A target that is always out of date.
+cmake_force:
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+# The shell in which to execute make rules.
+SHELL = /bin/sh
+
+# The CMake executable.
+CMAKE_COMMAND = /opt/cmake-3.24.2-linux-x86_64/bin/cmake
+
+# The command to remove a file.
+RM = /opt/cmake-3.24.2-linux-x86_64/bin/cmake -E rm -f
+
+# Escaping for special characters.
+EQUALS = =
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = /home/oushu/dev/timechodb-edge
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = /home/oushu/dev/timechodb-edge/build/Debug
+
+#=============================================================================
+# Targets provided globally by CMake.
+
+# Special rule for the target edit_cache
+edit_cache:
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..."
+ /opt/cmake-3.24.2-linux-x86_64/bin/ccmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : edit_cache
+
+# Special rule for the target edit_cache
+edit_cache/fast: edit_cache
+.PHONY : edit_cache/fast
+
+# Special rule for the target rebuild_cache
+rebuild_cache:
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
+ /opt/cmake-3.24.2-linux-x86_64/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : rebuild_cache
+
+# Special rule for the target rebuild_cache
+rebuild_cache/fast: rebuild_cache
+.PHONY : rebuild_cache/fast
+
+# Special rule for the target list_install_components
+list_install_components:
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\""
+.PHONY : list_install_components
+
+# Special rule for the target list_install_components
+list_install_components/fast: list_install_components
+.PHONY : list_install_components/fast
+
+# Special rule for the target install
+install: preinstall
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
+ /opt/cmake-3.24.2-linux-x86_64/bin/cmake -P cmake_install.cmake
+.PHONY : install
+
+# Special rule for the target install
+install/fast: preinstall/fast
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
+ /opt/cmake-3.24.2-linux-x86_64/bin/cmake -P cmake_install.cmake
+.PHONY : install/fast
+
+# Special rule for the target install/local
+install/local: preinstall
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
+ /opt/cmake-3.24.2-linux-x86_64/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
+.PHONY : install/local
+
+# Special rule for the target install/local
+install/local/fast: preinstall/fast
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
+ /opt/cmake-3.24.2-linux-x86_64/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
+.PHONY : install/local/fast
+
+# Special rule for the target install/strip
+install/strip: preinstall
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
+ /opt/cmake-3.24.2-linux-x86_64/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
+.PHONY : install/strip
+
+# Special rule for the target install/strip
+install/strip/fast: preinstall/fast
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
+ /opt/cmake-3.24.2-linux-x86_64/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
+.PHONY : install/strip/fast
+
+# The main all target
+all: cmake_check_build_system
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(CMAKE_COMMAND) -E cmake_progress_start /home/oushu/dev/timechodb-edge/build/Debug/CMakeFiles /home/oushu/dev/timechodb-edge/build/Debug/src/storage/tsfile//CMakeFiles/progress.marks
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 src/storage/tsfile/all
+ $(CMAKE_COMMAND) -E cmake_progress_start /home/oushu/dev/timechodb-edge/build/Debug/CMakeFiles 0
+.PHONY : all
+
+# The main clean target
+clean:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 src/storage/tsfile/clean
+.PHONY : clean
+
+# The main clean target
+clean/fast: clean
+.PHONY : clean/fast
+
+# Prepare targets for installation.
+preinstall: all
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 src/storage/tsfile/preinstall
+.PHONY : preinstall
+
+# Prepare targets for installation.
+preinstall/fast:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 src/storage/tsfile/preinstall
+.PHONY : preinstall/fast
+
+# clear depends
+depend:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
+.PHONY : depend
+
+# Convenience name for target.
+src/storage/tsfile/CMakeFiles/storage_tsfile.dir/rule:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 src/storage/tsfile/CMakeFiles/storage_tsfile.dir/rule
+.PHONY : src/storage/tsfile/CMakeFiles/storage_tsfile.dir/rule
+
+# Convenience name for target.
+storage_tsfile: src/storage/tsfile/CMakeFiles/storage_tsfile.dir/rule
+.PHONY : storage_tsfile
+
+# fast build rule for target.
+storage_tsfile/fast:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build
+.PHONY : storage_tsfile/fast
+
+# Convenience name for target.
+src/storage/tsfile/CMakeFiles/tsfile.dir/rule:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 src/storage/tsfile/CMakeFiles/tsfile.dir/rule
+.PHONY : src/storage/tsfile/CMakeFiles/tsfile.dir/rule
+
+# Convenience name for target.
+tsfile: src/storage/tsfile/CMakeFiles/tsfile.dir/rule
+.PHONY : tsfile
+
+# fast build rule for target.
+tsfile/fast:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/build
+.PHONY : tsfile/fast
+
+__/__/common/allocator/mem_alloc.o: __/__/common/allocator/mem_alloc.cc.o
+.PHONY : __/__/common/allocator/mem_alloc.o
+
+# target to build an object file
+__/__/common/allocator/mem_alloc.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/allocator/mem_alloc.cc.o
+.PHONY : __/__/common/allocator/mem_alloc.cc.o
+
+__/__/common/allocator/mem_alloc.i: __/__/common/allocator/mem_alloc.cc.i
+.PHONY : __/__/common/allocator/mem_alloc.i
+
+# target to preprocess a source file
+__/__/common/allocator/mem_alloc.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/allocator/mem_alloc.cc.i
+.PHONY : __/__/common/allocator/mem_alloc.cc.i
+
+__/__/common/allocator/mem_alloc.s: __/__/common/allocator/mem_alloc.cc.s
+.PHONY : __/__/common/allocator/mem_alloc.s
+
+# target to generate assembly for a file
+__/__/common/allocator/mem_alloc.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/allocator/mem_alloc.cc.s
+.PHONY : __/__/common/allocator/mem_alloc.cc.s
+
+__/__/common/allocator/page_arena.o: __/__/common/allocator/page_arena.cc.o
+.PHONY : __/__/common/allocator/page_arena.o
+
+# target to build an object file
+__/__/common/allocator/page_arena.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/allocator/page_arena.cc.o
+.PHONY : __/__/common/allocator/page_arena.cc.o
+
+__/__/common/allocator/page_arena.i: __/__/common/allocator/page_arena.cc.i
+.PHONY : __/__/common/allocator/page_arena.i
+
+# target to preprocess a source file
+__/__/common/allocator/page_arena.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/allocator/page_arena.cc.i
+.PHONY : __/__/common/allocator/page_arena.cc.i
+
+__/__/common/allocator/page_arena.s: __/__/common/allocator/page_arena.cc.s
+.PHONY : __/__/common/allocator/page_arena.s
+
+# target to generate assembly for a file
+__/__/common/allocator/page_arena.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/allocator/page_arena.cc.s
+.PHONY : __/__/common/allocator/page_arena.cc.s
+
+__/__/common/container/bit_map.o: __/__/common/container/bit_map.cc.o
+.PHONY : __/__/common/container/bit_map.o
+
+# target to build an object file
+__/__/common/container/bit_map.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/container/bit_map.cc.o
+.PHONY : __/__/common/container/bit_map.cc.o
+
+__/__/common/container/bit_map.i: __/__/common/container/bit_map.cc.i
+.PHONY : __/__/common/container/bit_map.i
+
+# target to preprocess a source file
+__/__/common/container/bit_map.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/container/bit_map.cc.i
+.PHONY : __/__/common/container/bit_map.cc.i
+
+__/__/common/container/bit_map.s: __/__/common/container/bit_map.cc.s
+.PHONY : __/__/common/container/bit_map.s
+
+# target to generate assembly for a file
+__/__/common/container/bit_map.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/container/bit_map.cc.s
+.PHONY : __/__/common/container/bit_map.cc.s
+
+__/__/common/container/blocking_queue.o: __/__/common/container/blocking_queue.cc.o
+.PHONY : __/__/common/container/blocking_queue.o
+
+# target to build an object file
+__/__/common/container/blocking_queue.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/container/blocking_queue.cc.o
+.PHONY : __/__/common/container/blocking_queue.cc.o
+
+__/__/common/container/blocking_queue.i: __/__/common/container/blocking_queue.cc.i
+.PHONY : __/__/common/container/blocking_queue.i
+
+# target to preprocess a source file
+__/__/common/container/blocking_queue.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/container/blocking_queue.cc.i
+.PHONY : __/__/common/container/blocking_queue.cc.i
+
+__/__/common/container/blocking_queue.s: __/__/common/container/blocking_queue.cc.s
+.PHONY : __/__/common/container/blocking_queue.s
+
+# target to generate assembly for a file
+__/__/common/container/blocking_queue.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/container/blocking_queue.cc.s
+.PHONY : __/__/common/container/blocking_queue.cc.s
+
+__/__/common/container/murmur_hash3.o: __/__/common/container/murmur_hash3.cc.o
+.PHONY : __/__/common/container/murmur_hash3.o
+
+# target to build an object file
+__/__/common/container/murmur_hash3.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/container/murmur_hash3.cc.o
+.PHONY : __/__/common/container/murmur_hash3.cc.o
+
+__/__/common/container/murmur_hash3.i: __/__/common/container/murmur_hash3.cc.i
+.PHONY : __/__/common/container/murmur_hash3.i
+
+# target to preprocess a source file
+__/__/common/container/murmur_hash3.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/container/murmur_hash3.cc.i
+.PHONY : __/__/common/container/murmur_hash3.cc.i
+
+__/__/common/container/murmur_hash3.s: __/__/common/container/murmur_hash3.cc.s
+.PHONY : __/__/common/container/murmur_hash3.s
+
+# target to generate assembly for a file
+__/__/common/container/murmur_hash3.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/container/murmur_hash3.cc.s
+.PHONY : __/__/common/container/murmur_hash3.cc.s
+
+__/__/common/global.o: __/__/common/global.cc.o
+.PHONY : __/__/common/global.o
+
+# target to build an object file
+__/__/common/global.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/global.cc.o
+.PHONY : __/__/common/global.cc.o
+
+__/__/common/global.i: __/__/common/global.cc.i
+.PHONY : __/__/common/global.i
+
+# target to preprocess a source file
+__/__/common/global.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/global.cc.i
+.PHONY : __/__/common/global.cc.i
+
+__/__/common/global.s: __/__/common/global.cc.s
+.PHONY : __/__/common/global.s
+
+# target to generate assembly for a file
+__/__/common/global.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/global.cc.s
+.PHONY : __/__/common/global.cc.s
+
+__/__/common/logger/elog.o: __/__/common/logger/elog.cc.o
+.PHONY : __/__/common/logger/elog.o
+
+# target to build an object file
+__/__/common/logger/elog.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog.cc.o
+.PHONY : __/__/common/logger/elog.cc.o
+
+__/__/common/logger/elog.i: __/__/common/logger/elog.cc.i
+.PHONY : __/__/common/logger/elog.i
+
+# target to preprocess a source file
+__/__/common/logger/elog.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog.cc.i
+.PHONY : __/__/common/logger/elog.cc.i
+
+__/__/common/logger/elog.s: __/__/common/logger/elog.cc.s
+.PHONY : __/__/common/logger/elog.s
+
+# target to generate assembly for a file
+__/__/common/logger/elog.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog.cc.s
+.PHONY : __/__/common/logger/elog.cc.s
+
+__/__/common/logger/elog_async.o: __/__/common/logger/elog_async.cc.o
+.PHONY : __/__/common/logger/elog_async.o
+
+# target to build an object file
+__/__/common/logger/elog_async.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_async.cc.o
+.PHONY : __/__/common/logger/elog_async.cc.o
+
+__/__/common/logger/elog_async.i: __/__/common/logger/elog_async.cc.i
+.PHONY : __/__/common/logger/elog_async.i
+
+# target to preprocess a source file
+__/__/common/logger/elog_async.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_async.cc.i
+.PHONY : __/__/common/logger/elog_async.cc.i
+
+__/__/common/logger/elog_async.s: __/__/common/logger/elog_async.cc.s
+.PHONY : __/__/common/logger/elog_async.s
+
+# target to generate assembly for a file
+__/__/common/logger/elog_async.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_async.cc.s
+.PHONY : __/__/common/logger/elog_async.cc.s
+
+__/__/common/logger/elog_buf.o: __/__/common/logger/elog_buf.cc.o
+.PHONY : __/__/common/logger/elog_buf.o
+
+# target to build an object file
+__/__/common/logger/elog_buf.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_buf.cc.o
+.PHONY : __/__/common/logger/elog_buf.cc.o
+
+__/__/common/logger/elog_buf.i: __/__/common/logger/elog_buf.cc.i
+.PHONY : __/__/common/logger/elog_buf.i
+
+# target to preprocess a source file
+__/__/common/logger/elog_buf.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_buf.cc.i
+.PHONY : __/__/common/logger/elog_buf.cc.i
+
+__/__/common/logger/elog_buf.s: __/__/common/logger/elog_buf.cc.s
+.PHONY : __/__/common/logger/elog_buf.s
+
+# target to generate assembly for a file
+__/__/common/logger/elog_buf.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_buf.cc.s
+.PHONY : __/__/common/logger/elog_buf.cc.s
+
+__/__/common/logger/elog_file.o: __/__/common/logger/elog_file.cc.o
+.PHONY : __/__/common/logger/elog_file.o
+
+# target to build an object file
+__/__/common/logger/elog_file.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_file.cc.o
+.PHONY : __/__/common/logger/elog_file.cc.o
+
+__/__/common/logger/elog_file.i: __/__/common/logger/elog_file.cc.i
+.PHONY : __/__/common/logger/elog_file.i
+
+# target to preprocess a source file
+__/__/common/logger/elog_file.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_file.cc.i
+.PHONY : __/__/common/logger/elog_file.cc.i
+
+__/__/common/logger/elog_file.s: __/__/common/logger/elog_file.cc.s
+.PHONY : __/__/common/logger/elog_file.s
+
+# target to generate assembly for a file
+__/__/common/logger/elog_file.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_file.cc.s
+.PHONY : __/__/common/logger/elog_file.cc.s
+
+__/__/common/logger/elog_utils.o: __/__/common/logger/elog_utils.cc.o
+.PHONY : __/__/common/logger/elog_utils.o
+
+# target to build an object file
+__/__/common/logger/elog_utils.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_utils.cc.o
+.PHONY : __/__/common/logger/elog_utils.cc.o
+
+__/__/common/logger/elog_utils.i: __/__/common/logger/elog_utils.cc.i
+.PHONY : __/__/common/logger/elog_utils.i
+
+# target to preprocess a source file
+__/__/common/logger/elog_utils.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_utils.cc.i
+.PHONY : __/__/common/logger/elog_utils.cc.i
+
+__/__/common/logger/elog_utils.s: __/__/common/logger/elog_utils.cc.s
+.PHONY : __/__/common/logger/elog_utils.s
+
+# target to generate assembly for a file
+__/__/common/logger/elog_utils.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/logger/elog_utils.cc.s
+.PHONY : __/__/common/logger/elog_utils.cc.s
+
+__/__/common/tsblock/tsblock.o: __/__/common/tsblock/tsblock.cc.o
+.PHONY : __/__/common/tsblock/tsblock.o
+
+# target to build an object file
+__/__/common/tsblock/tsblock.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/tsblock/tsblock.cc.o
+.PHONY : __/__/common/tsblock/tsblock.cc.o
+
+__/__/common/tsblock/tsblock.i: __/__/common/tsblock/tsblock.cc.i
+.PHONY : __/__/common/tsblock/tsblock.i
+
+# target to preprocess a source file
+__/__/common/tsblock/tsblock.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/tsblock/tsblock.cc.i
+.PHONY : __/__/common/tsblock/tsblock.cc.i
+
+__/__/common/tsblock/tsblock.s: __/__/common/tsblock/tsblock.cc.s
+.PHONY : __/__/common/tsblock/tsblock.s
+
+# target to generate assembly for a file
+__/__/common/tsblock/tsblock.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/tsblock/tsblock.cc.s
+.PHONY : __/__/common/tsblock/tsblock.cc.s
+
+__/__/common/tsblock/tuple_desc.o: __/__/common/tsblock/tuple_desc.cc.o
+.PHONY : __/__/common/tsblock/tuple_desc.o
+
+# target to build an object file
+__/__/common/tsblock/tuple_desc.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/tsblock/tuple_desc.cc.o
+.PHONY : __/__/common/tsblock/tuple_desc.cc.o
+
+__/__/common/tsblock/tuple_desc.i: __/__/common/tsblock/tuple_desc.cc.i
+.PHONY : __/__/common/tsblock/tuple_desc.i
+
+# target to preprocess a source file
+__/__/common/tsblock/tuple_desc.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/tsblock/tuple_desc.cc.i
+.PHONY : __/__/common/tsblock/tuple_desc.cc.i
+
+__/__/common/tsblock/tuple_desc.s: __/__/common/tsblock/tuple_desc.cc.s
+.PHONY : __/__/common/tsblock/tuple_desc.s
+
+# target to generate assembly for a file
+__/__/common/tsblock/tuple_desc.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/__/__/common/tsblock/tuple_desc.cc.s
+.PHONY : __/__/common/tsblock/tuple_desc.cc.s
+
+bloom_filter.o: bloom_filter.cc.o
+.PHONY : bloom_filter.o
+
+# target to build an object file
+bloom_filter.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/bloom_filter.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/bloom_filter.cc.o
+.PHONY : bloom_filter.cc.o
+
+bloom_filter.i: bloom_filter.cc.i
+.PHONY : bloom_filter.i
+
+# target to preprocess a source file
+bloom_filter.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/bloom_filter.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/bloom_filter.cc.i
+.PHONY : bloom_filter.cc.i
+
+bloom_filter.s: bloom_filter.cc.s
+.PHONY : bloom_filter.s
+
+# target to generate assembly for a file
+bloom_filter.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/bloom_filter.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/bloom_filter.cc.s
+.PHONY : bloom_filter.cc.s
+
+chunk_reader.o: chunk_reader.cc.o
+.PHONY : chunk_reader.o
+
+# target to build an object file
+chunk_reader.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/chunk_reader.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/chunk_reader.cc.o
+.PHONY : chunk_reader.cc.o
+
+chunk_reader.i: chunk_reader.cc.i
+.PHONY : chunk_reader.i
+
+# target to preprocess a source file
+chunk_reader.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/chunk_reader.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/chunk_reader.cc.i
+.PHONY : chunk_reader.cc.i
+
+chunk_reader.s: chunk_reader.cc.s
+.PHONY : chunk_reader.s
+
+# target to generate assembly for a file
+chunk_reader.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/chunk_reader.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/chunk_reader.cc.s
+.PHONY : chunk_reader.cc.s
+
+chunk_writer.o: chunk_writer.cc.o
+.PHONY : chunk_writer.o
+
+# target to build an object file
+chunk_writer.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/chunk_writer.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/chunk_writer.cc.o
+.PHONY : chunk_writer.cc.o
+
+chunk_writer.i: chunk_writer.cc.i
+.PHONY : chunk_writer.i
+
+# target to preprocess a source file
+chunk_writer.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/chunk_writer.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/chunk_writer.cc.i
+.PHONY : chunk_writer.cc.i
+
+chunk_writer.s: chunk_writer.cc.s
+.PHONY : chunk_writer.s
+
+# target to generate assembly for a file
+chunk_writer.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/chunk_writer.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/chunk_writer.cc.s
+.PHONY : chunk_writer.cc.s
+
+compress/compressor.o: compress/compressor.c.o
+.PHONY : compress/compressor.o
+
+# target to build an object file
+compress/compressor.c.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/compress/compressor.c.o
+.PHONY : compress/compressor.c.o
+
+compress/compressor.i: compress/compressor.c.i
+.PHONY : compress/compressor.i
+
+# target to preprocess a source file
+compress/compressor.c.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/compress/compressor.c.i
+.PHONY : compress/compressor.c.i
+
+compress/compressor.s: compress/compressor.c.s
+.PHONY : compress/compressor.s
+
+# target to generate assembly for a file
+compress/compressor.c.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/compress/compressor.c.s
+.PHONY : compress/compressor.c.s
+
+compress/gzip_compressor.o: compress/gzip_compressor.cc.o
+.PHONY : compress/gzip_compressor.o
+
+# target to build an object file
+compress/gzip_compressor.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/compress/gzip_compressor.cc.o
+.PHONY : compress/gzip_compressor.cc.o
+
+compress/gzip_compressor.i: compress/gzip_compressor.cc.i
+.PHONY : compress/gzip_compressor.i
+
+# target to preprocess a source file
+compress/gzip_compressor.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/compress/gzip_compressor.cc.i
+.PHONY : compress/gzip_compressor.cc.i
+
+compress/gzip_compressor.s: compress/gzip_compressor.cc.s
+.PHONY : compress/gzip_compressor.s
+
+# target to generate assembly for a file
+compress/gzip_compressor.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/compress/gzip_compressor.cc.s
+.PHONY : compress/gzip_compressor.cc.s
+
+compress/lz4_compressor.o: compress/lz4_compressor.cc.o
+.PHONY : compress/lz4_compressor.o
+
+# target to build an object file
+compress/lz4_compressor.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/compress/lz4_compressor.cc.o
+.PHONY : compress/lz4_compressor.cc.o
+
+compress/lz4_compressor.i: compress/lz4_compressor.cc.i
+.PHONY : compress/lz4_compressor.i
+
+# target to preprocess a source file
+compress/lz4_compressor.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/compress/lz4_compressor.cc.i
+.PHONY : compress/lz4_compressor.cc.i
+
+compress/lz4_compressor.s: compress/lz4_compressor.cc.s
+.PHONY : compress/lz4_compressor.s
+
+# target to generate assembly for a file
+compress/lz4_compressor.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/compress/lz4_compressor.cc.s
+.PHONY : compress/lz4_compressor.cc.s
+
+expression.o: expression.cc.o
+.PHONY : expression.o
+
+# target to build an object file
+expression.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/expression.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/expression.cc.o
+.PHONY : expression.cc.o
+
+expression.i: expression.cc.i
+.PHONY : expression.i
+
+# target to preprocess a source file
+expression.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/expression.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/expression.cc.i
+.PHONY : expression.cc.i
+
+expression.s: expression.cc.s
+.PHONY : expression.s
+
+# target to generate assembly for a file
+expression.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/expression.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/expression.cc.s
+.PHONY : expression.cc.s
+
+filter/time_filter.o: filter/time_filter.cc.o
+.PHONY : filter/time_filter.o
+
+# target to build an object file
+filter/time_filter.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/filter/time_filter.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/filter/time_filter.cc.o
+.PHONY : filter/time_filter.cc.o
+
+filter/time_filter.i: filter/time_filter.cc.i
+.PHONY : filter/time_filter.i
+
+# target to preprocess a source file
+filter/time_filter.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/filter/time_filter.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/filter/time_filter.cc.i
+.PHONY : filter/time_filter.cc.i
+
+filter/time_filter.s: filter/time_filter.cc.s
+.PHONY : filter/time_filter.s
+
+# target to generate assembly for a file
+filter/time_filter.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/filter/time_filter.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/filter/time_filter.cc.s
+.PHONY : filter/time_filter.cc.s
+
+filter/time_operator.o: filter/time_operator.cc.o
+.PHONY : filter/time_operator.o
+
+# target to build an object file
+filter/time_operator.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/filter/time_operator.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/filter/time_operator.cc.o
+.PHONY : filter/time_operator.cc.o
+
+filter/time_operator.i: filter/time_operator.cc.i
+.PHONY : filter/time_operator.i
+
+# target to preprocess a source file
+filter/time_operator.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/filter/time_operator.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/filter/time_operator.cc.i
+.PHONY : filter/time_operator.cc.i
+
+filter/time_operator.s: filter/time_operator.cc.s
+.PHONY : filter/time_operator.s
+
+# target to generate assembly for a file
+filter/time_operator.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/filter/time_operator.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/filter/time_operator.cc.s
+.PHONY : filter/time_operator.cc.s
+
+open_file.o: open_file.cc.o
+.PHONY : open_file.o
+
+# target to build an object file
+open_file.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/open_file.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/open_file.cc.o
+.PHONY : open_file.cc.o
+
+open_file.i: open_file.cc.i
+.PHONY : open_file.i
+
+# target to preprocess a source file
+open_file.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/open_file.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/open_file.cc.i
+.PHONY : open_file.cc.i
+
+open_file.s: open_file.cc.s
+.PHONY : open_file.s
+
+# target to generate assembly for a file
+open_file.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/open_file.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/open_file.cc.s
+.PHONY : open_file.cc.s
+
+page_writer.o: page_writer.cc.o
+.PHONY : page_writer.o
+
+# target to build an object file
+page_writer.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/page_writer.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/page_writer.cc.o
+.PHONY : page_writer.cc.o
+
+page_writer.i: page_writer.cc.i
+.PHONY : page_writer.i
+
+# target to preprocess a source file
+page_writer.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/page_writer.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/page_writer.cc.i
+.PHONY : page_writer.cc.i
+
+page_writer.s: page_writer.cc.s
+.PHONY : page_writer.s
+
+# target to generate assembly for a file
+page_writer.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/page_writer.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/page_writer.cc.s
+.PHONY : page_writer.cc.s
+
+qds_with_timegenerator.o: qds_with_timegenerator.cc.o
+.PHONY : qds_with_timegenerator.o
+
+# target to build an object file
+qds_with_timegenerator.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/qds_with_timegenerator.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/qds_with_timegenerator.cc.o
+.PHONY : qds_with_timegenerator.cc.o
+
+qds_with_timegenerator.i: qds_with_timegenerator.cc.i
+.PHONY : qds_with_timegenerator.i
+
+# target to preprocess a source file
+qds_with_timegenerator.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/qds_with_timegenerator.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/qds_with_timegenerator.cc.i
+.PHONY : qds_with_timegenerator.cc.i
+
+qds_with_timegenerator.s: qds_with_timegenerator.cc.s
+.PHONY : qds_with_timegenerator.s
+
+# target to generate assembly for a file
+qds_with_timegenerator.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/qds_with_timegenerator.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/qds_with_timegenerator.cc.s
+.PHONY : qds_with_timegenerator.cc.s
+
+qds_without_timegenerator.o: qds_without_timegenerator.cc.o
+.PHONY : qds_without_timegenerator.o
+
+# target to build an object file
+qds_without_timegenerator.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/qds_without_timegenerator.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/qds_without_timegenerator.cc.o
+.PHONY : qds_without_timegenerator.cc.o
+
+qds_without_timegenerator.i: qds_without_timegenerator.cc.i
+.PHONY : qds_without_timegenerator.i
+
+# target to preprocess a source file
+qds_without_timegenerator.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/qds_without_timegenerator.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/qds_without_timegenerator.cc.i
+.PHONY : qds_without_timegenerator.cc.i
+
+qds_without_timegenerator.s: qds_without_timegenerator.cc.s
+.PHONY : qds_without_timegenerator.s
+
+# target to generate assembly for a file
+qds_without_timegenerator.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/qds_without_timegenerator.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/qds_without_timegenerator.cc.s
+.PHONY : qds_without_timegenerator.cc.s
+
+read_file.o: read_file.cc.o
+.PHONY : read_file.o
+
+# target to build an object file
+read_file.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/read_file.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/read_file.cc.o
+.PHONY : read_file.cc.o
+
+read_file.i: read_file.cc.i
+.PHONY : read_file.i
+
+# target to preprocess a source file
+read_file.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/read_file.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/read_file.cc.i
+.PHONY : read_file.cc.i
+
+read_file.s: read_file.cc.s
+.PHONY : read_file.s
+
+# target to generate assembly for a file
+read_file.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/read_file.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/read_file.cc.s
+.PHONY : read_file.cc.s
+
+tablet.o: tablet.cc.o
+.PHONY : tablet.o
+
+# target to build an object file
+tablet.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tablet.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tablet.cc.o
+.PHONY : tablet.cc.o
+
+tablet.i: tablet.cc.i
+.PHONY : tablet.i
+
+# target to preprocess a source file
+tablet.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tablet.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tablet.cc.i
+.PHONY : tablet.cc.i
+
+tablet.s: tablet.cc.s
+.PHONY : tablet.s
+
+# target to generate assembly for a file
+tablet.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tablet.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tablet.cc.s
+.PHONY : tablet.cc.s
+
+tsfile_common.o: tsfile_common.cc.o
+.PHONY : tsfile_common.o
+
+# target to build an object file
+tsfile_common.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_common.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_common.cc.o
+.PHONY : tsfile_common.cc.o
+
+tsfile_common.i: tsfile_common.cc.i
+.PHONY : tsfile_common.i
+
+# target to preprocess a source file
+tsfile_common.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_common.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_common.cc.i
+.PHONY : tsfile_common.cc.i
+
+tsfile_common.s: tsfile_common.cc.s
+.PHONY : tsfile_common.s
+
+# target to generate assembly for a file
+tsfile_common.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_common.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_common.cc.s
+.PHONY : tsfile_common.cc.s
+
+tsfile_executor.o: tsfile_executor.cc.o
+.PHONY : tsfile_executor.o
+
+# target to build an object file
+tsfile_executor.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_executor.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_executor.cc.o
+.PHONY : tsfile_executor.cc.o
+
+tsfile_executor.i: tsfile_executor.cc.i
+.PHONY : tsfile_executor.i
+
+# target to preprocess a source file
+tsfile_executor.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_executor.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_executor.cc.i
+.PHONY : tsfile_executor.cc.i
+
+tsfile_executor.s: tsfile_executor.cc.s
+.PHONY : tsfile_executor.s
+
+# target to generate assembly for a file
+tsfile_executor.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_executor.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_executor.cc.s
+.PHONY : tsfile_executor.cc.s
+
+tsfile_io_reader.o: tsfile_io_reader.cc.o
+.PHONY : tsfile_io_reader.o
+
+# target to build an object file
+tsfile_io_reader.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_io_reader.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_io_reader.cc.o
+.PHONY : tsfile_io_reader.cc.o
+
+tsfile_io_reader.i: tsfile_io_reader.cc.i
+.PHONY : tsfile_io_reader.i
+
+# target to preprocess a source file
+tsfile_io_reader.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_io_reader.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_io_reader.cc.i
+.PHONY : tsfile_io_reader.cc.i
+
+tsfile_io_reader.s: tsfile_io_reader.cc.s
+.PHONY : tsfile_io_reader.s
+
+# target to generate assembly for a file
+tsfile_io_reader.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_io_reader.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_io_reader.cc.s
+.PHONY : tsfile_io_reader.cc.s
+
+tsfile_io_writer.o: tsfile_io_writer.cc.o
+.PHONY : tsfile_io_writer.o
+
+# target to build an object file
+tsfile_io_writer.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_io_writer.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_io_writer.cc.o
+.PHONY : tsfile_io_writer.cc.o
+
+tsfile_io_writer.i: tsfile_io_writer.cc.i
+.PHONY : tsfile_io_writer.i
+
+# target to preprocess a source file
+tsfile_io_writer.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_io_writer.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_io_writer.cc.i
+.PHONY : tsfile_io_writer.cc.i
+
+tsfile_io_writer.s: tsfile_io_writer.cc.s
+.PHONY : tsfile_io_writer.s
+
+# target to generate assembly for a file
+tsfile_io_writer.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_io_writer.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_io_writer.cc.s
+.PHONY : tsfile_io_writer.cc.s
+
+tsfile_mgr.o: tsfile_mgr.cc.o
+.PHONY : tsfile_mgr.o
+
+# target to build an object file
+tsfile_mgr.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_mgr.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_mgr.cc.o
+.PHONY : tsfile_mgr.cc.o
+
+tsfile_mgr.i: tsfile_mgr.cc.i
+.PHONY : tsfile_mgr.i
+
+# target to preprocess a source file
+tsfile_mgr.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_mgr.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_mgr.cc.i
+.PHONY : tsfile_mgr.cc.i
+
+tsfile_mgr.s: tsfile_mgr.cc.s
+.PHONY : tsfile_mgr.s
+
+# target to generate assembly for a file
+tsfile_mgr.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_mgr.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_mgr.cc.s
+.PHONY : tsfile_mgr.cc.s
+
+tsfile_reader.o: tsfile_reader.cc.o
+.PHONY : tsfile_reader.o
+
+# target to build an object file
+tsfile_reader.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_reader.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_reader.cc.o
+.PHONY : tsfile_reader.cc.o
+
+tsfile_reader.i: tsfile_reader.cc.i
+.PHONY : tsfile_reader.i
+
+# target to preprocess a source file
+tsfile_reader.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_reader.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_reader.cc.i
+.PHONY : tsfile_reader.cc.i
+
+tsfile_reader.s: tsfile_reader.cc.s
+.PHONY : tsfile_reader.s
+
+# target to generate assembly for a file
+tsfile_reader.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_reader.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_reader.cc.s
+.PHONY : tsfile_reader.cc.s
+
+tsfile_series_scan_iterator.o: tsfile_series_scan_iterator.cc.o
+.PHONY : tsfile_series_scan_iterator.o
+
+# target to build an object file
+tsfile_series_scan_iterator.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_series_scan_iterator.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_series_scan_iterator.cc.o
+.PHONY : tsfile_series_scan_iterator.cc.o
+
+tsfile_series_scan_iterator.i: tsfile_series_scan_iterator.cc.i
+.PHONY : tsfile_series_scan_iterator.i
+
+# target to preprocess a source file
+tsfile_series_scan_iterator.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_series_scan_iterator.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_series_scan_iterator.cc.i
+.PHONY : tsfile_series_scan_iterator.cc.i
+
+tsfile_series_scan_iterator.s: tsfile_series_scan_iterator.cc.s
+.PHONY : tsfile_series_scan_iterator.s
+
+# target to generate assembly for a file
+tsfile_series_scan_iterator.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_series_scan_iterator.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_series_scan_iterator.cc.s
+.PHONY : tsfile_series_scan_iterator.cc.s
+
+tsfile_writer.o: tsfile_writer.cc.o
+.PHONY : tsfile_writer.o
+
+# target to build an object file
+tsfile_writer.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_writer.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_writer.cc.o
+.PHONY : tsfile_writer.cc.o
+
+tsfile_writer.i: tsfile_writer.cc.i
+.PHONY : tsfile_writer.i
+
+# target to preprocess a source file
+tsfile_writer.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_writer.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_writer.cc.i
+.PHONY : tsfile_writer.cc.i
+
+tsfile_writer.s: tsfile_writer.cc.s
+.PHONY : tsfile_writer.s
+
+# target to generate assembly for a file
+tsfile_writer.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/tsfile_writer.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/tsfile_writer.cc.s
+.PHONY : tsfile_writer.cc.s
+
+write_file.o: write_file.cc.o
+.PHONY : write_file.o
+
+# target to build an object file
+write_file.cc.o:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/write_file.cc.o
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/write_file.cc.o
+.PHONY : write_file.cc.o
+
+write_file.i: write_file.cc.i
+.PHONY : write_file.i
+
+# target to preprocess a source file
+write_file.cc.i:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/write_file.cc.i
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/write_file.cc.i
+.PHONY : write_file.cc.i
+
+write_file.s: write_file.cc.s
+.PHONY : write_file.s
+
+# target to generate assembly for a file
+write_file.cc.s:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/storage_tsfile.dir/build.make src/storage/tsfile/CMakeFiles/storage_tsfile.dir/write_file.cc.s
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(MAKE) $(MAKESILENT) -f src/storage/tsfile/CMakeFiles/tsfile.dir/build.make src/storage/tsfile/CMakeFiles/tsfile.dir/write_file.cc.s
+.PHONY : write_file.cc.s
+
+# Help Target
+help:
+ @echo "The following are some of the valid targets for this Makefile:"
+ @echo "... all (the default if no target is provided)"
+ @echo "... clean"
+ @echo "... depend"
+ @echo "... edit_cache"
+ @echo "... install"
+ @echo "... install/local"
+ @echo "... install/strip"
+ @echo "... list_install_components"
+ @echo "... rebuild_cache"
+ @echo "... storage_tsfile"
+ @echo "... tsfile"
+ @echo "... __/__/common/allocator/mem_alloc.o"
+ @echo "... __/__/common/allocator/mem_alloc.i"
+ @echo "... __/__/common/allocator/mem_alloc.s"
+ @echo "... __/__/common/allocator/page_arena.o"
+ @echo "... __/__/common/allocator/page_arena.i"
+ @echo "... __/__/common/allocator/page_arena.s"
+ @echo "... __/__/common/container/bit_map.o"
+ @echo "... __/__/common/container/bit_map.i"
+ @echo "... __/__/common/container/bit_map.s"
+ @echo "... __/__/common/container/blocking_queue.o"
+ @echo "... __/__/common/container/blocking_queue.i"
+ @echo "... __/__/common/container/blocking_queue.s"
+ @echo "... __/__/common/container/murmur_hash3.o"
+ @echo "... __/__/common/container/murmur_hash3.i"
+ @echo "... __/__/common/container/murmur_hash3.s"
+ @echo "... __/__/common/global.o"
+ @echo "... __/__/common/global.i"
+ @echo "... __/__/common/global.s"
+ @echo "... __/__/common/logger/elog.o"
+ @echo "... __/__/common/logger/elog.i"
+ @echo "... __/__/common/logger/elog.s"
+ @echo "... __/__/common/logger/elog_async.o"
+ @echo "... __/__/common/logger/elog_async.i"
+ @echo "... __/__/common/logger/elog_async.s"
+ @echo "... __/__/common/logger/elog_buf.o"
+ @echo "... __/__/common/logger/elog_buf.i"
+ @echo "... __/__/common/logger/elog_buf.s"
+ @echo "... __/__/common/logger/elog_file.o"
+ @echo "... __/__/common/logger/elog_file.i"
+ @echo "... __/__/common/logger/elog_file.s"
+ @echo "... __/__/common/logger/elog_utils.o"
+ @echo "... __/__/common/logger/elog_utils.i"
+ @echo "... __/__/common/logger/elog_utils.s"
+ @echo "... __/__/common/tsblock/tsblock.o"
+ @echo "... __/__/common/tsblock/tsblock.i"
+ @echo "... __/__/common/tsblock/tsblock.s"
+ @echo "... __/__/common/tsblock/tuple_desc.o"
+ @echo "... __/__/common/tsblock/tuple_desc.i"
+ @echo "... __/__/common/tsblock/tuple_desc.s"
+ @echo "... bloom_filter.o"
+ @echo "... bloom_filter.i"
+ @echo "... bloom_filter.s"
+ @echo "... chunk_reader.o"
+ @echo "... chunk_reader.i"
+ @echo "... chunk_reader.s"
+ @echo "... chunk_writer.o"
+ @echo "... chunk_writer.i"
+ @echo "... chunk_writer.s"
+ @echo "... compress/compressor.o"
+ @echo "... compress/compressor.i"
+ @echo "... compress/compressor.s"
+ @echo "... compress/gzip_compressor.o"
+ @echo "... compress/gzip_compressor.i"
+ @echo "... compress/gzip_compressor.s"
+ @echo "... compress/lz4_compressor.o"
+ @echo "... compress/lz4_compressor.i"
+ @echo "... compress/lz4_compressor.s"
+ @echo "... expression.o"
+ @echo "... expression.i"
+ @echo "... expression.s"
+ @echo "... filter/time_filter.o"
+ @echo "... filter/time_filter.i"
+ @echo "... filter/time_filter.s"
+ @echo "... filter/time_operator.o"
+ @echo "... filter/time_operator.i"
+ @echo "... filter/time_operator.s"
+ @echo "... open_file.o"
+ @echo "... open_file.i"
+ @echo "... open_file.s"
+ @echo "... page_writer.o"
+ @echo "... page_writer.i"
+ @echo "... page_writer.s"
+ @echo "... qds_with_timegenerator.o"
+ @echo "... qds_with_timegenerator.i"
+ @echo "... qds_with_timegenerator.s"
+ @echo "... qds_without_timegenerator.o"
+ @echo "... qds_without_timegenerator.i"
+ @echo "... qds_without_timegenerator.s"
+ @echo "... read_file.o"
+ @echo "... read_file.i"
+ @echo "... read_file.s"
+ @echo "... tablet.o"
+ @echo "... tablet.i"
+ @echo "... tablet.s"
+ @echo "... tsfile_common.o"
+ @echo "... tsfile_common.i"
+ @echo "... tsfile_common.s"
+ @echo "... tsfile_executor.o"
+ @echo "... tsfile_executor.i"
+ @echo "... tsfile_executor.s"
+ @echo "... tsfile_io_reader.o"
+ @echo "... tsfile_io_reader.i"
+ @echo "... tsfile_io_reader.s"
+ @echo "... tsfile_io_writer.o"
+ @echo "... tsfile_io_writer.i"
+ @echo "... tsfile_io_writer.s"
+ @echo "... tsfile_mgr.o"
+ @echo "... tsfile_mgr.i"
+ @echo "... tsfile_mgr.s"
+ @echo "... tsfile_reader.o"
+ @echo "... tsfile_reader.i"
+ @echo "... tsfile_reader.s"
+ @echo "... tsfile_series_scan_iterator.o"
+ @echo "... tsfile_series_scan_iterator.i"
+ @echo "... tsfile_series_scan_iterator.s"
+ @echo "... tsfile_writer.o"
+ @echo "... tsfile_writer.i"
+ @echo "... tsfile_writer.s"
+ @echo "... write_file.o"
+ @echo "... write_file.i"
+ @echo "... write_file.s"
+.PHONY : help
+
+
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+ cd /home/oushu/dev/timechodb-edge/build/Debug && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
+.PHONY : cmake_check_build_system
+
diff --git a/cpp/tsfile/src/tsfile/bloom_filter.cc b/cpp/tsfile/src/tsfile/bloom_filter.cc
new file mode 100644
index 00000000..374285a8
--- /dev/null
+++ b/cpp/tsfile/src/tsfile/bloom_filter.cc
@@ -0,0 +1,254 @@
+
+#include "bloom_filter.h"
+#if USE_SYS_MATH
+#include <math.h>
+#endif
+
+using namespace timecho::common;
+
+namespace timecho
+{
+namespace storage
+{
+
+#if USE_SYS_MATH
+// Returns the natural logarithm (base e) of a double value
+double math_log(double in)
+{
+ return math.log(in);
+}
+#else
+// Returns the natural logarithm (base e) of a double value
+// To avoid use libm.so (however libstdc++ use libm.so sigh..)
+double math_log(double in)
+{
+ // result table: 0.90, 0.91, ... , 0.99
+ const double in_arr[10] = {
+ 0.01,
+ 0.02,
+ 0.03,
+ 0.04,
+ 0.05,
+ 0.06,
+ 0.07,
+ 0.08,
+ 0.09,
+ 0.10,
+ };
+ const double res_arr[10] = {
+ /* ln(0.01) = */ -4.60517018599,
+ /* ln(0.02) = */ -3.91202300543,
+ /* ln(0.03) = */ -3.50655789732,
+ /* ln(0.04) = */ -3.21887582487,
+ /* ln(0.05) = */ -2.99573227355,
+ /* ln(0.06) = */ -2.81341071676,
+ /* ln(0.07) = */ -2.65926003693,
+ /* ln(0.08) = */ -2.52572864431,
+ /* ln(0.09) = */ -2.40794560865,
+ /* ln(0.10) = */ -2.30258509299,
+ };
+
+ if (in <= 0.01) {
+ return res_arr[0];
+ } else if (in >= 0.10) {
+ return res_arr[9];
+ }
+ int i = 0;
+ for (; i < 10; i++) {
+ if (in < in_arr[i]) {
+ break;
+ }
+ }
+ if (i > 0) { // float number is not precise
+ return res_arr[i - 1];
+ } else {
+ return res_arr[0];
+ }
+}
+#endif
+
+/* ================ BitSet ================ */
+void BitSet::to_bytes(uint8_t *&ret_bytes, int32_t &ret_len) const
+{
+ int32_t words_in_use = get_words_in_use();
+ if (words_in_use == 0) {
+ return;
+ }
+
+ int len = 8 * (words_in_use - 1);
+ uint64_t x = words_[words_in_use - 1];
+ while (x != 0) {
+ len++;
+ x = x >> 8;
+ }
+
+ uint8_t *res = (uint8_t*)mem_alloc(sizeof(uint8_t) * len, MOD_BLOOM_FILTER);
+ int32_t res_pos = 0;
+ for (int32_t w = 0; w < words_in_use - 1; w++) {
+ uint64_t word = words_[w];
+ for (int b = 0; b < 8; b++) {
+ *(res + res_pos) = (uint8_t)(word & 0xFF);
+ word = word >> 8;
+ res_pos++;
+ }
+ }
+ uint64_t last_word = words_[words_in_use - 1];
+ for (; res_pos < len; res_pos++) {
+ *(res + res_pos) = (uint8_t)(last_word & 0xFF);
+ last_word = last_word >> 8;
+ }
+
+ ASSERT(res_pos == len);
+ ret_bytes = res;
+ ret_len = len;
+}
+
+// TODO byte-wise unittest
+int BitSet::from_bytes(uint8_t *filter_data, uint32_t filter_data_bytes_len)
+{
+ int ret = E_OK;
+
+ word_count_ = (filter_data_bytes_len / 8) + (filter_data_bytes_len % 8 == 0 ? 0 : 1);
+ words_ = (uint64_t*)mem_alloc(word_count_ * sizeof(uint64_t), MOD_BLOOM_FILTER);
+ if (IS_NULL(words_)) {
+ return E_OOM;
+ }
+
+ uint32_t word_idx = 0;
+ for (; word_idx < (filter_data_bytes_len / 8); word_idx += 1) {
+ uint64_t cur_word = 0;
+ uint8_t *cur_word_start_byte = filter_data + (word_idx * 8);
+ cur_word |= *(cur_word_start_byte + 0); cur_word = cur_word << 8;
+ cur_word |= *(cur_word_start_byte + 1); cur_word = cur_word << 8;
+ cur_word |= *(cur_word_start_byte + 2); cur_word = cur_word << 8;
+ cur_word |= *(cur_word_start_byte + 3); cur_word = cur_word << 8;
+ cur_word |= *(cur_word_start_byte + 4); cur_word = cur_word << 8;
+ cur_word |= *(cur_word_start_byte + 5); cur_word = cur_word << 8;
+ cur_word |= *(cur_word_start_byte + 6); cur_word = cur_word << 8;
+ cur_word |= *(cur_word_start_byte + 7); cur_word = cur_word << 8;
+ *(words_ + word_idx) = cur_word;
+ }
+
+ if (filter_data_bytes_len - word_idx * 8 > 0) {
+ uint64_t cur_word = 0;
+ uint8_t *cur_word_start_byte = filter_data + (word_idx * 8);
+ for (uint32_t r = 0; r < filter_data_bytes_len - word_idx * 8; r++) {
+ cur_word |= *(cur_word_start_byte + r);
+ cur_word = cur_word << 8;
+ }
+ *(words_ + word_idx) = cur_word;
+ }
+ return ret;
+}
+
+/* ================ Bloom Filter ================ */
+const double BloomFilter::MIN_BF_ERROR_RATE = 0.01;
+const double BloomFilter::MAX_BF_ERROR_RATE = 0.1;
+const int32_t BloomFilter::SEEDS[MAX_HASH_FUNC_COUNT] = {5, 7, 11, 19, 31, 37, 43, 59};
+
+int BloomFilter::init(double error_percent, int entry_count)
+{
+ if (error_percent < MIN_BF_ERROR_RATE) {
+ error_percent = MIN_BF_ERROR_RATE;
+ } else if (error_percent > MAX_BF_ERROR_RATE) {
+ error_percent = MAX_BF_ERROR_RATE;
+ }
+
+ double ln2 = 0.6931471805599453;
+ double math_log_error_percent = math_log(error_percent);
+ int32_t size = (-1) * ((int32_t)(entry_count * math_log_error_percent / ln2 / ln2)) + 1;
+ int32_t hash_func_count = (-1) * (math_log_error_percent / ln2) + 1;
+ size_ = UTIL_MAX(size, MIN_SIZE);
+ hash_func_count_ = UTIL_MIN(hash_func_count, MAX_HASH_FUNC_COUNT);
+
+ for (uint32_t i = 0; i < hash_func_count_; i++) {
+ hash_func_arr_[i].init(size_, SEEDS[i]);
+ }
+ int ret = bitset_.init(size_);
+ return ret;
+}
+
+String BloomFilter::get_entry_string(const String &device_name,
+ const String &measurement_name)
+{
+ String ret_str;
+ int len = device_name.len_ + measurement_name.len_ + 2; // '.' and '\0'
+ char *path_buf = (char*)mem_alloc(len, MOD_BLOOM_FILTER);
+ if (IS_NULL(path_buf)) {
+ return ret_str;
+ }
+ memcpy(path_buf, device_name.buf_, device_name.len_);
+ *(path_buf + device_name.len_) = '.';
+ memcpy(path_buf + device_name.len_ + 1, measurement_name.buf_, measurement_name.len_);
+ *(path_buf + device_name.len_ + measurement_name.len_ + 1) = '\0';
+ ret_str.buf_ = path_buf;
+ ret_str.len_ = len;
+ return ret_str;
+}
+
+int BloomFilter::add_path_entry(const String &device_name,
+ const String &measurement_name)
+{
+ if (device_name.is_null() || measurement_name.is_null()) {
+ return E_INVALID_ARG;
+ }
+
+ String entry = get_entry_string(device_name, measurement_name);
+ if (IS_NULL(entry.buf_)) {
+ return E_OOM;
+ }
+
+ for (uint32_t i = 0; i < hash_func_count_; i++) {
+ HashFunction &hf = hash_func_arr_[i];
+ int32_t hv = hf.hash(entry);
+ bitset_.set(hv);
+ }
+ free_entry_buf(entry.buf_);
+ return E_OK;
+}
+
+int BloomFilter::serialize_to(ByteStream &out)
+{
+ int ret = E_OK;
+ uint8_t *filter_data_bytes = nullptr;
+ int32_t filter_data_bytes_len = 0;
+ bitset_.to_bytes(filter_data_bytes, filter_data_bytes_len);
+ ASSERT(filter_data_bytes_len > 0);
+
+ if (RET_FAIL(SerializationUtil::write_var_uint(filter_data_bytes_len, out))) {
+ } else if (RET_FAIL(out.write_buf(filter_data_bytes, filter_data_bytes_len))) {
+ } else if (RET_FAIL(SerializationUtil::write_var_uint(size_, out))) {
+ } else if (RET_FAIL(SerializationUtil::write_var_uint(hash_func_count_, out))) {
+ }
+ bitset_.revert_bytes(filter_data_bytes);
+ return ret;
+}
+
+int BloomFilter::deserialize_from(ByteStream &in)
+{
+ int ret = E_OK;
+ uint32_t filter_data_bytes_len = 0;
+ uint32_t ret_read_len = 0;
+ uint8_t *filter_data = nullptr;
+ if (RET_FAIL(SerializationUtil::read_var_uint(filter_data_bytes_len, in))) {
+ } else if (UNLIKELY(nullptr == (filter_data = (uint8_t*)mem_alloc(filter_data_bytes_len,
+ MOD_BLOOM_FILTER)))) {
+ ret = E_OOM;
+ } else if (RET_FAIL(in.read_buf(filter_data, filter_data_bytes_len, ret_read_len))) {
+ } else if (RET_FAIL(bitset_.from_bytes(filter_data, filter_data_bytes_len))) {
+ } else if (RET_FAIL(SerializationUtil::read_var_uint(size_, in))) {
+ } else if (RET_FAIL(SerializationUtil::read_var_uint(hash_func_count_, in))) {
+ } else {
+ for (uint32_t i = 0; i < hash_func_count_; i++) {
+ hash_func_arr_[i].init(size_, SEEDS[i]);
+ }
+ }
+ if (filter_data != nullptr) {
+ mem_free(filter_data);
+ }
+ return ret;
+}
+
+} // namespace storage
+} // namespace timecho
+
diff --git a/cpp/tsfile/src/tsfile/bloom_filter.h b/cpp/tsfile/src/tsfile/bloom_filter.h
new file mode 100644
index 00000000..b1bbf490
--- /dev/null
+++ b/cpp/tsfile/src/tsfile/bloom_filter.h
@@ -0,0 +1,120 @@
+
+#ifndef STORAGE_TSFILE_BLOOM_FILTER_H
+#define STORAGE_TSFILE_BLOOM_FILTER_H
+
+#include "common/allocator/alloc_base.h"
+#include "common/allocator/my_string.h"
+#include "common/allocator/byte_stream.h"
+#include "common/container/murmur_hash3.h"
+
+namespace timecho
+{
+namespace storage
+{
+
+class HashFunction
+{
+public:
+ HashFunction() : cap_(0), seed_(0) {}
+ void init(int32_t cap, int32_t seed)
+ {
+ ASSERT(cap > 1);
+ cap_ = cap;
+ seed_ = seed;
+ }
+ FORCE_INLINE int32_t hash(common::String buf)
+ {
+ int res = common::Murmur128Hash::hash(buf, seed_);
+ if (res == INT32_MIN) {
+ res = 0;
+ }
+ res = (res > 0 ? res : (0 - res)) % cap_;
+ return res;
+ }
+private:
+ int32_t cap_;
+ int32_t seed_;
+};
+
+class BitSet
+{
+public:
+ BitSet() : words_(nullptr), word_count_(0) {}
+ int init(int32_t size)
+ {
+ ASSERT(size > 1);
+ word_count_ = (size - 1) / 64 + 1;
+ int32_t alloc_size = word_count_ * sizeof(uint64_t);
+ words_ = (uint64_t*)common::mem_alloc(alloc_size, common::MOD_BLOOM_FILTER);
+ if (IS_NULL(words_)) {
+ return common::E_OOM;
+ }
+ memset(words_, 0, alloc_size);
+ return common::E_OK;
+ }
+ void destroy()
+ {
+ if (!IS_NULL(words_)) {
+ common::mem_free(words_);
+ words_ = nullptr;
+ }
+ }
+ void set(int32_t pos)
+ {
+ int32_t word_idx = pos / 64;
+ int32_t word_offset = pos % 64;
+ words_[word_idx] |= (1ul << word_offset);
+ }
+ int32_t get_words_in_use() const
+ {
+ for (int32_t i = word_count_ - 1; i >= 0; i--) {
+ if (words_[i] != 0) {
+ return i + 1;
+ }
+ }
+ return 0;
+ }
+ void to_bytes(uint8_t *&ret_bytes, int32_t &ret_len) const;
+ void revert_bytes(uint8_t *bytes) { common::mem_free(bytes); }
+ int from_bytes(uint8_t *filter_data, uint32_t filter_data_bytes_len);
+private:
+ uint64_t *words_;
+ int32_t word_count_;
+};
+
+class BloomFilter
+{
+public:
+ static const int32_t MAX_HASH_FUNC_COUNT = 8;
+ static const int32_t MIN_SIZE = 256;
+ // static const non-integer variable can not be intialiazed in class
+ static const double MIN_BF_ERROR_RATE;
+ static const double MAX_BF_ERROR_RATE;
+ static const int32_t SEEDS[MAX_HASH_FUNC_COUNT];
+
+public:
+ BloomFilter() : size_(0), hash_func_count_(0), bitset_() {}
+ ~BloomFilter() { destroy(); }
+ int init(double error_percent, int entry_count);
+ void destroy() { bitset_.destroy(); }
+ int add_path_entry(const common::String &device_name,
+ const common::String &measurement_name);
+ int serialize_to(common::ByteStream &out);
+ int deserialize_from(common::ByteStream &in);
+
+private:
+ common::String get_entry_string(const common::String &device_name,
+ const common::String &measurement_name);
+ FORCE_INLINE void free_entry_buf(char *entry_buf) { common::mem_free(entry_buf); }
+private:
+ uint32_t size_;
+ uint32_t hash_func_count_;
+ HashFunction hash_func_arr_[MAX_HASH_FUNC_COUNT];
+ BitSet bitset_;
+};
+
+} // end namespace storage
+} // end namespace timecho
+
+#endif
+
diff --git a/cpp/tsfile/src/tsfile/chunk_reader b/cpp/tsfile/src/tsfile/chunk_reader
new file mode 100644
index 00000000..e69de29b
diff --git a/cpp/tsfile/src/tsfile/chunk_reader.cc b/cpp/tsfile/src/tsfile/chunk_reader.cc
new file mode 100644
index 00000000..d4976831
--- /dev/null
+++ b/cpp/tsfile/src/tsfile/chunk_reader.cc
@@ -0,0 +1,425 @@
+
+#include "chunk_reader.h"
+#include "tsfile/encode/decoder_factory.h"
+#include "tsfile/compress/compressor_factory.h"
+
+namespace timecho
+{
+using namespace common;
+namespace storage
+{
+
+int ChunkReader::init(ReadFile *read_file,
+ String m_name,
+ TSDataType data_type,
+ Filter *time_filter)
+{
+ read_file_ = read_file;
+ measurement_name_.shallow_copy_from(m_name);
+ time_decoder_ = DecoderFactory::alloc_time_decoder();
+ value_decoder_ = nullptr;
+ compressor_ = nullptr;
+ time_filter_ = time_filter;
+ uncompressed_buf_ = nullptr;
+ if (IS_NULL(time_decoder_)) {
+ return E_OOM;
+ }
+ return E_OK;
+}
+
+void ChunkReader::reset()
+{
+ chunk_meta_ = nullptr;
+ chunk_header_.reset();
+ cur_page_header_.reset();
+
+ char *file_data_buf = in_stream_.get_wrapped_buf();
+ if (file_data_buf != nullptr) {
+ mem_free(file_data_buf);
+ }
+ in_stream_.reset();
+ file_data_buf_size_ = 0;
+ chunk_visit_offset_ = 0;
+}
+
+void ChunkReader::destroy()
+{
+ if (time_decoder_ != nullptr) {
+ time_decoder_->~Decoder();
+ DecoderFactory::free(time_decoder_);
+ time_decoder_ = nullptr;
+ }
+ if (value_decoder_ != nullptr) {
+ value_decoder_->~Decoder();
+ DecoderFactory::free(value_decoder_);
+ value_decoder_ = nullptr;
+ }
+ if (compressor_ != nullptr) {
+ compressor_->~Compressor();
+ CompressorFactory::free(compressor_);
+ compressor_ = nullptr;
+ }
+ char *buf = in_stream_.get_wrapped_buf();
+ if (buf != nullptr) {
+ mem_free(buf);
+ in_stream_.clear_wrapped_buf();
+ }
+ cur_page_header_.reset();
+}
+
+int ChunkReader::load_by_meta(ChunkMeta *meta)
+{
+ int ret = E_OK;
+ chunk_meta_ = meta;
+#if DEBUG_SE
+ std::cout << "ChunkReader::load_by_meta, meta=" << *meta << std::endl;
+#endif
+ /* ================ Step 1: read data from file ================*/
+ // at least, we can read the chunk header and the first page header.
+ // TODO configurable
+ file_data_buf_size_ = 1024;
+ int32_t ret_read_len = 0;
+ char *file_data_buf = (char*)mem_alloc(file_data_buf_size_, MOD_CHUNK_READER);
+ if (IS_NULL(file_data_buf)) {
+ return E_OOM;
+ }
+ ret = read_file_->read(chunk_meta_->offset_of_chunk_header_, file_data_buf,
+ file_data_buf_size_, ret_read_len);
+ if (IS_SUCC(ret) && ret_read_len < ChunkHeader::MIN_SERIALIZED_SIZE) {
+ ret = E_TSFILE_CORRUPTED;
+ log_error("file corrupted, ret=%d, offset=%d, read_len=%d",
+ ret, chunk_meta_->offset_of_chunk_header_, ret_read_len);
+ }
+
+ /* ================ Step 2: deserialize chunk_header ================*/
+ if (IS_SUCC(ret)) {
+ in_stream_.wrap_from(file_data_buf, ret_read_len);
+ // std::cout << "in_stream_.wrap_from " << (void*)file_data_buf << std::endl;
+ if (RET_FAIL(chunk_header_.deserialize_from(in_stream_))) {
+ } else if (RET_FAIL(alloc_compressor_and_value_decoder(chunk_header_.encoding_type_,
+ chunk_header_.data_type_, chunk_header_.compression_type_))) {
+ } else {
+ chunk_visit_offset_ = in_stream_.read_pos(); // point to end of chunk_header_
+#if DEBUG_SE
+ std::cout << "ChunkReader::load_by_meta, chunk_header=" << chunk_header_ << std::endl;
+#endif
+ }
+ }
+ return ret;
+}
+
+int ChunkReader::alloc_compressor_and_value_decoder(TSEncoding encoding,
+ TSDataType data_type,
+ CompressionType compression)
+{
+ if (value_decoder_ != nullptr) {
+ delete value_decoder_;
+ value_decoder_ = nullptr;
+ }
+ value_decoder_ = DecoderFactory::alloc_value_decoder(encoding, data_type);
+ if (IS_NULL(value_decoder_)) {
+ return E_OOM;
+ }
+
+ if (compressor_ != nullptr) {
+ compressor_->reset(/*for_compress*/false);
+ } else {
+ compressor_ = CompressorFactory::alloc_compressor(compression);
+ if (compressor_ == nullptr) {
+ return E_OOM;
+ }
+ }
+ return E_OK;
+}
+
+int ChunkReader::get_next_page(TsBlock *ret_tsblock, Filter *oneshoot_filter)
+{
+ int ret = E_OK;
+ Filter *filter = (oneshoot_filter != nullptr ? oneshoot_filter : time_filter_);
+
+ if (prev_page_not_finish()) {
+ ret = decode_tv_buf_into_tsblock_by_datatype(time_in_, value_in_, ret_tsblock, filter);
+ if (ret == E_OVERFLOW) {
+ ret = E_OK;
+ } else {
+ if (uncompressed_buf_ != nullptr) {
+ compressor_->after_uncompress(uncompressed_buf_);
+ uncompressed_buf_ = nullptr;
+ }
+ time_in_.reset();
+ value_in_.reset();
+ }
+ return ret;
+ }
+
+ while (IS_SUCC(ret)) {
+ if (!has_more_data()) {
+ return E_NO_MORE_DATA;
+ }
+ if (RET_FAIL(get_cur_page_header())) {
+ } else if (cur_page_statisify_filter(filter)) {
+ break;
+ } else if (RET_FAIL(skip_cur_page())) {
+ }
+ }
+
+ if (IS_SUCC(ret)) {
+ ret = decode_cur_page_data(ret_tsblock, filter);
+ }
+ return ret;
+}
+
+int ChunkReader::get_cur_page_header()
+{
+ int ret = E_OK;
+ bool retry = true;
+ int cur_page_header_serialized_size = 0;
+ do {
+ in_stream_.mark_read_pos();
+ cur_page_header_.reset();
+ ret = cur_page_header_.deserialize_from(in_stream_,
+ !chunk_has_only_one_page(),
+ chunk_header_.data_type_);
+ cur_page_header_serialized_size = in_stream_.get_mark_len();
+ if (deserialize_buf_not_enough(ret) && retry) {
+ retry = false;
+ ret = read_from_file_and_rewrap();
+ if (E_OK == ret) {
+ continue;
+ }
+ }
+ break;
+ } while (true);
+ if (IS_SUCC(ret)) {
+ // visit a header
+ chunk_visit_offset_ += cur_page_header_serialized_size;
+ }
+#if DEBUG_SE
+ std::cout << "get_cur_page_header, ret=" << ret
+ << ", retry=" << retry
+ << ", cur_page_header_=" << cur_page_header_
+ << ", chunk_meta_->offset_of_chunk_header_=" << chunk_meta_->offset_of_chunk_header_
+ << ", cur_page_header_serialized_size=" << cur_page_header_serialized_size << std::endl;
+#endif
+ return ret;
+}
+
+// read at least @want_size bytes from file and wrap the buffer into @in_stream_
+int ChunkReader::read_from_file_and_rewrap(int want_size)
+{
+ int ret = E_OK;
+ const int DEFAULT_READ_SIZE = 4096; // may use page_size + page_header_size
+ char *file_data_buf = in_stream_.get_wrapped_buf();
+ int offset = chunk_meta_->offset_of_chunk_header_ + chunk_visit_offset_;
+ int read_size = (want_size < DEFAULT_READ_SIZE ? DEFAULT_READ_SIZE : want_size);
+ if (file_data_buf_size_ < read_size || read_size < file_data_buf_size_ / 10) {
+ file_data_buf = (char*)mem_realloc(file_data_buf, read_size);
+ if (IS_NULL(file_data_buf)) {
+ return E_OOM;
+ }
+ file_data_buf_size_ = read_size;
+ }
+ int ret_read_len = 0;
+ if (RET_FAIL(read_file_->read(offset,
+ file_data_buf,
+ DEFAULT_READ_SIZE,
+ ret_read_len))) {
+ } else {
+ in_stream_.wrap_from(file_data_buf, ret_read_len);
+ // DEBUG_hex_dump_buf("wrapped buf = ", file_data_buf, 256);
+ }
+ return ret;
+}
+
+bool ChunkReader::cur_page_statisify_filter(Filter *filter)
+{
+ return filter == nullptr
+ || cur_page_header_.statistic_ == nullptr
+ || filter->satisfy(cur_page_header_.statistic_);
+}
+
+int ChunkReader::skip_cur_page()
+{
+ int ret = E_OK;
+ // visit a page tv data
+ chunk_visit_offset_ += cur_page_header_.compressed_size_;
+ in_stream_.wrapped_buf_advance_read_pos(cur_page_header_.compressed_size_);
+ return ret;
+}
+
+int ChunkReader::decode_cur_page_data(TsBlock *&ret_tsblock, Filter *filter)
+{
+ int ret = E_OK;
+
+ // Step 1: make sure we load the whole page data in @in_stream_
+ if (in_stream_.remaining_size() < cur_page_header_.compressed_size_) {
+ // std::cout << "decode_cur_page_data. in_stream_.remaining_size="<< in_stream_.remaining_size() << ", cur_page_header_.compressed_size_=" << cur_page_header_.compressed_size_ << std::endl;
+ if (RET_FAIL(read_from_file_and_rewrap(cur_page_header_.compressed_size_))) {
+ }
+ }
+
+ char *compressed_buf = nullptr;
+ char *uncompressed_buf = nullptr;
+ uint32_t compressed_buf_size = 0; // cppcheck-suppress unreadVariable
+ uint32_t uncompressed_buf_size = 0;
+ char *time_buf = nullptr;
+ char *value_buf = nullptr;
+ uint32_t time_buf_size = 0;
+ uint32_t value_buf_size = 0;
+
+ // Step 2: do uncompress
+ if (IS_SUCC(ret)) {
+ compressed_buf = in_stream_.get_wrapped_buf() + in_stream_.read_pos();
+ // std::cout << "ChunkReader::decode_cur_page_data, in_stream_.get_wrapped_buf=" <<(void*)(in_stream_.get_wrapped_buf())<< ", in_stream_.read_pos=" << in_stream_.read_pos() << std::endl;
+ compressed_buf_size = cur_page_header_.compressed_size_;
+ in_stream_.wrapped_buf_advance_read_pos(compressed_buf_size);
+ chunk_visit_offset_ += compressed_buf_size;
+ if (RET_FAIL(compressor_->reset(false))) {
+ } else if (RET_FAIL(compressor_->uncompress(compressed_buf, compressed_buf_size,
+ uncompressed_buf, uncompressed_buf_size))) {
+ } else {
+ uncompressed_buf_ = uncompressed_buf;
+ }
+ // DEBUG_hex_dump_buf("ChunkReader read, uncompressed buf = ", uncompressed_buf, uncompressed_buf_size);
+ if (ret != E_OK || uncompressed_buf_size != cur_page_header_.uncompressed_size_) {
+ ret = E_TSFILE_CORRUPTED;
+ ASSERT(false);
+ }
+ }
+
+ // Step 3: get time_buf & value_buf
+ if (IS_SUCC(ret)) {
+ int var_size = 0;
+ if (RET_FAIL(SerializationUtil::read_var_uint(time_buf_size, uncompressed_buf,
+ uncompressed_buf_size, &var_size))) {
+ } else {
+ time_buf = uncompressed_buf + var_size;
+ value_buf = time_buf + time_buf_size;
+ value_buf_size = uncompressed_buf_size - var_size - time_buf_size;
+#if DEBUG_SE
+ std::cout << "ChunkReader uncompress: compressed_buf_size=" << compressed_buf_size
+ << ", uncompressed_buf_size=" << uncompressed_buf_size
+ << ", var_size=" << var_size
+ << ", time_buf_size=" << time_buf_size << std::endl;
+#endif
+ if (uncompressed_buf_size <= var_size + time_buf_size) {
+ ret = E_TSFILE_CORRUPTED;
+ ASSERT(false);
+ }
+ }
+ }
+
+ // Step 4: decode time-value buffer into @ret_tsblock
+ if (IS_SUCC(ret)) {
+ time_decoder_->reset();
+ value_decoder_->reset();
+ time_in_.wrap_from(time_buf, time_buf_size);
+ value_in_.wrap_from(value_buf, value_buf_size);
+ // ret = decode_tv_buf_into_tsblock(time_buf, value_buf, time_buf_size,
+ // value_buf_size, ret_tsblock, filter);
+ ret = decode_tv_buf_into_tsblock_by_datatype(time_in_, value_in_, ret_tsblock, filter);
+ // if we return during @decode_tv_buf_into_tsblock, we should keep
+ // @uncompressed_buf_ valid until all TV pairs are decoded.
+ if (ret != E_OVERFLOW) {
+ if (uncompressed_buf_ != nullptr) {
+ compressor_->after_uncompress(uncompressed_buf_);
+ uncompressed_buf_ = nullptr;
+ }
+ time_in_.reset();
+ value_in_.reset();
+ } else {
+ ret = E_OK;
+ }
+ }
+ return ret;
+}
+
+#define DECODE_TYPED_TV_INTO_TSBLOCK(CppType, ReadType, time_in, value_in, row_appender) \
+ do { \
+ int64_t time = 0; \
+ CppType value; \
+ while (time_decoder_->has_remaining() || time_in.has_remaining()) { \
+ ASSERT(value_decoder_->has_remaining() || value_in.has_remaining()); \
+ if (UNLIKELY(!row_appender.add_row())) { \
+ ret = E_OVERFLOW; \
+ break; \
+ } else if (RET_FAIL(time_decoder_->read_int64(time, time_in))) { \
+ } else if (RET_FAIL(value_decoder_->read_##ReadType(value, value_in))) { \
+ } else if (filter != nullptr && !filter->satisfy(time, value)) { \
+ row_appender.backoff_add_row(); \
+ continue; \
+ } else { \
+ /*std::cout << "decoder: time=" << time << ", value=" << value << std::endl;*/ \
+ row_appender.append(0, (char*)&time, sizeof(time)); \
+ row_appender.append(1, (char*)&value, sizeof(value)); \
+ } \
+ } \
+ } while (false)
+
+int ChunkReader::i32_DECODE_TYPED_TV_INTO_TSBLOCK(ByteStream &time_in,
+ ByteStream &value_in,
+ RowAppender &row_appender,
+ Filter *filter)
+{
+ int ret = E_OK;
+ do {
+ int64_t time = 0;
+ int32_t value;
+ while (time_decoder_->has_remaining() || time_in.has_remaining()) {
+ ASSERT(value_decoder_->has_remaining() || value_in.has_remaining());
+ if (UNLIKELY(!row_appender.add_row())) {
+ ret = E_OVERFLOW;
+ break;
+ } else if (RET_FAIL(time_decoder_->read_int64(time, time_in))) {
+ } else if (RET_FAIL(value_decoder_->read_int32(value, value_in))) {
+ } else if (filter != nullptr && !filter->satisfy(time, value)) {
+ row_appender.backoff_add_row();
+ continue;
+ } else {
+ /*std::cout << "decoder: time=" << time << ", value=" << value << std::endl;*/
+ row_appender.append(0, (char*)&time, sizeof(time));
+ row_appender.append(1, (char*)&value, sizeof(value));
+ }
+ }
+ } while (false);
+ return ret;
+}
+
+
+
+int ChunkReader::decode_tv_buf_into_tsblock_by_datatype(ByteStream &time_in,
+ ByteStream &value_in,
+ TsBlock *ret_tsblock,
+ Filter *filter)
+{
+ int ret = E_OK;
+ RowAppender row_appender(ret_tsblock);
+ switch (chunk_header_.data_type_) {
+ case timecho::common::BOOLEAN:
+ DECODE_TYPED_TV_INTO_TSBLOCK(bool, boolean, time_in_, value_in_, row_appender);
+ break;
+ case timecho::common::INT32:
+ // DECODE_TYPED_TV_INTO_TSBLOCK(int32_t, int32, time_in_, value_in_, row_appender);
+ ret = i32_DECODE_TYPED_TV_INTO_TSBLOCK(time_in_, value_in_, row_appender, filter);
+ break;
+ case timecho::common::INT64:
+ DECODE_TYPED_TV_INTO_TSBLOCK(int64_t, int64, time_in_, value_in_, row_appender);
+ break;
+ case timecho::common::FLOAT:
+ DECODE_TYPED_TV_INTO_TSBLOCK(float, float, time_in_, value_in_, row_appender);
+ break;
+ case timecho::common::DOUBLE:
+ DECODE_TYPED_TV_INTO_TSBLOCK(double, double, time_in_, value_in_, row_appender);
+ break;
+ default:
+ ret = E_NOT_SUPPORT;
+ ASSERT(false);
+ }
+ if (ret_tsblock->get_row_count() == 0 && ret == E_OK) {
+ ret = E_NO_MORE_DATA;
+ }
+ return ret;
+}
+
+} // end namespace storage
+} // end namespace timecho
diff --git a/cpp/tsfile/src/tsfile/chunk_reader.h b/cpp/tsfile/src/tsfile/chunk_reader.h
new file mode 100644
index 00000000..ea901626
--- /dev/null
+++ b/cpp/tsfile/src/tsfile/chunk_reader.h
@@ -0,0 +1,128 @@
+
+#ifndef STORAGE_TSFILE_CHUNK_READER_H
+#define STORAGE_TSFILE_CHUNK_READER_H
+
+#include "common/allocator/my_string.h"
+#include "tsfile/tsfile_common.h"
+#include "tsfile/read_file.h"
+#include "tsfile/encode/decoder.h"
+#include "tsfile/compress/compressor.h"
+#include "tsfile/filter/filter.h"
+
+namespace timecho
+{
+namespace storage
+{
+
+class ChunkReader
+{
+public:
+ ChunkReader() : read_file_(nullptr),
+ chunk_meta_(nullptr),
+ measurement_name_(),
+ chunk_header_(),
+ cur_page_header_(),
+ in_stream_(),
+ file_data_buf_size_(0),
+ chunk_visit_offset_(0),
+ compressor_(nullptr),
+ time_filter_(nullptr),
+ time_decoder_(nullptr),
+ value_decoder_(nullptr),
+ time_in_(),
+ value_in_(),
+ uncompressed_buf_(nullptr) {}
+ int init(ReadFile *read_file,
+ common::String m_name,
+ common::TSDataType data_type,
+ Filter *time_filter);
+ void reset();
+ void destroy();
+
+ bool has_more_data() const
+ {
+ return prev_page_not_finish()
+ || (chunk_visit_offset_ - chunk_header_.serialized_size_ < chunk_header_.data_size_);
+ }
+ ChunkHeader &get_chunk_header() { return chunk_header_; }
+
+ /*
+ * prepare data buffer, load the chunk_header
+ * and the first page_header.
+ */
+ int load_by_meta(ChunkMeta *meta);
+
+ int get_next_page(common::TsBlock *tsblock, Filter *oneshoot_filter);
+
+private:
+ FORCE_INLINE bool chunk_has_only_one_page() const
+ {
+ return chunk_header_.chunk_type_ == ONLY_ONE_PAGE_CHUNK_HEADER_MARKER;
+ }
+ int alloc_compressor_and_value_decoder(common::TSEncoding encoding,
+ common::TSDataType data_type,
+ common::CompressionType compression_type);
+ int get_cur_page_header();
+ int read_from_file_and_rewrap(int want_size = 0);
+ bool cur_page_statisify_filter(Filter *filter);
+ int skip_cur_page();
+ int decode_cur_page_data(common::TsBlock *&ret_tsblock,
+ Filter *filter);
+ int decode_tv_buf_into_tsblock(char *time_buf,
+ char *value_buf,
+ uint32_t time_buf_size,
+ uint32_t value_buf_size,
+ common::TsBlock *ret_tsblock,
+ Filter *filter);
+ bool prev_page_not_finish() const
+ {
+ return (time_decoder_ && time_decoder_->has_remaining()) || time_in_.has_remaining();
+ }
+
+ int decode_tv_buf_into_tsblock_by_datatype(common::ByteStream &time_in,
+ common::ByteStream &value_in,
+ common::TsBlock *ret_tsblock,
+ Filter *filter);
+ int i32_DECODE_TYPED_TV_INTO_TSBLOCK(common::ByteStream &time_in,
+ common::ByteStream &value_in,
+ common::RowAppender &row_appender,
+ Filter *filter);
+private:
+ ReadFile *read_file_;
+ ChunkMeta *chunk_meta_;
+ common::String measurement_name_;
+ ChunkHeader chunk_header_;
+ PageHeader cur_page_header_;
+
+ /*
+ * Data read from file is stored in @in_stream_, and the size
+ * is stored in @file_data_buf_size_. Note, in_stream_.total_size_
+ * is used to limit deserialization, that is why we still have
+ * @file_data_buf_size_.
+ *
+ * Since we may want keep data of current page (and page header
+ * of next page) in memory, we need a byte-size cursor to tell
+ * us which byte we are processing, so we have @chunk_visit_offset_
+ * it refer to position from the start of chunk_header_,
+ * also refer to offset within the chunk (including chunk header).
+ * It advanced by step of a page header or a page tv data.
+ */
+ common::ByteStream in_stream_;
+ int32_t file_data_buf_size_;
+ uint32_t chunk_visit_offset_;
+
+ // Statistic *page_statistic_;
+ Compressor *compressor_;
+ Filter *time_filter_;
+
+ Decoder *time_decoder_;
+ Decoder *value_decoder_;
+ common::ByteStream time_in_;
+ common::ByteStream value_in_;
+ char *uncompressed_buf_;
+};
+
+} // end namespace storage
+} // end namespace timecho
+
+#endif // STORAGE_TSFILE_CHUNK_READER_H
diff --git a/cpp/tsfile/src/tsfile/chunk_writer.cc b/cpp/tsfile/src/tsfile/chunk_writer.cc
new file mode 100644
index 00000000..527c88a0
--- /dev/null
+++ b/cpp/tsfile/src/tsfile/chunk_writer.cc
@@ -0,0 +1,140 @@
+
+#include "chunk_writer.h"
+#include "common/logger/elog.h"
+
+using namespace timecho::common;
+
+namespace timecho
+{
+namespace storage
+{
+
+int ChunkWriter::init(const ColumnDesc &col_desc)
+{
+ return init(col_desc.column_name_, col_desc.type_, col_desc.encoding_, col_desc.compression_);
+}
+
+int ChunkWriter::init(const std::string &measurement_name,
+ TSDataType data_type,
+ TSEncoding encoding,
+ CompressionType compression_type)
+{
+ int ret = E_OK;
+ chunk_statistic_ = StatisticFactory::alloc_statistic(data_type);
+ if (chunk_statistic_ == nullptr) {
+ return E_OOM;
+ } else if (RET_FAIL(page_writer_.init(data_type, encoding, compression_type))) {
+ } else if (IS_NULL((first_page_statistic_ = StatisticFactory::alloc_statistic(data_type)))) {
+ ret = E_OOM;
+ } else {
+ data_type_ = data_type;
+ chunk_header_.measurement_name_ = measurement_name;
+ chunk_header_.data_type_ = data_type;
+ chunk_header_.compression_type_ = compression_type;
+ chunk_header_.encoding_type_ = encoding;
+ }
+ return ret;
+}
+
+void ChunkWriter::destroy()
+{
+ page_writer_.destroy();
+ if (chunk_statistic_ != nullptr) {
+ StatisticFactory::free(chunk_statistic_);
+ chunk_statistic_ = nullptr;
+ }
+ if (first_page_statistic_ != nullptr) {
+ StatisticFactory::free(first_page_statistic_);
+ first_page_statistic_ = nullptr;
... 18011 lines suppressed ...