leizhiyuan opened a new pull request, #11496:
URL: https://github.com/apache/rocketmq/pull/11496

   ### Which Issue(s) This PR Fixes
   
   - Fixes #11495
   
   ### Brief Description
   
   `RocksDBOptionsFactory#createOffsetCFOptions()` enabled 
`setInplaceUpdateSupport(true)` on the `offset` column family.
   
   `RocksDBConsumeQueueStore#putMessagePosition0` writes the CQ units (default 
CF) and the queue's MAX offset (offset CF) in one `WriteBatch`, and readers 
such as `correctMinCqOffset` rely on that batch being visible atomically. An 
in-place overwrite of an existing MAX key in the memtable is not protected by 
sequence-number visibility. A reader can therefore see the new MAX before the 
CQ units of the same batch. The first min lookup of a new queue then 
binary-searches a range whose entries are not visible yet and persists a min 
offset > 0, so consumers silently skip the first messages. See #11495 for the 
full analysis and standalone reproducers.
   
   This PR removes `setInplaceUpdateSupport(true)` from the offset CF options. 
That is the only production change.
   
   Trade-off: without in-place update, every MAX update adds a new version to 
the memtable instead of overwriting the old one. The offset CF only holds a few 
keys per queue (MAX/MIN), and it already uses a 64 MB write buffer. Obsolete 
versions are dropped on flush/compaction, and point lookups still return only 
the latest visible version. The extra memtable usage and write cost are small, 
and in return the batch is atomic again. Data already on disk stays compatible; 
this option only affects memtable behavior.
   
   `ConfigHelper#createConfigColumnFamilyOptions` (metadata storage) also 
enables in-place update, but it does not have this cross-CF batch visibility 
dependency, so it is out of scope here.
   
   ### How Did You Test This Change?
   
   New tests in `RocksDBOptionsFactoryTest`:
   - `testOffsetCFOptionsDisableInplaceUpdate`: deterministic check that 
`createOffsetCFOptions()` does not enable in-place update.
   - `testOffsetCFMaxOffsetVisibleWithConsumeQueueUnit`: opens a RocksDB 
instance with the real `createCQCFOptions` / `createOffsetCFOptions` and 
broker-like DB options. A writer puts a CQ unit and MAX into one `WriteBatch` 
(like `putMessagePosition0`), and 4 readers check that `CQ[MAX]` is visible 
whenever MAX is visible. It runs for at most 3 seconds and stops at the first 
anomaly.
   
   Before the fix (develop), 3 out of 3 runs failed:
   
   ```
   RocksDBOptionsFactoryTest.testOffsetCFOptionsDisableInplaceUpdate  FAILURE
   
RocksDBOptionsFactoryTest.testOffsetCFMaxOffsetVisibleWithConsumeQueueUnit:165 
max offset visible before its consume queue unit, reads: 6299 expected:<0> but 
was:<1>
   
RocksDBOptionsFactoryTest.testOffsetCFMaxOffsetVisibleWithConsumeQueueUnit:165 
max offset visible before its consume queue unit, reads: 10427 expected:<0> but 
was:<51>
   
RocksDBOptionsFactoryTest.testOffsetCFMaxOffsetVisibleWithConsumeQueueUnit:165 
max offset visible before its consume queue unit, reads: 16531 expected:<0> but 
was:<19>
   ```
   
   After the fix: `Tests run: 4, Failures: 0`, stable over 6 runs.
   
   Related store tests (checkstyle enabled):
   
   ```
   mvn -pl store -am -DskipTests=false -Dsurefire.failIfNoSpecifiedTests=false 
-DfailIfNoTests=false \
     
-Dtest='RocksDBOptionsFactoryTest,RocksDBConsumeQueue*Test,CombineConsumeQueueStoreTest,ConsumeQueueStoreTest,MessageRocksDBStorageTest,CqCompactionFilterJniTest'
 test
   Tests run: 47, Failures: 0, Errors: 0, Skipped: 0 -- BUILD SUCCESS
   ```
   
   I also ran an end-to-end check against the real `RocksDBConsumeQueueStore`. 
Each run did 1000 rounds of 200 fresh queues: batch1 = `{offset 0}`, then 
batch2 = `{offsets 1..4}` via `putMessagePosition`, while 4 threads called 
`getMinOffsetInQueue`. Before the fix it occasionally left min offset = 4 
(failures in 1 of 8 runs and in a few earlier runs). After the fix, 8 out of 8 
runs reported 0 wrong min offsets. It is too timing-dependent to be a reliable 
unit test, so it is not included.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to