Skip to content

introduce ndarr support #98

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 123 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
87aa240
c client nd array begin.
kafka1991 Apr 1, 2025
6bd3223
Ndarray support for rust client.
kafka1991 Apr 2, 2025
b518a99
optimize doc.
kafka1991 Apr 2, 2025
53a430e
add tests.
kafka1991 Apr 2, 2025
b1ebd1d
fix comments.
kafka1991 Apr 2, 2025
006af98
fix docs.
kafka1991 Apr 3, 2025
a31716a
fix tests and compile error in ffi.
kafka1991 Apr 3, 2025
463a2d3
format code.
kafka1991 Apr 3, 2025
44fae08
ffi supported
kafka1991 Apr 3, 2025
93c6f9d
ndarray c api
kafka1991 Apr 3, 2025
e9da558
format
kafka1991 Apr 3, 2025
0e8a9e5
c++ api support.
kafka1991 Apr 3, 2025
261163c
add include.
kafka1991 Apr 3, 2025
a565109
code format.
kafka1991 Apr 3, 2025
d1edbbc
Merge remote-tracking branch 'origin/main' into array
kafka1991 Apr 6, 2025
e161b1d
conflict resolve
kafka1991 Apr 6, 2025
4a59ec0
code review.
kafka1991 Apr 7, 2025
0c513b1
code format.
kafka1991 Apr 7, 2025
4a58346
c example
kafka1991 Apr 7, 2025
1a6cf6f
make mock.rs recv works.
kafka1991 Apr 7, 2025
9caed7a
easier pre-ci 'proj' script to build lint and test changes
amunra Apr 7, 2025
c2583f1
c api add strides.
kafka1991 Apr 7, 2025
0476faf
add strideArrayView for rust array ingress api
kafka1991 Apr 8, 2025
31e57c5
add strideArrayView for rust array ingress api
kafka1991 Apr 8, 2025
533224a
add benchmark test.
kafka1991 Apr 8, 2025
8d30e57
fix tests
kafka1991 Apr 9, 2025
36203a6
better memory copy.
kafka1991 Apr 9, 2025
feaf5be
code format
kafka1991 Apr 9, 2025
c4bed10
make c api works.
kafka1991 Apr 9, 2025
f3011e1
make c api works.
kafka1991 Apr 9, 2025
70eaa24
code format
kafka1991 Apr 9, 2025
526e8ae
make c++ tests work.
kafka1991 Apr 9, 2025
9c16d74
fix compile error.
kafka1991 Apr 9, 2025
5dae9d0
make c++20 build happy
kafka1991 Apr 9, 2025
ea52293
code format
kafka1991 Apr 9, 2025
193b887
fix cpp problem on windows.
kafka1991 Apr 10, 2025
523a855
lint issues
amunra Apr 10, 2025
3442cbe
introduce line protocol version
kafka1991 Apr 14, 2025
2b927ae
support https
kafka1991 May 5, 2025
edb40fc
code format.
kafka1991 May 5, 2025
c9f1476
implement NDArrayView for common built-in array, vector and slices.
kafka1991 May 6, 2025
a883112
code format
kafka1991 May 6, 2025
f3e8681
add tests for build-in array,vector and slice.
kafka1991 May 6, 2025
1ee3b58
add line protocol version tests for rust client.
kafka1991 May 6, 2025
d34c651
make line protocol version c++ interface more ideamatic
kafka1991 May 6, 2025
9c78839
fix build failure.
kafka1991 May 6, 2025
ced8e05
fix little comment
kafka1991 May 6, 2025
ef8ab61
add system_test.
kafka1991 May 7, 2025
ed3fc06
add more system array tests
kafka1991 May 7, 2025
3839403
code format
kafka1991 May 7, 2025
33767f3
better c/cpp array examples.
kafka1991 May 7, 2025
6e8d77e
fix test.py
kafka1991 May 7, 2025
6168e7f
add array example tests.
kafka1991 May 7, 2025
d758e6d
c error code.
kafka1991 May 8, 2025
bf8ae37
remove unnecessary mut.
kafka1991 May 8, 2025
fa6f04d
make c++20 happy
kafka1991 May 8, 2025
3ce862e
more ideamatic python array interface
kafka1991 May 8, 2025
6678679
code format and cpp compile fix.
kafka1991 May 8, 2025
6f1e7e3
fixed encapsulation issue (we were leaking internal types to the publ…
amunra May 8, 2025
d76b272
Merge branch 'array' of https://github.com/questdb/c-questdb-client i…
amunra May 8, 2025
8d739f1
typo fixed.
kafka1991 May 9, 2025
710a69f
cleanup and added todo comments
amunra May 9, 2025
997937c
Merge branch 'array' of https://github.com/questdb/c-questdb-client i…
amunra May 9, 2025
75d01ae
removed slow build debug artifacts upload which we generally don't need
amunra May 9, 2025
066d0a1
Merge remote-tracking branch 'origin/main' into array
amunra May 9, 2025
b091bf6
fix failed tests.
kafka1991 May 12, 2025
ca4f47c
optimize internal implementation
kafka1991 May 13, 2025
68d89d3
fix benchmark
kafka1991 May 13, 2025
47cdde6
optimize array internal implementation
kafka1991 May 13, 2025
542da03
fix compile error.
kafka1991 May 13, 2025
175d895
test format
kafka1991 May 13, 2025
b89788c
code review.
kafka1991 May 14, 2025
58c6539
fix c api
kafka1991 May 15, 2025
8fb0c4a
code reviews.
kafka1991 May 15, 2025
56e349a
rename c api `new_buffer()` name.
kafka1991 May 15, 2025
ce8a084
Merge remote-tracking branch 'origin/main' into array
amunra May 15, 2025
f163a31
fix system.tests
kafka1991 May 15, 2025
82b0dc3
Merge remote-tracking branch 'origin/array' into array
kafka1991 May 15, 2025
0c5e509
renamed Influx to Ingestion in various places to avoid being misleadi…
amunra May 15, 2025
6e1e68d
fix systemtests
kafka1991 May 15, 2025
a461bfd
reworked the python system tests for cross version testing
amunra May 15, 2025
bf419f1
enrich rust tests.
kafka1991 May 15, 2025
01bfd91
clearing all tables before each test run
amunra May 15, 2025
36cb2e3
Merge branch 'array' of https://github.com/questdb/c-questdb-client i…
amunra May 15, 2025
8c1d9b9
fixed broken C example
amunra May 15, 2025
36f4bd5
minor fixes
amunra May 15, 2025
3392627
fix abnormal tests hang.
kafka1991 May 16, 2025
d4d6bb1
enrich tests
kafka1991 May 16, 2025
e3a6bec
remove buffer size overflow test
kafka1991 May 16, 2025
c05753e
empty array throw exception.
kafka1991 May 16, 2025
b9e023f
enrich tests.
kafka1991 May 16, 2025
3fd415f
test assertion improvements
amunra May 16, 2025
eadbadf
fixed failing test on Windows
amunra May 16, 2025
cba4c33
fix tests
kafka1991 May 16, 2025
a25e66c
tweaks to speed tests up on Windows
amunra May 16, 2025
3b134d2
skipping redundant tests
amunra May 16, 2025
692088e
skipping more redundant tests
amunra May 16, 2025
9521d0f
reduced some timeouts on expected-timeout tests
amunra May 16, 2025
54f6969
skipping even more redundant tests
amunra May 16, 2025
bba4192
ignoring profile result from git-tracked files
amunra May 16, 2025
039ecf6
use `assert_err_contains` in all tests.
kafka1991 May 17, 2025
b3d982f
use `assert_err_contains` in all tests.
kafka1991 May 17, 2025
7c75cdb
fixed buffer/sender version checks
amunra May 19, 2025
d9dd58b
refactoring of the C and C++ public apis and some minor Rust changes
amunra May 20, 2025
ac38b3c
removed convenience constructors, users should prefer conf or env
amunra May 20, 2025
e5fc025
less broken
amunra May 20, 2025
81675ad
gcc fix
amunra May 20, 2025
5889e05
incomplete: moving C strides view to ffi crate
amunra May 20, 2025
0c12e6d
add max_name_len ffi
kafka1991 May 21, 2025
8df0379
You shall pass!
amunra May 21, 2025
48748cb
removed no-panic dependency and cleaned up unused code when building …
amunra May 21, 2025
c51fef2
export max_array_dims
kafka1991 May 21, 2025
09a1172
Merge branch 'array' of github.com:questdb/c-questdb-client into array
kafka1991 May 21, 2025
ea90636
Revert "export max_array_dims"
kafka1991 May 21, 2025
5da905e
remove comment.
kafka1991 May 22, 2025
1ed8d6c
add `line_sender_c_example_array_elem_strides` api
kafka1991 May 23, 2025
27383c8
remove buffer size overflow test
kafka1991 May 23, 2025
f8a1771
remove buffer size overflow test
kafka1991 May 23, 2025
dc8b43b
fix typo.
kafka1991 May 23, 2025
9ecdad9
adapt server json path format.
kafka1991 May 23, 2025
3d9ab0e
code format
kafka1991 May 24, 2025
0c70977
Updated readmes
amunra May 25, 2025
76296ec
add non-contiguous minus strides array.
kafka1991 May 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions include/questdb/ingress/line_sender.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,32 @@ bool line_sender_buffer_column_str(
line_sender_utf8 value,
line_sender_error** err_out);

/**
* Record a multidimensional array of double for the given column.
* The array data must be stored in row-major order (C-style contiguous layout).
*
* @param[in] buffer Line buffer object.
* @param[in] name Column name.
* @param[in] rank Number of dimensions of the array.
* @param[in] shapes Array of dimension sizes (length = `rank`).
* Each element must be a positive integer.
* @param[in] data_buffer Raw bytes of the array data in little-endian format.
* Size must be `sizeof(double) * (shapes[0] * ... *
* shapes[rank-1])`.
* @param[in] data_buffer_len Byte length of the data buffer.
* @param[out] err_out Set to an error object on failure (if non-NULL).
* @return true on success, false on error.
*/
LINESENDER_API
bool line_sender_buffer_column_f64_arr(
line_sender_buffer* buffer,
line_sender_column_name name,
size_t rank,
const uint32_t* shapes,
const uint8_t* data_buffer,
size_t data_buffer_len,
line_sender_error** err_out);

/**
* Record a nanosecond timestamp value for the given column.
* @param[in] buffer Line buffer object.
Expand Down
35 changes: 35 additions & 0 deletions include/questdb/ingress/line_sender.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@

#include "line_sender.h"

#include <array>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>
#if __cplusplus >= 202002L
# include <span>
#endif
Expand Down Expand Up @@ -624,6 +626,39 @@ class line_sender_buffer
return *this;
}

/**
* Record a multidimensional double-precision array for the given column.
*
* @param name Column name.
* @param shape Array dimensions (e.g., [2,3] for a 2x3 matrix).
* @param data Array data in row-major order. Size must match product of
* dimensions.
*
* @note Data is stored contiguously in row-major (C-style) order.
* Example: shape [2,3] expects 6 elements ordered as:
* [a11, a12, a13, a21, a22, a23]
*/
template <typename T, size_t N>
line_sender_buffer& column(
column_name_view name,
const std::vector<uint32_t>& shape,
const std::array<T, N>& data)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to come up with something that's a bit more idiomatic C++.
Let's park the C++ API for now until we have everything else nailed down.

{
static_assert(
std::is_same_v<T, double>,
"Only double types are supported for arrays");
may_init();
line_sender_error::wrapped_call(
::line_sender_buffer_column_f64_arr,
_impl,
name._impl,
shape.size(),
shape.data(),
reinterpret_cast<const uint8_t*>(data.data()),
sizeof(double) * N);
return *this;
}

/**
* Record a string value for the given column.
* @param name Column name.
Expand Down
107 changes: 104 additions & 3 deletions questdb-rs-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

#![allow(non_camel_case_types, clippy::missing_safety_doc)]

use libc::{c_char, size_t};
use libc::{c_char, c_uint, size_t};
use std::ascii;
use std::boxed::Box;
use std::convert::{From, Into};
Expand All @@ -35,8 +35,8 @@ use std::str;

use questdb::{
ingress::{
Buffer, CertificateAuthority, ColumnName, Protocol, Sender, SenderBuilder, TableName,
TimestampMicros, TimestampNanos,
ArrayElement, Buffer, CertificateAuthority, ColumnName, NdArrayView, Protocol, Sender,
SenderBuilder, TableName, TimestampMicros, TimestampNanos,
},
Error, ErrorCode,
};
Expand Down Expand Up @@ -135,6 +135,15 @@ pub enum line_sender_error_code {

/// Bad configuration.
line_sender_error_config_error,

/// Currently, only arrays with a maximum 32 dimensions are supported.
line_sender_error_array_large_dim,

/// ArrayView internal error, such as failure to get the size of a valid dimension.
line_sender_error_array_view_internal_error,

/// Buffer Out Of Memory
line_sender_error_buffer_out_of_memory,
}

impl From<ErrorCode> for line_sender_error_code {
Expand All @@ -159,6 +168,15 @@ impl From<ErrorCode> for line_sender_error_code {
line_sender_error_code::line_sender_error_server_flush_error
}
ErrorCode::ConfigError => line_sender_error_code::line_sender_error_config_error,
ErrorCode::ArrayHasTooManyDims => {
line_sender_error_code::line_sender_error_array_large_dim
}
ErrorCode::ArrayViewError => {
line_sender_error_code::line_sender_error_array_view_internal_error
}
ErrorCode::BufferOutOfMemory => {
line_sender_error_code::line_sender_error_buffer_out_of_memory
}
}
}
}
Expand Down Expand Up @@ -291,6 +309,52 @@ impl line_sender_utf8 {
}
}

#[derive(Debug, Copy, Clone)]
struct line_sender_array {
dims: size_t,
shapes: *const u32,
buf_len: size_t,
buf: *const u8,
}

impl<T> NdArrayView<T> for line_sender_array
where
T: ArrayElement,
{
fn ndim(&self) -> usize {
self.dims
}

fn dim(&self, index: usize) -> Option<usize> {
if index >= self.dims {
return None;
}

unsafe {
if self.shapes.is_null() {
return None;
}

let dim_size = *self.shapes.add(index);
Some(dim_size as usize)
}
}

fn write_row_major_buf(&self, buff: &mut [u8]) {
let elem_size = size_of::<T>();
let total_elements: usize = (0..self.dims)
.filter_map(|i| <line_sender_array as NdArrayView<T>>::dim(self, i))
.product();
assert_eq!(
self.buf_len,
total_elements * elem_size,
"Buffer length mismatch"
);
let bytes = unsafe { slice::from_raw_parts(self.buf, self.buf_len) };
buff[..self.buf_len].copy_from_slice(bytes);
}
}

/// An ASCII-safe description of a binary buffer. Trimmed if too long.
fn describe_buf(buf: &[u8]) -> String {
let max_len = 100usize;
Expand Down Expand Up @@ -804,6 +868,43 @@ pub unsafe extern "C" fn line_sender_buffer_column_str(
true
}

/// Record a float multidimensional array value for the given column.
/// @param[in] buffer Line buffer object.
/// @param[in] name Column name.
/// @param[in] rank Array dims.
/// @param[in] shape Array shapes.
/// @param[in] data_buffer Array data memory ptr.
/// @param[in] data_buffer_len Array data memory length.
/// @param[out] err_out Set on error.
/// # Safety
/// - All pointer parameters must be valid and non-null
/// - shape must point to an array of `rank` integers
/// - data_buffer must point to a buffer of size `data_buffer_len` bytes
#[no_mangle]
pub unsafe extern "C" fn line_sender_buffer_column_f64_arr(
buffer: *mut line_sender_buffer,
name: line_sender_column_name,
rank: size_t,
shape: *const c_uint, // C array of dimension sizes
data_buffer: *const u8, // Raw array data
data_buffer_len: size_t, // Total bytes length
err_out: *mut *mut line_sender_error,
) -> bool {
let buffer = unwrap_buffer_mut(buffer);
let name = name.as_name();
let view = line_sender_array {
dims: rank,
shapes: shape,
buf_len: data_buffer_len,
buf: data_buffer,
};
bubble_err_to_c!(
err_out,
buffer.column_arr::<ColumnName<'_>, line_sender_array, f64>(name, &view)
);
true
}

/// Record a nanosecond timestamp value for the given column.
/// @param[in] buffer Line buffer object.
/// @param[in] name Column name.
Expand Down
5 changes: 3 additions & 2 deletions questdb-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ ureq = { version = "=2.9", optional = true }
serde_json = { version = "1.0.108", optional = true }
questdb-confstr = "0.1.0"
rand = { version = "0.8.5", optional = true }
ndarray = { version = "0.16.1", optional = true }
no-panic = { version = "0.1", optional = true }

[target.'cfg(windows)'.dependencies]
Expand Down Expand Up @@ -74,7 +75,7 @@ chrono_timestamp = ["chrono"]

[[example]]
name = "basic"
required-features = ["chrono_timestamp"]
required-features = ["chrono_timestamp", "ndarray"]

[[example]]
name = "auth"
Expand All @@ -86,4 +87,4 @@ required-features = ["chrono_timestamp"]

[[example]]
name = "http"
required-features = ["ilp-over-http"]
required-features = ["ilp-over-http", "ndarray"]
2 changes: 2 additions & 0 deletions questdb-rs/examples/basic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use chrono::{TimeZone, Utc};
use ndarray::arr1;
use questdb::{
ingress::{Buffer, Sender, TimestampNanos},
Result,
Expand All @@ -17,6 +18,7 @@ fn main() -> Result<()> {
.symbol("side", "sell")?
.column_f64("price", 2615.54)?
.column_f64("amount", 0.00044)?
.column_arr("location", &arr1(&[100.0, 100.1, 100.2]).view())?
.at(designated_timestamp)?;

//// If you want to pass the current system timestamp, replace with:
Expand Down
2 changes: 2 additions & 0 deletions questdb-rs/examples/http.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use ndarray::arr1;
use questdb::{
ingress::{Buffer, Sender, TimestampNanos},
Result,
Expand All @@ -12,6 +13,7 @@ fn main() -> Result<()> {
.symbol("side", "sell")?
.column_f64("price", 2615.54)?
.column_f64("amount", 0.00044)?
.column_arr("location", &arr1(&[100.0, 100.1, 100.2]).view())?
.at(TimestampNanos::now())?;
sender.flush(&mut buffer)?;
Ok(())
Expand Down
9 changes: 9 additions & 0 deletions questdb-rs/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ pub enum ErrorCode {

/// Bad configuration.
ConfigError,

/// Array has too many dims. Currently, only arrays with a maximum [`crate::ingress::ndarr::MAX_DIMS`] dimensions are supported.
ArrayHasTooManyDims,

/// Array view internal error.
ArrayViewError,

/// Buffer outOfMemory.
BufferOutOfMemory,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

/// An error that occurred when using QuestDB client library.
Expand Down
Loading