perf(reader): lock-free ConcurrentQNameMap (снятие контеншена на synchronizedMap)#645
Merged
Conversation
…ap contention Профилирование чтения показало, что QNameMap.getJavaClassName вызывается на каждый XML-элемент и делает get по Collections.synchronizedMap. Метаданные читаются параллельно (parallelStream), поэтому все потоки сериализуются на мониторе одной общей карты — по профилю ~5% CPU уходит в SynchronizedMap.get. Вводим ConcurrentQNameMap с картами на ConcurrentHashMap (чтение без блокировок). Отображения регистрируются один раз до чтения, во время чтения карты только читаются. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HLvkKQCwBjTHwuZ4EGBQK6
📝 WalkthroughWalkthroughAdds a thread-safe ChangesConcurrent QName mapping
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Contributor
- registerMapping помечен synchronized, чтобы соответствовать контракту родителя QNameMap (Sonar S3551); метод вызывается только на этапе настройки, на горячий путь чтения не влияет. - Добавлен ConcurrentQNameMapTest (регистрация/резолв, фолбэки) — покрытие нового класса. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HLvkKQCwBjTHwuZ4EGBQK6
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Описание
Профилирование чтения (JFR на cpm) показало, что
QNameMap.getJavaClassNameвызывается накаждый XML-элемент и делает
getпоCollections.synchronizedMap. Метаданные читаютсяпараллельно (
parallelStream), поэтому все потоки сериализуются на мониторе одной общей карты.Вводим
ConcurrentQNameMap— наследникQNameMapс картами наConcurrentHashMap(чтение безблокировок). Отображения регистрируются один раз до начала чтения, во время чтения карты только
читаются. Поведение не меняется.
Замеры (JMH
MDClassesBenchmarkна cpm; CPU — доля JFR-сэмплов, устойчива к шуму машины)Правильный объект профилирования — стоимость самой операции поиска
getJavaClassName(inclusive), а не фрейм реализации: в новой версии
synchronizedMapфизически нет, поэтомусчитать его сэмплы бессмысленно. Inclusive-метрика учитывает и новую стоимость
ConcurrentHashMap.get:getJavaClassName(inclusive) в CPU чтенияТ.е. вся операция поиска (включая
ConcurrentHashMap.getв новой версии) подешевела ~5 п.п. —за счёт снятия монитора/контеншена на общей
synchronizedMap. Wall на тестовой машине имеетразброс ~±35 %, поэтому по нему изменение ~5 % не разрешается; CPU меряем долей сэмплов.
Связанные задачи
Closes
Чеклист
Общие
ConcurrentQNameMapTest; интеграционныеMDOReaderTest/MDMergerMergeTestчитают Designer-формы через это отображение)gradlew precommit) — прогонял reader-тестыДополнительно
registerMappingпомеченsynchronizedпод контракт родителя (Sonar S3551); вызывается толькона этапе настройки, на горячий путь не влияет.
getJavaClassNameinclusive, а не самSynchronizedMap.get(которого в новой версии нет).