Skip to content

Commit 7c7b1c8

Browse files
committed
chore: Rust metadata, doc and src tree cleanup.
1 parent 6ca9d3b commit 7c7b1c8

File tree

18 files changed

+491
-318
lines changed

18 files changed

+491
-318
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ build
33
.vs
44
.vscode
55
questdb-rs/Cargo.lock
6-
questdb-rs/src/tests/json_tests.rs
6+
include/questdb/ilp/line_sender.gen.h
7+
cython/questdb/ilp/line_sender.pxd

README.md

Lines changed: 31 additions & 277 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
# c-questdb-client
2-
**QuestDB - InfluxDB Line Protocol - Ingestion Client Library for C and C++**
2+
**QuestDB - Client Library for Rust, C and C++**
33

44
This library makes it easy to insert data into [QuestDB](https://questdb.io/).
55

66
This client library implements the [InfluxDB Line Protocol](
77
https://questdb.io/docs/reference/api/ilp/overview/) (ILP) over TCP.
88

99
* Implementation is in Rust, with no additional
10-
[run-time or link-time dependencies](BUILD.md#pre-requisites-and-dependencies)
10+
[run-time or link-time dependencies](doc/BUILD.md#pre-requisites-and-dependencies)
1111
on the C++ standard library or other libraries.
1212
* We ship both a static and a dynamic library.
13-
* The library exposes both a C and a C++17 API.
13+
* The library exposes Rust, C11 and C++17 APIs.
1414
* The C++ API is a header-only wrapper over the C API.
15+
* This library also has separate Python bindings.
1516

16-
## Protocol
17+
## Insertion Protocols Overview
1718

1819
Inserting data into QuestDB can be done via one of three protocols.
1920

@@ -23,296 +24,49 @@ Inserting data into QuestDB can be done via one of three protocols.
2324
| [CSV Upload via HTTP](https://questdb.io/docs/reference/api/rest/#imp---import-data) | Configurable | Very Good |
2425
| [PostgreSQL](https://questdb.io/docs/reference/api/postgres/) | Transaction-level | Good |
2526

26-
This library mitigates the lack of confirmation and error reporting by
27-
validating data ahead of time before any data is sent to the database instance.
27+
This library implements the **ILP protocol** and mitigates the lack of confirmation
28+
and error reporting by validating data ahead of time before any data is sent
29+
to the database instance.
2830

2931
For example, the client library will report that a supplied string isn't encoded
3032
in UTF-8. Some issues unfortunately can't be caught by the library and require
31-
some [care and diligence to avoid data problems](#data-quality-considerations).
33+
some [care and diligence to avoid data problems](doc/CONSIDERATIONS.md).
3234

3335
For an overview and code examples, see the
3436
[ILP page of the developer docs](https://questdb.io/docs/develop/insert-data/#influxdb-line-protocol).
3537

3638
To understand the protocol in more depth, consult the
3739
[protocol reference docs](https://questdb.io/docs/reference/api/ilp/overview/).
3840

39-
## Using this Library
41+
## Getting Started
4042

41-
Start with the [build instructions](BUILD.md), then read the guide for including
42-
this library as a [dependency from your project](DEPENDENCY.md).
43+
To get started, read the language-specific guides.
4344

44-
Once you've all set up, you can take a look at our examples:
45+
**C**
46+
* [Getting started with C](doc/C.md)
47+
* [`.h` header file](include/questdb/ilp/line_sender.h)
4548

46-
### From a C program
49+
**C++**
50+
* [Getting started with C++](doc/CPP.md)
51+
* [`.hpp` header file](include/questdb/ilp/line_sender.hpp)
4752

48-
```c
49-
#include <questdb/ilp/line_sender.h>
53+
**Rust**
54+
* [Getting started with Rust](questdb-rs/README.md)
55+
* [`questdb-rs` crate on crates.io](https://crates.io/crates/questdb-rs)
56+
* [API docs on docs.rs](https://docs.rs/questdb-rs/latest/)
57+
* [`questdb-rs` source code](questdb-rs)
58+
* [`questdb-rs-ffi` source code](questdb-rs-ffi) - C bindings code
5059

51-
...
60+
**Python**
61+
* [Python GitHub Repo](https://github.com/questdb/py-questdb-client/)
62+
* [`questdb` package on PyPI](https://pypi.org/project/questdb/)
63+
* [Documentation](https://py-questdb-client.readthedocs.io/en/latest/)
5264

53-
line_sender_error* err = NULL;
54-
line_sender_opts* opts = NULL;
55-
line_sender* sender = NULL;
65+
## Further Topics
5666

57-
line_sender_utf8 host = QDB_UTF8_LITERAL("localhost");
58-
opts = line_sender_opts_new(host, 9009, &err);
59-
if (!opts) {
60-
/* ... handle error ... */
61-
}
62-
63-
sender = line_sender_connect(opts, &err);
64-
line_sender_opts_free(opts);
65-
opts = NULL;
66-
if (!sender) {
67-
/* ... handle error ... */
68-
}
69-
70-
```
71-
72-
The `opts` object can additionally take parameters for the outbound interface,
73-
authentication, full-connection encryption via TLS and more.
74-
75-
Examples:
76-
* [Basic example in C](examples/line_sender_c_example.c).
77-
* [With authentication](examples/line_sender_c_example_auth.c).
78-
* [With authentication and TLS](examples/line_sender_c_example_tls.c).
79-
80-
### From a C++ program
81-
82-
```cpp
83-
#include <questdb/ilp/line_sender.hpp>
84-
85-
...
86-
87-
// Automatically connects on object construction.
88-
questdb::ilp::line_sender sender{
89-
"localhost", // QuestDB hostname
90-
9009}; // QuestDB port
91-
92-
```
93-
94-
For more advanced use cases, such as those requiring authentication or
95-
full-connection encryption via TLS, first, create an `opts` object then call its
96-
methods to populate its options and then pass the `opts` object to the
97-
`line_sender` constructor.
98-
99-
Examples:
100-
* [Basic example in C++](examples/line_sender_cpp_example.cpp).
101-
* [With authentication](examples/line_sender_cpp_example_auth.cpp).
102-
* [With authentication and TLS](examples/line_sender_cpp_example_tls.cpp).
103-
104-
See a [complete example in C++](examples/line_sender_cpp_example.cpp).
105-
106-
### How to use the API
107-
The API is sequentially coupled, meaning that methods need to be called in a
108-
specific order.
109-
110-
For each row, you need to specify a table name and at least one symbol or
111-
column. Symbols must be specified before columns.
112-
Once you're done with a row you must add a timestamp calling `at` or `at_now`.
113-
114-
This ordering of operations is documented for both the C and C++ APIs below.
115-
116-
#### Buffer API
117-
118-
The `line_sender` object is responsible for connecting to the network and
119-
sending data.
120-
121-
The buffer it sends is constructed separately through a `line_sender_buffer`
122-
object.
123-
124-
To avoid malformed messages, this object's methods (`line_sender_buffer_*`
125-
functions in C) must be called in a specific order.
126-
127-
You can accumulate multiple lines (rows) with a given buffer and a buffer is
128-
re-usable, but a buffer may only be flushed via the sender after a `.at()` or
129-
`.at_now()` method call (or equivalent C function).
130-
131-
![Sequential Coupling](api_seq/seq.svg)
132-
133-
#### Threading Considerations
134-
135-
By design, the sender and buffer objects perform all operations on the current
136-
thread. The library will not spawn any threads internally.
137-
138-
By constructing multiple buffers you can design your application to build ILP
139-
messages on multiple threads whilst handling network connectivity in a separate
140-
part of your application on a different thread (for example by passing buffers
141-
that need sending over a concurrent queue and sending flushed buffers back over
142-
another queue).
143-
144-
Buffer and sender objects don't use any locks, so it's down to you to ensure
145-
that a single thread owns a buffer or sender at any given point in time.
146-
147-
#### Error handling in the C API
148-
149-
In the C API, functions that can result in errors take a `line_sender_error**`
150-
parameter as the last argument. When calling such functions you must check the
151-
return value for errors. Functions that return `bool` use `false` to indicate
152-
a failure, whilst functions that return a pointer use NULL as the failure
153-
sentinel value.
154-
155-
You may then call `line_sender_error_msg(err)` and
156-
`line_sender_error_get_code(err)` to extract error details.
157-
158-
Once handled, the error object *must* be disposed of by calling
159-
`line_sender_error_free(err)`.
160-
161-
On error, you must also call `line_sender_close(sender)`.
162-
163-
Here's a complete example of how to handle an error without leaks:
164-
165-
```c
166-
line_sender* sender = ...;
167-
line_sender_error* err = NULL;
168-
if (!line_sender_flush(sender, &err))
169-
{
170-
size_t msg_len = 0;
171-
const char* msg = line_sender_error_msg(err, &msg_len);
172-
fprintf(stderr, "Could not set table name: %.*s", (int)msg_len, msg);
173-
174-
// Clean-up
175-
line_sender_error_free(err);
176-
line_sender_close(sender);
177-
return;
178-
}
179-
```
180-
181-
This type of error handling can get error-prone and verbose,
182-
so you may want to use a `goto` to simplify handling
183-
(see [example](examples/line_sender_c_example.c)).
184-
185-
#### Error handling in the C++ API
186-
187-
Note that most methods in C++ may throw `questdb::ilp::line_sender_error`
188-
exceptions. The C++ `line_sender_error` type inherits from `std::runtime_error`
189-
and you can obtain an error message description by calling `.what()` and an
190-
error code calling `.code()`.
191-
192-
### Data types
193-
194-
The ILP protocol has its own set of data types which is smaller
195-
that the set supported by QuestDB.
196-
We map these types into QuestDB types and perform conversions
197-
as necessary wherever possible.
198-
199-
Strings may be recorded as either the `STRING` type or the `SYMBOL` type.
200-
201-
`SYMBOL`s are strings with which are automatically
202-
[interned](https://en.wikipedia.org/wiki/String_interning) by the database on a
203-
per-column basis.
204-
You should use this type if you expect the string to be re-used over and over.
205-
This is common for identifiers, etc.
206-
207-
For one-off strings use `STRING` columns which aren't interned.
208-
209-
For more details see our
210-
[datatypes](https://questdb.io/docs/reference/sql/datatypes) page.
211-
212-
## Data quality considerations
213-
214-
When inserting data through the API, you must follow a set of considerations.
215-
216-
### Library-validated considerations
217-
218-
* Strings and symbols must be passed in as valid UTF-8 which
219-
need not be nul-terminated.
220-
* Table names and column names must conform to valid names as accepted by the
221-
database (see `isValidTableName` and `isValidColumnName` in the QuestDB java
222-
[codebase](https://github.com/questdb/questdb) for details).
223-
* Each row should contain, *in order*:
224-
* table name
225-
* at least one of:
226-
* symbols, zero or more
227-
* columns, zero or more
228-
* timestamp, optionally
229-
230-
Breaking these rules above will result in an error in the client library.
231-
232-
### Additional considerations
233-
234-
Additionally you should also ensure that:
235-
236-
* For a given row, a column name should not be repeated.
237-
If it's repeated, only the first value will be kept.
238-
This also applies to symbols.
239-
* Values for a given column should always have the same type.
240-
If changing types the whole row will be dropped (unless we can cast).
241-
* If supplying timestamps these need to be at least equal to
242-
previous ones in the same table, unless using the out of order
243-
feature. Out of order rows would be dropped.
244-
* The timestamp column should be written out through the provided
245-
`line_sender_at` function (in C) or or `.at()` method in (C++).
246-
It is also possible to write out additional timestamps values
247-
as columns.
248-
249-
The client library will not check any of these types of data issues.
250-
251-
To debug these issues you may consult the QuestDB instance logs.
252-
253-
#### Resuming after an error
254-
255-
If you intend to retry, you must create a new sender object: The same sender
256-
object can't be reused.
257-
258-
## Connection Security
259-
260-
You may choose to enable authentication and/or TLS encryption by setting the
261-
appropriate properties on the `opts` object used for connecting.
262-
263-
### Authentication
264-
265-
We support QuestDB's ECDSA P256 SHA256 signing-based authentication.
266-
267-
To create your own keys, follow the QuestDB's [authentication documentation](https://questdb.io/docs/reference/api/ilp/authenticate/).
268-
269-
Authentication can be used independently of TLS encryption.
270-
271-
### TLS Encryption
272-
273-
As of writing, whilst QuestDB itself can't be configured to support TLS natively
274-
it is recommended that you use `haproxy` or other to secure the connection
275-
for any public-facing servers.
276-
277-
TLS can be used independently and provides no authentication itself.
278-
279-
The `tls_certs` directory of this project contains tests certificates, its
280-
[README](tls_certs/README.md) page describes generating your own certs.
281-
282-
For API usage, see the C and C++ auth examples:
283-
* [examples/line_sender_c_example_auth.c](examples/line_sender_c_example_auth.c)
284-
* [examples/line_sender_cpp_example_auth.cpp](examples/line_sender_cpp_example_auth.cpp)
285-
286-
## If you don't see any data
287-
288-
You may be experiencing one of these issues:
289-
290-
### QuestDB configuration
291-
292-
If you can't initially see your data through a `select` query straight away,
293-
this is normal: by default the database will only commit data it receives
294-
though the line protocol periodically to maximize throughput.
295-
296-
For dev/testing you may want to tune the following database configuration
297-
parameters as so:
298-
299-
```ini
300-
# server.conf
301-
cairo.max.uncommitted.rows=1
302-
line.tcp.maintenance.job.interval=100
303-
```
304-
305-
The defaults are more applicable for a production environment.
306-
307-
For these and more configuration parameters refer to [database configuration
308-
](https://questdb.io/docs/reference/configuration/)documentation.
309-
310-
### API usage
311-
The API doesn't send any data over the network until the `line_sender_flush`
312-
function (if using the C API) or `.flush()` method (if using the C++ API API)
313-
is called.
314-
315-
*Closing the connection will not auto-flush.*
67+
* [Data quality and threading considerations](doc/CONSIDERATIONS.md)
68+
* [Authentication and TLS encryption](doc/SECURITY.md)
69+
* [Troubleshooting](doc/TROUBLESHOOTING.md)
31670

31771
## Community
31872

File renamed without changes.

0 commit comments

Comments
 (0)