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
2 changes: 1 addition & 1 deletion 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.1.1 LANGUAGES CXX)
project(tidesdb_cpp VERSION 2.2.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
5 changes: 5 additions & 0 deletions include/tidesdb/tidesdb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ struct ColumnFamilyConfig
std::uint64_t minDiskSpace = 100 * 1024 * 1024;
int l1FileCountTrigger = 4;
int l0QueueStallThreshold = 20;
bool useBtree = false; ///< Use B+tree format for klog (default: false = block-based)

/**
* @brief Get default column family configuration from TidesDB
Expand Down Expand Up @@ -245,6 +246,10 @@ struct Stats
std::vector<std::uint64_t> levelKeyCounts;
double readAmp = 0.0;
double hitRate = 0.0;
bool useBtree = false; ///< Whether column family uses B+tree format
std::uint64_t btreeTotalNodes = 0; ///< Total B+tree nodes across all SSTables
std::uint32_t btreeMaxHeight = 0; ///< Maximum tree height across all SSTables
double btreeAvgHeight = 0.0; ///< Average tree height across all SSTables
};

/**
Expand Down
12 changes: 12 additions & 0 deletions src/tidesdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ ColumnFamilyConfig ColumnFamilyConfig::defaultConfig()
config.minDiskSpace = cConfig.min_disk_space;
config.l1FileCountTrigger = cConfig.l1_file_count_trigger;
config.l0QueueStallThreshold = cConfig.l0_queue_stall_threshold;
config.useBtree = cConfig.use_btree != 0;

return config;
}
Expand Down Expand Up @@ -101,6 +102,7 @@ ColumnFamilyConfig ColumnFamilyConfig::loadFromIni(const std::string& iniFile,
config.minDiskSpace = cConfig.min_disk_space;
config.l1FileCountTrigger = cConfig.l1_file_count_trigger;
config.l0QueueStallThreshold = cConfig.l0_queue_stall_threshold;
config.useBtree = cConfig.use_btree != 0;

return config;
}
Expand Down Expand Up @@ -130,6 +132,7 @@ void ColumnFamilyConfig::saveToIni(const std::string& iniFile, const std::string
cConfig.min_disk_space = config.minDiskSpace;
cConfig.l1_file_count_trigger = config.l1FileCountTrigger;
cConfig.l0_queue_stall_threshold = config.l0QueueStallThreshold;
cConfig.use_btree = config.useBtree ? 1 : 0;

std::memset(cConfig.comparator_name, 0, TDB_MAX_COMPARATOR_NAME);
if (!config.comparatorName.empty())
Expand Down Expand Up @@ -200,6 +203,12 @@ Stats ColumnFamily::getStats() const
stats.readAmp = cStats->read_amp;
stats.hitRate = cStats->hit_rate;

// B+tree stats
stats.useBtree = cStats->use_btree != 0;
stats.btreeTotalNodes = cStats->btree_total_nodes;
stats.btreeMaxHeight = cStats->btree_max_height;
stats.btreeAvgHeight = cStats->btree_avg_height;

if (cStats->num_levels > 0 && cStats->level_key_counts != nullptr)
{
stats.levelKeyCounts.resize(cStats->num_levels);
Expand Down Expand Up @@ -234,6 +243,7 @@ Stats ColumnFamily::getStats() const
cfConfig.minDiskSpace = cStats->config->min_disk_space;
cfConfig.l1FileCountTrigger = cStats->config->l1_file_count_trigger;
cfConfig.l0QueueStallThreshold = cStats->config->l0_queue_stall_threshold;
cfConfig.useBtree = cStats->config->use_btree != 0;
stats.config = cfConfig;
}

Expand Down Expand Up @@ -287,6 +297,7 @@ void ColumnFamily::updateRuntimeConfig(const ColumnFamilyConfig& config, bool pe
cConfig.min_disk_space = config.minDiskSpace;
cConfig.l1_file_count_trigger = config.l1FileCountTrigger;
cConfig.l0_queue_stall_threshold = config.l0QueueStallThreshold;
cConfig.use_btree = config.useBtree ? 1 : 0;

std::memset(cConfig.comparator_name, 0, TDB_MAX_COMPARATOR_NAME);
if (!config.comparatorName.empty())
Expand Down Expand Up @@ -607,6 +618,7 @@ void TidesDB::createColumnFamily(const std::string& name, const ColumnFamilyConf
cConfig.min_disk_space = config.minDiskSpace;
cConfig.l1_file_count_trigger = config.l1FileCountTrigger;
cConfig.l0_queue_stall_threshold = config.l0QueueStallThreshold;
cConfig.use_btree = config.useBtree ? 1 : 0;

std::memset(cConfig.comparator_name, 0, TDB_MAX_COMPARATOR_NAME);
if (!config.comparatorName.empty())
Expand Down
70 changes: 70 additions & 0 deletions tests/tidesdb_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,76 @@ TEST_F(TidesDBTest, DefaultConfig)
ASSERT_GE(defaultConfig.maxOpenSSTables, 0u);
}

TEST_F(TidesDBTest, UseBtreeConfig)
{
tidesdb::TidesDB db(getConfig());

// Test with useBtree = false (default, block-based format)
{
auto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig();
ASSERT_FALSE(cfConfig.useBtree); // Default should be false
db.createColumnFamily("block_cf", cfConfig);

auto cf = db.getColumnFamily("block_cf");
auto stats = cf.getStats();
ASSERT_FALSE(stats.useBtree);
if (stats.config.has_value())
{
ASSERT_FALSE(stats.config->useBtree);
}
}

// Test with useBtree = true (B+tree format)
{
auto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig();
cfConfig.useBtree = true;
db.createColumnFamily("btree_cf", cfConfig);

auto cf = db.getColumnFamily("btree_cf");
auto stats = cf.getStats();
ASSERT_TRUE(stats.useBtree);
if (stats.config.has_value())
{
ASSERT_TRUE(stats.config->useBtree);
}
}
}

TEST_F(TidesDBTest, BtreeStats)
{
tidesdb::TidesDB db(getConfig());

auto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig();
cfConfig.useBtree = true;
cfConfig.writeBufferSize = 1024; // Small buffer to trigger flush
db.createColumnFamily("btree_cf", cfConfig);

auto cf = db.getColumnFamily("btree_cf");

// Insert data to populate B+tree structures
{
auto txn = db.beginTransaction();
for (int i = 0; i < 50; ++i)
{
std::string key = "key" + std::to_string(i);
std::string value = "value" + std::to_string(i);
txn.put(cf, key, value, -1);
}
txn.commit();
}

// Force flush to create SSTables with B+tree format
cf.flushMemtable();

auto stats = cf.getStats();

// Verify B+tree stats fields exist and are valid
ASSERT_TRUE(stats.useBtree);
ASSERT_GE(stats.btreeTotalNodes, 0u);
ASSERT_GE(stats.btreeMaxHeight, 0u);
ASSERT_GE(stats.btreeAvgHeight, 0.0);
}

int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
Expand Down
Loading