A lightweight, thread-safe key-value database manager written in C, designed for embedded systems and applications requiring both volatile (RAM) and non-volatile memory (NVM) storage capabilities.
- Dual Storage Support: Store data in either RAM or Non-Volatile Memory (NVM)
- Thread-Safe: Built-in mutex support for concurrent access
- Configurable: Customizable database size and value length limits
- Lightweight: Minimal memory footprint suitable for embedded systems
- Zero Dependencies: No external libraries required for core functionality
- Caching: Automatic caching of NVM entries in RAM for faster access
- Mock Support: Includes mock implementation for testing
The k_dbm library implements a hybrid storage architecture:
- RAM Storage: Fast access, volatile data
- NVM Storage: Persistent data with automatic RAM caching
- Thread Safety: Configurable mutex operations for multi-threaded environments
Define the database parameters at compile time:
#define K_DBM_DB_SIZE 100 // Maximum number of entries
#define K_DBM_VALUE_MAX_LENGTH 256 // Maximum value length in bytesImplement the required callback functions:
#include "k_dbm.h"
// Mutex operations
int my_mutex_lock(int timeout_ms) {
// Your mutex lock implementation
return 0; // Success
}
void my_mutex_unlock(void) {
// Your mutex unlock implementation
}
// NVM operations
int my_nvm_insert(const char *key, const char *value) {
// Your NVM insert implementation
return 0; // Success
}
int my_nvm_get(const char *key, char *value, size_t value_buffer_size) {
// Your NVM get implementation
return 0; // Success
}
int my_nvm_delete(const char *key) {
// Your NVM delete implementation
return 0; // Success
}k_dbm_config_t config = {
.k_dbm_lock_mutex_f = my_mutex_lock,
.k_dbm_unlock_mutex_f = my_mutex_unlock,
.k_dbm_insert_f = my_nvm_insert,
.k_dbm_get_f = my_nvm_get,
.k_dbm_delete_f = my_nvm_delete
};
if (k_dbm_init(&config) == 0) {
// Database manager initialized successfully
}// Insert data
k_dbm_insert("temperature", "25.5", K_DBM_STORAGE_RAM);
k_dbm_insert("device_id", "ESP32_001", K_DBM_STORAGE_NVM);
// Retrieve data
char value[K_DBM_VALUE_MAX_LENGTH];
if (k_dbm_get("temperature", value, sizeof(value)) == 0) {
printf("Temperature: %s°C\n", value);
}
// Delete data
k_dbm_delete("temperature");
// Check free space
size_t free_entries = k_dbm_get_free_space();
printf("Free entries: %zu\n", free_entries);Initializes the database manager with the provided configuration.
Parameters:
config_p: Pointer to configuration structure containing callback functions
Returns:
0on success-1on failure (NULL config or missing callbacks)
Inserts or updates a key-value pair.
Parameters:
key_p: Entry key (null-terminated string)value_p: Entry value (null-terminated string)storage: Storage type (K_DBM_STORAGE_RAMorK_DBM_STORAGE_NVM)
Returns:
0on success-1on failure
Retrieves a value by key.
Parameters:
key_p: Key to search forvalue_buffer_p: Buffer to store the retrieved valuevalue_buffer_size: Size of the value buffer
Returns:
0on success-1on failure (key not found or buffer too small)
Deletes a key-value pair.
Parameters:
key_p: Key to delete
Returns:
0on success-1on failure
Returns the number of free entries in the database.
Returns: Number of available entries
typedef enum {
K_DBM_STORAGE_NONE, // Internal use only
K_DBM_STORAGE_RAM, // Volatile storage
K_DBM_STORAGE_NVM // Non-volatile storage (also cached in RAM)
} k_dbm_storage_t;For development (includes tests):
mkdir build && cd build
cmake .. -DK_DBM_DEV=ON -DK_DBM_DB_SIZE=100 -DK_DBM_VALUE_MAX_LENGTH=256
makeInclude the library in your project using the provided CMake module:
include(path/to/k_dbm.cmake)
k_dbm_get_sources(K_DBM_SOURCES)
k_dbm_get_public_headers(K_DBM_PUBLIC_HEADERS)
add_library(my_app ${K_DBM_SOURCES} main.c)
target_include_directories(my_app PRIVATE ${K_DBM_PUBLIC_HEADERS})
target_compile_definitions(my_app PRIVATE
K_DBM_DB_SIZE=100
K_DBM_VALUE_MAX_LENGTH=256
)The project includes comprehensive unit tests using Google Test framework:
# Build and run tests
cd build
make
ctest --verboseTests cover:
- Initialization scenarios
- Insert/Update operations
- Retrieval operations
- Delete operations
- Thread safety
- Storage type handling
- Error conditions
For testing applications that use k_dbm, a mock library is provided using the FFF (Fake Function Framework):
#include "k_dbm_mock.h"
// Use mocked functions in your tests
FAKE_VALUE_FUNC(int, k_dbm_init, const k_dbm_config_t*);
FAKE_VALUE_FUNC(int, k_dbm_insert, const char*, const char*, k_dbm_storage_t);| Definition | Description | Required |
|---|---|---|
K_DBM_DB_SIZE |
Maximum number of database entries | Yes |
K_DBM_VALUE_MAX_LENGTH |
Maximum length of values in bytes | Yes |
The k_dbm_config_t structure must provide:
k_dbm_lock_mutex_f: Mutex locking functionk_dbm_unlock_mutex_f: Mutex unlocking functionk_dbm_insert_f: NVM insert functionk_dbm_get_f: NVM get functionk_dbm_delete_f: NVM delete function
k_dbm is designed to be thread-safe when proper mutex implementations are provided. All operations are protected by the configured mutex functions.
- Keys must be persistent string pointers (they are not copied internally)
- Maximum database size is fixed at compile time
- No dynamic memory allocation
- Single database instance per application
- Open a new issue
- Create a branch
- Add tests
- Ensure all tests pass
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.