TidesDB C++ API Reference
If you want to download the source of this document, you can find it here.
Getting Started
Prerequisites
You must have the TidesDB shared C library installed on your system. You can find the installation instructions here.
Installation
git clone https://github.com/tidesdb/tidesdb-cpp.gitcd tidesdb-cppcmake -S . -B buildcmake --build buildsudo cmake --install buildCustom Installation Paths
If you installed TidesDB to a non-standard location, you can specify custom paths:
cmake -S . -B build -DCMAKE_PREFIX_PATH=/custom/pathcmake --build buildUsage
Opening and Closing a Database
#include <tidesdb.hpp>#include <iostream>
int main() { tidesdb::Config config; config.dbPath = "./mydb"; config.numFlushThreads = 2; config.numCompactionThreads = 2; config.logLevel = tidesdb::LogLevel::Info; config.blockCacheSize = 64 * 1024 * 1024; config.maxOpenSSTables = 256;
try { tidesdb::TidesDB db(config); std::cout << "Database opened successfully" << std::endl; // Database automatically closes when db goes out of scope } catch (const tidesdb::Exception& e) { std::cerr << "Failed to open database: " << e.what() << std::endl; return 1; }
return 0;}Creating and Dropping Column Families
Column families are isolated key-value stores with independent configuration.
auto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig();db.createColumnFamily("my_cf", cfConfig);
// Create with custom configurationauto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig();cfConfig.writeBufferSize = 128 * 1024 * 1024;cfConfig.levelSizeRatio = 10;cfConfig.minLevels = 5;cfConfig.compressionAlgorithm = tidesdb::CompressionAlgorithm::LZ4;cfConfig.enableBloomFilter = true;cfConfig.bloomFPR = 0.01;cfConfig.enableBlockIndexes = true;cfConfig.syncMode = tidesdb::SyncMode::Interval;cfConfig.syncIntervalUs = 128000;cfConfig.defaultIsolationLevel = tidesdb::IsolationLevel::ReadCommitted;
db.createColumnFamily("my_cf", cfConfig);
db.dropColumnFamily("my_cf");CRUD Operations
All operations in TidesDB are performed through transactions for ACID guarantees.
Writing Data
auto cf = db.getColumnFamily("my_cf");
auto txn = db.beginTransaction();txn.put(cf, "key", "value", -1); // TTL -1 means no expirationtxn.commit();Writing with TTL
#include <ctime>
auto cf = db.getColumnFamily("my_cf");
auto txn = db.beginTransaction();
// Set expiration time (Unix timestamp)auto ttl = std::time(nullptr) + 10; // Expires in 10 seconds
txn.put(cf, "temp_key", "temp_value", ttl);txn.commit();TTL Examples
// No expirationauto ttl = static_cast<std::time_t>(-1);
// Expire in 5 minutesauto ttl = std::time(nullptr) + (5 * 60);
// Expire in 1 hourauto ttl = std::time(nullptr) + (60 * 60);
// Expire at specific timeauto ttl = static_cast<std::time_t>(1735689599); // Specific Unix timestampReading Data
auto cf = db.getColumnFamily("my_cf");
auto txn = db.beginTransaction();auto value = txn.get(cf, "key");std::string valueStr(value.begin(), value.end());std::cout << "Value: " << valueStr << std::endl;Deleting Data
auto cf = db.getColumnFamily("my_cf");
auto txn = db.beginTransaction();txn.del(cf, "key");txn.commit();Multi-Operation Transactions
auto cf = db.getColumnFamily("my_cf");
auto txn = db.beginTransaction();
// Multiple operations in one transactiontxn.put(cf, "key1", "value1", -1);txn.put(cf, "key2", "value2", -1);txn.del(cf, "old_key");
// Commit atomically -- all or nothingtxn.commit();Iterating Over Data
Iterators provide efficient bidirectional traversal over key-value pairs.
Forward Iteration
auto cf = db.getColumnFamily("my_cf");
auto txn = db.beginTransaction();auto iter = txn.newIterator(cf);
iter.seekToFirst();
while (iter.valid()) { auto key = iter.key(); auto value = iter.value();
std::string keyStr(key.begin(), key.end()); std::string valueStr(value.begin(), value.end());
std::cout << "Key: " << keyStr << ", Value: " << valueStr << std::endl;
iter.next();}Backward Iteration
auto cf = db.getColumnFamily("my_cf");
auto txn = db.beginTransaction();auto iter = txn.newIterator(cf);
iter.seekToLast();
while (iter.valid()) { auto key = iter.key(); auto value = iter.value(); // Process entries in reverse order iter.prev();}Seeking
auto iter = txn.newIterator(cf);
// Seek to first key >= "user:1000"iter.seek("user:1000");
// Seek to last key <= "user:2000"iter.seekForPrev("user:2000");Getting Column Family Statistics
Retrieve detailed statistics about a column family.
auto cf = db.getColumnFamily("my_cf");
auto stats = cf.getStats();
std::cout << "Number of Levels: " << stats.numLevels << std::endl;std::cout << "Memtable Size: " << stats.memtableSize << " bytes" << std::endl;
if (stats.config.has_value()) { std::cout << "Write Buffer Size: " << stats.config->writeBufferSize << std::endl; std::cout << "Compression: " << static_cast<int>(stats.config->compressionAlgorithm) << std::endl; std::cout << "Bloom Filter: " << (stats.config->enableBloomFilter ? "enabled" : "disabled") << std::endl;}Listing Column Families
auto cfList = db.listColumnFamilies();
std::cout << "Available column families:" << std::endl;for (const auto& name : cfList) { std::cout << " - " << name << std::endl;}Compaction
Manual Compaction
auto cf = db.getColumnFamily("my_cf");
// Manually trigger compactioncf.compact();Manual Memtable Flush
auto cf = db.getColumnFamily("my_cf");
// Manually trigger memtable flush (Queues sorted run for L1)cf.flushMemtable();Sync Modes
Control the durability vs performance tradeoff.
auto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig();
// SyncNone -- Fastest, least durablecfConfig.syncMode = tidesdb::SyncMode::None;
// SyncInterval -- Balanced (periodic background syncing)cfConfig.syncMode = tidesdb::SyncMode::Interval;cfConfig.syncIntervalUs = 128000; // Sync every 128ms
// SyncFull -- Most durable (fsync on every write)cfConfig.syncMode = tidesdb::SyncMode::Full;
db.createColumnFamily("my_cf", cfConfig);Compression Algorithms
TidesDB supports multiple compression algorithms:
auto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig();
cfConfig.compressionAlgorithm = tidesdb::CompressionAlgorithm::None;cfConfig.compressionAlgorithm = tidesdb::CompressionAlgorithm::LZ4;cfConfig.compressionAlgorithm = tidesdb::CompressionAlgorithm::LZ4Fast;cfConfig.compressionAlgorithm = tidesdb::CompressionAlgorithm::Zstd;
db.createColumnFamily("my_cf", cfConfig);Error Handling
The C++ wrapper uses exceptions for error handling. All errors throw tidesdb::Exception.
try { auto cf = db.getColumnFamily("my_cf");
auto txn = db.beginTransaction(); txn.put(cf, "key", "value", -1); txn.commit();} catch (const tidesdb::Exception& e) { std::cerr << "Error: " << e.what() << std::endl; std::cerr << "Code: " << static_cast<int>(e.code()) << std::endl;}Error Codes
ErrorCode::Success(0) — Operation successfulErrorCode::Memory(-1) — Memory allocation failedErrorCode::InvalidArgs(-2) — Invalid argumentsErrorCode::NotFound(-3) — Key not foundErrorCode::IO(-4) — I/O errorErrorCode::Corruption(-5) — Data corruptionErrorCode::Exists(-6) — Resource already existsErrorCode::Conflict(-7) — Transaction conflictErrorCode::TooLarge(-8) — Key or value too largeErrorCode::MemoryLimit(-9) — Memory limit exceededErrorCode::InvalidDB(-10) — Invalid database handleErrorCode::Unknown(-11) — Unknown errorErrorCode::Locked(-12) — Database is locked
Complete Example
#include <tidesdb/tidesdb.hpp>#include <iostream>#include <ctime>
int main() { try { tidesdb::Config config; config.dbPath = "./example_db"; config.numFlushThreads = 1; config.numCompactionThreads = 1; config.logLevel = tidesdb::LogLevel::Info; config.blockCacheSize = 64 * 1024 * 1024; config.maxOpenSSTables = 256;
tidesdb::TidesDB db(config);
auto cfConfig = tidesdb::ColumnFamilyConfig::defaultConfig(); cfConfig.writeBufferSize = 64 * 1024 * 1024; cfConfig.compressionAlgorithm = tidesdb::CompressionAlgorithm::LZ4; cfConfig.enableBloomFilter = true; cfConfig.bloomFPR = 0.01; cfConfig.syncMode = tidesdb::SyncMode::Interval; cfConfig.syncIntervalUs = 128000;
db.createColumnFamily("users", cfConfig);
auto cf = db.getColumnFamily("users");
// Write data { auto txn = db.beginTransaction(); txn.put(cf, "user:1", "Alice", -1); txn.put(cf, "user:2", "Bob", -1);
auto ttl = std::time(nullptr) + 30; txn.put(cf, "session:abc", "temp_data", ttl);
txn.commit(); }
// Read data { auto txn = db.beginTransaction(); auto value = txn.get(cf, "user:1"); std::string valueStr(value.begin(), value.end()); std::cout << "user:1 = " << valueStr << std::endl; }
// Iterate { auto txn = db.beginTransaction(); auto iter = txn.newIterator(cf);
std::cout << "\nAll entries:" << std::endl; iter.seekToFirst(); while (iter.valid()) { auto key = iter.key(); auto value = iter.value(); std::string keyStr(key.begin(), key.end()); std::string valueStr(value.begin(), value.end()); std::cout << " " << keyStr << " = " << valueStr << std::endl; iter.next(); } }
auto stats = cf.getStats(); std::cout << "\nColumn Family Statistics:" << std::endl; std::cout << " Number of Levels: " << stats.numLevels << std::endl; std::cout << " Memtable Size: " << stats.memtableSize << " bytes" << std::endl;
db.dropColumnFamily("users");
} catch (const tidesdb::Exception& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; }
return 0;}Isolation Levels
TidesDB supports five MVCC isolation levels:
auto txn = db.beginTransaction(tidesdb::IsolationLevel::ReadCommitted);// Perform operationstxn.commit();Available Isolation Levels
IsolationLevel::ReadUncommitted— Sees all data including uncommitted changesIsolationLevel::ReadCommitted— Sees only committed data (default)IsolationLevel::RepeatableRead— Consistent snapshot, phantom reads possibleIsolationLevel::Snapshot— Write-write conflict detectionIsolationLevel::Serializable— Full read-write conflict detection (SSI)
Savepoints
Savepoints allow partial rollback within a transaction:
auto txn = db.beginTransaction();
txn.put(cf, "key1", "value1", -1);
txn.savepoint("sp1");txn.put(cf, "key2", "value2", -1);
// Rollback to savepoint -- key2 is discarded, key1 remainstxn.rollbackToSavepoint("sp1");
// Commit -- only key1 is writtentxn.commit();Testing
# Build with testscmake -S . -B build -DTIDESDB_CPP_BUILD_TESTS=ONcmake --build build
# Run testscd buildctest --output-on-failure