Skip to content

Commit edbdc3a

Browse files
authored
feat(ilp): QWiP store-and-forward client buffer (#17)
1 parent 64b7ee6 commit edbdc3a

154 files changed

Lines changed: 30644 additions & 6342 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/review-pr/SKILL.md

Lines changed: 133 additions & 15 deletions
Large diffs are not rendered by default.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ core/questdb/client/bin-local
2121
core/cmake-build-debug
2222
core/cmake-build-debug-coverage
2323
core/cmake-build-release
24+
core/build_native
2425
core/CMakeCache.txt
2526
**/.project
2627
**/.settings

ci/run_tests_pipeline.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,16 @@ stages:
8484
maven | "$(Agent.OS)"
8585
path: $(HOME)/.m2/repository
8686
displayName: "Cache Maven repository"
87-
- script: git clone --depth 1 https://github.com/questdb/questdb.git ./questdb
87+
- bash: |
88+
BRANCH="${SYSTEM_PULLREQUEST_SOURCEBRANCH:-$BUILD_SOURCEBRANCHNAME}"
89+
BRANCH="${BRANCH#refs/heads/}"
90+
if git ls-remote --exit-code --heads https://github.com/questdb/questdb.git "$BRANCH" >/dev/null 2>&1; then
91+
echo "Cloning matching questdb branch: $BRANCH"
92+
git clone --depth 1 --branch "$BRANCH" https://github.com/questdb/questdb.git ./questdb
93+
else
94+
echo "No matching questdb branch '$BRANCH', falling back to master"
95+
git clone --depth 1 https://github.com/questdb/questdb.git ./questdb
96+
fi
8897
displayName: git clone questdb
8998
- task: Maven@3
9099
displayName: "Update client version"

core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ set(
5353
src/main/c/share/cpprt_overrides.cpp
5454
src/main/c/share/byte_sink.cpp
5555
src/main/c/share/byte_sink.h
56+
src/main/c/share/crc32c.c
5657
)
5758

5859
# libzstd is included via a git submodule at src/main/c/share/zstd (pinned to

core/pom.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
<argLine>-ea -Dfile.encoding=UTF-8 -XX:+UseParallelGC -Dslf4j.provider=ch.qos.logback.classic.spi.LogbackServiceProvider</argLine>
3737
<test.exclude>None</test.exclude>
3838
<test.include>%regex[.*[^o].class]</test.include><!-- exclude module-info.class-->
39+
<jmh.version>1.37</jmh.version>
3940
</properties>
4041

4142
<version>1.2.1-SNAPSHOT</version>
@@ -88,6 +89,13 @@
8889
<excludes>
8990
<exclude>${excludeTestPattern1}</exclude>
9091
</excludes>
92+
<annotationProcessorPaths>
93+
<path>
94+
<groupId>org.openjdk.jmh</groupId>
95+
<artifactId>jmh-generator-annprocess</artifactId>
96+
<version>${jmh.version}</version>
97+
</path>
98+
</annotationProcessorPaths>
9199
</configuration>
92100
</plugin>
93101
<plugin>
@@ -434,5 +442,17 @@
434442
<version>1.5.25</version>
435443
<scope>test</scope>
436444
</dependency>
445+
<dependency>
446+
<groupId>org.openjdk.jmh</groupId>
447+
<artifactId>jmh-core</artifactId>
448+
<version>${jmh.version}</version>
449+
<scope>test</scope>
450+
</dependency>
451+
<dependency>
452+
<groupId>org.openjdk.jmh</groupId>
453+
<artifactId>jmh-generator-annprocess</artifactId>
454+
<version>${jmh.version}</version>
455+
<scope>test</scope>
456+
</dependency>
437457
</dependencies>
438458
</project>

core/src/main/c/share/crc32c.c

Lines changed: 404 additions & 0 deletions
Large diffs are not rendered by default.

core/src/main/c/share/files.c

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,296 @@
2222
*
2323
******************************************************************************/
2424

25+
#define _GNU_SOURCE
26+
2527
#include <unistd.h>
28+
#include <sys/stat.h>
29+
#include <sys/file.h>
30+
#include <sys/mman.h>
31+
#include <fcntl.h>
32+
#include <errno.h>
33+
#include <stdlib.h>
34+
#include <string.h>
35+
#include <dirent.h>
36+
#include <stdint.h>
37+
2638
#include "files.h"
2739

40+
/* Mirror of io.questdb.client.std.Files.MAP_RO / MAP_RW. Hard-coded rather
41+
* than #include'd from a javah-generated header because this file does not
42+
* pull in any generated symbols (the rest of the file works the same way). */
43+
#define QDB_MAP_RO 1
44+
#define QDB_MAP_RW 2
45+
46+
#define RESTARTABLE(_expr_, _rc_) \
47+
do { _rc_ = (_expr_); } while ((_rc_) == -1 && errno == EINTR)
48+
2849
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_close0
2950
(JNIEnv *e, jclass cl, jint fd) {
3051
return close((int) fd);
3152
}
53+
54+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_openRO0
55+
(JNIEnv *e, jclass cl, jlong lpszName) {
56+
int fd;
57+
RESTARTABLE(open((const char *) (uintptr_t) lpszName, O_RDONLY), fd);
58+
return (jint) fd;
59+
}
60+
61+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_openRW0
62+
(JNIEnv *e, jclass cl, jlong lpszName) {
63+
int fd;
64+
RESTARTABLE(open((const char *) (uintptr_t) lpszName, O_CREAT | O_RDWR, 0644), fd);
65+
return (jint) fd;
66+
}
67+
68+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_openAppend0
69+
(JNIEnv *e, jclass cl, jlong lpszName) {
70+
int fd;
71+
RESTARTABLE(open((const char *) (uintptr_t) lpszName, O_CREAT | O_WRONLY | O_APPEND, 0644), fd);
72+
return (jint) fd;
73+
}
74+
75+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_openCleanRW0
76+
(JNIEnv *e, jclass cl, jlong lpszName, jlong size) {
77+
int fd;
78+
RESTARTABLE(open((const char *) (uintptr_t) lpszName, O_CREAT | O_TRUNC | O_RDWR, 0644), fd);
79+
if (fd < 0) {
80+
return -1;
81+
}
82+
if (size > 0) {
83+
int rc;
84+
RESTARTABLE(ftruncate(fd, (off_t) size), rc);
85+
if (rc != 0) {
86+
int saved = errno;
87+
close(fd);
88+
errno = saved;
89+
return -1;
90+
}
91+
}
92+
return (jint) fd;
93+
}
94+
95+
JNIEXPORT jlong JNICALL Java_io_questdb_client_std_Files_read
96+
(JNIEnv *e, jclass cl, jint fd, jlong addr, jlong len, jlong offset) {
97+
// Reject negative len explicitly: jlong is signed but pread takes a
98+
// size_t. Without this guard the cast wraps a small negative value
99+
// into an enormous unsigned read length and the kernel may either
100+
// SEGV on the address space or scribble far past the caller's buffer.
101+
// The Win32 path already does this; matching here.
102+
if (len < 0) {
103+
errno = EINVAL;
104+
return -1;
105+
}
106+
ssize_t res;
107+
RESTARTABLE(pread((int) fd, (void *) (uintptr_t) addr, (size_t) len, (off_t) offset), res);
108+
return (jlong) res;
109+
}
110+
111+
JNIEXPORT jlong JNICALL Java_io_questdb_client_std_Files_write
112+
(JNIEnv *e, jclass cl, jint fd, jlong addr, jlong len, jlong offset) {
113+
if (len < 0) {
114+
errno = EINVAL;
115+
return -1;
116+
}
117+
ssize_t res;
118+
RESTARTABLE(pwrite((int) fd, (const void *) (uintptr_t) addr, (size_t) len, (off_t) offset), res);
119+
return (jlong) res;
120+
}
121+
122+
JNIEXPORT jlong JNICALL Java_io_questdb_client_std_Files_append
123+
(JNIEnv *e, jclass cl, jint fd, jlong addr, jlong len) {
124+
if (len < 0) {
125+
errno = EINVAL;
126+
return -1;
127+
}
128+
ssize_t res;
129+
RESTARTABLE(write((int) fd, (const void *) (uintptr_t) addr, (size_t) len), res);
130+
return (jlong) res;
131+
}
132+
133+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_fsync
134+
(JNIEnv *e, jclass cl, jint fd) {
135+
int res;
136+
RESTARTABLE(fsync((int) fd), res);
137+
return res;
138+
}
139+
140+
JNIEXPORT jboolean JNICALL Java_io_questdb_client_std_Files_truncate
141+
(JNIEnv *e, jclass cl, jint fd, jlong size) {
142+
int res;
143+
RESTARTABLE(ftruncate((int) fd, (off_t) size), res);
144+
return res == 0 ? JNI_TRUE : JNI_FALSE;
145+
}
146+
147+
JNIEXPORT jboolean JNICALL Java_io_questdb_client_std_Files_allocate
148+
(JNIEnv *e, jclass cl, jint fd, jlong size) {
149+
#if defined(__linux__)
150+
int res = posix_fallocate((int) fd, 0, (off_t) size);
151+
if (res == 0) {
152+
return JNI_TRUE;
153+
}
154+
if (res != EINVAL && res != EOPNOTSUPP) {
155+
errno = res;
156+
return JNI_FALSE;
157+
}
158+
/* fall through to ftruncate */
159+
#elif defined(__APPLE__)
160+
fstore_t fst;
161+
fst.fst_flags = F_ALLOCATECONTIG | F_ALLOCATEALL;
162+
fst.fst_posmode = F_PEOFPOSMODE;
163+
fst.fst_offset = 0;
164+
fst.fst_length = (off_t) size;
165+
fst.fst_bytesalloc = 0;
166+
if (fcntl((int) fd, F_PREALLOCATE, &fst) == -1) {
167+
fst.fst_flags = F_ALLOCATEALL;
168+
(void) fcntl((int) fd, F_PREALLOCATE, &fst);
169+
/* if F_PREALLOCATE fails we still try ftruncate to set logical size */
170+
}
171+
#endif
172+
int res2;
173+
RESTARTABLE(ftruncate((int) fd, (off_t) size), res2);
174+
return res2 == 0 ? JNI_TRUE : JNI_FALSE;
175+
}
176+
177+
JNIEXPORT jlong JNICALL Java_io_questdb_client_std_Files_length
178+
(JNIEnv *e, jclass cl, jint fd) {
179+
struct stat st;
180+
if (fstat((int) fd, &st) != 0) {
181+
return -1;
182+
}
183+
return (jlong) st.st_size;
184+
}
185+
186+
JNIEXPORT jlong JNICALL Java_io_questdb_client_std_Files_length0
187+
(JNIEnv *e, jclass cl, jlong lpszName) {
188+
struct stat st;
189+
if (stat((const char *) (uintptr_t) lpszName, &st) != 0) {
190+
return -1;
191+
}
192+
return (jlong) st.st_size;
193+
}
194+
195+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_lock
196+
(JNIEnv *e, jclass cl, jint fd) {
197+
return flock((int) fd, LOCK_EX | LOCK_NB);
198+
}
199+
200+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_mkdir0
201+
(JNIEnv *e, jclass cl, jlong lpszPath, jint mode) {
202+
return mkdir((const char *) (uintptr_t) lpszPath, (mode_t) mode);
203+
}
204+
205+
JNIEXPORT jboolean JNICALL Java_io_questdb_client_std_Files_exists0
206+
(JNIEnv *e, jclass cl, jlong lpszPath) {
207+
return access((const char *) (uintptr_t) lpszPath, F_OK) == 0 ? JNI_TRUE : JNI_FALSE;
208+
}
209+
210+
JNIEXPORT jboolean JNICALL Java_io_questdb_client_std_Files_remove0
211+
(JNIEnv *e, jclass cl, jlong lpszPath) {
212+
return remove((const char *) (uintptr_t) lpszPath) == 0 ? JNI_TRUE : JNI_FALSE;
213+
}
214+
215+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_rename0
216+
(JNIEnv *e, jclass cl, jlong lpszOld, jlong lpszNew) {
217+
return rename((const char *) (uintptr_t) lpszOld, (const char *) (uintptr_t) lpszNew);
218+
}
219+
220+
typedef struct {
221+
DIR *dir;
222+
struct dirent *entry;
223+
} qdb_find_t;
224+
225+
JNIEXPORT jlong JNICALL Java_io_questdb_client_std_Files_findFirst0
226+
(JNIEnv *e, jclass cl, jlong lpszName) {
227+
DIR *dir = opendir((const char *) (uintptr_t) lpszName);
228+
if (!dir) {
229+
return 0;
230+
}
231+
qdb_find_t *find = (qdb_find_t *) malloc(sizeof(qdb_find_t));
232+
if (!find) {
233+
closedir(dir);
234+
return 0;
235+
}
236+
find->dir = dir;
237+
errno = 0;
238+
find->entry = readdir(dir);
239+
if (!find->entry) {
240+
int saved = errno;
241+
closedir(dir);
242+
free(find);
243+
errno = saved;
244+
return 0;
245+
}
246+
return (jlong) (uintptr_t) find;
247+
}
248+
249+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_findNext
250+
(JNIEnv *e, jclass cl, jlong findPtr) {
251+
qdb_find_t *find = (qdb_find_t *) (uintptr_t) findPtr;
252+
if (!find) {
253+
return -1;
254+
}
255+
errno = 0;
256+
find->entry = readdir(find->dir);
257+
if (find->entry) {
258+
return 1;
259+
}
260+
return errno == 0 ? 0 : -1;
261+
}
262+
263+
JNIEXPORT jlong JNICALL Java_io_questdb_client_std_Files_findName
264+
(JNIEnv *e, jclass cl, jlong findPtr) {
265+
qdb_find_t *find = (qdb_find_t *) (uintptr_t) findPtr;
266+
if (!find || !find->entry) {
267+
return 0;
268+
}
269+
return (jlong) (uintptr_t) find->entry->d_name;
270+
}
271+
272+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_findType
273+
(JNIEnv *e, jclass cl, jlong findPtr) {
274+
qdb_find_t *find = (qdb_find_t *) (uintptr_t) findPtr;
275+
if (!find || !find->entry) {
276+
return 0;
277+
}
278+
return (jint) find->entry->d_type;
279+
}
280+
281+
JNIEXPORT void JNICALL Java_io_questdb_client_std_Files_findClose
282+
(JNIEnv *e, jclass cl, jlong findPtr) {
283+
qdb_find_t *find = (qdb_find_t *) (uintptr_t) findPtr;
284+
if (find) {
285+
closedir(find->dir);
286+
free(find);
287+
}
288+
}
289+
290+
JNIEXPORT jlong JNICALL Java_io_questdb_client_std_Files_getPageSize0
291+
(JNIEnv *e, jclass cl) {
292+
long sz = sysconf(_SC_PAGESIZE);
293+
return (jlong) (sz > 0 ? sz : 4096);
294+
}
295+
296+
JNIEXPORT jlong JNICALL Java_io_questdb_client_std_Files_mmap0
297+
(JNIEnv *e, jclass cl, jint fd, jlong len, jlong offset, jint flags, jlong baseAddress) {
298+
int prot = 0;
299+
if (flags == QDB_MAP_RO) {
300+
prot = PROT_READ;
301+
} else if (flags == QDB_MAP_RW) {
302+
prot = PROT_READ | PROT_WRITE;
303+
}
304+
void *addr = mmap((void *) (uintptr_t) baseAddress, (size_t) len, prot, MAP_SHARED, (int) fd, (off_t) offset);
305+
/* MAP_FAILED is (void *) -1; cast to jlong gives -1 sentinel matching FAILED_MMAP_ADDRESS. */
306+
return (jlong) (intptr_t) addr;
307+
}
308+
309+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_munmap0
310+
(JNIEnv *e, jclass cl, jlong address, jlong len) {
311+
return munmap((void *) (uintptr_t) address, (size_t) len);
312+
}
313+
314+
JNIEXPORT jint JNICALL Java_io_questdb_client_std_Files_msync
315+
(JNIEnv *e, jclass cl, jlong addr, jlong len, jboolean async) {
316+
return msync((void *) (uintptr_t) addr, (size_t) len, async ? MS_ASYNC : MS_SYNC);
317+
}

0 commit comments

Comments
 (0)