Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
e4d46b1
Extract engine-construction factory from Sender.build()
jovfer Aug 17, 2026
6f3a3cf
Restore shared quarantined counter across construction and connect
jovfer Aug 17, 2026
3a30e4d
Add symbol_dict_reset config knobs
jovfer Aug 17, 2026
dc8a3f2
Arm symbol-dict recycle at flush; add advisory reset API
jovfer Aug 17, 2026
8f90f45
Prove threshold arming survives full-dict degradation
jovfer Aug 17, 2026
59559cf
Translate user-visible FSNs by a recycle epoch base
jovfer Aug 17, 2026
69255bd
Enforce roll precondition and fix a non-discriminating test
jovfer Aug 17, 2026
f9e986f
Recycle the send stack at the empty-backlog barrier
jovfer Aug 17, 2026
a2a1240
Guard the recycle swap against an unrebuildable engine
jovfer Aug 17, 2026
91b2f66
Pin memory-mode recycle behavior
jovfer Aug 17, 2026
903f2f6
Bounded blocking wait for a starved dictionary reset
jovfer Aug 17, 2026
3e68673
Fix round 1: correct starvation-wait javadoc, tighten tests
jovfer Aug 17, 2026
6180156
Pin recycle refusal conditions
jovfer Aug 17, 2026
2841394
Pin recycle behavior under outage and orphan drain
jovfer Aug 17, 2026
efd3e4f
Pin zero-catch-up on the recycle epoch boundary
jovfer Aug 17, 2026
c1a29bb
Fix round 1: correct Pin 4 mechanism attribution
jovfer Aug 17, 2026
debd45d
Pin recycle crash-window recovery
jovfer Aug 18, 2026
b5ba2b2
Fix round 1: pin arm (b) disk image, tighten oracles
jovfer Aug 18, 2026
07ecb27
Recycle heals full-dict degrade; expose recycle metrics
jovfer Aug 18, 2026
631ce88
Fix round 1: volatile metrics, tighten healing oracles
jovfer Aug 18, 2026
555fd48
Point cap error at the reset valve; raise client cap to 2M
jovfer Aug 18, 2026
e22376e
Fix round 1: drop tautological arm-state assertions
jovfer Aug 18, 2026
6dc84e5
Final wave: survive a step-7 connect failure without latching
jovfer Aug 18, 2026
06dcb6d
Fix round 2: recycle awaits a deferred engine close
jovfer Aug 19, 2026
65029ce
Make recycle-read monitoring fields volatile
jovfer Aug 20, 2026
6793928
Pin buffer-through-outage contract for the recycle
jovfer Aug 20, 2026
abed2a8
Defer the recycle reconnect to the I/O loop
jovfer Aug 20, 2026
dbbabf4
Seed the rebuilt loop's ever-connected flag
jovfer Aug 20, 2026
aa6a98f
Await the async post-recycle handshake in tests
jovfer Aug 20, 2026
fb28718
Make awaitAckedFsn recycle-safe; fix step-7 prose
jovfer Aug 20, 2026
d00acf9
Pin step-7 non-latching with a fault-injection test
jovfer Aug 24, 2026
895cc22
Add regression test for the batch-watermark reset guard
jovfer Aug 24, 2026
5986609
Split close()'s drain guard by true dependency
jovfer Aug 24, 2026
77d4ad7
Add re-arm floor to stop recycle thrash
jovfer Aug 24, 2026
16ac394
Commit the recycle swap only after a successful rebuild
jovfer Aug 24, 2026
b0a0126
Fix stale step-number docs left by the recycle reorder
jovfer Aug 24, 2026
dc99042
Make the recycle resumable instead of latching terminal
jovfer Aug 24, 2026
2ae927d
Pin the recycle's slot-heal and breach verdicts
jovfer Aug 24, 2026
8c41635
Never arm the reset on senders that cannot recycle
jovfer Aug 24, 2026
4bb08fb
Fix accessor truthfulness across the recycle window
jovfer Aug 24, 2026
dc6526b
Fix up M9 javadoc overclaim and make hasLoopEverConnected volatile
jovfer Aug 24, 2026
4b3894d
Fix stale doc claims left by the review wave
jovfer Aug 24, 2026
1d869cc
Pin the recycle re-arm floor arithmetic
jovfer Aug 27, 2026
269aa8a
Point comments at the renamed arming test
jovfer Aug 27, 2026
5591741
Hand the live error handler to the rebuild factory
jovfer Aug 27, 2026
e02a52c
Track a recovered engine's deferred close in the recycle
jovfer Aug 27, 2026
9d83a38
Pre-size the fresh dictionary, clamp getAckedFsn
jovfer Aug 27, 2026
2338976
Drop review finding IDs from the recycle tests
jovfer Aug 27, 2026
3ba9fbd
Pin the rebuild-time quarantine notification
jovfer Aug 27, 2026
1e7b73d
Pin getAckedFsn's torn-read clamp and null-engine window
jovfer Aug 27, 2026
c96ff5c
Spend one deferred-close budget per pending close
jovfer Aug 27, 2026
1391b9f
Clear the stale slot-lock latch before the rebuild
jovfer Aug 27, 2026
9969130
Report external FSNs in close-drain diagnostics
jovfer Aug 27, 2026
f83c21d
Bound the recycle threshold and wait knobs
jovfer Aug 27, 2026
66a91d7
Fit the ceiling test's threshold to the new bound
jovfer Aug 27, 2026
421ea94
State the recycle's listener and handler contract
jovfer Aug 27, 2026
9abc3be
Drop the redundant swap counter
jovfer Aug 27, 2026
9fc6060
Count the recycle counters correctly
jovfer Aug 27, 2026
7ef2381
Drop the last mention of the swap counter
jovfer Aug 27, 2026
42d55c6
Tighten the recycle suites and strip narration
jovfer Aug 27, 2026
50de646
Drop the last planning reference from a javadoc
jovfer Aug 27, 2026
f1c737d
Skip visibly when the interrupt loses the race
jovfer Aug 27, 2026
8e76d43
Rebase the abandon WARN and tidy three javadocs
jovfer Aug 27, 2026
a7c78c4
Merge remote-tracking branch 'origin/main' into qwp-dict-recycle-r1
jovfer Sep 8, 2026
f8d0876
Restore the pre-branch 23-arg connect(String,...) overload
jovfer Sep 8, 2026
06f8eda
Make the symbol-dict reset opportunistic by default
jovfer Sep 8, 2026
cd4d644
Pin the interrupt policy in the recycle park loops
jovfer Sep 8, 2026
7cd2201
Restore the interrupt flag on every deferred-close throw path
jovfer Sep 8, 2026
0794216
Re-register the delta baseline on CLOSE_LOOP resume
jovfer Sep 8, 2026
c6cf00d
Close the chunk debt on the resume's Error path
jovfer Sep 8, 2026
9d2de1f
Pin the resume fallback: baseline drop plus debt close
jovfer Sep 8, 2026
1b564c7
Prove the resume group is crash-safe end to end
jovfer Sep 8, 2026
9625a4a
State what the crash-replay test actually proves
jovfer Sep 8, 2026
a87779a
State the recycle trigger point in the three contracts
jovfer Sep 8, 2026
54b5297
Pin the everConnected seed against a post-recycle 401
jovfer Sep 8, 2026
1473b48
Pin FSN epoch-base accumulation across real recycles
jovfer Sep 8, 2026
7aa6dc4
Harden the monitoring surface and close review nits
jovfer Sep 8, 2026
280e379
Default the symbol-dict starvation wait to 2 s
jovfer Sep 9, 2026
259a16b
Snapshot arm (c)'s crash image only after the hot spare is installed
jovfer Sep 9, 2026
dd3e904
Poll the handshake count before pinning it in the refusal tests
jovfer Sep 9, 2026
81d5175
Keep the re-arm floor from being lowered by a manual reset
jovfer Sep 10, 2026
145a2de
Move the loop and engine counters into an adoptable holder
jovfer Sep 10, 2026
f28d9b5
Make the getTotal* counters sender-lifetime across recycles
jovfer Sep 10, 2026
ddb8ff0
Keep the delta baseline equal to the ringed coverage on a resume failure
jovfer Sep 10, 2026
b0497e8
Fold only the engine's own counter on adoption; pin the memory-mode r…
jovfer Sep 10, 2026
0d81211
Await the hot spare in the post-recycle slot-listing assertion
jovfer Sep 11, 2026
dde293c
test(qwp): pin the deferred-close park's interrupt policy; name the r…
jovfer Sep 14, 2026
0699205
fix(qwp): keep a carried interrupt flag from abandoning the recycle's…
jovfer Sep 17, 2026
65acc8e
docs(qwp): say what the recycle's loop-close helper does and does not…
jovfer Sep 17, 2026
bd8f0df
docs(qwp): say which calls complete a pending recycle; pin the rebuil…
jovfer Sep 17, 2026
cc8bcb3
test(qwp): pin the ever-connected seed across a recycle and a CLOSE_L…
jovfer Sep 17, 2026
8e9e0f4
test(qwp): pin the heal's second recovered pass
jovfer Sep 17, 2026
c5c56d3
test(qwp): drop a vacuous terminal-latch assertion from the keeps-rec…
jovfer Sep 17, 2026
13edfdc
docs(qwp): state why the recycle rebuild does not retry a slot-lock c…
jovfer Sep 17, 2026
ce20e09
docs(qwp): name all three ever-connected carriers; describe both resu…
jovfer Sep 17, 2026
f9932f0
fix(qwp): keep build() from throwing or leaking on an error the I/O t…
jovfer Sep 18, 2026
cb0c988
fix(qwp): hand the caller's interrupt flag back on every recycle wait…
jovfer Sep 18, 2026
2cf6eef
docs(qwp): say the deferred-close budget leaves the recycle pending, …
jovfer Sep 18, 2026
91fd445
fix(qwp): swap the symbol dictionary only while the I/O loop holds a …
jovfer Sep 18, 2026
046e668
fix(qwp): keep the released CursorWebSocketSendLoop constructor linking
jovfer Sep 23, 2026
ec10834
fix(qwp): keep the released QwpWebSocketSender.connectWithCredentialS…
jovfer Sep 23, 2026
996c3b0
test(qwp): pin that the rebuild-factory setter refuses only a closed …
jovfer Sep 23, 2026
fa8be57
test(qwp): pin that the recycle parks sleep under a set interrupt flag
jovfer Sep 23, 2026
131c767
docs(qwp): state the live-connection gate in the recycle javadocs
jovfer Sep 23, 2026
dba51c1
docs(qwp): say which compat pins guard a released signature and which…
jovfer Sep 23, 2026
ba54a13
Merge remote-tracking branch 'origin/main' into qwp-dict-recycle-r1
jovfer Sep 23, 2026
2deecfd
Document connect recycling prerequisite
bluestreak01 Sep 24, 2026
aaabff3
test(qwp): cover starvation wait across continuous flushes
bluestreak01 Sep 24, 2026
3074b1e
fix(qwp): keep the SF slot owned across the symbol dictionary recycle
jovfer Sep 25, 2026
fe0762b
fix(qwp): have the sender own the recycle slot lock, drop factory sel…
jovfer Sep 25, 2026
f5ebf00
test(qwp): pin SF slot ownership across the recycle
jovfer Sep 25, 2026
700d849
test(qwp): pin one starvation wait per armed window across a recycle
jovfer Sep 25, 2026
5898e48
fix(qwp): prove the post-recycle loop is linked before window 2's tim…
jovfer Sep 25, 2026
fb8f35f
fix(qwp): awaitAckedFsn re-reads the epoch base and the engine on eve…
jovfer Sep 25, 2026
54b75cd
docs(qwp): state that FSNs are scoped to the sender instance
jovfer Sep 25, 2026
9579771
Merge remote-tracking branch 'origin/main' into qwp-dict-recycle-r1
jovfer Sep 25, 2026
0496f03
fix(qwp): snapshot the loop in checkConnectionError; release the recy…
jovfer Sep 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ core/CMakeCache.txt
**/.project
**/.settings
**/.classpath
**/.factorypath
**/build
**/CMakeFiles
.envrc
Expand Down
451 changes: 372 additions & 79 deletions core/src/main/java/io/questdb/client/Sender.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,19 @@ public enum Kind {

/**
* The active wire connection dropped and the reconnect loop is about
* to start. Fired once per outage, before any retry attempts.
* to start. Fired once per outage, before any retry attempts. Not
* fired for the deliberate reconnect a symbol-dictionary recycle
* performs.
*/
DISCONNECTED,

/**
* A reconnect attempt succeeded against the same endpoint that was
* previously active. Fired once per successful reconnect to the same
* endpoint; {@link Kind#FAILED_OVER} is fired instead when the new
* endpoint differs.
* endpoint differs. Also fired — without a preceding
* {@link #DISCONNECTED} — for the reconnect that follows a
* symbol-dictionary recycle, which is deliberate, not an outage.
*/
RECONNECTED,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@
* ({@link SenderConnectionEvent.Kind#CONNECTED},
* {@link SenderConnectionEvent.Kind#FAILED_OVER},
* {@link SenderConnectionEvent.Kind#RECONNECTED}) are guaranteed to fire on
* each transition. Failure events ({@code ENDPOINT_ATTEMPT_FAILED},
* each transition. A symbol-dictionary recycle tears the wire connection down
* and reconnects deliberately; that reconnect reports {@code RECONNECTED}
* (or {@code FAILED_OVER}) with no {@code DISCONNECTED} before it, so a
* listener pairing the two must not assume every success follows an outage.
* Failure events ({@code ENDPOINT_ATTEMPT_FAILED},
* {@code ALL_ENDPOINTS_UNREACHABLE}) may be coalesced under inbox pressure.
* The terminal event {@code AUTH_FAILED}
* fires before the producer-thread {@code LineSenderException} is observable on
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/java/io/questdb/client/SenderError.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@
*
* <p>The {@code [fromFsn, toFsn]} span is the load-bearing correlation key — join it to
* whatever the producer thread logged alongside the published-sequence value returned by
* the sender to identify the rejected data. Background orphan-drainer reports use
* the same sender instance to identify the rejected data. Both bounds are on the reporting
* sender's own FSN scale (see {@link Sender#flushAndGetSequence()}): a sender restarted on
* the same store-and-forward slot reports replayed frames on its own scale, not on the
* closed process's. Background orphan-drainer reports use
* {@link #NO_MESSAGE_SEQUENCE} for both bounds because those FSNs belong to another sender
* engine and must not be joined to the live producer's rows.
*
Expand Down
13 changes: 9 additions & 4 deletions core/src/main/java/io/questdb/client/SenderErrorHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@
*
* <h2>Threading</h2>
* Handlers normally run on a dedicated daemon dispatcher thread, never on the
* I/O thread or the producer thread. One exception: a build()-time quarantine
* I/O thread or the producer thread. One exception: a slot quarantine
* ({@link SenderError.Category#DATA_LOSS}) is dispatched synchronously on the
* thread calling {@code build()} — the async dispatcher belongs to the
* connected sender, which does not exist yet at build time. Handlers must not
* block: for the build-time case, {@code build()} is waiting.
* calling thread — at {@code build()} time because the async dispatcher does
* not exist yet, and during a symbol-dictionary recycle rebuild (on the
* producer thread: inside the {@code table(...)} call that triggered the
* recycle or, when an earlier attempt failed transiently, inside the
* {@code table(...)}, {@code flush()} or {@code drain(...)} call that
* resumes it) because a data-loss notice must
* not be dropped under inbox pressure. Handlers must not block or call back
* into the sender: in both cases the caller is waiting.
* Slow handlers cannot stall publishing; if the bounded
* inbox fills up, surplus notifications are dropped (visible via
* {@code QwpWebSocketSender.getDroppedErrorNotifications()}).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,11 @@ public int getOrAddSymbol(CharSequence symbol) {
+ ". Rows using already-registered symbol values continue to work. To start a fresh "
+ "dictionary, close this sender and build a new one (with store-and-forward the "
+ "buffered backlog drains first). For unbounded-cardinality data use varchar "
+ "columns instead of symbol");
+ "columns instead of symbol. The automatic dictionary reset "
+ "(symbol_dict_reset, symbol_dict_reset_threshold) and "
+ "Sender.resetSymbolDictionary() avoid this cap, but both act only "
+ "on senders created via Sender.build()/fromConfig(), and the reset "
+ "itself runs at a table() call once the backlog is acknowledged.");
}

// Assign new ID — toString() only for new symbols that must be stored
Expand Down
Loading
Loading