Commit 0fe4873
Close four data-integrity holes in the delta symbol dictionary
C1. CursorSendEngine.close() unlinked the parent-anchored logical slot
lock while Sender.build() still held it. A fresh slot is "fully drained"
by definition (publishedFsn() < 0), and build() closes the engine from
inside its acquireLogical scope whenever connect fails -- the ordinary
"server isn't up yet" startup. On POSIX the unlink frees the pathname
without releasing the flock, so the next acquireLogical creates a second
inode and locks it successfully: two parties owning the lock that exists
solely to serialise the quarantine close->rename->recreate window.
close(boolean) lets a caller that holds the lock skip the reclaim;
build() and quarantineTornSlot pass false. An unheld lock is still
reclaimed, so .slot-locks does not grow without bound.
C2. Recovery rebuilds the producer dictionary from the side-file's
intact prefix AND the surviving frames' own deltas, then resumes
sentMaxSymbolId at the combined tip -- above pd.size(). Every frame
published afterwards then carried a deltaStart the side-file could not
describe. The steady-state write-ahead did not close that gap: it
persists [pd.size() .. currentBatchMaxSymbolId] and returns early when
the batch's highest id is below pd.size(), so it healed only if, and
only as far as, later traffic referenced the recovered high ids. The
frames carrying those ids are the oldest unacked and so the first to be
acked and trimmed; once gone, an ordinary process crash -- which
store-and-forward promises to survive -- left a slot whose frames
reference ids nothing holds, and build() quarantined it. Recovery now
heals the side-file eagerly and in full, before any new frame publishes.
That heal advances pd.size() before the send loop is built, and the loop
seeded sentDictCount from the live size() while taking its bytes from
the fixed loaded region -- so the mirror would have claimed symbols it
did not hold. PersistedSymbolDict now exposes recoveredSize(), the entry
count that matches loadedEntriesAddr/Len, and the loop and the loaded-
region decoder both key off that instead.
C3. deltaDictEnabled was written once at setCursorEngine with no runtime
disable, so a mid-run .symbol-dict write failure killed flush() forever.
A full disk reaches exactly that state: SF's segments are pre-allocated
mmap files and stay writable while the growing side-file does not. Full
self-sufficient frames need no side file at all, so a persist failure
now degrades to them. The failing flush still throws -- beginMessage has
already baked a delta deltaStart into the staged frame -- but the throw
precedes every publish, so the rows stay buffered and the next flush
re-encodes them from id 0.
C4. Two recovery-seed exits threw raw IllegalStateException, which
Sender.build() does not route to its quarantine handler: with a stable
senderId every restart re-recovered the same slot and rethrew, so the
application could never construct a Sender and could not even buffer.
Both now throw UnreplayableSlotException. QwpWebSocketSender.connect's
rollback also let a close() failure replace the original exception and
demote a recoverable slot back to that brick; it now addSuppressed.
Regression tests, each verified to fail with its fix reverted:
EngineCloseSlotLockReleaseTest#testCloseDoesNotUnlinkALogicalLockItsCallerHolds
("close(false) must leave the logical lock file alone") and
DeltaDictRecoveryTest#testRecoveryHealsThePersistedDictionaryBeforeAnyNewFrame
("expected:<3> but was:<2>"). A companion test pins that an unheld
logical lock is still reclaimed. Full client suite: 2687 tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent d76ef16 commit 0fe4873
7 files changed
Lines changed: 348 additions & 44 deletions
File tree
- core/src
- main/java/io/questdb/client
- cutlass/qwp/client
- sf/cursor
- test/java/io/questdb/client/test/cutlass/qwp/client
- sf/cursor
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1643 | 1643 | | |
1644 | 1644 | | |
1645 | 1645 | | |
1646 | | - | |
| 1646 | + | |
| 1647 | + | |
1647 | 1648 | | |
1648 | 1649 | | |
1649 | 1650 | | |
| |||
1655 | 1656 | | |
1656 | 1657 | | |
1657 | 1658 | | |
1658 | | - | |
| 1659 | + | |
| 1660 | + | |
| 1661 | + | |
| 1662 | + | |
1659 | 1663 | | |
1660 | | - | |
| 1664 | + | |
1661 | 1665 | | |
1662 | 1666 | | |
1663 | 1667 | | |
| |||
3064 | 3068 | | |
3065 | 3069 | | |
3066 | 3070 | | |
3067 | | - | |
3068 | | - | |
| 3071 | + | |
| 3072 | + | |
| 3073 | + | |
| 3074 | + | |
3069 | 3075 | | |
3070 | 3076 | | |
3071 | 3077 | | |
| |||
Lines changed: 102 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
804 | 804 | | |
805 | 805 | | |
806 | 806 | | |
807 | | - | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
808 | 817 | | |
809 | 818 | | |
810 | 819 | | |
| |||
3864 | 3873 | | |
3865 | 3874 | | |
3866 | 3875 | | |
| 3876 | + | |
| 3877 | + | |
| 3878 | + | |
| 3879 | + | |
| 3880 | + | |
| 3881 | + | |
| 3882 | + | |
| 3883 | + | |
| 3884 | + | |
| 3885 | + | |
| 3886 | + | |
| 3887 | + | |
| 3888 | + | |
| 3889 | + | |
| 3890 | + | |
| 3891 | + | |
| 3892 | + | |
| 3893 | + | |
| 3894 | + | |
| 3895 | + | |
| 3896 | + | |
| 3897 | + | |
| 3898 | + | |
| 3899 | + | |
| 3900 | + | |
| 3901 | + | |
| 3902 | + | |
| 3903 | + | |
| 3904 | + | |
| 3905 | + | |
| 3906 | + | |
| 3907 | + | |
| 3908 | + | |
| 3909 | + | |
| 3910 | + | |
| 3911 | + | |
| 3912 | + | |
| 3913 | + | |
| 3914 | + | |
| 3915 | + | |
| 3916 | + | |
| 3917 | + | |
| 3918 | + | |
| 3919 | + | |
| 3920 | + | |
| 3921 | + | |
| 3922 | + | |
| 3923 | + | |
| 3924 | + | |
| 3925 | + | |
| 3926 | + | |
| 3927 | + | |
| 3928 | + | |
| 3929 | + | |
| 3930 | + | |
| 3931 | + | |
| 3932 | + | |
| 3933 | + | |
| 3934 | + | |
| 3935 | + | |
| 3936 | + | |
| 3937 | + | |
| 3938 | + | |
| 3939 | + | |
| 3940 | + | |
| 3941 | + | |
| 3942 | + | |
| 3943 | + | |
| 3944 | + | |
| 3945 | + | |
| 3946 | + | |
| 3947 | + | |
| 3948 | + | |
| 3949 | + | |
| 3950 | + | |
| 3951 | + | |
| 3952 | + | |
| 3953 | + | |
3867 | 3954 | | |
3868 | 3955 | | |
3869 | 3956 | | |
| |||
3932 | 4019 | | |
3933 | 4020 | | |
3934 | 4021 | | |
3935 | | - | |
| 4022 | + | |
| 4023 | + | |
| 4024 | + | |
| 4025 | + | |
| 4026 | + | |
| 4027 | + | |
| 4028 | + | |
| 4029 | + | |
| 4030 | + | |
| 4031 | + | |
3936 | 4032 | | |
3937 | 4033 | | |
3938 | 4034 | | |
| |||
4054 | 4150 | | |
4055 | 4151 | | |
4056 | 4152 | | |
| 4153 | + | |
| 4154 | + | |
| 4155 | + | |
| 4156 | + | |
4057 | 4157 | | |
4058 | 4158 | | |
4059 | 4159 | | |
| |||
Lines changed: 46 additions & 20 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
409 | 409 | | |
410 | 410 | | |
411 | 411 | | |
412 | | - | |
413 | | - | |
414 | | - | |
415 | | - | |
416 | | - | |
417 | | - | |
418 | | - | |
419 | | - | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
420 | 419 | | |
421 | 420 | | |
422 | 421 | | |
| |||
640 | 639 | | |
641 | 640 | | |
642 | 641 | | |
643 | | - | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
644 | 660 | | |
645 | 661 | | |
646 | 662 | | |
| |||
728 | 744 | | |
729 | 745 | | |
730 | 746 | | |
731 | | - | |
732 | | - | |
733 | | - | |
734 | | - | |
735 | | - | |
736 | | - | |
737 | | - | |
738 | | - | |
739 | | - | |
740 | | - | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
741 | 761 | | |
742 | 762 | | |
743 | 763 | | |
| |||
812 | 832 | | |
813 | 833 | | |
814 | 834 | | |
815 | | - | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
816 | 842 | | |
817 | 843 | | |
818 | 844 | | |
| |||
Lines changed: 7 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
726 | 726 | | |
727 | 727 | | |
728 | 728 | | |
729 | | - | |
| 729 | + | |
730 | 730 | | |
731 | 731 | | |
732 | 732 | | |
| |||
739 | 739 | | |
740 | 740 | | |
741 | 741 | | |
742 | | - | |
743 | | - | |
744 | | - | |
745 | | - | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
746 | 748 | | |
747 | 749 | | |
748 | 750 | | |
| |||
0 commit comments