Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(tidesdb_cpp VERSION 2.0.1 LANGUAGES CXX)
project(tidesdb_cpp VERSION 2.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand All @@ -13,7 +13,7 @@ if(MSVC)
elseif(MINGW)
add_compile_options(-Wall -Wextra)
else()
add_compile_options(-Wall -Wextra -Wpedantic)
add_compile_options(-Wall -Wextra -Wpedantic -fpermissive)
endif()

find_library(TIDESDB_LIBRARY NAMES tidesdb REQUIRED)
Expand Down
87 changes: 82 additions & 5 deletions include/tidesdb/tidesdb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@ namespace tidesdb
*/
enum class CompressionAlgorithm
{
None = NO_COMPRESSION,
LZ4 = LZ4_COMPRESSION,
Zstd = ZSTD_COMPRESSION,
LZ4Fast = LZ4_FAST_COMRESSION
None = TDB_COMPRESS_NONE,
#ifndef __sun
Snappy = TDB_COMPRESS_SNAPPY,
#endif
LZ4 = TDB_COMPRESS_LZ4,
Zstd = TDB_COMPRESS_ZSTD,
LZ4Fast = TDB_COMPRESS_LZ4_FAST
};

/**
Expand Down Expand Up @@ -190,6 +193,24 @@ struct ColumnFamilyConfig
* @brief Get default column family configuration from TidesDB
*/
static ColumnFamilyConfig defaultConfig();

/**
* @brief Load column family configuration from an INI file
* @param iniFile Path to the INI file
* @param sectionName Section name in the INI file
* @return Loaded configuration
*/
static ColumnFamilyConfig loadFromIni(const std::string& iniFile,
const std::string& sectionName);

/**
* @brief Save column family configuration to an INI file
* @param iniFile Path to the INI file
* @param sectionName Section name in the INI file
* @param config Configuration to save
*/
static void saveToIni(const std::string& iniFile, const std::string& sectionName,
const ColumnFamilyConfig& config);
};

/**
Expand All @@ -215,6 +236,13 @@ struct Stats
std::vector<std::size_t> levelSizes;
std::vector<int> levelNumSSTables;
std::optional<ColumnFamilyConfig> config;
std::uint64_t totalKeys = 0;
std::uint64_t totalDataSize = 0;
double avgKeySize = 0.0;
double avgValueSize = 0.0;
std::vector<std::uint64_t> levelKeyCounts;
double readAmp = 0.0;
double hitRate = 0.0;
};

/**
Expand Down Expand Up @@ -258,6 +286,25 @@ class ColumnFamily
*/
void flushMemtable();

/**
* @brief Check if a flush operation is in progress
* @return true if flushing, false otherwise
*/
[[nodiscard]] bool isFlushing() const;

/**
* @brief Check if a compaction operation is in progress
* @return true if compacting, false otherwise
*/
[[nodiscard]] bool isCompacting() const;

/**
* @brief Update runtime-safe configuration settings
* @param config New configuration (only runtime-safe fields are applied)
* @param persistToDisk If true, save changes to config.ini
*/
void updateRuntimeConfig(const ColumnFamilyConfig& config, bool persistToDisk = true);

/**
* @brief Get the underlying C handle (for internal use)
*/
Expand Down Expand Up @@ -503,9 +550,39 @@ class TidesDB
/**
* @brief Register a custom comparator
* @param name Comparator name
* @param fn Comparator function
* @param ctxStr Context string (optional)
* @param ctx Context pointer (optional)
*/
void registerComparator(const std::string& name, tidesdb_comparator_fn fn = nullptr,
const std::string& ctxStr = "", void* ctx = nullptr);

/**
* @brief Get a registered comparator
* @param name Comparator name
* @param fn Output comparator function
* @param ctx Output context pointer
*/
void getComparator(const std::string& name, tidesdb_comparator_fn* fn, void** ctx);

/**
* @brief Rename a column family
* @param oldName Current name of the column family
* @param newName New name for the column family
*/
void renameColumnFamily(const std::string& oldName, const std::string& newName);

/**
* @brief Create a backup of the database
* @param dir Backup directory (must be empty or non-existent)
*/
void backup(const std::string& dir);

/**
* @brief Get default database configuration
* @return Default Config struct
*/
void registerComparator(const std::string& name, const std::string& ctxStr = "");
static Config defaultConfig();

private:
tidesdb_t* db_ = nullptr;
Expand Down
187 changes: 181 additions & 6 deletions src/tidesdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ ColumnFamilyConfig ColumnFamilyConfig::defaultConfig()
config.minLevels = cConfig.min_levels;
config.dividingLevelOffset = cConfig.dividing_level_offset;
config.klogValueThreshold = cConfig.klog_value_threshold;
config.compressionAlgorithm = static_cast<CompressionAlgorithm>(cConfig.compression_algo);
config.compressionAlgorithm =
static_cast<CompressionAlgorithm>(static_cast<int>(cConfig.compression_algorithm));
config.enableBloomFilter = cConfig.enable_bloom_filter != 0;
config.bloomFPR = cConfig.bloom_fpr;
config.enableBlockIndexes = cConfig.enable_block_indexes != 0;
Expand All @@ -71,6 +72,79 @@ ColumnFamilyConfig ColumnFamilyConfig::defaultConfig()
return config;
}

ColumnFamilyConfig ColumnFamilyConfig::loadFromIni(const std::string& iniFile,
const std::string& sectionName)
{
tidesdb_column_family_config_t cConfig;
int result = tidesdb_cf_config_load_from_ini(iniFile.c_str(), sectionName.c_str(), &cConfig);
checkResult(result, "failed to load config from INI");

ColumnFamilyConfig config;
config.writeBufferSize = cConfig.write_buffer_size;
config.levelSizeRatio = cConfig.level_size_ratio;
config.minLevels = cConfig.min_levels;
config.dividingLevelOffset = cConfig.dividing_level_offset;
config.klogValueThreshold = cConfig.klog_value_threshold;
config.compressionAlgorithm =
static_cast<CompressionAlgorithm>(static_cast<int>(cConfig.compression_algorithm));
config.enableBloomFilter = cConfig.enable_bloom_filter != 0;
config.bloomFPR = cConfig.bloom_fpr;
config.enableBlockIndexes = cConfig.enable_block_indexes != 0;
config.indexSampleRatio = cConfig.index_sample_ratio;
config.blockIndexPrefixLen = cConfig.block_index_prefix_len;
config.syncMode = static_cast<SyncMode>(cConfig.sync_mode);
config.syncIntervalUs = cConfig.sync_interval_us;
config.comparatorName = cConfig.comparator_name;
config.skipListMaxLevel = cConfig.skip_list_max_level;
config.skipListProbability = cConfig.skip_list_probability;
config.defaultIsolationLevel = static_cast<IsolationLevel>(cConfig.default_isolation_level);
config.minDiskSpace = cConfig.min_disk_space;
config.l1FileCountTrigger = cConfig.l1_file_count_trigger;
config.l0QueueStallThreshold = cConfig.l0_queue_stall_threshold;

return config;
}

void ColumnFamilyConfig::saveToIni(const std::string& iniFile, const std::string& sectionName,
const ColumnFamilyConfig& config)
{
tidesdb_column_family_config_t cConfig;
cConfig.write_buffer_size = config.writeBufferSize;
cConfig.level_size_ratio = config.levelSizeRatio;
cConfig.min_levels = config.minLevels;
cConfig.dividing_level_offset = config.dividingLevelOffset;
cConfig.klog_value_threshold = config.klogValueThreshold;
cConfig.compression_algorithm =
static_cast<::compression_algorithm>(config.compressionAlgorithm);
cConfig.enable_bloom_filter = config.enableBloomFilter ? 1 : 0;
cConfig.bloom_fpr = config.bloomFPR;
cConfig.enable_block_indexes = config.enableBlockIndexes ? 1 : 0;
cConfig.index_sample_ratio = config.indexSampleRatio;
cConfig.block_index_prefix_len = config.blockIndexPrefixLen;
cConfig.sync_mode = static_cast<int>(config.syncMode);
cConfig.sync_interval_us = config.syncIntervalUs;
cConfig.skip_list_max_level = config.skipListMaxLevel;
cConfig.skip_list_probability = config.skipListProbability;
cConfig.default_isolation_level =
static_cast<tidesdb_isolation_level_t>(config.defaultIsolationLevel);
cConfig.min_disk_space = config.minDiskSpace;
cConfig.l1_file_count_trigger = config.l1FileCountTrigger;
cConfig.l0_queue_stall_threshold = config.l0QueueStallThreshold;

std::memset(cConfig.comparator_name, 0, TDB_MAX_COMPARATOR_NAME);
if (!config.comparatorName.empty())
{
std::strncpy(cConfig.comparator_name, config.comparatorName.c_str(),
TDB_MAX_COMPARATOR_NAME - 1);
}
std::memset(cConfig.comparator_ctx_str, 0, TDB_MAX_COMPARATOR_CTX);
cConfig.comparator_fn_cached = nullptr;
cConfig.comparator_ctx_cached = nullptr;

int result = tidesdb_cf_config_save_to_ini(iniFile.c_str(), sectionName.c_str(), &cConfig);
checkResult(result, "failed to save config to INI");
}

//-----------------------------------------------------------------------------
// ColumnFamily
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -118,6 +192,23 @@ Stats ColumnFamily::getStats() const
}
}

// New stats fields
stats.totalKeys = cStats->total_keys;
stats.totalDataSize = cStats->total_data_size;
stats.avgKeySize = cStats->avg_key_size;
stats.avgValueSize = cStats->avg_value_size;
stats.readAmp = cStats->read_amp;
stats.hitRate = cStats->hit_rate;

if (cStats->num_levels > 0 && cStats->level_key_counts != nullptr)
{
stats.levelKeyCounts.resize(cStats->num_levels);
for (int i = 0; i < cStats->num_levels; ++i)
{
stats.levelKeyCounts[i] = cStats->level_key_counts[i];
}
}

if (cStats->config != nullptr)
{
ColumnFamilyConfig cfConfig;
Expand All @@ -126,8 +217,8 @@ Stats ColumnFamily::getStats() const
cfConfig.minLevels = cStats->config->min_levels;
cfConfig.dividingLevelOffset = cStats->config->dividing_level_offset;
cfConfig.klogValueThreshold = cStats->config->klog_value_threshold;
cfConfig.compressionAlgorithm =
static_cast<CompressionAlgorithm>(cStats->config->compression_algo);
cfConfig.compressionAlgorithm = static_cast<CompressionAlgorithm>(
static_cast<int>(cStats->config->compression_algorithm));
cfConfig.enableBloomFilter = cStats->config->enable_bloom_filter != 0;
cfConfig.bloomFPR = cStats->config->bloom_fpr;
cfConfig.enableBlockIndexes = cStats->config->enable_block_indexes != 0;
Expand Down Expand Up @@ -162,6 +253,55 @@ void ColumnFamily::flushMemtable()
checkResult(result, "failed to flush memtable");
}

bool ColumnFamily::isFlushing() const
{
return tidesdb_is_flushing(cf_) != 0;
}

bool ColumnFamily::isCompacting() const
{
return tidesdb_is_compacting(cf_) != 0;
}

void ColumnFamily::updateRuntimeConfig(const ColumnFamilyConfig& config, bool persistToDisk)
{
tidesdb_column_family_config_t cConfig;
cConfig.write_buffer_size = config.writeBufferSize;
cConfig.level_size_ratio = config.levelSizeRatio;
cConfig.min_levels = config.minLevels;
cConfig.dividing_level_offset = config.dividingLevelOffset;
cConfig.klog_value_threshold = config.klogValueThreshold;
cConfig.compression_algorithm =
static_cast<::compression_algorithm>(config.compressionAlgorithm);
cConfig.enable_bloom_filter = config.enableBloomFilter ? 1 : 0;
cConfig.bloom_fpr = config.bloomFPR;
cConfig.enable_block_indexes = config.enableBlockIndexes ? 1 : 0;
cConfig.index_sample_ratio = config.indexSampleRatio;
cConfig.block_index_prefix_len = config.blockIndexPrefixLen;
cConfig.sync_mode = static_cast<int>(config.syncMode);
cConfig.sync_interval_us = config.syncIntervalUs;
cConfig.skip_list_max_level = config.skipListMaxLevel;
cConfig.skip_list_probability = config.skipListProbability;
cConfig.default_isolation_level =
static_cast<tidesdb_isolation_level_t>(config.defaultIsolationLevel);
cConfig.min_disk_space = config.minDiskSpace;
cConfig.l1_file_count_trigger = config.l1FileCountTrigger;
cConfig.l0_queue_stall_threshold = config.l0QueueStallThreshold;

std::memset(cConfig.comparator_name, 0, TDB_MAX_COMPARATOR_NAME);
if (!config.comparatorName.empty())
{
std::strncpy(cConfig.comparator_name, config.comparatorName.c_str(),
TDB_MAX_COMPARATOR_NAME - 1);
}
std::memset(cConfig.comparator_ctx_str, 0, TDB_MAX_COMPARATOR_CTX);
cConfig.comparator_fn_cached = nullptr;
cConfig.comparator_ctx_cached = nullptr;

int result = tidesdb_cf_update_runtime_config(cf_, &cConfig, persistToDisk ? 1 : 0);
checkResult(result, "failed to update runtime config");
}

//-----------------------------------------------------------------------------
// Iterator
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -449,7 +589,8 @@ void TidesDB::createColumnFamily(const std::string& name, const ColumnFamilyConf
cConfig.min_levels = config.minLevels;
cConfig.dividing_level_offset = config.dividingLevelOffset;
cConfig.klog_value_threshold = config.klogValueThreshold;
cConfig.compression_algo = static_cast<compression_algorithm>(config.compressionAlgorithm);
cConfig.compression_algorithm =
static_cast<::compression_algorithm>(config.compressionAlgorithm);
cConfig.enable_bloom_filter = config.enableBloomFilter ? 1 : 0;
cConfig.bloom_fpr = config.bloomFPR;
cConfig.enable_block_indexes = config.enableBlockIndexes ? 1 : 0;
Expand Down Expand Up @@ -551,11 +692,45 @@ CacheStats TidesDB::getCacheStats()
return stats;
}

void TidesDB::registerComparator(const std::string& name, const std::string& ctxStr)
void TidesDB::registerComparator(const std::string& name, tidesdb_comparator_fn fn,
const std::string& ctxStr, void* ctx)
{
const char* ctxStrPtr = ctxStr.empty() ? nullptr : ctxStr.c_str();
int result = tidesdb_register_comparator(db_, name.c_str(), nullptr, ctxStrPtr, nullptr);
int result = tidesdb_register_comparator(db_, name.c_str(), fn, ctxStrPtr, ctx);
checkResult(result, "failed to register comparator");
}

void TidesDB::getComparator(const std::string& name, tidesdb_comparator_fn* fn, void** ctx)
{
int result = tidesdb_get_comparator(db_, name.c_str(), fn, ctx);
checkResult(result, "failed to get comparator");
}

void TidesDB::renameColumnFamily(const std::string& oldName, const std::string& newName)
{
int result = tidesdb_rename_column_family(db_, oldName.c_str(), newName.c_str());
checkResult(result, "failed to rename column family");
}

void TidesDB::backup(const std::string& dir)
{
int result = tidesdb_backup(db_, const_cast<char*>(dir.c_str()));
checkResult(result, "failed to create backup");
}

Config TidesDB::defaultConfig()
{
tidesdb_config_t cConfig = tidesdb_default_config();

Config config;
config.dbPath = cConfig.db_path ? cConfig.db_path : "";
config.numFlushThreads = cConfig.num_flush_threads;
config.numCompactionThreads = cConfig.num_compaction_threads;
config.logLevel = static_cast<LogLevel>(cConfig.log_level);
config.blockCacheSize = cConfig.block_cache_size;
config.maxOpenSSTables = cConfig.max_open_sstables;

return config;
}

} // namespace tidesdb
Loading
Loading