perf: XPathパターンキャッシュと XPathMatchesInjectionResolver の per-spec キャッシュを追加#137
Merged
Conversation
- XPathUtil._patternCache (ConcurrentHashMap): PatternParser.parse() を毎回呼び出していたのを
初回のみパースしてキャッシュするよう変更。XPath 式はアプリ起動後に固定のため安全。
- XPathMatchesInjectionResolver: spec インスタンスへの _xpathInjectNodes キャッシュ導入
- 毎ノードの spec 階層走査を削減(100ノード → 1回の構築)
- per-spec キャッシュにより複数スレッドで共用。deprecate() でクリア。
- XPATH_NAMESPACE を static 定数化(毎回 createNamespace() 廃止)
- SpecificationImpl: isDeprecated() の存在チェックを 500ms 間隔に throttle
- getExistsCheckIntervalMillis() で設定値をインスタンスフィールドに遅延キャッシュし
毎回の EngineSetting 参照と Long.parseLong() オーバーヘッドを除去
ベンチマーク結果 (BuildPerformanceTest、2000 iters):
inject_xpath (template-only): 0.592ms → 0.365ms (-38%)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Collaborator
Author
|
isDeprecated の呼び出し内での実際の確認処理が行われる頻度を抑制するのは #83 にも寄与する。 |
There was a problem hiding this comment.
Pull request overview
XPath ベース injection のビルド処理を中心に、パース/探索/設定参照のコストをキャッシュで削減して性能改善する PR です。テンプレートビルド(特に injection フェーズ)で繰り返し発生する処理を、スレッドセーフなキャッシュや参照回数削減で最適化しています。
Changes:
- XPathUtil に XPath パターン(PatternParser.parse)のグローバルキャッシュを追加
- XPathMatchesInjectionResolver に spec 単位の m:xpath ノード探索結果キャッシュと static Namespace を追加
- SpecificationImpl の isDeprecated() に存在チェックのスロットリングと設定値の遅延キャッシュを追加(+ベンチマーク用テスト追加)
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/test/java/org/seasar/mayaa/functional/engine/BuildPerformanceTest.java | injection フェーズの簡易ベンチマークを追加 |
| src-impl/org/seasar/mayaa/impl/engine/specification/xpath/XPathUtil.java | XPath Pattern の初回コンパイル結果をキャッシュして再利用 |
| src-impl/org/seasar/mayaa/impl/engine/specification/SpecificationImpl.java | isDeprecated の存在チェックをスロットリングし、XPath injection ノードキャッシュ用の保持領域を追加 |
| src-impl/org/seasar/mayaa/impl/CONST_IMPL.java | checkTimestampInterval 設定キーを追加 |
| src-impl/org/seasar/mayaa/impl/builder/injection/XPathMatchesInjectionResolver.java | spec 単位の injection 対象ノードキャッシュと Namespace の static 化 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
123
to
131
| public boolean isDeprecated() { | ||
| if (_deprecated == false) { | ||
| long intervalMillis = getExistsCheckIntervalMillis(); | ||
| long now = System.currentTimeMillis(); | ||
| if (intervalMillis > 0 && (now - _lastExistsCheckMillis) < intervalMillis) { | ||
| return false; | ||
| } | ||
| _lastExistsCheckMillis = now; | ||
| _deprecated = _hasSource != isSourceExists(); |
Comment on lines
+157
to
+170
| /** | ||
| * この spec の XPath injection ノードリストを返す。 | ||
| * まだ構築されていない場合は {@code null} を返す。 | ||
| */ | ||
| public List<SpecificationNode> getCachedXpathInjectNodes() { | ||
| return _xpathInjectNodes; | ||
| } | ||
|
|
||
| /** | ||
| * この spec の XPath injection ノードリストをセットする。 | ||
| * 複数スレッドが同時に呼んでも内容は等価なので、上書きは許容する。 | ||
| */ | ||
| public void setCachedXpathInjectNodes(List<SpecificationNode> nodes) { | ||
| _xpathInjectNodes = nodes; |
Comment on lines
51
to
80
| @@ -65,12 +70,16 @@ public static boolean matches(SpecificationNode test, | |||
| SpecificationNavigator.getInstance()); | |||
| Context context = new Context(support); | |||
| try { | |||
| Pattern pattern = PatternParser.parse(xpathExpr); | |||
| Pattern pattern = _patternCache.computeIfAbsent(xpathExpr, expr -> { | |||
| try { | |||
| return PatternParser.parse(expr); | |||
| } catch (SAXPathException e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| }); | |||
| return pattern.matches(test, context); | |||
Comment on lines
+32
to
+60
| private static final int WARMUP = 100; | ||
| private static final int ITERATIONS = 2000; | ||
|
|
||
| /** | ||
| * XPath ベースの injection (XPathMatchesInjectionResolver) の繰り返しビルド時間を計測。 | ||
| */ | ||
| @Test | ||
| public void bench_inject_xpath() throws IOException { | ||
| final String TARGET = "/it-case/engine/inject_xpath/target.html"; | ||
| runBench("inject_xpath (XPath cache)", TARGET); | ||
| } | ||
|
|
||
| /** | ||
| * ID ベースの injection (EqualsIDInjectionResolver) の繰り返しビルド時間を計測。 | ||
| */ | ||
| @Test | ||
| public void bench_inject_mayaa() throws IOException { | ||
| final String TARGET = "/it-case/engine/inject_mayaa/target.html"; | ||
| runBench("inject_mayaa (ID cache) ", TARGET); | ||
| } | ||
|
|
||
| /** | ||
| * XPath ベースの injection — テンプレートのみ deprecate(.mayaa は再読み込みしない)。 | ||
| * injection フェーズ単体の性能を計測しやすい。 | ||
| */ | ||
| @Test | ||
| public void bench_inject_xpath_templateonly() throws IOException { | ||
| final String TARGET = "/it-case/engine/inject_xpath/target.html"; | ||
| runBench("inject_xpath (template-only) ", TARGET, false); |
- SpecificationImpl._deprecated を volatile 化 isDeprecated() のスロットリングでは _lastExistsCheckMillis(volatile)を 更新後に _deprecated(非volatile)を更新していたため、他スレッドが新しい _lastExistsCheckMillis を見て早期 return しつつ古い _deprecated を読む 恐れがあった。volatile 化により可視性を保証する。 - setCachedXpathInjectNodes() で Collections.unmodifiableList() でラップ getter が返すリストが外部から変更されないよう保護する。 - XPathUtil._patternCache を Caffeine キャッシュに変更(max 10,000、30分 TTI) ConcurrentHashMap の無制限成長を防ぐ。XPath 式が動的に生成される環境でも メモリを回収できるようにする。 - BuildPerformanceTest に @tag("test.PerformanceTest") を付与 pom.xml の testExcludedGroups 設定により通常 CI では除外される。 実行するには mvn test -P withPerformanceTest を使う。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
XPathUtil._patternCache (ConcurrentHashMap): PatternParser.parse() を毎回呼び出していたのを 初回のみパースしてキャッシュするよう変更。XPath 式はアプリ起動後に固定のため安全。
XPathMatchesInjectionResolver: spec インスタンスへの _xpathInjectNodes キャッシュ導入
SpecificationImpl: isDeprecated() の存在チェックを 500ms 間隔に throttle
ベンチマーク結果 (BuildPerformanceTest、2000 iters):
inject_xpath (template-only): 0.592ms → 0.365ms (-38%)