Skip to content

feat: ILP over HTTP (InfluxDB compatible) #50

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

Merged
merged 68 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
9225cd2
feat: ILP over HTTP (InfluxDB compatibility)
amunra Dec 7, 2023
b39b403
simpler API for HTTP
amunra Dec 7, 2023
9d0991b
C and C++ APIs
amunra Dec 7, 2023
8a614b4
tweaks and tests
amunra Dec 8, 2023
d13cc63
dependency updates and error code fix
amunra Dec 8, 2023
006c951
json parsing and more tests
amunra Dec 8, 2023
a95a524
implemented (not tested yet) basic auth
amunra Dec 8, 2023
25840a0
headers tweak and manual testing of auth via http://httpbin.org/basic…
amunra Dec 8, 2023
d092970
argument validation and exposing basic auth to C and C++
amunra Dec 8, 2023
35686ee
error message parsing improvements in case of auth failure
amunra Dec 8, 2023
6ac7d85
Fixed a typo
amunra Dec 8, 2023
1fe0edc
auth test cases
amunra Dec 8, 2023
ed19ad9
proportional timeouts to request size
amunra Dec 8, 2023
aa16866
added precision=u url param and updated example
amunra Dec 8, 2023
f62bbfe
debris removal
amunra Dec 8, 2023
5b93efd
user agent tweak
amunra Dec 8, 2023
b747b0b
test fixes
amunra Dec 8, 2023
fbcf28d
bearer auth and ensuring http is optional
amunra Dec 11, 2023
e7f8eb1
Token auth test
amunra Dec 11, 2023
825eb72
timeout improvements and tests
amunra Dec 11, 2023
f113897
token auth C and C++
amunra Dec 11, 2023
4fff9f0
cargo fmt
amunra Dec 11, 2023
bf09c02
tls proxy API for the win
amunra Dec 11, 2023
58e16ad
hopefully fixing tls_proxy
amunra Dec 11, 2023
eae1b91
HTTP TLS tests
amunra Dec 12, 2023
aaca75a
dropped mockito as test dependency and fully using own mock server al…
amunra Dec 12, 2023
a210746
cargo fmt, cargo clippy
amunra Dec 12, 2023
f4414b2
more cargo fmt
amunra Dec 12, 2023
7340662
adding some timeouts for tests that are failing on windows
amunra Dec 12, 2023
7d735b3
hopefully fixing windows issues
amunra Dec 13, 2023
98985e9
MockServer fixed timeout logic, improve waiting for event with a loop…
amunra Dec 13, 2023
37362f0
cargo fmt
amunra Dec 13, 2023
8d63b38
http retry partially done (no config or tests yet)
amunra Dec 13, 2023
d49eb4a
cargo fmt
amunra Dec 14, 2023
e3582c6
parameterised http retry logic and added a test
amunra Dec 15, 2023
da56fa7
cargo fmt
amunra Dec 15, 2023
ef7aab7
timeout tweak to facilitate passing on CI where boxes are slower
amunra Dec 15, 2023
54dbe17
another CI fix attempt
amunra Dec 15, 2023
a359991
on error max retry test
amunra Dec 15, 2023
bbdb254
cargo fmt
amunra Dec 15, 2023
05a1991
buffer.row_count()
amunra Dec 15, 2023
7ea4817
transactional flushes (no tests yet)
amunra Dec 29, 2023
f099895
transactional test case
amunra Dec 29, 2023
fec8c7f
Added missing APIs to C and C++
amunra Dec 29, 2023
48b9d05
Basic HTTP API C++ test
amunra Dec 29, 2023
f0716e4
support for running tests out of a questdb repo directory
amunra Jan 2, 2024
0984ae7
fixed test_mismatched_types_across_rows (though might have broken som…
amunra Jan 2, 2024
abc4d02
fixed precision=u http test cases
amunra Jan 3, 2024
4d074c7
Added C and C++ HTTP example tests
amunra Jan 3, 2024
57cf346
Transactional flush testcases
amunra Jan 3, 2024
ab62b61
royally breaking CI
amunra Jan 3, 2024
08fe2d0
CI attempt fix
amunra Jan 3, 2024
f9c7e09
added missing file
amunra Jan 3, 2024
ef3d4ef
CI fix
amunra Jan 3, 2024
5429102
another ci fix
amunra Jan 3, 2024
dca8093
yet another ci fix
amunra Jan 3, 2024
c67b4c1
yet yet another ci fix
amunra Jan 3, 2024
f8e9bf9
Fix BUILD_RUST_EXAMPLES in CI
amunra Jan 3, 2024
559d4ef
Add integration test step in CI
amunra Jan 3, 2024
0abfb62
CI fix
amunra Jan 3, 2024
f171866
Rust examples CI
amunra Jan 3, 2024
657485f
test refactoring for reuse in py-questdb-client
amunra Jan 4, 2024
0ab1b08
fix: don't sleep after last retry
amunra Jan 4, 2024
e1a0d27
refactored http logic into separate private module
amunra Jan 4, 2024
5ce3c1f
minor fix from iter+clone to into_iter
amunra Jan 4, 2024
b697063
removal of RowCount usize type alias
amunra Jan 4, 2024
993c958
cargo fmt and clippy
amunra Jan 4, 2024
b37c4ca
Simplifed the verification for transactional batches: No longer needs…
amunra Jan 4, 2024
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
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ if (QUESTDB_TESTS_AND_EXAMPLES)
compile_example(
line_sender_c_example_auth_tls
examples/line_sender_c_example_auth_tls.c)
compile_example(
line_sender_c_example_http
examples/line_sender_c_example_http.c)
compile_example(
line_sender_cpp_example
examples/line_sender_cpp_example.cpp)
Expand All @@ -112,6 +115,9 @@ if (QUESTDB_TESTS_AND_EXAMPLES)
compile_example(
line_sender_cpp_example_auth_tls
examples/line_sender_cpp_example_auth_tls.cpp)
compile_example(
line_sender_cpp_example_http
examples/line_sender_cpp_example_http.cpp)

# Include Rust tests as part of the tests run
add_test(
Expand Down
14 changes: 14 additions & 0 deletions ci/compile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
steps:
- script: |
rustup update $(toolchain)
rustup default $(toolchain)
condition: ne(variables['toolchain'], '')
displayName: "Update and set Rust toolchain"
- script: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DQUESTDB_TESTS_AND_EXAMPLES=ON
env:
JAVA_HOME: $(JAVA_HOME_11_X64)
displayName: "Build Makefile with CMake"
- script: cmake --build build
env:
JAVA_HOME: $(JAVA_HOME_11_X64)
displayName: "Make"
3 changes: 2 additions & 1 deletion ci/run_all_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ def main():
test_line_sender_path = next(iter(
build_dir.glob(f'**/test_line_sender{exe_suffix}')))
system_test_path = pathlib.Path('system_test') / 'test.py'
qdb_v = '7.3.2' # The version of QuestDB we'll test against.
qdb_v = '7.3.7' # The version of QuestDB we'll test against.

run_cmd('cargo', 'test', '--', '--nocapture', cwd='questdb-rs')
run_cmd('cargo', 'test', '--all-features', '--', '--nocapture', cwd='questdb-rs')
run_cmd(str(test_line_sender_path))
run_cmd('python3', str(system_test_path), 'run', '--versions', qdb_v, '-v')
Expand Down
64 changes: 26 additions & 38 deletions ci/run_tests_pipeline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,27 @@ stages:
linux:
imageName: "ubuntu-latest"
poolName: "Azure Pipelines"
BUILD_WITH_MINGW: "0"
linux-stable:
imageName: "ubuntu-latest"
poolName: "Azure Pipelines"
BUILD_WITH_MINGW: "0"
toolchain: "stable"
linux-beta:
imageName: "ubuntu-latest"
poolName: "Azure Pipelines"
BUILD_WITH_MINGW: "0"
toolchain: "beta"
linux-nightly:
imageName: "ubuntu-latest"
poolName: "Azure Pipelines"
BUILD_WITH_MINGW: "0"
toolchain: "nightly"
mac:
imageName: "macos-latest"
poolName: "Azure Pipelines"
BUILD_WITH_MINGW: "0"
windows-msvc-2022:
imageName: "windows-2022"
poolName: "Azure Pipelines"
BUILD_WITH_MINGW: "0"
windows-msvc-2019:
imageName: "windows-2019"
poolName: "Azure Pipelines"
BUILD_WITH_MINGW: "0"
# windows-mingw:
# imageName: "windows-2022"
# poolName: "Azure Pipelines"
# BUILD_WITH_MINGW: "1"
pool:
name: $(poolName)
vmImage: $(imageName)
Expand All @@ -60,34 +49,11 @@ stages:
fetchDepth: 1
lfs: false
submodules: false
- script: |
rustup update $(toolchain)
rustup default $(toolchain)
condition: ne(variables['toolchain'], '')
displayName: "Update and set Rust toolchain"
- template: compile.yaml
- script: |
cd questdb-rs
cargo build --example basic --features=chrono_timestamp
cargo build --example auth --features=chrono_timestamp
cargo build --example auth_tls --features=chrono_timestamp
displayName: Build Rust examples.
- script: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DQUESTDB_TESTS_AND_EXAMPLES=ON
env:
JAVA_HOME: $(JAVA_HOME_11_X64)
displayName: "Build Makefile with CMake"
condition: eq(variables['BUILD_WITH_MINGW'], '0')
# - script: |
# choco upgrade mingw -y
# rustup target add x86_64-pc-windows-gnu
# cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -G "MinGW Makefiles"
# env:
# JAVA_HOME: $(JAVA_HOME_11_X64)
# displayName: "Build Makefile with CMake"
# condition: eq(variables['BUILD_WITH_MINGW'], '1')
- script: cmake --build build
env:
JAVA_HOME: $(JAVA_HOME_11_X64)
displayName: "Make"
cargo build --examples --all-features
displayName: "Build Rust examples"
- script: python3 ci/run_all_tests.py
env:
JAVA_HOME: $(JAVA_HOME_11_X64)
Expand All @@ -96,7 +62,6 @@ stages:
inputs:
pathToPublish: ./build
displayName: "Publish build directory"
condition: eq(variables['BUILD_WITH_MINGW'], '1')
- job: CargoFmtAndClippy
displayName: "cargo fmt and clippy"
pool:
Expand Down Expand Up @@ -134,3 +99,26 @@ stages:
cd tls_proxy
cargo clippy --all-targets --all-features -- -D warnings
displayName: "tls_proxy: clippy"
- job: TestVsQuestDBMaster
displayName: "Vs QuestDB 'master'"
pool:
vmImage: 'ubuntu-latest'
timeoutInMinutes: 60
steps:
- checkout: self
fetchDepth: 1
lfs: false
submodules: false
- template: compile.yaml
- script: |
git clone --depth 1 https://github.com/questdb/questdb.git
displayName: git clone questdb
- task: Maven@3
displayName: "Compile QuestDB"
inputs:
mavenPOMFile: 'questdb/pom.xml'
jdkVersionOption: '1.11'
options: "install -DskipTests -Pbuild-web-console"
- script: |
python3 system_test/test.py run --repo ./questdb -v
displayName: "integration test"
15 changes: 15 additions & 0 deletions cpp_test/test_line_sender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,4 +715,19 @@ TEST_CASE("Empty Buffer") {
sender.flush_and_keep(b1),
"State error: Bad call to `flush`, should have called `table` instead.",
questdb::ingress::line_sender_error);
}

TEST_CASE("HTTP basics") {
questdb::ingress::opts opts1{"localhost", 1};
questdb::ingress::opts opts2{"localhost", 1};
opts1.http().transactional().max_retries(5).retry_interval(10).basic_auth("user", "pass");
opts2.http().token_auth("token").min_throughput(1000);
questdb::ingress::line_sender sender1{opts1};
questdb::ingress::line_sender sender2{opts2};

questdb::ingress::line_sender_buffer b1;
b1.table("test").symbol("a", "b").at_now();

CHECK_THROWS_AS(sender1.flush(b1), questdb::ingress::line_sender_error);
CHECK_THROWS_AS(sender2.flush(b1), questdb::ingress::line_sender_error);
}
135 changes: 135 additions & 0 deletions examples/line_sender_c_example_http.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include <questdb/ingress/line_sender.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

static bool example(const char* host, const char* port)
{
line_sender_error* err = NULL;
line_sender_opts* opts = NULL;
line_sender* sender = NULL;
line_sender_buffer* buffer = NULL;

line_sender_utf8 host_utf8 = { 0, NULL };
if (!line_sender_utf8_init(&host_utf8, strlen(host), host, &err))
goto on_error;

line_sender_utf8 port_utf8 = { 0, NULL };
if (!line_sender_utf8_init(&port_utf8, strlen(port), port, &err))
goto on_error;

// Call `line_sender_opts_new` if instead you have an integer port.
opts = line_sender_opts_new_service(host_utf8, port_utf8);

// Use ILP/HTTP instead of ILP/TCP for better error messages.
line_sender_opts_http(opts);

// Ensure that each buffer contains lines for a single table on each flush.
line_sender_opts_transactional(opts);

sender = line_sender_connect(opts, &err);
line_sender_opts_free(opts);
opts = NULL;
if (!sender)
goto on_error;

buffer = line_sender_buffer_new();
line_sender_buffer_reserve(buffer, 64 * 1024); // 64KB buffer initial size.

// We prepare all our table names and column names in advance.
// If we're inserting multiple rows, this allows us to avoid
// re-validating the same strings over and over again.
line_sender_table_name table_name = QDB_TABLE_NAME_LITERAL("c_cars_http");
line_sender_column_name id_name = QDB_COLUMN_NAME_LITERAL("id");
line_sender_column_name x_name = QDB_COLUMN_NAME_LITERAL("x");
line_sender_column_name y_name = QDB_COLUMN_NAME_LITERAL("y");
line_sender_column_name booked_name = QDB_COLUMN_NAME_LITERAL("booked");
line_sender_column_name passengers_name = QDB_COLUMN_NAME_LITERAL(
"passengers");
line_sender_column_name driver_name = QDB_COLUMN_NAME_LITERAL("driver");

if (!line_sender_buffer_table(buffer, table_name, &err))
goto on_error;

line_sender_utf8 id_value = QDB_UTF8_LITERAL(
"d6e5fe92-d19f-482a-a97a-c105f547f721");
if (!line_sender_buffer_symbol(buffer, id_name, id_value, &err))
goto on_error;

if (!line_sender_buffer_column_f64(buffer, x_name, 30.5, &err))
goto on_error;

if (!line_sender_buffer_column_f64(buffer, y_name, -150.25, &err))
goto on_error;

if (!line_sender_buffer_column_bool(buffer, booked_name, true, &err))
goto on_error;

if (!line_sender_buffer_column_i64(buffer, passengers_name, 3, &err))
goto on_error;

line_sender_utf8 driver_value = QDB_UTF8_LITERAL("John Doe");
if (!line_sender_buffer_column_str(buffer, driver_name, driver_value, &err))
goto on_error;

// 1997-07-04 04:56:55 UTC
int64_t designated_timestamp = 867992215000000000;
if (!line_sender_buffer_at_nanos(buffer, designated_timestamp, &err))
goto on_error;

//// If you want to get the current system timestamp as nanos, call:
// if (!line_sender_buffer_at_nanos(buffer, line_sender_now_nanos(), &err))
// goto on_error;

// To insert more records, call `line_sender_buffer_table(..)...` again.
// It's recommended to keep a timer and/or maximum buffer size to flush
// the buffer periodically with any accumulated records.
if (!line_sender_flush(sender, buffer, &err))
goto on_error;

line_sender_close(sender);

return true;

on_error: ;
line_sender_opts_free(opts);
size_t err_len = 0;
const char* err_msg = line_sender_error_msg(err, &err_len);
fprintf(stderr, "Error running example: %.*s\n", (int)err_len, err_msg);
line_sender_error_free(err);
line_sender_buffer_free(buffer);
line_sender_close(sender);
return false;
}

static bool displayed_help(int argc, const char* argv[])
{
for (int index = 1; index < argc; ++index)
{
const char* arg = argv[index];
if ((strncmp(arg, "-h", 2) == 0) || (strncmp(arg, "--help", 6) == 0))
{
fprintf(stderr, "Usage:\n");
fprintf(stderr, "line_sender_c_example: [HOST [PORT]]\n");
fprintf(stderr, " HOST: ILP host (defaults to \"localhost\").\n");
fprintf(stderr, " PORT: ILP port (defaults to \"9009\").\n");
return true;
}
}
return false;
}

int main(int argc, const char* argv[])
{
if (displayed_help(argc, argv))
return 0;

const char* host = "localhost";
if (argc >= 2)
host = argv[1];
const char* port = "9009";
if (argc >= 3)
port = argv[2];

return !example(host, port);
}
Loading