Commit b665b8c
Harden QWP client decoder, binds, and close paths
Tier 1 findings from the QWP client review, consolidated into one
change so client and server wire formats stay aligned.
Decoder (QwpResultBatchDecoder)
- Non-delta parseSymbolColumn now rejects a dict size that is negative
or exceeds rowCount, and rejects an entry length that is negative or
above Integer.MAX_VALUE. Previously dictSize*8 could overflow int and
bypass ensureOwnedEntriesAddr; a signed-wrap entryLen could slip the
p + entryLen > limit check and advance p backwards through already-
consumed bytes.
- parseDeltaSymbolDict caps entryLen at Integer.MAX_VALUE before the
int cast, computes newHeapPos in long space, and rejects growth
beyond MAX_CONN_DICT_HEAP_BYTES. connDictSize is capped at
MAX_CONN_DICT_SIZE. These guards keep a server that fails to emit
CACHE_RESET from wrapping connDictHeapPos negative and letting
copyMemory write past the heap.
- GEOHASH decode rejects precisionBits outside [1, 60], mirroring the
server's own range check.
Bind encoder (QwpBindValues)
- checkScale split into per-width variants (DECIMAL64 <= 18,
DECIMAL128 <= 38, DECIMAL256 <= 76) so out-of-range scales are
rejected at the type boundary instead of silently passing through
under the shared MAX_SCALE cap.
- setNull for DECIMAL64/128/256 emits the trailing scale byte and
setNull for GEOHASH emits the precision_bits varint. The server
reads both fields unconditionally before checking the null flag, so
omitting them misframed every bind that followed in the batch.
- setDecimal128(Decimal128) and setDecimal256(Decimal256) now preserve
value.getScale() on the null-sentinel path.
- New explicit helpers setNullDecimal64/128/256(int, int scale) and
setNullGeohash(int, int precisionBits) let callers pin the type's
scale/precision without a non-null value.
- setGeohash masks value to precisionBits before emitting, so bits
above the declared precision cannot leak into the top wire byte
when precisionBits is not a multiple of 8.
Buffer (QwpBatchBuffer)
- ensureCapacity rejects a negative required length, starts doubling
at max(current, 1) so a zero initial capacity can still grow, and
computes the doubling in long space with a clamp at
Integer.MAX_VALUE. The old int doubling spun forever at 0 and
wrapped negative above 2^30.
Concurrency (QwpQueryClient, QwpEgressIoThread)
- close() is gated by an AtomicBoolean so concurrent or repeat calls
no longer walk the shutdown body twice.
- GenerationListener now owns its own AtomicReference<TerminalFailure>
instead of sharing one across generations. An orphaned-but-in-flight
listener's compareAndSet lands on a ref nobody reads, so a late
callback from a dying I/O thread cannot poison the next connection.
- releaseBuffer re-checks closed after the freeBuffers.offer and
removes the buffer back out if closePool raced it; the buffer is
closed in place rather than stranded in a drained-and-abandoned
pool. ArrayBlockingQueue.remove gives us the atomicity we need to
avoid a double close when closePool's drain beat us to the same
buffer.
Regression tests
- QwpBindEncoderTest: new coverage for per-width scale rejection
(DECIMAL64 > 18, DECIMAL128 > 38, DECIMAL256 accepts 76), the four
typed setNullDecimal*/setNullGeohash helpers, the geohash masking
at sub-byte and 60-bit precisions, and updated expectations for
the NULL path of the convenience Decimal128/256 overloads and the
exhaustive null-types walk.
- QwpResultBatchDecoderHardeningTest: new frames for non-delta
dict-size-above-rowCount, delta entry length > Integer.MAX_VALUE,
and GEOHASH precision 0 / 61.
- QwpBatchBufferTest: new file covering grow-from-zero, reject-
negative, and bounded-time growth.
- QwpQueryClientUnitTest: new concurrent-close stress test.
- QwpEgressIoThreadCloseRaceTest: new file; 200 iterations racing
releaseBuffer against closePool under assertMemoryLeak so a
stranded buffer surfaces as a native-memory leak.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent ee8876e commit b665b8c
10 files changed
Lines changed: 944 additions & 59 deletions
File tree
- core/src
- main/java/io/questdb/client/cutlass/qwp/client
- test/java/io/questdb/client/test/cutlass/qwp/client
Lines changed: 25 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
96 | 101 | | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
101 | 122 | | |
102 | 123 | | |
Lines changed: 139 additions & 19 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
63 | 79 | | |
64 | 80 | | |
65 | 81 | | |
| |||
108 | 124 | | |
109 | 125 | | |
110 | 126 | | |
111 | | - | |
| 127 | + | |
112 | 128 | | |
113 | 129 | | |
114 | 130 | | |
| |||
120 | 136 | | |
121 | 137 | | |
122 | 138 | | |
123 | | - | |
124 | | - | |
| 139 | + | |
| 140 | + | |
125 | 141 | | |
126 | 142 | | |
127 | | - | |
128 | | - | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
129 | 148 | | |
130 | 149 | | |
131 | 150 | | |
132 | 151 | | |
133 | 152 | | |
134 | | - | |
| 153 | + | |
135 | 154 | | |
136 | 155 | | |
137 | 156 | | |
| |||
145 | 164 | | |
146 | 165 | | |
147 | 166 | | |
148 | | - | |
| 167 | + | |
| 168 | + | |
149 | 169 | | |
150 | 170 | | |
151 | | - | |
152 | | - | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
153 | 176 | | |
154 | 177 | | |
155 | 178 | | |
156 | 179 | | |
157 | 180 | | |
158 | | - | |
| 181 | + | |
159 | 182 | | |
160 | 183 | | |
161 | 184 | | |
| |||
181 | 204 | | |
182 | 205 | | |
183 | 206 | | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
184 | 212 | | |
185 | 213 | | |
186 | | - | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
| 214 | + | |
191 | 215 | | |
192 | 216 | | |
193 | 217 | | |
| 218 | + | |
194 | 219 | | |
195 | 220 | | |
196 | | - | |
| 221 | + | |
197 | 222 | | |
198 | 223 | | |
199 | 224 | | |
| |||
226 | 251 | | |
227 | 252 | | |
228 | 253 | | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
229 | 260 | | |
230 | 261 | | |
231 | 262 | | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
232 | 275 | | |
233 | 276 | | |
234 | 277 | | |
235 | 278 | | |
236 | 279 | | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
237 | 331 | | |
238 | 332 | | |
239 | 333 | | |
| |||
351 | 445 | | |
352 | 446 | | |
353 | 447 | | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
354 | 456 | | |
355 | 457 | | |
356 | 458 | | |
| |||
360 | 462 | | |
361 | 463 | | |
362 | 464 | | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
363 | 469 | | |
364 | 470 | | |
365 | 471 | | |
| |||
400 | 506 | | |
401 | 507 | | |
402 | 508 | | |
403 | | - | |
404 | | - | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
405 | 525 | | |
406 | | - | |
| 526 | + | |
407 | 527 | | |
408 | 528 | | |
409 | 529 | | |
| |||
Lines changed: 11 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
247 | 247 | | |
248 | 248 | | |
249 | 249 | | |
| 250 | + | |
250 | 251 | | |
251 | 252 | | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
252 | 263 | | |
253 | 264 | | |
254 | 265 | | |
| |||
0 commit comments