Fix Non-Deterministic Behavior in NewReadChunkCompactionPerformerWithAlignedSeriesTest
Fix Non-Deterministic Behavior in NewReadChunkCompactionPerformerWithAlignedSeriesTest
Problem
Thirteen tests in NewReadChunkCompactionPerformerWithAlignedSeriesTest were failing non-deterministically under NonDex due to order-dependent measurement schema comparisons:
-
testCompactionWithAllDeletion -
testCompactionWithDeletion -
testCompactionWithDeletionAndEmptyPage -
testCompactionWithPartialDeletion -
testCompactionWithPartialDeletionAndEmptyPage -
testSimpleCompaction -
testSimpleCompactionByFlushChunk -
testSimpleCompactionWithEmptyChunk -
testSimpleCompactionWithEmptyPage -
testSimpleCompactionWithNullValue -
testSimpleCompactionWithNullValueAndEmptyChunk -
testSimpleCompactionWithNullValueAndEmptyPage -
testSimpleCompactionWithSomeDeviceNotInTargetFile
Way to Reproduce
cd iotdb-core/datanode
mvn edu.illinois:nondex-maven-plugin:2.1.7:nondex \
-Dtest=NewReadChunkCompactionPerformerWithAlignedSeriesTest \
-DnondexRuns=3 -Drat.skip=true
# Result: Multiple failures due to non-deterministic measurement order
Root Cause
The CompactionCheckerUtils.getAllPathsOfResources() method used HashSet for storing paths and did not sort measurement schemas before constructing AlignedFullPath objects:
Set<IFullPath> paths = new HashSet<>(); // Non-deterministic iteration order
// ...
List<IMeasurementSchema> measurementSchemas = new ArrayList<>(schemaMap.values()); // Unsorted
// ...
seriesPath = new AlignedFullPath(deviceID, existedMeasurements, measurementSchemas);
The schemaMap is backed by ConcurrentHashMap which has non-deterministic iteration order. When NonDex shuffled collection order, measurements appeared in different positions within AlignedFullPath, causing data comparison assertions to fail even though the compaction results were semantically correct.
Solution
Made measurement ordering deterministic by sorting schemas and using ordered collections.
Changes Made
Before (Order-Dependent):
Set<IFullPath> paths = new HashSet<>();
// ...
List<IMeasurementSchema> measurementSchemas = new ArrayList<>(schemaMap.values());
After (Order-Independent):
Set<IFullPath> paths = new LinkedHashSet<>();
// ...
List<IMeasurementSchema> measurementSchemas =
schemaMap.values().stream()
.sorted(Comparator.comparing(IMeasurementSchema::getMeasurementName))
.collect(Collectors.toList());
Key Improvements
- Changed
HashSettoLinkedHashSetto preserve insertion order for deterministic iteration - Added sorting of measurement schemas by measurement name using
Comparator.comparing() - Ensures
AlignedFullPathobjects always have measurements in consistent alphabetical order - Added
java.util.Comparatorimport
Verification
mvn edu.illinois:nondex-maven-plugin:2.1.7:nondex \
-Dtest=NewReadChunkCompactionPerformerWithAlignedSeriesTest \
-DnondexRuns=3 -Drat.skip=true
# Result: All 15 tests pass across 3 different random seeds (933178, 974622, 1016066)
Key Changed Classes
-
CompactionCheckerUtils: Modified
getAllPathsOfResources()method (~10 lines), test utility changes only