Repository navigation
Avoid quadratic result ordering when bulkfetching DBRefs - #5265
PriyanshuGagiya wants to merge 1 commit into
Conversation
Signed-off-by: Priyanshu Gagiya <priyanshu.gagiya@sprinklr.com>
|
I also see repeated reference scans during sorting in ReferenceLookupDelegate.ListDocumentReferenceQuery, used for @DocumentReference collections can make it from O(n² log n) to O(n² + n log n) Opened a separate PR for this optimization: #5272. Benchmark results are included in the description. |
| .collect(Collectors.toList()); | ||
| Map<DbRefId, Document> documentsById = new HashMap<>(result.size()); | ||
| for (Document document : result) { | ||
| documentsById.putIfAbsent(new DbRefId(document.get(BasicMongoPersistentProperty.ID_FIELD_NAME)), document); |
There was a problem hiding this comment.
Why do we have another wrapper around the identifier?
There was a problem hiding this comment.
I added the wrapper to keep the old ObjectUtils.nullSafeEquals() matching behavior. For example, two separate byte[] IDs with the same bytes matched before, but wouldn’t match as plain map keys. I’m not sure we actually get byte[] here, the default driver returns Binary. I kept it to avoid breaking any existing scenario, but can remove it if we’re sure it isn’t needed.
There was a problem hiding this comment.
The binary-ID test I added uses byte[] directly, so it fails with Map<Object, Document>. Since the default driver returns Binary, should I update the test to use new Binary(new byte[] { 1, 2 }) and remove the wrapper, or keep the wrapper to preserve the previous ObjectUtils.nullSafeEquals() behavior?
There was a problem hiding this comment.
Hi @mp911de, a quick follow-up when you have a chance: would you prefer keeping the wrapper to preserve the previous matching behavior, or using the identifier directly and updating the test to use Binary?
Replace repeated document scans with an ID lookup, reducing expected result-ordering work from O(n²) to O(n) while preserving existing matching behavior. Adds two short regression tests; existing tests are unchanged.
Validation: 6,295 tests passed, 50 skipped, zero failures.
At 1,000 references, local processing was ~151× faster and allocation fell from 364 KB/op to 93 KB/op. JMH 1.37, JDK 24.0.2, three forks; in-memory responses exclude database/network time.
Benchmark source and reproduction instructions
Save these two files outside the repository under /tmp/dbref-bench/src/perf/. These are the exact harness sources used for the reported measurements.
ResolverBenchmark.java
ResolverFixture.java
Run the same harness on the PR base and on the proposed change. Build each version before measuring it, keep the benchmark sources unchanged, and use separate result filenames. The classpath must point to the compiled production classes for the version being measured.
From the repository root, after saving the source files above:
The baseline and optimized resolver sources in the original experiment were compiled into separate directories and placed first on each JVM's classpath; the commands above reproduce the comparison using the corresponding repository versions instead.
@mp911de, could you please review this change?
(I was just exploring the repository to see what was new and came across a performance issue.✌️.)