Skip to content

Commit da2be14

Browse files
committed
Update to 4.0.1
1 parent f20be78 commit da2be14

File tree

12 files changed

+205
-28
lines changed

12 files changed

+205
-28
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
ObjectBox C and C++ API Changelog
22
=================================
33

4+
4.0.1 (2024-07-17)
5+
------------------
6+
* Query: "visit with score" added, so you can consume vector search results one-by-one with a visitor callback
7+
48
4.0.0 (2024-05-15)
5-
-------------------
9+
------------------
610
* ObjectBox now supports vector search ("vector database") to enable efficient similarity searches.
711
This is particularly useful for AI/ML/RAG applications, e.g. image, audio, or text similarity.
812
Other use cases include semantic search or recommendation engines.

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ else ()
3939

4040
function(defineObjectBoxLib VARIANT)
4141
# Configuration updated for each release
42-
set(DL_VERSION 4.0.0)
42+
set(DL_VERSION 4.0.1)
4343

4444
# Platform detection and other setup
4545
set(DL_URL https://github.com/objectbox/objectbox-c/releases/download)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ box.put({.text = "Buy milk"});
1818
1919
See [ObjectBox C and C++ docs](https://cpp.objectbox.io/) for API details.
2020
21-
**Latest version: 4.0.0** (2024-05-15).
21+
**Latest version: 4.0.1** (2024-07-17).
2222
See [changelog](CHANGELOG.md) for more details.
2323
2424
## Table of Contents:

download.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ tty -s || quiet=true
4444

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

47-
version=${1:-4.0.0}
47+
version=${1:-4.0.1}
4848
os=${2:-$(uname)}
4949
arch=${3:-$(uname -m)}
5050
echo "Base config: OS ${os} and architecture ${arch}"

doxygen/Changelog.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
ObjectBox C and C++ API Changelog
44
=================================
55

6+
4.0.1 (2024-07-17)
7+
------------------
8+
* Query: "visit with score" added, so you can consume vector search results one-by-one with a visitor callback
9+
610
4.0.0 (2024-05-15)
7-
-------------------
11+
------------------
812
* ObjectBox now supports vector search ("vector database") to enable efficient similarity searches.
913
This is particularly useful for AI/ML/RAG applications, e.g. image, audio, or text similarity.
1014
Other use cases include semantic search or recommendation engines.

doxygen/Doxyfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ PROJECT_NAME = "ObjectBox C and C++ API"
3838
# could be handy for archiving the generated documentation or if some version
3939
# control system is used.
4040

41-
PROJECT_NUMBER = "4.0.0"
41+
PROJECT_NUMBER = "4.0.1"
4242

4343
# Using the PROJECT_BRIEF tag one can provide an optional one line description
4444
# for a project that appears at the top of each page and should give viewer a

include/objectbox-sync.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#include "objectbox.h"
3535

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

include/objectbox-sync.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include "objectbox-sync.h"
2020
#include "objectbox.hpp"
2121

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

2525
namespace obx {
@@ -334,6 +334,10 @@ class SyncClient : public Closable {
334334
err = obx_sync_credentials_user_password(cPtr(), creds.type_, creds.username_.c_str(),
335335
creds.password_.c_str());
336336
break;
337+
case OBXSyncCredentialsType_NONE:
338+
case OBXSyncCredentialsType_SHARED_SECRET:
339+
case OBXSyncCredentialsType_SHARED_SECRET_SIPPED:
340+
case OBXSyncCredentialsType_GOOGLE_AUTH:
337341
default:
338342
err = obx_sync_credentials(cPtr(), creds.type_, creds.data_.empty() ? nullptr : creds.data_.data(),
339343
creds.data_.size());

include/objectbox.h

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ extern "C" {
5353
/// obx_version() or obx_version_is_at_least().
5454
#define OBX_VERSION_MAJOR 4
5555
#define OBX_VERSION_MINOR 0
56-
#define OBX_VERSION_PATCH 0 // values >= 100 are reserved for dev releases leading to the next minor/major increase
56+
#define OBX_VERSION_PATCH 1 // values >= 100 are reserved for dev releases leading to the next minor/major increase
5757

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

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

89+
/// The callback for reading data (i.e. object bytes) with a search score one-by-one.
90+
/// @param data contains the current data with score element
91+
/// @param user_data is a pass-through argument passed to the called API
92+
/// @return The visitor returns true to keep going or false to cancel.
93+
typedef bool obx_data_score_visitor(const struct OBX_bytes_score* data, void* user_data);
94+
8995
//----------------------------------------------
9096
// Runtime library information
9197
//
@@ -805,6 +811,15 @@ typedef enum {
805811
OBXBackupFlags_ExcludeSalt = 0x2,
806812
} OBXBackupFlags;
807813

814+
/// WAL flags control how the store handles WAL files.
815+
typedef enum {
816+
/// Enable Wal
817+
OBXWalFlags_EnableWal = 0x1,
818+
819+
/// Does not wait for the disk to acknowledge; faster but not ACID compliant (not generally recommended).
820+
OBXWalFlags_NoSyncFile = 0x2,
821+
} OBXWalFlags;
822+
808823
/// This bytes struct is an input/output wrapper used for a single data object (represented as FlatBuffers).
809824
typedef struct OBX_bytes {
810825
const void* data;
@@ -1087,6 +1102,23 @@ typedef enum {
10871102
/// e.g., to overwrite all existing data in the database.
10881103
OBX_C_API void obx_opt_backup_restore(OBX_store_options* opt, const char* backup_file, uint32_t flags);
10891104

1105+
/// Enables Write-ahead logging (WAL) if OBXWalFlags_EnableWal is given.
1106+
/// For now this is only supported for in-memory DBs.
1107+
/// @param flags OBXWalFlags_EnableWal with optional other flags (bitwise OR).
1108+
OBX_C_API void obx_opt_wal(OBX_store_options* opt, uint32_t flags);
1109+
1110+
/// The WAL file gets consolidated when it reached this size limit when opening the database.
1111+
/// This setting is meant for applications that prefer to consolidate on startup,
1112+
/// which may avoid consolidations on commits while the application is running.
1113+
/// The default is 4096 (4 MB).
1114+
OBX_C_API void obx_opt_wal_max_file_size_on_open_in_kb(OBX_store_options* opt, uint64_t size_in_kb);
1115+
1116+
/// The WAL file gets consolidated when it reaches this size limit after a commit.
1117+
/// As consolidation takes some time, it is a trade-off between accumulating enough data
1118+
/// and the time the consolidation takes (longer with more data).
1119+
/// The default is 16384 (16 MB).
1120+
OBX_C_API void obx_opt_wal_max_file_size_in_kb(OBX_store_options* opt, uint64_t size_in_kb);
1121+
10901122
/// Gets the option for "directory"; this is either the default, or, the value set by obx_opt_directory().
10911123
/// The returned value must not be modified and is only valid for the lifetime of the options or until the value is
10921124
/// changed.
@@ -1235,7 +1267,10 @@ typedef enum {
12351267
OBXStoreTypeId_LMDB = 1,
12361268

12371269
/// Store type ID for in-memory database (non-persistent)
1238-
OBXStoreTypeId_InMemory = 2
1270+
OBXStoreTypeId_InMemory = 2,
1271+
1272+
/// Store type ID for in-memory WAL-enabled (persistent)
1273+
OBXStoreTypeId_InMemoryWal = 3
12391274

12401275
} OBXStoreTypeId;
12411276

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

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

2095+
/// Walk over matching objects with their query score one-by-one using the given data visitor (a callback function).
2096+
/// Note: the elements are ordered by the score (ascending).
2097+
OBX_C_API obx_err obx_query_visit_with_score(OBX_query* query, obx_data_score_visitor* visitor, void* user_data);
2098+
20602099
/// Return the IDs of all matching objects.
20612100
/// Note: if no order conditions is present, the order is arbitrary (sometimes ordered by ID, but never guaranteed to).
20622101
OBX_C_API OBX_id_array* obx_query_find_ids(OBX_query* query);
@@ -2492,6 +2531,29 @@ OBX_C_API obx_id obx_tree_leaves_info_id(OBX_tree_leaves_info* leaves_info, size
24922531
/// Frees a leaves info reference.
24932532
OBX_C_API void obx_tree_leaves_info_free(OBX_tree_leaves_info* leaves_info);
24942533

2534+
/// Callback for obx_tree_async_get_raw().
2535+
/// \note If the given status is an error, you can use functions like obx_last_error_message() to gather more info
2536+
/// during this callback (error state is thread bound and the callback uses an internal thread).
2537+
/// @param status The result status of the async operation
2538+
/// @param id If the operation was successful, the ID of the leaf, which was get (otherwise zero).
2539+
/// @param path The leafs path as string.
2540+
/// @param leaf_data The leafs data flatbuffer pointer.
2541+
/// @param leaf_data_size The leafs data flatbuffer size.
2542+
/// @param leaf_metadata The leafs metadata flatbuffer pointer.
2543+
/// @param leaf_metadata_size The leafs meatdata flatbuffer size.
2544+
/// @param user_data The data initially passed to the async function call is passed back.
2545+
typedef void obx_tree_async_get_callback(obx_err status, obx_id id, const char* path, const void* leaf_data,
2546+
size_t leaf_data_size, const void* leaf_metadata, size_t leaf_metadata_size,
2547+
void* user_data);
2548+
2549+
/// Like obx_tree_cursor_get_raw(), but asynchronous.
2550+
/// @param with_metadata Flag if the callback also wants to receive the metadata (also as raw FlatBuffers).
2551+
/// @param callback Optional (may be null) function that is called with results once the async operation completes.
2552+
/// @param callback_user_data Any value you can supply, which is passed on to the callback (e.g. to identify user
2553+
/// specific context).
2554+
OBX_C_API obx_err obx_tree_async_get_raw(OBX_tree* tree, const char* path, bool with_metadata,
2555+
obx_tree_async_get_callback* callback, void* callback_user_data);
2556+
24952557
/// Callback for obx_tree_async_put_raw().
24962558
/// \note If the given status is an error, you can use functions like obx_last_error_message() to gather more info
24972559
/// during this callback (error state is thread bound and the callback uses an internal thread).

include/objectbox.hpp

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
#include <optional>
3737
#endif
3838

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

4242
#ifdef __clang__
@@ -625,6 +625,32 @@ class Options {
625625
obx_opt_backup_restore(opt, backupFile, flags);
626626
return *this;
627627
}
628+
629+
/// Enables Write-ahead logging (WAL); for now this is only supported for in-memory DBs.
630+
/// @param flags WAL itself is enabled by setting flag OBXWalFlags_EnableWal (also the default parameter value).
631+
/// Combine with other flags using bitwise OR or switch off WAL by passing 0.
632+
Options& wal(uint32_t flags = OBXWalFlags_EnableWal) {
633+
obx_opt_wal(opt, flags);
634+
return *this;
635+
}
636+
637+
/// The WAL file gets consolidated when it reached this size limit when opening the database.
638+
/// This setting is meant for applications that prefer to consolidate on startup,
639+
/// which may avoid consolidations on commits while the application is running.
640+
/// The default is 4096 (4 MB).
641+
Options& walMaxFileSizeOnOpenInKb(uint64_t size_in_kb) {
642+
obx_opt_wal_max_file_size_on_open_in_kb(opt, size_in_kb);
643+
return *this;
644+
}
645+
646+
/// The WAL file gets consolidated when it reaches this size limit after a commit.
647+
/// As consolidation takes some time, it is a trade-off between accumulating enough data
648+
/// and the time the consolidation takes (longer with more data).
649+
/// The default is 16384 (16 MB).
650+
Options& walMaxFileSizeInKb(uint64_t size_in_kb) {
651+
obx_opt_wal_max_file_size_in_kb(opt, size_in_kb);
652+
return *this;
653+
}
628654
};
629655

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

21222148
std::vector<std::pair<obx_id, double>> result(cResult->count);
2123-
for (int i = 0; i < cResult->count; ++i) {
2149+
for (size_t i = 0; i < cResult->count; ++i) {
21242150
std::pair<obx_id, double>& entry = result[i];
21252151
const OBX_id_score& idScore = cResult->ids_scores[i];
21262152
entry.first = idScore.id;
@@ -2135,8 +2161,23 @@ class QueryBase {
21352161
/// Find object IDs matching the query ordered by their query score (e.g. distance in NN search).
21362162
/// The resulting array is sorted by score in ascending order (unlike findIds()).
21372163
/// Unlike findIdsWithScores(), this method returns a simple vector of IDs without scores.
2138-
std::vector<obx_id> findIdsByScore() {
2139-
return internal::idVectorOrThrow(obx_query_find_ids_by_score(cQuery_));
2164+
std::vector<obx_id> findIdsByScore() { return internal::idVectorOrThrow(obx_query_find_ids_by_score(cQuery_)); }
2165+
2166+
/// Walk over matching objects one-by-one using the given data visitor (C-style callback function with user data).
2167+
/// Note: if no order conditions is present, the order is arbitrary (sometimes ordered by ID, but never guaranteed
2168+
/// to).
2169+
void visit(obx_data_visitor* visitor, void* userData) {
2170+
OBX_VERIFY_STATE(cQuery_);
2171+
obx_err err = obx_query_visit(cQuery_, visitor, userData);
2172+
internal::checkErrOrThrow(err);
2173+
}
2174+
2175+
/// Walk over matching objects one-by-one using the given data visitor (C-style callback function with user data).
2176+
/// Note: the elements are ordered by the score.
2177+
void visitWithScore(obx_data_score_visitor* visitor, void* userData) {
2178+
OBX_VERIFY_STATE(cQuery_);
2179+
obx_err err = obx_query_visit_with_score(cQuery_, visitor, userData);
2180+
internal::checkErrOrThrow(err);
21402181
}
21412182

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

3153-
using AsyncTreePutCallback = std::function<void(const AsyncTreePutResult& result)>;
3194+
struct AsyncTreeGetResult {
3195+
std::string path; ///< Path of leaf
3196+
obx_err status; ///< OBX_SUCCESS or OBX_NOT_FOUND if operation did not succeed
3197+
3198+
obx_id id; ///< ID of the leaf that was get if operation succeeded or 0 if not found
3199+
OBX_bytes leaf_data; ///< Leaf data if operation succeeded
3200+
OBX_bytes leaf_metadata; ///< Leaf metadata if operation succeeded
3201+
3202+
std::string errorMessage; ///< Non-empty if an error occurred (result is "Undefined")
3203+
3204+
///@returns true if the operation was successful.
3205+
inline bool isSuccess() { return status == OBX_SUCCESS; }
3206+
3207+
/// Alternative to checking error codes: throw an exception instead.
3208+
/// Note that this will always throw, so you should at least check for a successful outcome, e.g. via isSuccess().
3209+
[[noreturn]] void throwException() { internal::throwError(status, "Async tree get failed: " + errorMessage); }
3210+
};
31543211

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

3254+
/// \brief A get operation for a tree leaf,
3255+
/// @param withMetadata Flag if the callback also wants to receive the metadata (also as raw FlatBuffers).
3256+
/// @param callback Once the operation has completed (successfully or not), the callback is called with
3257+
/// AsyncTreeGetResult.
3258+
void getAsync(const char* path, bool withMetadata, AsyncTreeGetCallback callback);
3259+
3260+
/// Like getAsync(), but the callback uses a C function ptr and user data instead of a std::function wrapper.
3261+
/// @param withMetadata Flag if the callback also wants to receive the metadata (also as raw FlatBuffers).
3262+
void getAsyncRawCallback(const char* path, bool withMetadata, obx_tree_async_get_callback* callback,
3263+
void* callback_user_data = nullptr);
3264+
31953265
/// \brief A "low-level" put operation for a tree leaf using given raw FlatBuffer bytes.
31963266
/// Any non-existing branches and meta nodes are put on the fly if an optional meta-leaf FlatBuffers is given.
31973267
/// A typical usage pattern is to first try without the meta-leaf, and if it does not work, create the meta-leaf and
@@ -3263,6 +3333,12 @@ void Tree::putAsyncRawCallback(const char* path, void* data, size_t size, OBXPro
32633333
internal::checkErrOrThrow(err);
32643334
}
32653335

3336+
void Tree::getAsyncRawCallback(const char* path, bool withMetadata, obx_tree_async_get_callback* callback,
3337+
void* callback_user_data) {
3338+
obx_err err = obx_tree_async_get_raw(cTree_, path, withMetadata, callback, callback_user_data);
3339+
internal::checkErrOrThrow(err);
3340+
}
3341+
32663342
namespace {
32673343
void cCallbackTrampolineAsyncTreePut(obx_err status, obx_id id, void* userData) {
32683344
assert(userData);
@@ -3272,6 +3348,17 @@ void cCallbackTrampolineAsyncTreePut(obx_err status, obx_id id, void* userData)
32723348
AsyncTreePutResult result{internal::mapErrorToTreePutResult(status), status, id, std::move(errorMessage)};
32733349
(*callback)(result);
32743350
}
3351+
void cCallbackTrampolineAsyncTreeGet(obx_err status, obx_id id, const char* path, const void* leaf_data,
3352+
size_t leaf_data_size, const void* leaf_metadata, size_t leaf_metadata_size,
3353+
void* userData) {
3354+
assert(userData);
3355+
std::unique_ptr<AsyncTreeGetCallback> callback(static_cast<AsyncTreeGetCallback*>(userData));
3356+
std::string errorMessage;
3357+
if (status != OBX_SUCCESS) internal::appendLastErrorText(status, errorMessage);
3358+
AsyncTreeGetResult result{
3359+
path, status, id, {leaf_data, leaf_data_size}, {leaf_metadata, leaf_metadata_size}, std::move(errorMessage)};
3360+
(*callback)(result);
3361+
}
32753362
} // namespace
32763363

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

3380+
void Tree::getAsync(const char* path, bool withMetadata,
3381+
std::function<void(const AsyncTreeGetResult& result)> callback) {
3382+
auto funPtr = new std::function<void(const AsyncTreeGetResult&)>(std::move(callback));
3383+
obx_tree_async_get_callback* cCallback = cCallbackTrampolineAsyncTreeGet;
3384+
obx_err err = obx_tree_async_get_raw(cTree_, path, withMetadata, cCallback, funPtr);
3385+
internal::checkErrOrThrow(err);
3386+
}
3387+
32933388
#endif
32943389

32953390
class TreeCursor;

0 commit comments

Comments
 (0)