TidesDB GO 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
go get github.com/tidesdb/tidesdb-goCustom Installation Paths
If you installed TidesDB to a non-standard location, you can specify custom paths using CGO environment variables:
# Set custom include and library pathsexport CGO_CFLAGS="-I/custom/path/include"export CGO_LDFLAGS="-L/custom/path/lib -ltidesdb"
# Then install/buildgo get github.com/tidesdb/tidesdb-goCustom prefix installation
# Install TidesDB to custom locationcd tidesdbcmake -S . -B build -DCMAKE_INSTALL_PREFIX=/opt/tidesdbcmake --build buildsudo cmake --install build
# Configure Go to use custom locationexport CGO_CFLAGS="-I/opt/tidesdb/include"export CGO_LDFLAGS="-L/opt/tidesdb/lib -ltidesdb"export LD_LIBRARY_PATH="/opt/tidesdb/lib:$LD_LIBRARY_PATH" # Linux# orexport DYLD_LIBRARY_PATH="/opt/tidesdb/lib:$DYLD_LIBRARY_PATH" # macOS
go get github.com/tidesdb/tidesdb-goUsage
Opening and Closing a Database
package main
import ( "fmt" "log"
tidesdb "github.com/tidesdb/tidesdb-go")
func main() { config := tidesdb.Config{ DBPath: "./mydb", NumFlushThreads: 2, NumCompactionThreads: 2, LogLevel: tidesdb.LogInfo, BlockCacheSize: 64 * 1024 * 1024, MaxOpenSSTables: 256, }
db, err := tidesdb.Open(config) if err != nil { log.Fatal(err) } defer db.Close()
fmt.Println("Database opened successfully")}Creating and Dropping Column Families
Column families are isolated key-value stores with independent configuration.
cfConfig := tidesdb.DefaultColumnFamilyConfig()err := db.CreateColumnFamily("my_cf", cfConfig)if err != nil { log.Fatal(err)}
// Create with custom configuration based on defaultscfConfig := tidesdb.DefaultColumnFamilyConfig()
// You can modify the configuration as neededcfConfig.WriteBufferSize = 128 * 1024 * 1024cfConfig.LevelSizeRatio = 10cfConfig.MinLevels = 5cfConfig.CompressionAlgorithm = tidesdb.LZ4CompressioncfConfig.EnableBloomFilter = truecfConfig.BloomFPR = 0.01cfConfig.EnableBlockIndexes = truecfConfig.SyncMode = tidesdb.SyncIntervalcfConfig.SyncIntervalUs = 128000cfConfig.DefaultIsolationLevel = tidesdb.IsolationReadCommitted
err = db.CreateColumnFamily("my_cf", cfConfig)if err != nil { log.Fatal(err)}
err = db.DropColumnFamily("my_cf")if err != nil { log.Fatal(err)}CRUD Operations
All operations in TidesDB are performed through transactions for ACID guarantees.
Writing Data
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
txn, err := db.BeginTxn()if err != nil { log.Fatal(err)}defer txn.Free()
// Put a key-value pair (TTL -1 means no expiration)err = txn.Put(cf, []byte("key"), []byte("value"), -1)if err != nil { log.Fatal(err)}
err = txn.Commit()if err != nil { log.Fatal(err)}Writing with TTL
import "time"
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
txn, err := db.BeginTxn()if err != nil { log.Fatal(err)}defer txn.Free()
// Set expiration time (Unix timestamp)ttl := time.Now().Add(10 * time.Second).Unix()
err = txn.Put(cf, []byte("temp_key"), []byte("temp_value"), ttl)if err != nil { log.Fatal(err)}
err = txn.Commit()if err != nil { log.Fatal(err)}TTL Examples
// No expirationttl := int64(-1)
// Expire in 5 minutesttl := time.Now().Add(5 * time.Minute).Unix()
// Expire in 1 hourttl := time.Now().Add(1 * time.Hour).Unix()
// Expire at specific timettl := time.Date(2026, 12, 31, 23, 59, 59, 0, time.UTC).Unix()Reading Data
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
txn, err := db.BeginTxn()if err != nil { log.Fatal(err)}defer txn.Free()
value, err := txn.Get(cf, []byte("key"))if err != nil { log.Fatal(err)}
fmt.Printf("Value: %s\n", value)Deleting Data
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
txn, err := db.BeginTxn()if err != nil { log.Fatal(err)}defer txn.Free()
err = txn.Delete(cf, []byte("key"))if err != nil { log.Fatal(err)}
err = txn.Commit()if err != nil { log.Fatal(err)}Multi-Operation Transactions
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
txn, err := db.BeginTxn()if err != nil { log.Fatal(err)}defer txn.Free()
// Multiple operations in one transaction, across column families as wellerr = txn.Put(cf, []byte("key1"), []byte("value1"), -1)if err != nil { txn.Rollback() log.Fatal(err)}
err = txn.Put(cf, []byte("key2"), []byte("value2"), -1)if err != nil { txn.Rollback() log.Fatal(err)}
err = txn.Delete(cf, []byte("old_key"))if err != nil { txn.Rollback() log.Fatal(err)}
// Commit atomically -- all or nothingerr = txn.Commit()if err != nil { log.Fatal(err)}Iterating Over Data
Iterators provide efficient bidirectional traversal over key-value pairs.
Forward Iteration
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
txn, err := db.BeginTxn()if err != nil { log.Fatal(err)}defer txn.Free()
iter, err := txn.NewIterator(cf)if err != nil { log.Fatal(err)}defer iter.Free()
iter.SeekToFirst()
for iter.Valid() { key, err := iter.Key() if err != nil { log.Fatal(err) }
value, err := iter.Value() if err != nil { log.Fatal(err) }
fmt.Printf("Key: %s, Value: %s\n", key, value)
iter.Next()}Backward Iteration
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
txn, err := db.BeginTxn()if err != nil { log.Fatal(err)}defer txn.Free()
iter, err := txn.NewIterator(cf)if err != nil { log.Fatal(err)}defer iter.Free()
iter.SeekToLast()
for iter.Valid() { key, err := iter.Key() if err != nil { log.Fatal(err) }
value, err := iter.Value() if err != nil { log.Fatal(err) }
fmt.Printf("Key: %s, Value: %s\n", key, value)
iter.Prev()}Getting Column Family Statistics
Retrieve detailed statistics about a column family.
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
stats, err := cf.GetStats()if err != nil { log.Fatal(err)}
fmt.Printf("Number of Levels: %d\n", stats.NumLevels)fmt.Printf("Memtable Size: %d bytes\n", stats.MemtableSize)
if stats.Config != nil { fmt.Printf("Write Buffer Size: %d\n", stats.Config.WriteBufferSize) fmt.Printf("Compression: %d\n", stats.Config.CompressionAlgorithm) fmt.Printf("Bloom Filter: %v\n", stats.Config.EnableBloomFilter) fmt.Printf("Sync Mode: %d\n", stats.Config.SyncMode)}Listing Column Families
cfList, err := db.ListColumnFamilies()if err != nil { log.Fatal(err)}
fmt.Println("Available column families:")for _, name := range cfList { fmt.Printf(" - %s\n", name)}Compaction
Manual Compaction
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
// Manually trigger compaction (queues compaction from L1+)err = cf.Compact()if err != nil { log.Printf("Compaction note: %v", err)}Manual Memtable Flush
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
// Manually trigger memtable flush (queues memtable for sorted run to disk (L1))err = cf.FlushMemtable()if err != nil { log.Printf("Flush note: %v", err)}Sync Modes
Control the durability vs performance tradeoff.
cfConfig := tidesdb.DefaultColumnFamilyConfig()
// SyncNone -- Fastest, least durable (OS handles flushing on sorted runs and compaction to sync after completion)cfConfig.SyncMode = tidesdb.SyncNone
// SyncInterval -- Balanced (periodic background syncing)cfConfig.SyncMode = tidesdb.SyncIntervalcfConfig.SyncIntervalUs = 128000 // Sync every 128ms
// SyncFull -- Most durable (fsync on every write)cfConfig.SyncMode = tidesdb.SyncFull
err := db.CreateColumnFamily("my_cf", cfConfig)if err != nil { log.Fatal(err)}Compression Algorithms
TidesDB supports multiple compression algorithms:
cfConfig := tidesdb.DefaultColumnFamilyConfig()
cfConfig.CompressionAlgorithm = tidesdb.NoCompressioncfConfig.CompressionAlgorithm = tidesdb.LZ4CompressioncfConfig.CompressionAlgorithm = tidesdb.LZ4FastCompressioncfConfig.CompressionAlgorithm = tidesdb.ZstdCompression
err := db.CreateColumnFamily("my_cf", cfConfig)if err != nil { log.Fatal(err)}Error Handling
cf, err := db.GetColumnFamily("my_cf")if err != nil { log.Fatal(err)}
txn, err := db.BeginTxn()if err != nil { log.Fatal(err)}defer txn.Free()
err = txn.Put(cf, []byte("key"), []byte("value"), -1)if err != nil { // Errors include context and error codes fmt.Printf("Error: %v\n", err)
// Example error message: // "failed to put key-value pair: memory allocation failed (code: -1)"
txn.Rollback() return}
err = txn.Commit()if err != nil { log.Fatal(err)}Error Codes
ErrSuccess(0) — Operation successfulErrMemory(-1) — Memory allocation failedErrInvalidArgs(-2) — Invalid argumentsErrNotFound(-3) — Key not foundErrIO(-4) — I/O errorErrCorruption(-5) — Data corruptionErrExists(-6) — Resource already existsErrConflict(-7) — Transaction conflictErrTooLarge(-8) — Key or value too largeErrMemoryLimit(-9) — Memory limit exceededErrInvalidDB(-10) — Invalid database handleErrUnknown(-11) — Unknown errorErrLocked(-12) — Database is locked
Complete Example
package main
import ( "fmt" "log" "time"
tidesdb "github.com/tidesdb/tidesdb-go")
func main() { config := tidesdb.Config{ DBPath: "./example_db", NumFlushThreads: 1, NumCompactionThreads: 1, LogLevel: tidesdb.LogInfo, BlockCacheSize: 64 * 1024 * 1024, MaxOpenSSTables: 256, }
db, err := tidesdb.Open(config) if err != nil { log.Fatal(err) } defer db.Close()
cfConfig := tidesdb.DefaultColumnFamilyConfig() cfConfig.WriteBufferSize = 64 * 1024 * 1024 cfConfig.CompressionAlgorithm = tidesdb.LZ4Compression cfConfig.EnableBloomFilter = true cfConfig.BloomFPR = 0.01 cfConfig.SyncMode = tidesdb.SyncInterval cfConfig.SyncIntervalUs = 128000
err = db.CreateColumnFamily("users", cfConfig) if err != nil { log.Fatal(err) } defer db.DropColumnFamily("users")
cf, err := db.GetColumnFamily("users") if err != nil { log.Fatal(err) }
txn, err := db.BeginTxn() if err != nil { log.Fatal(err) }
err = txn.Put(cf, []byte("user:1"), []byte("Alice"), -1) if err != nil { txn.Rollback() log.Fatal(err) }
err = txn.Put(cf, []byte("user:2"), []byte("Bob"), -1) if err != nil { txn.Rollback() log.Fatal(err) }
ttl := time.Now().Add(30 * time.Second).Unix() err = txn.Put(cf, []byte("session:abc"), []byte("temp_data"), ttl) if err != nil { txn.Rollback() log.Fatal(err) }
err = txn.Commit() if err != nil { log.Fatal(err) } txn.Free()
readTxn, err := db.BeginTxn() if err != nil { log.Fatal(err) } defer readTxn.Free()
value, err := readTxn.Get(cf, []byte("user:1")) if err != nil { log.Fatal(err) } fmt.Printf("user:1 = %s\n", value)
iter, err := readTxn.NewIterator(cf) if err != nil { log.Fatal(err) } defer iter.Free()
fmt.Println("\nAll entries:") iter.SeekToFirst() for iter.Valid() { key, _ := iter.Key() value, _ := iter.Value() fmt.Printf(" %s = %s\n", key, value) iter.Next() }
stats, err := cf.GetStats() if err != nil { log.Fatal(err) }
fmt.Printf("\nColumn Family Statistics:\n") fmt.Printf(" Number of Levels: %d\n", stats.NumLevels) fmt.Printf(" Memtable Size: %d bytes\n", stats.MemtableSize)}Isolation Levels
TidesDB supports five MVCC isolation levels:
txn, err := db.BeginTxnWithIsolation(tidesdb.IsolationReadCommitted)if err != nil { log.Fatal(err)}defer txn.Free()Available Isolation Levels
IsolationReadUncommitted— Sees all data including uncommitted changesIsolationReadCommitted— Sees only committed data (default)IsolationRepeatableRead— Consistent snapshot, phantom reads possibleIsolationSnapshot— Write-write conflict detectionIsolationSerializable— Full read-write conflict detection (SSI)
Savepoints
Savepoints allow partial rollback within a transaction:
txn, err := db.BeginTxn()if err != nil { log.Fatal(err)}defer txn.Free()
err = txn.Put(cf, []byte("key1"), []byte("value1"), -1)
err = txn.Savepoint("sp1")err = txn.Put(cf, []byte("key2"), []byte("value2"), -1)
// Rollback to savepoint -- key2 is discarded, key1 remainserr = txn.RollbackToSavepoint("sp1")
// Commit -- only key1 is writtenerr = txn.Commit()Testing
# Run all testsgo test -v
# Run specific testgo test -v -run TestOpenClose
# Run with race detectorgo test -race -v