diff --git a/core/src/main/c/share/files.c b/core/src/main/c/share/files.c index 629eacb2..02fb93a1 100644 --- a/core/src/main/c/share/files.c +++ b/core/src/main/c/share/files.c @@ -164,9 +164,16 @@ JNIEXPORT jboolean JNICALL Java_io_questdb_client_std_Files_allocate fst.fst_length = (off_t) size; fst.fst_bytesalloc = 0; if (fcntl((int) fd, F_PREALLOCATE, &fst) == -1) { + /* Contiguous allocation failed (e.g. fragmented filesystem); retry + * non-contiguous all-or-nothing. Only fall through to ftruncate when + * the filesystem doesn't support F_PREALLOCATE at all; real failures + * (notably ENOSPC) must surface so the caller doesn't end up with a + * sparse file that SIGBUSes on later mmap store (sf-client.md §6). */ fst.fst_flags = F_ALLOCATEALL; - (void) fcntl((int) fd, F_PREALLOCATE, &fst); - /* if F_PREALLOCATE fails we still try ftruncate to set logical size */ + if (fcntl((int) fd, F_PREALLOCATE, &fst) == -1 + && errno != ENOTSUP && errno != EOPNOTSUPP) { + return JNI_FALSE; + } } #endif int res2; diff --git a/core/src/main/java/io/questdb/client/Sender.java b/core/src/main/java/io/questdb/client/Sender.java index 790a2210..27a79962 100644 --- a/core/src/main/java/io/questdb/client/Sender.java +++ b/core/src/main/java/io/questdb/client/Sender.java @@ -620,6 +620,10 @@ final class LineSenderBuilder { private static final long DEFAULT_WS_AUTO_FLUSH_INTERVAL_NANOS = 100_000_000L; // 100ms private static final int DEFAULT_WS_AUTO_FLUSH_ROWS = 1_000; private static final int MIN_BUFFER_SIZE = AuthUtils.CHALLENGE_LEN + 1; // challenge size + 1; + // sf-client.md section 4.4: the inbox capacity must accommodate the + // distinct error categories in a bursty error stream so that drop-oldest + // does not erase the trailing distribution of categories. + private static final int MIN_ERROR_INBOX_CAPACITY = 16; // The PARAMETER_NOT_SET_EXPLICITLY constant is used to detect if a parameter was set explicitly in configuration parameters // where it matters. This is needed to detect invalid combinations of parameters. Why? // We want to fail-fast even when an explicitly configured options happens to be same value as the default value, @@ -1864,15 +1868,20 @@ public LineSenderBuilder errorHandler(io.questdb.client.SenderErrorHandler handl * *

WebSocket transport only; setting on other transports throws. * - * @param capacity must be {@code >= 1} + * @param capacity must be {@code >= 16} (sf-client.md section 4.4). + * The floor exists because overflow drops the oldest + * entry and watermarks are monotonic, so the inbox + * must be wide enough to keep a useful trailing + * window of categories under bursty errors. * @return this instance for method chaining */ public LineSenderBuilder errorInboxCapacity(int capacity) { if (protocol != PARAMETER_NOT_SET_EXPLICITLY && protocol != PROTOCOL_WEBSOCKET) { throw new LineSenderException("error_inbox_capacity is only supported for WebSocket transport"); } - if (capacity < 1) { - throw new LineSenderException("error_inbox_capacity must be >= 1, was " + capacity); + if (capacity < MIN_ERROR_INBOX_CAPACITY) { + throw new LineSenderException("error_inbox_capacity must be >= " + + MIN_ERROR_INBOX_CAPACITY + ", was " + capacity); } this.errorInboxCapacity = capacity; return this; diff --git a/core/src/main/java/io/questdb/client/cutlass/qwp/client/QwpQueryClient.java b/core/src/main/java/io/questdb/client/cutlass/qwp/client/QwpQueryClient.java index deb9a75f..178d35d0 100644 --- a/core/src/main/java/io/questdb/client/cutlass/qwp/client/QwpQueryClient.java +++ b/core/src/main/java/io/questdb/client/cutlass/qwp/client/QwpQueryClient.java @@ -293,7 +293,9 @@ private QwpQueryClient(String host, int port) { *