Skip to content

Commit 05c2595

Browse files
committed
wip: less copying
1 parent cb37f52 commit 05c2595

12 files changed

Lines changed: 806 additions & 370 deletions

File tree

core/src/main/c/share/net.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <unistd.h>
3232
#include <sys/errno.h>
3333
#include <stdlib.h>
34+
#include <stdint.h>
3435
#include <string.h>
3536
#include "net.h"
3637
#include <netdb.h>
@@ -356,4 +357,36 @@ JNIEXPORT jint JNICALL Java_io_questdb_client_network_Net_sendTo
356357
(JNIEnv *e, jclass cl, jint fd, jlong ptr, jint len, jlong sockaddr) {
357358
return (jint) sendto((int) fd, (const void *) ptr, (size_t) len, 0, (const struct sockaddr *) sockaddr,
358359
sizeof(struct sockaddr_in));
359-
}
360+
}
361+
362+
JNIEXPORT jint JNICALL Java_io_questdb_client_network_Net_sendToScatter
363+
(JNIEnv *e, jclass cl, jint fd, jlong segmentsPtr, jint segmentCount, jlong sockaddr) {
364+
if (segmentCount <= 0) {
365+
return 0;
366+
}
367+
368+
struct iovec *iov = calloc((size_t) segmentCount, sizeof(struct iovec));
369+
if (iov == NULL) {
370+
errno = ENOMEM;
371+
return -1;
372+
}
373+
374+
const char *segment = (const char *) segmentsPtr;
375+
for (int i = 0; i < segmentCount; i++) {
376+
iov[i].iov_base = (void *) (uintptr_t) (*(const jlong *) segment);
377+
iov[i].iov_len = (size_t) (*(const jlong *) (segment + 8));
378+
segment += 16;
379+
}
380+
381+
struct msghdr msg;
382+
memset(&msg, 0, sizeof(msg));
383+
msg.msg_name = (void *) sockaddr;
384+
msg.msg_namelen = sizeof(struct sockaddr_in);
385+
msg.msg_iov = iov;
386+
msg.msg_iovlen = (size_t) segmentCount;
387+
388+
ssize_t sent;
389+
RESTARTABLE(sendmsg((int) fd, &msg, 0), sent);
390+
free(iov);
391+
return sent < 0 ? -1 : (jint) sent;
392+
}

core/src/main/c/share/net.h

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/main/c/windows/net.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <winsock2.h>
2626
#include <ws2tcpip.h>
2727
#include <mstcpip.h>
28+
#include <stdint.h>
2829
#include "../share/net.h"
2930
#include "errno.h"
3031

@@ -287,4 +288,45 @@ JNIEXPORT jint JNICALL Java_io_questdb_client_network_Net_sendTo
287288
SaveLastError();
288289
}
289290
return result;
290-
}
291+
}
292+
293+
JNIEXPORT jint JNICALL Java_io_questdb_client_network_Net_sendToScatter
294+
(JNIEnv *e, jclass cl, jint fd, jlong segmentsPtr, jint segmentCount, jlong sockaddr) {
295+
if (segmentCount <= 0) {
296+
return 0;
297+
}
298+
299+
WSABUF *buffers = calloc((size_t) segmentCount, sizeof(WSABUF));
300+
if (buffers == NULL) {
301+
WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
302+
SaveLastError();
303+
return -1;
304+
}
305+
306+
const char *segment = (const char *) segmentsPtr;
307+
for (int i = 0; i < segmentCount; i++) {
308+
buffers[i].buf = (CHAR *) (uintptr_t) (*(const jlong *) segment);
309+
buffers[i].len = (ULONG) (*(const jlong *) (segment + 8));
310+
segment += 16;
311+
}
312+
313+
DWORD bytesSent = 0;
314+
int result = WSASendTo(
315+
(SOCKET) fd,
316+
buffers,
317+
(DWORD) segmentCount,
318+
&bytesSent,
319+
0,
320+
(const struct sockaddr *) sockaddr,
321+
sizeof(struct sockaddr_in),
322+
NULL,
323+
NULL
324+
);
325+
free(buffers);
326+
327+
if (result == SOCKET_ERROR) {
328+
SaveLastError();
329+
return -1;
330+
}
331+
return (jint) bytesSent;
332+
}

core/src/main/java/io/questdb/client/cutlass/line/udp/UdpLineChannel.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,10 @@ public void send(long ptr, int len) {
8585
throw new LineSenderException("send error").errno(nf.errno());
8686
}
8787
}
88+
89+
public void sendSegments(long segmentsPtr, int segmentCount, int totalLen) {
90+
if (nf.sendToRawScatter(fd, segmentsPtr, segmentCount, sockaddr) != totalLen) {
91+
throw new LineSenderException("send error").errno(nf.errno());
92+
}
93+
}
8894
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* ___ _ ____ ____
3+
* / _ \ _ _ ___ ___| |_| _ \| __ )
4+
* | | | | | | |/ _ \/ __| __| | | | _ \
5+
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
6+
* \__\_\\__,_|\___||___/\__|____/|____/
7+
*
8+
* Copyright (c) 2014-2019 Appsicle
9+
* Copyright (c) 2019-2026 QuestDB
10+
*
11+
* Licensed under the Apache License, Version 2.0 (the "License");
12+
* you may not use this file except in compliance with the License.
13+
* You may obtain a copy of the License at
14+
*
15+
* http://www.apache.org/licenses/LICENSE-2.0
16+
*
17+
* Unless required by applicable law or agreed to in writing, software
18+
* distributed under the License is distributed on an "AS IS" BASIS,
19+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20+
* See the License for the specific language governing permissions and
21+
* limitations under the License.
22+
*/
23+
24+
package io.questdb.client.cutlass.qwp.client;
25+
26+
import io.questdb.client.std.MemoryTag;
27+
import io.questdb.client.std.QuietCloseable;
28+
import io.questdb.client.std.Unsafe;
29+
30+
final class NativeSegmentList implements QuietCloseable {
31+
static final int SEGMENT_SIZE = 16;
32+
33+
private int capacity;
34+
private long ptr;
35+
private int size;
36+
private long totalLength;
37+
38+
NativeSegmentList() {
39+
this(16);
40+
}
41+
42+
NativeSegmentList(int initialCapacity) {
43+
this.capacity = Math.max(initialCapacity, 4);
44+
this.ptr = Unsafe.malloc((long) capacity * SEGMENT_SIZE, MemoryTag.NATIVE_DEFAULT);
45+
}
46+
47+
void add(long address, long length) {
48+
if (length <= 0) {
49+
return;
50+
}
51+
ensureCapacity(size + 1);
52+
long segmentPtr = ptr + (long) size * SEGMENT_SIZE;
53+
Unsafe.getUnsafe().putLong(segmentPtr, address);
54+
Unsafe.getUnsafe().putLong(segmentPtr + 8, length);
55+
size++;
56+
totalLength += length;
57+
}
58+
59+
void appendFrom(NativeSegmentList other) {
60+
if (other.size == 0) {
61+
return;
62+
}
63+
ensureCapacity(size + other.size);
64+
Unsafe.getUnsafe().copyMemory(
65+
other.ptr,
66+
ptr + (long) size * SEGMENT_SIZE,
67+
(long) other.size * SEGMENT_SIZE
68+
);
69+
size += other.size;
70+
totalLength += other.totalLength;
71+
}
72+
73+
long getAddress() {
74+
return ptr;
75+
}
76+
77+
int getSegmentCount() {
78+
return size;
79+
}
80+
81+
long getTotalLength() {
82+
return totalLength;
83+
}
84+
85+
@Override
86+
public void close() {
87+
if (ptr != 0) {
88+
Unsafe.free(ptr, (long) capacity * SEGMENT_SIZE, MemoryTag.NATIVE_DEFAULT);
89+
ptr = 0;
90+
capacity = 0;
91+
size = 0;
92+
totalLength = 0;
93+
}
94+
}
95+
96+
void reset() {
97+
size = 0;
98+
totalLength = 0;
99+
}
100+
101+
private void ensureCapacity(int required) {
102+
if (required <= capacity) {
103+
return;
104+
}
105+
106+
int newCapacity = capacity;
107+
while (newCapacity < required) {
108+
newCapacity *= 2;
109+
}
110+
111+
ptr = Unsafe.realloc(
112+
ptr,
113+
(long) capacity * SEGMENT_SIZE,
114+
(long) newCapacity * SEGMENT_SIZE,
115+
MemoryTag.NATIVE_DEFAULT
116+
);
117+
capacity = newCapacity;
118+
}
119+
}

0 commit comments

Comments
 (0)