blob: faec4840ea9d574eb14a735a9dab15ef4591ad6e [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef DATASET_DATASET_INDEX_H
#define DATASET_DATASET_INDEX_H
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <vector>
namespace storage {
namespace dataset {
static const uint16_t DATASET_INDEX_VERSION_MAJOR = 1;
static const uint16_t DATASET_INDEX_VERSION_MINOR = 0;
static const uint32_t DATASET_INDEX_HEADER_SIZE = 64;
static const uint32_t DATASET_INDEX_DIRECTORY_ENTRY_SIZE = 32;
static const uint32_t DATASET_INDEX_SECTION_COUNT = 13;
static const uint64_t DATASET_INDEX_ALIGNMENT = 64;
enum class DatasetIndexStatus {
OK = 0,
INVALID_ARGUMENT,
IO_ERROR,
OUT_OF_MEMORY,
BAD_MAGIC,
UNSUPPORTED_VERSION,
BAD_HEADER,
BAD_DIRECTORY,
BAD_SECTION,
BAD_CHECKSUM,
BAD_REFERENCE,
NOT_FOUND,
};
const char* dataset_index_status_name(DatasetIndexStatus status);
enum class DatasetIndexSectionType : uint32_t {
STRING_OFFSETS = 1,
STRING_BYTES = 2,
TABLE_NAME_INDEX = 3,
TABLE_RECORD = 4,
DEVICE_NAME_INDEX = 5,
DEVICE_RECORD = 6,
COLUMN_NAME_INDEX = 7,
COLUMN_SCHEMA = 8,
LOGICAL_SERIES = 9,
TSFILE_RECORD = 10,
DEVICE_FILE_SPAN = 11,
SERIES_FILE_SPAN = 12,
SERIES_LOCATOR = 13,
};
#pragma pack(push, 1)
struct DatasetIndexHeader {
char magic[8];
uint16_t version_major;
uint16_t version_minor;
uint32_t header_size;
uint64_t directory_offset;
uint32_t section_count;
uint32_t directory_entry_size;
uint64_t file_length;
uint32_t header_crc32c;
uint8_t reserved[20];
};
struct DatasetIndexDirectoryEntry {
uint32_t section_type;
uint32_t record_size;
uint64_t offset;
uint64_t length;
uint32_t count;
uint32_t crc32c;
};
struct TableNameIndexRecord {
uint64_t name_hash;
uint32_t name_sid;
uint32_t table_id;
};
struct TableRecord {
uint32_t name_sid;
uint32_t reserved0;
uint32_t first_device_name_index;
uint32_t device_count;
uint32_t first_column_name_index;
uint32_t column_count;
uint64_t reserved1;
};
struct DeviceNameIndexRecord {
uint32_t table_id;
uint32_t device_id;
uint64_t name_hash;
uint32_t name_sid;
uint32_t reserved;
};
struct DeviceRecord {
uint32_t table_id;
uint32_t name_sid;
uint32_t reserved0;
uint32_t reserved1;
uint32_t first_series_id;
uint32_t series_count;
uint32_t first_file_span;
uint32_t file_span_count;
int64_t min_time;
int64_t max_time;
};
struct ColumnNameIndexRecord {
uint32_t table_id;
uint32_t column_id;
uint64_t name_hash;
uint32_t name_sid;
uint32_t reserved;
};
struct ColumnSchemaRecord {
uint32_t table_id;
uint32_t name_sid;
uint32_t column_ordinal;
uint16_t logical_type;
uint16_t physical_type;
uint16_t encoding;
uint16_t compression;
uint16_t role;
uint16_t nullable;
uint64_t reserved;
};
struct LogicalSeriesRecord {
uint32_t device_id;
uint32_t column_id;
uint32_t first_file_span;
uint32_t file_span_count;
int64_t min_time;
int64_t max_time;
};
struct TsFileRecord {
uint32_t path_sid;
uint32_t reserved0;
uint64_t file_size;
uint64_t file_fingerprint;
uint64_t reserved1;
};
struct DeviceFileSpanRecord {
uint32_t device_id;
uint32_t file_id;
uint64_t time_meta_offset;
uint32_t time_meta_length;
uint16_t layout;
uint16_t flags;
uint64_t row_count;
};
struct SeriesFileSpanRecord {
uint32_t series_id;
uint32_t file_id;
uint32_t locator_id;
uint32_t reserved;
int64_t min_time;
int64_t max_time;
uint64_t row_count;
};
struct SeriesLocatorRecord {
uint32_t device_file_span_id;
uint16_t locator_kind;
uint16_t flags;
uint64_t timeseries_meta_offset;
uint32_t timeseries_meta_length;
uint32_t padding;
};
#pragma pack(pop)
static_assert(sizeof(DatasetIndexHeader) == 64,
"DatasetIndexHeader must be 64 bytes");
static_assert(sizeof(DatasetIndexDirectoryEntry) == 32,
"DatasetIndexDirectoryEntry must be 32 bytes");
static_assert(sizeof(TableNameIndexRecord) == 16,
"TableNameIndexRecord must be 16 bytes");
static_assert(sizeof(TableRecord) == 32, "TableRecord must be 32 bytes");
static_assert(sizeof(DeviceNameIndexRecord) == 24,
"DeviceNameIndexRecord must be 24 bytes");
static_assert(sizeof(DeviceRecord) == 48, "DeviceRecord must be 48 bytes");
static_assert(sizeof(ColumnNameIndexRecord) == 24,
"ColumnNameIndexRecord must be 24 bytes");
static_assert(sizeof(ColumnSchemaRecord) == 32,
"ColumnSchemaRecord must be 32 bytes");
static_assert(sizeof(LogicalSeriesRecord) == 32,
"LogicalSeriesRecord must be 32 bytes");
static_assert(sizeof(TsFileRecord) == 32, "TsFileRecord must be 32 bytes");
static_assert(sizeof(DeviceFileSpanRecord) == 32,
"DeviceFileSpanRecord must be 32 bytes");
static_assert(sizeof(SeriesFileSpanRecord) == 40,
"SeriesFileSpanRecord must be 40 bytes");
static_assert(sizeof(SeriesLocatorRecord) == 24,
"SeriesLocatorRecord must be 24 bytes");
struct DatasetIndexSectionData {
DatasetIndexSectionType type;
uint32_t record_size;
uint32_t count;
std::vector<uint8_t> bytes;
};
struct DatasetIndexSectionView {
const uint8_t* data;
uint64_t length;
uint32_t record_size;
uint32_t count;
DatasetIndexSectionView()
: data(nullptr), length(0), record_size(0), count(0) {}
};
struct DatasetIndexStringView {
const char* data;
uint32_t length;
DatasetIndexStringView() : data(nullptr), length(0) {}
std::string to_string() const {
return data == nullptr ? std::string() : std::string(data, length);
}
};
uint32_t dataset_index_crc32c(const void* data, size_t length);
uint64_t dataset_index_name_hash(const char* data, size_t length);
class DatasetIndexWriter {
public:
static DatasetIndexStatus write_atomic(
const std::string& output_path,
const std::vector<DatasetIndexSectionData>& sections,
std::string& error_message);
};
class MappedDatasetIndex {
public:
MappedDatasetIndex();
~MappedDatasetIndex();
DatasetIndexStatus open(const std::string& path);
void close();
bool is_open() const { return mapping_ != nullptr; }
const std::string& error_message() const { return error_message_; }
const std::string& path() const { return path_; }
uint64_t file_length() const { return mapping_size_; }
const DatasetIndexHeader* header() const { return header_; }
DatasetIndexStatus section(DatasetIndexSectionType type,
DatasetIndexSectionView& result) const;
DatasetIndexStatus string(uint32_t sid,
DatasetIndexStringView& result) const;
template <typename T>
DatasetIndexStatus record(DatasetIndexSectionType type, uint32_t id,
const T*& result) const {
DatasetIndexSectionView view;
DatasetIndexStatus status = section(type, view);
if (status != DatasetIndexStatus::OK) {
result = nullptr;
return status;
}
if (view.record_size != sizeof(T) || id >= view.count) {
result = nullptr;
return DatasetIndexStatus::NOT_FOUND;
}
result = reinterpret_cast<const T*>(
view.data + static_cast<uint64_t>(id) * view.record_size);
return DatasetIndexStatus::OK;
}
DatasetIndexStatus find_table_ids(const std::string& name,
std::vector<uint32_t>& table_ids) const;
DatasetIndexStatus find_device_id(uint32_t table_id,
const std::string& name,
uint32_t& device_id) const;
DatasetIndexStatus find_column_id(uint32_t table_id,
const std::string& name,
uint32_t& column_id) const;
DatasetIndexStatus find_series_id(uint32_t device_id, uint32_t column_id,
uint32_t& series_id) const;
private:
DatasetIndexStatus validate();
DatasetIndexStatus fail(DatasetIndexStatus status,
const std::string& message);
std::string path_;
std::string error_message_;
const uint8_t* mapping_;
uint64_t mapping_size_;
const DatasetIndexHeader* header_;
const DatasetIndexDirectoryEntry* directory_;
#ifdef _WIN32
void* file_handle_;
void* mapping_handle_;
#else
int fd_;
#endif
};
} // namespace dataset
} // namespace storage
#endif // DATASET_DATASET_INDEX_H