Skip to content

Commit

Permalink
Update to 4.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
greenrobot committed Jul 17, 2024
1 parent f20be78 commit da2be14
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 28 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
ObjectBox C and C++ API Changelog
=================================

4.0.1 (2024-07-17)
------------------
* Query: "visit with score" added, so you can consume vector search results one-by-one with a visitor callback

4.0.0 (2024-05-15)
-------------------
------------------
* ObjectBox now supports vector search ("vector database") to enable efficient similarity searches.
This is particularly useful for AI/ML/RAG applications, e.g. image, audio, or text similarity.
Other use cases include semantic search or recommendation engines.
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ else ()

function(defineObjectBoxLib VARIANT)
# Configuration updated for each release
set(DL_VERSION 4.0.0)
set(DL_VERSION 4.0.1)

# Platform detection and other setup
set(DL_URL https://github.com/objectbox/objectbox-c/releases/download)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ box.put({.text = "Buy milk"});
See [ObjectBox C and C++ docs](https://cpp.objectbox.io/) for API details.
**Latest version: 4.0.0** (2024-05-15).
**Latest version: 4.0.1** (2024-07-17).
See [changelog](CHANGELOG.md) for more details.
## Table of Contents:
Expand Down
2 changes: 1 addition & 1 deletion download.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ tty -s || quiet=true

# Note: optional arguments like "--quiet" shifts argument positions in the case block above

version=${1:-4.0.0}
version=${1:-4.0.1}
os=${2:-$(uname)}
arch=${3:-$(uname -m)}
echo "Base config: OS ${os} and architecture ${arch}"
Expand Down
6 changes: 5 additions & 1 deletion doxygen/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
ObjectBox C and C++ API Changelog
=================================

4.0.1 (2024-07-17)
------------------
* Query: "visit with score" added, so you can consume vector search results one-by-one with a visitor callback

4.0.0 (2024-05-15)
-------------------
------------------
* ObjectBox now supports vector search ("vector database") to enable efficient similarity searches.
This is particularly useful for AI/ML/RAG applications, e.g. image, audio, or text similarity.
Other use cases include semantic search or recommendation engines.
Expand Down
2 changes: 1 addition & 1 deletion doxygen/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ PROJECT_NAME = "ObjectBox C and C++ API"
# could be handy for archiving the generated documentation or if some version
# control system is used.

PROJECT_NUMBER = "4.0.0"
PROJECT_NUMBER = "4.0.1"

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
Expand Down
2 changes: 1 addition & 1 deletion include/objectbox-sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "objectbox.h"

#if defined(static_assert) || defined(__cplusplus)
static_assert(OBX_VERSION_MAJOR == 4 && OBX_VERSION_MINOR == 0 && OBX_VERSION_PATCH == 0, // NOLINT
static_assert(OBX_VERSION_MAJOR == 4 && OBX_VERSION_MINOR == 0 && OBX_VERSION_PATCH == 1, // NOLINT
"Versions of objectbox.h and objectbox-sync.h files do not match, please update");
#endif

Expand Down
6 changes: 5 additions & 1 deletion include/objectbox-sync.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include "objectbox-sync.h"
#include "objectbox.hpp"

static_assert(OBX_VERSION_MAJOR == 4 && OBX_VERSION_MINOR == 0 && OBX_VERSION_PATCH == 0, // NOLINT
static_assert(OBX_VERSION_MAJOR == 4 && OBX_VERSION_MINOR == 0 && OBX_VERSION_PATCH == 1, // NOLINT
"Versions of objectbox.h and objectbox-sync.hpp files do not match, please update");

namespace obx {
Expand Down Expand Up @@ -334,6 +334,10 @@ class SyncClient : public Closable {
err = obx_sync_credentials_user_password(cPtr(), creds.type_, creds.username_.c_str(),
creds.password_.c_str());
break;
case OBXSyncCredentialsType_NONE:
case OBXSyncCredentialsType_SHARED_SECRET:
case OBXSyncCredentialsType_SHARED_SECRET_SIPPED:
case OBXSyncCredentialsType_GOOGLE_AUTH:
default:
err = obx_sync_credentials(cPtr(), creds.type_, creds.data_.empty() ? nullptr : creds.data_.data(),
creds.data_.size());
Expand Down
72 changes: 67 additions & 5 deletions include/objectbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ extern "C" {
/// obx_version() or obx_version_is_at_least().
#define OBX_VERSION_MAJOR 4
#define OBX_VERSION_MINOR 0
#define OBX_VERSION_PATCH 0 // values >= 100 are reserved for dev releases leading to the next minor/major increase
#define OBX_VERSION_PATCH 1 // values >= 100 are reserved for dev releases leading to the next minor/major increase

//----------------------------------------------
// Common types
Expand All @@ -79,13 +79,19 @@ typedef struct OBX_id_score {
/// Error/success code returned by an obx_* function; see defines OBX_SUCCESS, OBX_NOT_FOUND, and OBX_ERROR_*
typedef int obx_err;

/// The callback for reading data one-by-one
/// The callback for reading data (i.e. object bytes) one-by-one.
/// @param data is the read data buffer
/// @param size specifies the length of the read data
/// @param user_data is a pass-through argument passed to the called API
/// @return true to keep going, false to cancel.
/// @return The visitor returns true to keep going or false to cancel.
typedef bool obx_data_visitor(const void* data, size_t size, void* user_data);

/// The callback for reading data (i.e. object bytes) with a search score one-by-one.
/// @param data contains the current data with score element
/// @param user_data is a pass-through argument passed to the called API
/// @return The visitor returns true to keep going or false to cancel.
typedef bool obx_data_score_visitor(const struct OBX_bytes_score* data, void* user_data);

//----------------------------------------------
// Runtime library information
//
Expand Down Expand Up @@ -805,6 +811,15 @@ typedef enum {
OBXBackupFlags_ExcludeSalt = 0x2,
} OBXBackupFlags;

/// WAL flags control how the store handles WAL files.
typedef enum {
/// Enable Wal
OBXWalFlags_EnableWal = 0x1,

/// Does not wait for the disk to acknowledge; faster but not ACID compliant (not generally recommended).
OBXWalFlags_NoSyncFile = 0x2,
} OBXWalFlags;

/// This bytes struct is an input/output wrapper used for a single data object (represented as FlatBuffers).
typedef struct OBX_bytes {
const void* data;
Expand Down Expand Up @@ -1087,6 +1102,23 @@ typedef enum {
/// e.g., to overwrite all existing data in the database.
OBX_C_API void obx_opt_backup_restore(OBX_store_options* opt, const char* backup_file, uint32_t flags);

/// Enables Write-ahead logging (WAL) if OBXWalFlags_EnableWal is given.
/// For now this is only supported for in-memory DBs.
/// @param flags OBXWalFlags_EnableWal with optional other flags (bitwise OR).
OBX_C_API void obx_opt_wal(OBX_store_options* opt, uint32_t flags);

/// The WAL file gets consolidated when it reached this size limit when opening the database.
/// This setting is meant for applications that prefer to consolidate on startup,
/// which may avoid consolidations on commits while the application is running.
/// The default is 4096 (4 MB).
OBX_C_API void obx_opt_wal_max_file_size_on_open_in_kb(OBX_store_options* opt, uint64_t size_in_kb);

/// The WAL file gets consolidated when it reaches this size limit after a commit.
/// As consolidation takes some time, it is a trade-off between accumulating enough data
/// and the time the consolidation takes (longer with more data).
/// The default is 16384 (16 MB).
OBX_C_API void obx_opt_wal_max_file_size_in_kb(OBX_store_options* opt, uint64_t size_in_kb);

/// Gets the option for "directory"; this is either the default, or, the value set by obx_opt_directory().
/// The returned value must not be modified and is only valid for the lifetime of the options or until the value is
/// changed.
Expand Down Expand Up @@ -1235,7 +1267,10 @@ typedef enum {
OBXStoreTypeId_LMDB = 1,

/// Store type ID for in-memory database (non-persistent)
OBXStoreTypeId_InMemory = 2
OBXStoreTypeId_InMemory = 2,

/// Store type ID for in-memory WAL-enabled (persistent)
OBXStoreTypeId_InMemoryWal = 3

} OBXStoreTypeId;

Expand Down Expand Up @@ -2053,10 +2088,14 @@ OBX_C_API obx_err obx_query_find_first(OBX_query* query, const void** data, size
/// operation (e.g. put/remove) was executed. Accessing data after this is undefined behavior.
OBX_C_API obx_err obx_query_find_unique(OBX_query* query, const void** data, size_t* size);

/// Walk over matching objects using the given data visitor.
/// Walk over matching objects one-by-one using the given data visitor (a callback function).
/// Note: if no order conditions is present, the order is arbitrary (sometimes ordered by ID, but never guaranteed to).
OBX_C_API obx_err obx_query_visit(OBX_query* query, obx_data_visitor* visitor, void* user_data);

/// Walk over matching objects with their query score one-by-one using the given data visitor (a callback function).
/// Note: the elements are ordered by the score (ascending).
OBX_C_API obx_err obx_query_visit_with_score(OBX_query* query, obx_data_score_visitor* visitor, void* user_data);

/// Return the IDs of all matching objects.
/// Note: if no order conditions is present, the order is arbitrary (sometimes ordered by ID, but never guaranteed to).
OBX_C_API OBX_id_array* obx_query_find_ids(OBX_query* query);
Expand Down Expand Up @@ -2492,6 +2531,29 @@ OBX_C_API obx_id obx_tree_leaves_info_id(OBX_tree_leaves_info* leaves_info, size
/// Frees a leaves info reference.
OBX_C_API void obx_tree_leaves_info_free(OBX_tree_leaves_info* leaves_info);

/// Callback for obx_tree_async_get_raw().
/// \note If the given status is an error, you can use functions like obx_last_error_message() to gather more info
/// during this callback (error state is thread bound and the callback uses an internal thread).
/// @param status The result status of the async operation
/// @param id If the operation was successful, the ID of the leaf, which was get (otherwise zero).
/// @param path The leafs path as string.
/// @param leaf_data The leafs data flatbuffer pointer.
/// @param leaf_data_size The leafs data flatbuffer size.
/// @param leaf_metadata The leafs metadata flatbuffer pointer.
/// @param leaf_metadata_size The leafs meatdata flatbuffer size.
/// @param user_data The data initially passed to the async function call is passed back.
typedef void obx_tree_async_get_callback(obx_err status, obx_id id, const char* path, const void* leaf_data,
size_t leaf_data_size, const void* leaf_metadata, size_t leaf_metadata_size,
void* user_data);

/// Like obx_tree_cursor_get_raw(), but asynchronous.
/// @param with_metadata Flag if the callback also wants to receive the metadata (also as raw FlatBuffers).
/// @param callback Optional (may be null) function that is called with results once the async operation completes.
/// @param callback_user_data Any value you can supply, which is passed on to the callback (e.g. to identify user
/// specific context).
OBX_C_API obx_err obx_tree_async_get_raw(OBX_tree* tree, const char* path, bool with_metadata,
obx_tree_async_get_callback* callback, void* callback_user_data);

/// Callback for obx_tree_async_put_raw().
/// \note If the given status is an error, you can use functions like obx_last_error_message() to gather more info
/// during this callback (error state is thread bound and the callback uses an internal thread).
Expand Down
105 changes: 100 additions & 5 deletions include/objectbox.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#include <optional>
#endif

static_assert(OBX_VERSION_MAJOR == 4 && OBX_VERSION_MINOR == 0 && OBX_VERSION_PATCH == 0, // NOLINT
static_assert(OBX_VERSION_MAJOR == 4 && OBX_VERSION_MINOR == 0 && OBX_VERSION_PATCH == 1, // NOLINT
"Versions of objectbox.h and objectbox.hpp files do not match, please update");

#ifdef __clang__
Expand Down Expand Up @@ -625,6 +625,32 @@ class Options {
obx_opt_backup_restore(opt, backupFile, flags);
return *this;
}

/// Enables Write-ahead logging (WAL); for now this is only supported for in-memory DBs.
/// @param flags WAL itself is enabled by setting flag OBXWalFlags_EnableWal (also the default parameter value).
/// Combine with other flags using bitwise OR or switch off WAL by passing 0.
Options& wal(uint32_t flags = OBXWalFlags_EnableWal) {
obx_opt_wal(opt, flags);
return *this;
}

/// The WAL file gets consolidated when it reached this size limit when opening the database.
/// This setting is meant for applications that prefer to consolidate on startup,
/// which may avoid consolidations on commits while the application is running.
/// The default is 4096 (4 MB).
Options& walMaxFileSizeOnOpenInKb(uint64_t size_in_kb) {
obx_opt_wal_max_file_size_on_open_in_kb(opt, size_in_kb);
return *this;
}

/// The WAL file gets consolidated when it reaches this size limit after a commit.
/// As consolidation takes some time, it is a trade-off between accumulating enough data
/// and the time the consolidation takes (longer with more data).
/// The default is 16384 (16 MB).
Options& walMaxFileSizeInKb(uint64_t size_in_kb) {
obx_opt_wal_max_file_size_in_kb(opt, size_in_kb);
return *this;
}
};

/// Transactions can be started in read (only) or write mode.
Expand Down Expand Up @@ -2120,7 +2146,7 @@ class QueryBase {
if (!cResult) internal::throwLastError();

std::vector<std::pair<obx_id, double>> result(cResult->count);
for (int i = 0; i < cResult->count; ++i) {
for (size_t i = 0; i < cResult->count; ++i) {
std::pair<obx_id, double>& entry = result[i];
const OBX_id_score& idScore = cResult->ids_scores[i];
entry.first = idScore.id;
Expand All @@ -2135,8 +2161,23 @@ class QueryBase {
/// Find object IDs matching the query ordered by their query score (e.g. distance in NN search).
/// The resulting array is sorted by score in ascending order (unlike findIds()).
/// Unlike findIdsWithScores(), this method returns a simple vector of IDs without scores.
std::vector<obx_id> findIdsByScore() {
return internal::idVectorOrThrow(obx_query_find_ids_by_score(cQuery_));
std::vector<obx_id> findIdsByScore() { return internal::idVectorOrThrow(obx_query_find_ids_by_score(cQuery_)); }

/// Walk over matching objects one-by-one using the given data visitor (C-style callback function with user data).
/// Note: if no order conditions is present, the order is arbitrary (sometimes ordered by ID, but never guaranteed
/// to).
void visit(obx_data_visitor* visitor, void* userData) {
OBX_VERIFY_STATE(cQuery_);
obx_err err = obx_query_visit(cQuery_, visitor, userData);
internal::checkErrOrThrow(err);
}

/// Walk over matching objects one-by-one using the given data visitor (C-style callback function with user data).
/// Note: the elements are ordered by the score.
void visitWithScore(obx_data_score_visitor* visitor, void* userData) {
OBX_VERIFY_STATE(cQuery_);
obx_err err = obx_query_visit_with_score(cQuery_, visitor, userData);
internal::checkErrOrThrow(err);
}

/// Returns the number of matching objects.
Expand Down Expand Up @@ -3150,8 +3191,26 @@ struct AsyncTreePutResult {
[[noreturn]] void throwException() { internal::throwError(status, "Async tree put failed: " + errorMessage); }
};

using AsyncTreePutCallback = std::function<void(const AsyncTreePutResult& result)>;
struct AsyncTreeGetResult {
std::string path; ///< Path of leaf
obx_err status; ///< OBX_SUCCESS or OBX_NOT_FOUND if operation did not succeed

obx_id id; ///< ID of the leaf that was get if operation succeeded or 0 if not found
OBX_bytes leaf_data; ///< Leaf data if operation succeeded
OBX_bytes leaf_metadata; ///< Leaf metadata if operation succeeded

std::string errorMessage; ///< Non-empty if an error occurred (result is "Undefined")

///@returns true if the operation was successful.
inline bool isSuccess() { return status == OBX_SUCCESS; }

/// Alternative to checking error codes: throw an exception instead.
/// Note that this will always throw, so you should at least check for a successful outcome, e.g. via isSuccess().
[[noreturn]] void throwException() { internal::throwError(status, "Async tree get failed: " + errorMessage); }
};

using AsyncTreePutCallback = std::function<void(const AsyncTreePutResult& result)>;
using AsyncTreeGetCallback = std::function<void(const AsyncTreeGetResult& result)>;
/// @brief Top level tree API representing a tree structure/schema associated with a store.
///
/// Data is accessed via TreeCursor.
Expand Down Expand Up @@ -3192,6 +3251,17 @@ class Tree {
/// Returns the leaf name of the given path (the string component after the last path delimiter).
std::string getLeafName(const std::string& path) const;

/// \brief A get operation for a tree leaf,
/// @param withMetadata Flag if the callback also wants to receive the metadata (also as raw FlatBuffers).
/// @param callback Once the operation has completed (successfully or not), the callback is called with
/// AsyncTreeGetResult.
void getAsync(const char* path, bool withMetadata, AsyncTreeGetCallback callback);

/// Like getAsync(), but the callback uses a C function ptr and user data instead of a std::function wrapper.
/// @param withMetadata Flag if the callback also wants to receive the metadata (also as raw FlatBuffers).
void getAsyncRawCallback(const char* path, bool withMetadata, obx_tree_async_get_callback* callback,
void* callback_user_data = nullptr);

/// \brief A "low-level" put operation for a tree leaf using given raw FlatBuffer bytes.
/// Any non-existing branches and meta nodes are put on the fly if an optional meta-leaf FlatBuffers is given.
/// A typical usage pattern is to first try without the meta-leaf, and if it does not work, create the meta-leaf and
Expand Down Expand Up @@ -3263,6 +3333,12 @@ void Tree::putAsyncRawCallback(const char* path, void* data, size_t size, OBXPro
internal::checkErrOrThrow(err);
}

void Tree::getAsyncRawCallback(const char* path, bool withMetadata, obx_tree_async_get_callback* callback,
void* callback_user_data) {
obx_err err = obx_tree_async_get_raw(cTree_, path, withMetadata, callback, callback_user_data);
internal::checkErrOrThrow(err);
}

namespace {
void cCallbackTrampolineAsyncTreePut(obx_err status, obx_id id, void* userData) {
assert(userData);
Expand All @@ -3272,6 +3348,17 @@ void cCallbackTrampolineAsyncTreePut(obx_err status, obx_id id, void* userData)
AsyncTreePutResult result{internal::mapErrorToTreePutResult(status), status, id, std::move(errorMessage)};
(*callback)(result);
}
void cCallbackTrampolineAsyncTreeGet(obx_err status, obx_id id, const char* path, const void* leaf_data,
size_t leaf_data_size, const void* leaf_metadata, size_t leaf_metadata_size,
void* userData) {
assert(userData);
std::unique_ptr<AsyncTreeGetCallback> callback(static_cast<AsyncTreeGetCallback*>(userData));
std::string errorMessage;
if (status != OBX_SUCCESS) internal::appendLastErrorText(status, errorMessage);
AsyncTreeGetResult result{
path, status, id, {leaf_data, leaf_data_size}, {leaf_metadata, leaf_metadata_size}, std::move(errorMessage)};
(*callback)(result);
}
} // namespace

void Tree::putAsync(const char* path, void* data, size_t size, OBXPropertyType type, void* metadata,
Expand All @@ -3290,6 +3377,14 @@ void Tree::consolidateNodeConflictsAsync() {
internal::checkErrOrThrow(err);
}

void Tree::getAsync(const char* path, bool withMetadata,
std::function<void(const AsyncTreeGetResult& result)> callback) {
auto funPtr = new std::function<void(const AsyncTreeGetResult&)>(std::move(callback));
obx_tree_async_get_callback* cCallback = cCallbackTrampolineAsyncTreeGet;
obx_err err = obx_tree_async_get_raw(cTree_, path, withMetadata, cCallback, funPtr);
internal::checkErrOrThrow(err);
}

#endif

class TreeCursor;
Expand Down
Loading

0 comments on commit da2be14

Please sign in to comment.