TidesDB C Reference
Error Handling
All TidesDB methods return a tidesdb_err_t*
which contains an error code and message. If no error occurs, NULL is returned.
typedef struct{ int code; char *message;} tidesdb_err_t;
Public Methods Reference
Database Operations
Opening a Database
Opens a TidesDB database instance at the specified path.
tidesdb_t *tdb = NULL;tidesdb_err_t *err = tidesdb_open("your_tdb_directory", &tdb);if (err != NULL) { printf("Error: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}
/* * If we get here, TidesDB opened successfully. * We can now perform operations. */printf("TidesDB opened successfully\n");
Closing a Database
Gracefully closes a TidesDB database instance.
tidesdb_err_t *err = tidesdb_close(tdb);if (err != NULL) { printf("Error closing TidesDB: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}
/** At this point, we have successfully closed TidesDB* and released all associated resources. Any further* operations on tdb would be invalid.*/printf("TidesDB closed successfully\n");
Column Family Operations
Creating a Column Family
Creates a new column family with specified configuration.
/* * Create a column family with Snappy compression and bloom filters * This will optimize read performance while still maintaining * good compression ratios for storage efficiency */tidesdb_err_t *err = tidesdb_create_column_family( tdb, /* TidesDB instance */ "users", /* Column family name */ (1024 * 1024) * 128, /* Memtable flush threshold (128MB) */ TDB_DEFAULT_SKIP_LIST_MAX_LEVEL, /* Skip list max level */ TDB_DEFAULT_SKIP_LIST_PROBABILITY, /* Skip list probability */ true, /* Enable compression */ TDB_COMPRESS_SNAPPY, /* Use Snappy compression */ true /* Enable bloom filters */);
if (err != NULL) { printf("Error creating column family: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Column family 'users' created successfully\n");
Dropping a Column Family
Deletes a column family and all its associated data.
/* * Dropping a Column Family * Deletes a column family and all its associated data. * WARNING: This operation cannot be undone and will * permanently remove all data in this family. */tidesdb_err_t *err = tidesdb_drop_column_family(tdb, "users");if (err != NULL) { printf("Error dropping column family: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Column family 'users' dropped successfully\n");
Listing Column Families
Gets a list of all column families in the TidesDB instance.
/** List all column families in the TidesDB instance* The function allocates memory for the result,* which must be freed by the caller*/char *column_families = NULL;tidesdb_err_t *err = tidesdb_list_column_families(tdb, &column_families);if (err != NULL) { printf("Error listing column families: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}
printf("Column families: %s\n", column_families);free(column_families); /* Don't forget to free the memory */
Getting Column Family Statistics
Retrieves detailed information about a column family.
/** Get statistics for a column family* This provides detailed information about the state of* the specified column family within the TidesDB instance*/tidesdb_column_family_stat_t *stat = NULL;tidesdb_err_t *err = tidesdb_get_column_family_stat(tdb, "users", &stat);if (err != NULL) { printf("Error getting column family stats: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}
/* Display the column family statistics */printf("Column family: %s\n", stat->cf_name);printf("Number of SSTables: %d\n", stat->num_sstables);printf("Memtable size: %zu bytes\n", stat->memtable_size);printf("Memtable entries: %zu\n", stat->memtable_entries_count);printf("Incremental merging: %s\n", stat->incremental_merging ? "Yes" : "No");printf("Flush threshold: %d bytes\n", stat->config.flush_threshold);
/* Free the stats when done to prevent memory leaks */tidesdb_free_column_family_stat(stat);
Key-Value Operations
Putting a Key-Value Pair
Stores a key-value pair in a column family.
/** Store a simple key-value pair with no expiration* This associates a JSON user profile with the key "user:1001"* in the "users" column family*/uint8_t key[] = "user:1001";uint8_t value[] = "{\"name\":\"Alice\",\"email\":\"alice@example.com\"}";
tidesdb_err_t *err = tidesdb_put( tdb, /* TidesDB instance */ "users", /* Column family name */ key, /* Key */ sizeof(key), /* Key size */ value, /* Value */ sizeof(value), /* Value size */ -1 /* TTL (-1 means no expiration) */);
if (err != NULL) { printf("Error putting key-value pair: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Key-value pair stored successfully\n");
Putting a Key-Value Pair with TTL
Stores a key-value pair that will expire after a specified time.
/** Store a key-value pair with expiration (TTL)* This associates a session with user ID 1001* The session will expire automatically after 1 hour*/uint8_t key[] = "session:12345";uint8_t value[] = "{\"user_id\":\"1001\",\"authenticated\":true}";
/* Set TTL to 1 hour from now */time_t ttl = time(NULL) + (60 * 60);
tidesdb_err_t *err = tidesdb_put( tdb, /* TidesDB instance */ "sessions", /* Column family name */ key, /* Key */ sizeof(key), /* Key size */ value, /* Value */ sizeof(value), /* Value size */ ttl /* TTL (1 hour from now) */);
if (err != NULL) { printf("Error putting key-value pair with TTL: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Key-value pair with TTL stored successfully\n");
Getting a Key-Value Pair
Retrieves a value by its key from a column family.
/** Retrieve a key-value pair from the TidesDB instance* Looks up the value associated with the key "user:1001"* The function allocates memory for the result,* which must be freed by the caller*/uint8_t key[] = "user:1001";uint8_t *value_out = NULL;size_t value_len = 0;
tidesdb_err_t *err = tidesdb_get( tdb, /* TidesDB instance */ "users", /* Column family name */ key, /* Key */ sizeof(key), /* Key size */ &value_out, /* Output value */ &value_len /* Output value size */);
if (err != NULL) { printf("Error getting key-value pair: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}
printf("Retrieved value: %.*s\n", (int)value_len, value_out);
/* Don't forget to free the value when done to prevent memory leaks */free(value_out);
Deleting a Key-Value Pair
Removes a key-value pair from a column family.
/** Delete a key-value pair from the TidesDB instance* This completely removes the entry for "user:1001"* from the "users" column family*/uint8_t key[] = "user:1001";
tidesdb_err_t *err = tidesdb_delete( tdb, /* TidesDB instance */ "users", /* Column family name */ key, /* Key */ sizeof(key) /* Key size */);
if (err != NULL) { printf("Error deleting key-value pair: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Key-value pair deleted successfully\n");
Range and Filter Operations
Range Queries
Retrieves a range of key-value pairs between two keys.
/** Perform a range query to retrieve all users with IDs between 1000 and 2000* This returns all key-value pairs where the key is lexicographically* between start_key and end_key (inclusive)*/uint8_t start_key[] = "user:1000";uint8_t end_key[] = "user:2000";tidesdb_key_value_pair_t **result = NULL;size_t result_size = 0;
tidesdb_err_t *err = tidesdb_range( tdb, /* TidesDB instance */ "users", /* Column family name */ start_key, /* Start key */ sizeof(start_key), /* Start key size */ end_key, /* End key */ sizeof(end_key), /* End key size */ &result, /* Output result array */ &result_size /* Output result size */);
if (err != NULL) { printf("Error in range query: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}
printf("Found %zu key-value pairs in range\n", result_size);
/* Process results */for (size_t i = 0; i < result_size; i++) { printf("Key: %.*s, Value: %.*s\n", (int)result[i]->key_size, result[i]->key, (int)result[i]->value_size, result[i]->value);
/* Free each key-value pair when done */ _tidesdb_free_key_value_pair(result[i]);}
/* Free the result array */free(result);
Filter Queries
Retrieves key-value pairs that match a specific filter function.
/** Define a filter function to find users with "admin" in their value* This will search through all users and return only those that match* our criteria (containing the string "admin" in their value)*/bool is_admin_user(const tidesdb_key_value_pair_t *kv) { /* Check if "admin" is in the value */ for (uint32_t i = 0; i <= kv->value_size - 5; i++) { if (memcmp(kv->value + i, "admin", 5) == 0) { return true; } } return false;}
tidesdb_key_value_pair_t **result = NULL;size_t result_size = 0;
tidesdb_err_t *err = tidesdb_filter( tdb, /* TidesDB instance */ "users", /* Column family name */ is_admin_user, /* Filter function */ &result, /* Output result array */ &result_size /* Output result size */);
if (err != NULL) { printf("Error in filter query: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}
printf("Found %zu admin users\n", result_size);
/* Process results */for (size_t i = 0; i < result_size; i++) { printf("Admin user - Key: %.*s, Value: %.*s\n", (int)result[i]->key_size, result[i]->key, (int)result[i]->value_size, result[i]->value);
/* Free each key-value pair when done */ _tidesdb_free_key_value_pair(result[i]);}
/* Free the result array */free(result);
Transactions
Transactions allow you to perform multiple operations atomically.
Beginning a Transaction
/** Begin a transaction on the 'users' column family* Transactions allow multiple operations to be executed atomically* Either all operations succeed, or none of them are applied*/tidesdb_txn_t *txn = NULL;tidesdb_err_t *err = tidesdb_txn_begin( tdb, /* TidesDB instance */ &txn, /* Transaction pointer */ "users" /* Column family name */);
if (err != NULL) { printf("Error beginning transaction: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Transaction started successfully\n");
/** Adding Operations to a Transaction* We can add multiple operations that will be executed atomically*/
/* Put operation - add or update a user */uint8_t key1[] = "user:1001";uint8_t value1[] = "{\"name\":\"Alice\",\"role\":\"admin\"}";err = tidesdb_txn_put( txn, /* Transaction */ key1, /* Key */ sizeof(key1), /* Key size */ value1, /* Value */ sizeof(value1), /* Value size */ -1 /* TTL */);
if (err != NULL) { printf("Error adding put operation to transaction: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_txn_rollback(txn); tidesdb_txn_free(txn); return 1;}
/* Delete operation - remove a user */uint8_t key2[] = "user:1002";err = tidesdb_txn_delete( txn, /* Transaction */ key2, /* Key */ sizeof(key2) /* Key size */);
if (err != NULL) { printf("Error adding delete operation to transaction: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_txn_rollback(txn); tidesdb_txn_free(txn); return 1;}
Getting a Value in a Transaction
/** Read a value within the transaction context* This allows you to see the effects of previous operations* in the transaction before it is committed*/uint8_t key[] = "user:1001";uint8_t *value_out = NULL;size_t value_len = 0;
err = tidesdb_txn_get( txn, /* Transaction */ key, /* Key */ sizeof(key), /* Key size */ &value_out, /* Output value */ &value_len /* Output value size */);
if (err != NULL) { printf("Error getting value in transaction: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err);} else { printf("Value in transaction: %.*s\n", (int)value_len, value_out); free(value_out); /* Free the allocated memory */}
Committing a Transaction
err = tidesdb_txn_commit(txn);if (err != NULL) { printf("Error committing transaction: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_txn_rollback(txn); tidesdb_txn_free(txn); return 1;}printf("Transaction committed successfully\n");
Rolling Back a Transaction
err = tidesdb_txn_rollback(txn);if (err != NULL) { printf("Error rolling back transaction: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_txn_free(txn); return 1;}printf("Transaction rolled back successfully\n");
Freeing a Transaction
tidesdb_txn_free(txn);
Cursor Operations
Cursors allow you to iterate through key-value pairs in a column family.
Initializing a Cursor
/** Initialize a cursor to iterate through key-value pairs* A cursor allows bi-directional sequential access to the TidesDB isntance contents*/tidesdb_cursor_t *cursor = NULL;tidesdb_err_t *err = tidesdb_cursor_init( tdb, /* TidesDB instance */ "users", /* Column family name */ &cursor /* Cursor pointer */);
if (err != NULL) { printf("Error initializing cursor: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Cursor initialized successfully\n");
Iterating Forward
uint8_t *key = NULL;size_t key_size = 0;uint8_t *value = NULL;size_t value_size = 0;
/* Iterate forward through key-value pairs */do { err = tidesdb_cursor_get( cursor, /* Cursor */ &key, /* Output key */ &key_size, /* Output key size */ &value, /* Output value */ &value_size /* Output value size */ );
if (err != NULL) { printf("Error getting cursor value: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); break; }
printf("Key: %.*s, Value: %.*s\n", (int)key_size, key, (int)value_size, value);
/* Free the key and value when done to prevent memory leaks */ free(key); free(value);} while ((err = tidesdb_cursor_next(cursor)) == NULL);
/** Check if we reached the end of the cursor or if there was an error* TIDESDB_ERR_AT_END_OF_CURSOR is a special error code that indicates* we've processed all items in the TidesDB instance*/if (err != NULL && err->code != TIDESDB_ERR_AT_END_OF_CURSOR) { printf("Error iterating cursor: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err);}
Iterating Backward
/* Iterate backward through key-value pairs */do { err = tidesdb_cursor_get( cursor, /* Cursor */ &key, /* Output key */ &key_size, /* Output key size */ &value, /* Output value */ &value_size /* Output value size */ );
if (err != NULL) { printf("Error getting cursor value: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); break; }
printf("Key: %.*s, Value: %.*s\n", (int)key_size, key, (int)value_size, value);
/* Free the key and value when done */ free(key); free(value);} while ((err = tidesdb_cursor_prev(cursor)) == NULL);
/* Check if we reached the start of the cursor or if there was an error */if (err != NULL && err->code != TIDESDB_ERR_AT_START_OF_CURSOR) { printf("Error iterating cursor: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err);}
Freeing a Cursor
tidesdb_cursor_free(cursor);
Compaction Operations
Manual Compaction
Compacts SSTables to improve read performance and reduce storage space.
tidesdb_err_t *err = tidesdb_compact_sstables( tdb, /* TidesDB instance */ "users", /* Column family name */ 4 /* Number of threads to use for compaction */);
if (err != NULL) { printf("Error compacting SSTables: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("SSTables compacted successfully\n");
Automatic Incremental Compaction
Starts a background thread that incrementally merges SSTables.
tidesdb_err_t *err = tidesdb_start_incremental_merge( tdb, /* TidesDB instance */ "users", /* Column family name */ 30, /* Merge interval in seconds */ 10 /* Minimum number of SSTables to trigger a merge */);
if (err != NULL) { printf("Error starting incremental merge: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Incremental merge started successfully\n");
Range Deletion Operations
Deletes all key-value pairs within a specified range.
uint8_t start_key[] = "session:1000";uint8_t end_key[] = "session:2000";
tidesdb_err_t *err = tidesdb_delete_by_range( tdb, /* TidesDB instance */ "sessions", /* Column family name */ start_key, /* Start key */ sizeof(start_key), /* Start key size */ end_key, /* End key */ sizeof(end_key) /* End key size */);
if (err != NULL) { printf("Error deleting by range: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Range deleted successfully\n");
Deleting by Filter
Deletes all key-value pairs that match a specific filter function.
/* Define a filter function to find expired sessions */bool is_expired_session(const tidesdb_key_value_pair_t *kv) { /* Check if "expired" is in the value */ for (uint32_t i = 0; i <= kv->value_size - 7; i++) { if (memcmp(kv->value + i, "expired", 7) == 0) { return true; } } return false;}
tidesdb_err_t *err = tidesdb_delete_by_filter( tdb, /* TidesDB instance */ "sessions", /* Column family name */ is_expired_session /* Filter function */);
if (err != NULL) { printf("Error deleting by filter: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1;}printf("Filtered items deleted successfully\n");
Complete Example
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <tidesdb/tidesdb.h>
int main() { tidesdb_t *tdb = NULL; tidesdb_err_t *err = NULL;
/* Open a new TidesDB instance */ err = tidesdb_open("./my_tidesdb", &tdb); if (err != NULL) { printf("Error opening TidesDB: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1; } printf("TidesDB opened successfully\n");
/* Create a column family */ err = tidesdb_create_column_family( tdb, "users", (1024 * 1024) * 64, /* 64MB flush threshold */ TDB_DEFAULT_SKIP_LIST_MAX_LEVEL, TDB_DEFAULT_SKIP_LIST_PROBABILITY, true, TDB_COMPRESS_SNAPPY, true );
if (err != NULL) { printf("Error creating column family: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_close(tdb); return 1; } printf("Column family 'users' created successfully\n");
/* Put some key-value pairs */ uint8_t key1[] = "user:1001"; uint8_t value1[] = "{\"name\":\"Alice\",\"email\":\"alice@example.com\"}";
err = tidesdb_put(tdb, "users", key1, sizeof(key1), value1, sizeof(value1), -1); if (err != NULL) { printf("Error putting key-value pair: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_close(tdb); return 1; }
uint8_t key2[] = "user:1002"; uint8_t value2[] = "{\"name\":\"Bob\",\"email\":\"bob@example.com\"}";
err = tidesdb_put(tdb, "users", key2, sizeof(key2), value2, sizeof(value2), -1); if (err != NULL) { printf("Error putting key-value pair: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_close(tdb); return 1; } printf("Key-value pairs stored successfully\n");
/* Get a value */ uint8_t *value_out = NULL; size_t value_len = 0;
err = tidesdb_get(tdb, "users", key1, sizeof(key1), &value_out, &value_len); if (err != NULL) { printf("Error getting key-value pair: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_close(tdb); return 1; }
printf("Retrieved value for user:1001: %.*s\n", (int)value_len, value_out); free(value_out);
/* Use a transaction */ tidesdb_txn_t *txn = NULL; err = tidesdb_txn_begin(tdb, &txn, "users"); if (err != NULL) { printf("Error beginning transaction: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_close(tdb); return 1; }
uint8_t key3[] = "user:1003"; uint8_t value3[] = "{\"name\":\"Charlie\",\"email\":\"charlie@example.com\"}";
err = tidesdb_txn_put(txn, key3, sizeof(key3), value3, sizeof(value3), -1); if (err != NULL) { printf("Error adding put operation to transaction: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_txn_rollback(txn); tidesdb_txn_free(txn); tidesdb_close(tdb); return 1; }
err = tidesdb_txn_commit(txn); if (err != NULL) { printf("Error committing transaction: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_txn_rollback(txn); tidesdb_txn_free(txn); tidesdb_close(tdb); return 1; } printf("Transaction committed successfully\n"); tidesdb_txn_free(txn);
/* Use a cursor to iterate through all key-value pairs */ tidesdb_cursor_t *cursor = NULL; err = tidesdb_cursor_init(tdb, "users", &cursor); if (err != NULL) { printf("Error initializing cursor: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); tidesdb_close(tdb); return 1; }
printf("\nAll users:\n"); uint8_t *key = NULL; size_t key_size = 0; value_out = NULL; value_len = 0;
while ((err = tidesdb_cursor_next(cursor)) == NULL) { err = tidesdb_cursor_get(cursor, &key, &key_size, &value_out, &value_len); if (err != NULL) { printf("Error getting cursor value: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); break; }
printf("Key: %.*s, Value: %.*s\n", (int)key_size, key, (int)value_len, value_out);
free(key); free(value_out); }
if (err != NULL && err->code != TIDESDB_ERR_AT_END_OF_CURSOR) { printf("Error iterating cursor: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); }
tidesdb_cursor_free(cursor);
/* Close TidesDB */ err = tidesdb_close(tdb); if (err != NULL) { printf("Error closing TidesDB: %s (code: %d)\n", err->message, err->code); tidesdb_err_free(err); return 1; } printf("TidesDB closed successfully\n");
return 0;}