You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reason: During cluster slot migration, the source Dragonfly process exited with signal 6; the test then failed to connect to localhost:30094, and teardown reported exit code -6.
I reproduced this on a Debug build. It's a stress-only failure, about 1 in 30 runs with CPU load on the machine.
The abort is DCHECK_EQ(it.GetVersion(), snapshot_version_) in SerializerBase::SerializeBucket (src/server/serializer_base.cc:291 at 101a973). The log shows 39 vs. 0.
Root cause as I read it:
ProcessBucket sets the bucket version to snapshot_version_ and then calls SerializeBucket.
SerializeBucket loops over the entries in that bucket. A large value can preempt the fiber inside SerializeEntry.
If the migration is cancelled during that preemption, DbSlice::UnregisterOnChange sets consumer->snapshot_version_ = 0.
When the loop resumes, the next entry's DCHECK compares the bucket version (39) with 0 and aborts.
The DCHECK is compiled out in Release, so the effect there is serializing the rest of the bucket after cancel. In Debug it aborts, which is why CI sees it.
I plan to add a guard in the SerializeBucket loop that stops once the context is cancelled, before the DCHECK, plus a test that cancels during a large-value bucket. Before I start, is anyone already working on this? If not, I'd like to claim it.
Iit might make more sense to add your check or guard after SerializeEntry returns though, at the end of the loop. If there is a yield it will only happen in SerializeEntry so a check after it signals intent better and avoids an extra check the first time.
Iit might make more sense to add your check or guard after SerializeEntry returns though, at the end of the loop. If there is a yield it will only happen in SerializeEntry so a check after it signals intent better and avoids an extra check the first time.
I stress-tested this on a Debug build (CPU-saturated machine, 30 runs in a loop) and reproduced the signal 6 abort on commit 101a9736: DCHECK_EQ(it.GetVersion(), snapshot_version_) in SerializerBase::SerializeBucket (serializer_base.cc:291), firing as 39 vs. 0.
Root cause: a large value can preempt the traversal fiber inside SerializeEntry. If cancellation lands during that preemption, UnregisterOnChange used to reset snapshot_version_ to 0 while the bucket loop was still mid-flight, so the next entry's DCHECK failed.
I re-ran the same 30-iteration stress loop on current main and it passed cleanly. #8473 ("SlotMigrationStreamer::Cancel() waits for Run finish", merged 2026-10-05) makes Cancel() wait on traversal_latch_ before unregistering the listener, which closes exactly this race.
Activity
Shikha-code36 commentedon Oct 3, 2026
I reproduced this on a Debug build. It's a stress-only failure, about 1 in 30 runs with CPU load on the machine.
The abort is
DCHECK_EQ(it.GetVersion(), snapshot_version_)inSerializerBase::SerializeBucket(src/server/serializer_base.cc:291at 101a973). The log shows39 vs. 0.Root cause as I read it:
ProcessBucketsets the bucket version tosnapshot_version_and then callsSerializeBucket.SerializeBucketloops over the entries in that bucket. A large value can preempt the fiber insideSerializeEntry.DbSlice::UnregisterOnChangesetsconsumer->snapshot_version_ = 0.DCHECKcompares the bucket version (39) with 0 and aborts.The DCHECK is compiled out in Release, so the effect there is serializing the rest of the bucket after cancel. In Debug it aborts, which is why CI sees it.
I plan to add a guard in the
SerializeBucketloop that stops once the context is cancelled, before the DCHECK, plus a test that cancels during a large-value bucket. Before I start, is anyone already working on this? If not, I'd like to claim it.abhijat commentedon Oct 6, 2026
@Shikha-code36 please feel free to send a PR
Iit might make more sense to add your check or guard after
SerializeEntryreturns though, at the end of the loop. If there is a yield it will only happen inSerializeEntryso a check after it signals intent better and avoids an extra check the first time.Shikha-code36 commentedon Oct 7, 2026
I stress-tested this on a Debug build (CPU-saturated machine, 30 runs in a loop) and reproduced the signal 6 abort on commit
101a9736:DCHECK_EQ(it.GetVersion(), snapshot_version_)inSerializerBase::SerializeBucket(serializer_base.cc:291), firing as39 vs. 0.Root cause: a large value can preempt the traversal fiber inside
SerializeEntry. If cancellation lands during that preemption,UnregisterOnChangeused to resetsnapshot_version_to 0 while the bucket loop was still mid-flight, so the next entry's DCHECK failed.I re-ran the same 30-iteration stress loop on current
mainand it passed cleanly. #8473 ("SlotMigrationStreamer::Cancel()waits for Run finish", merged 2026-10-05) makesCancel()wait ontraversal_latch_before unregistering the listener, which closes exactly this race.Looks like this can be closed as fixed by #8473.