tree-sitter-analyzer 0.2.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tree-sitter-analyzer might be problematic. Click here for more details.

Files changed (78) hide show
  1. tree_sitter_analyzer/__init__.py +133 -121
  2. tree_sitter_analyzer/__main__.py +11 -12
  3. tree_sitter_analyzer/api.py +531 -539
  4. tree_sitter_analyzer/cli/__init__.py +39 -39
  5. tree_sitter_analyzer/cli/__main__.py +12 -13
  6. tree_sitter_analyzer/cli/commands/__init__.py +26 -27
  7. tree_sitter_analyzer/cli/commands/advanced_command.py +88 -88
  8. tree_sitter_analyzer/cli/commands/base_command.py +160 -155
  9. tree_sitter_analyzer/cli/commands/default_command.py +18 -19
  10. tree_sitter_analyzer/cli/commands/partial_read_command.py +141 -133
  11. tree_sitter_analyzer/cli/commands/query_command.py +81 -82
  12. tree_sitter_analyzer/cli/commands/structure_command.py +138 -121
  13. tree_sitter_analyzer/cli/commands/summary_command.py +101 -93
  14. tree_sitter_analyzer/cli/commands/table_command.py +232 -233
  15. tree_sitter_analyzer/cli/info_commands.py +120 -121
  16. tree_sitter_analyzer/cli_main.py +277 -276
  17. tree_sitter_analyzer/core/__init__.py +15 -20
  18. tree_sitter_analyzer/core/analysis_engine.py +591 -574
  19. tree_sitter_analyzer/core/cache_service.py +320 -330
  20. tree_sitter_analyzer/core/engine.py +557 -560
  21. tree_sitter_analyzer/core/parser.py +293 -288
  22. tree_sitter_analyzer/core/query.py +494 -502
  23. tree_sitter_analyzer/encoding_utils.py +458 -460
  24. tree_sitter_analyzer/exceptions.py +337 -340
  25. tree_sitter_analyzer/file_handler.py +217 -222
  26. tree_sitter_analyzer/formatters/__init__.py +1 -1
  27. tree_sitter_analyzer/formatters/base_formatter.py +167 -168
  28. tree_sitter_analyzer/formatters/formatter_factory.py +78 -74
  29. tree_sitter_analyzer/formatters/java_formatter.py +287 -270
  30. tree_sitter_analyzer/formatters/python_formatter.py +255 -235
  31. tree_sitter_analyzer/interfaces/__init__.py +9 -10
  32. tree_sitter_analyzer/interfaces/cli.py +528 -557
  33. tree_sitter_analyzer/interfaces/cli_adapter.py +322 -319
  34. tree_sitter_analyzer/interfaces/mcp_adapter.py +180 -170
  35. tree_sitter_analyzer/interfaces/mcp_server.py +405 -416
  36. tree_sitter_analyzer/java_analyzer.py +218 -219
  37. tree_sitter_analyzer/language_detector.py +398 -400
  38. tree_sitter_analyzer/language_loader.py +224 -228
  39. tree_sitter_analyzer/languages/__init__.py +10 -11
  40. tree_sitter_analyzer/languages/java_plugin.py +1129 -1113
  41. tree_sitter_analyzer/languages/python_plugin.py +737 -712
  42. tree_sitter_analyzer/mcp/__init__.py +31 -32
  43. tree_sitter_analyzer/mcp/resources/__init__.py +44 -47
  44. tree_sitter_analyzer/mcp/resources/code_file_resource.py +212 -213
  45. tree_sitter_analyzer/mcp/resources/project_stats_resource.py +560 -550
  46. tree_sitter_analyzer/mcp/server.py +333 -345
  47. tree_sitter_analyzer/mcp/tools/__init__.py +30 -31
  48. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +621 -557
  49. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +242 -245
  50. tree_sitter_analyzer/mcp/tools/base_tool.py +54 -55
  51. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +300 -302
  52. tree_sitter_analyzer/mcp/tools/table_format_tool.py +362 -359
  53. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +543 -476
  54. tree_sitter_analyzer/mcp/utils/__init__.py +105 -106
  55. tree_sitter_analyzer/mcp/utils/error_handler.py +549 -549
  56. tree_sitter_analyzer/models.py +470 -481
  57. tree_sitter_analyzer/output_manager.py +261 -264
  58. tree_sitter_analyzer/plugins/__init__.py +333 -334
  59. tree_sitter_analyzer/plugins/base.py +477 -446
  60. tree_sitter_analyzer/plugins/java_plugin.py +608 -625
  61. tree_sitter_analyzer/plugins/javascript_plugin.py +446 -439
  62. tree_sitter_analyzer/plugins/manager.py +362 -355
  63. tree_sitter_analyzer/plugins/plugin_loader.py +85 -83
  64. tree_sitter_analyzer/plugins/python_plugin.py +606 -598
  65. tree_sitter_analyzer/plugins/registry.py +374 -366
  66. tree_sitter_analyzer/queries/__init__.py +26 -27
  67. tree_sitter_analyzer/queries/java.py +391 -394
  68. tree_sitter_analyzer/queries/javascript.py +148 -149
  69. tree_sitter_analyzer/queries/python.py +285 -286
  70. tree_sitter_analyzer/queries/typescript.py +229 -230
  71. tree_sitter_analyzer/query_loader.py +254 -260
  72. tree_sitter_analyzer/table_formatter.py +468 -448
  73. tree_sitter_analyzer/utils.py +277 -277
  74. {tree_sitter_analyzer-0.2.0.dist-info → tree_sitter_analyzer-0.3.0.dist-info}/METADATA +21 -6
  75. tree_sitter_analyzer-0.3.0.dist-info/RECORD +77 -0
  76. tree_sitter_analyzer-0.2.0.dist-info/RECORD +0 -77
  77. {tree_sitter_analyzer-0.2.0.dist-info → tree_sitter_analyzer-0.3.0.dist-info}/WHEEL +0 -0
  78. {tree_sitter_analyzer-0.2.0.dist-info → tree_sitter_analyzer-0.3.0.dist-info}/entry_points.txt +0 -0
@@ -1,330 +1,320 @@
1
- #!/usr/bin/env python3
2
- """
3
- 統一キャッシュサービス - CLI・MCP共通キャッシュシステム
4
-
5
- このモジュールは、メモリ効率的な階層キャッシュシステムを提供します。
6
- L1(高速)、L2(中期)、L3(長期)の3層構造で最適なパフォーマンスを実現。
7
-
8
- Roo Code規約準拠:
9
- - 型ヒント: 全関数に型ヒント必須
10
- - MCPログ: 各ステップでログ出力
11
- - docstring: Google Style docstring
12
- - パフォーマンス重視: メモリ効率とアクセス速度の最適化
13
- """
14
-
15
- import asyncio
16
- import hashlib
17
- import threading
18
- import time
19
- from dataclasses import dataclass
20
- from datetime import datetime, timedelta
21
- from typing import Any, Dict, Optional, Union
22
- from cachetools import LRUCache, TTLCache
23
-
24
- from ..utils import log_debug, log_info, log_warning, log_error
25
-
26
-
27
- @dataclass(frozen=True)
28
- class CacheEntry:
29
- """
30
- キャッシュエントリ
31
-
32
- キャッシュされた値とメタデータを保持するデータクラス。
33
-
34
- Attributes:
35
- value: キャッシュされた値
36
- created_at: 作成日時
37
- expires_at: 有効期限
38
- access_count: アクセス回数
39
- """
40
- value: Any
41
- created_at: datetime
42
- expires_at: Optional[datetime] = None
43
- access_count: int = 0
44
-
45
- def is_expired(self) -> bool:
46
- """
47
- 有効期限チェック
48
-
49
- Returns:
50
- bool: 期限切れの場合True
51
- """
52
- if self.expires_at is None:
53
- return False
54
- return datetime.now() > self.expires_at
55
-
56
-
57
- class CacheService:
58
- """
59
- 統一キャッシュサービス
60
-
61
- 階層化キャッシュシステムを提供し、CLI・MCP間でキャッシュを共有。
62
- メモリ効率とアクセス速度を最適化した3層構造。
63
-
64
- Attributes:
65
- _l1_cache: L1キャッシュ(高速アクセス用)
66
- _l2_cache: L2キャッシュ(中期保存用)
67
- _l3_cache: L3キャッシュ(長期保存用)
68
- _lock: スレッドセーフ用ロック
69
- _stats: キャッシュ統計情報
70
- """
71
-
72
- def __init__(
73
- self,
74
- l1_maxsize: int = 100,
75
- l2_maxsize: int = 1000,
76
- l3_maxsize: int = 10000,
77
- ttl_seconds: int = 3600
78
- ) -> None:
79
- """
80
- 初期化
81
-
82
- Args:
83
- l1_maxsize: L1キャッシュの最大サイズ
84
- l2_maxsize: L2キャッシュの最大サイズ
85
- l3_maxsize: L3キャッシュの最大サイズ
86
- ttl_seconds: デフォルトTTL(秒)
87
- """
88
- # 階層化キャッシュの初期化
89
- self._l1_cache: LRUCache[str, CacheEntry] = LRUCache(maxsize=l1_maxsize)
90
- self._l2_cache: TTLCache[str, CacheEntry] = TTLCache(
91
- maxsize=l2_maxsize,
92
- ttl=ttl_seconds
93
- )
94
- self._l3_cache: LRUCache[str, CacheEntry] = LRUCache(maxsize=l3_maxsize)
95
-
96
- # スレッドセーフ用ロック
97
- self._lock = threading.RLock()
98
-
99
- # キャッシュ統計
100
- self._stats = {
101
- "hits": 0,
102
- "misses": 0,
103
- "l1_hits": 0,
104
- "l2_hits": 0,
105
- "l3_hits": 0,
106
- "sets": 0,
107
- "evictions": 0
108
- }
109
-
110
- # デフォルト設定
111
- self._default_ttl = ttl_seconds
112
-
113
- log_info(
114
- f"CacheService initialized: L1={l1_maxsize}, L2={l2_maxsize}, "
115
- f"L3={l3_maxsize}, TTL={ttl_seconds}s"
116
- )
117
-
118
- async def get(self, key: str) -> Optional[Any]:
119
- """
120
- キャッシュから値を取得
121
-
122
- 階層キャッシュを順番にチェックし、見つかった場合は
123
- 上位キャッシュに昇格させる。
124
-
125
- Args:
126
- key: キャッシュキー
127
-
128
- Returns:
129
- キャッシュされた値、見つからない場合はNone
130
-
131
- Raises:
132
- ValueError: 無効なキーの場合
133
- """
134
- if not key or key is None:
135
- raise ValueError("Cache key cannot be empty or None")
136
-
137
- with self._lock:
138
- # L1キャッシュをチェック
139
- entry = self._l1_cache.get(key)
140
- if entry and not entry.is_expired():
141
- self._stats["hits"] += 1
142
- self._stats["l1_hits"] += 1
143
- log_debug(f"Cache L1 hit: {key}")
144
- return entry.value
145
-
146
- # L2キャッシュをチェック
147
- entry = self._l2_cache.get(key)
148
- if entry and not entry.is_expired():
149
- self._stats["hits"] += 1
150
- self._stats["l2_hits"] += 1
151
- # L1に昇格
152
- self._l1_cache[key] = entry
153
- log_debug(f"Cache L2 hit: {key} (promoted to L1)")
154
- return entry.value
155
-
156
- # L3キャッシュをチェック
157
- entry = self._l3_cache.get(key)
158
- if entry and not entry.is_expired():
159
- self._stats["hits"] += 1
160
- self._stats["l3_hits"] += 1
161
- # L2とL1に昇格
162
- self._l2_cache[key] = entry
163
- self._l1_cache[key] = entry
164
- log_debug(f"Cache L3 hit: {key} (promoted to L1/L2)")
165
- return entry.value
166
-
167
- # キャッシュミス
168
- self._stats["misses"] += 1
169
- log_debug(f"Cache miss: {key}")
170
- return None
171
-
172
- async def set(
173
- self,
174
- key: str,
175
- value: Any,
176
- ttl_seconds: Optional[int] = None
177
- ) -> None:
178
- """
179
- キャッシュに値を設定
180
-
181
- Args:
182
- key: キャッシュキー
183
- value: キャッシュする値
184
- ttl_seconds: TTL(秒)、Noneの場合はデフォルト値
185
-
186
- Raises:
187
- ValueError: 無効なキーの場合
188
- TypeError: シリアライズできない値の場合
189
- """
190
- if not key or key is None:
191
- raise ValueError("Cache key cannot be empty or None")
192
-
193
- # シリアライズ可能性チェック
194
- try:
195
- import pickle
196
- pickle.dumps(value)
197
- except (pickle.PicklingError, TypeError) as e:
198
- raise TypeError(f"Value is not serializable: {e}")
199
-
200
- ttl = ttl_seconds or self._default_ttl
201
- expires_at = datetime.now() + timedelta(seconds=ttl)
202
-
203
- entry = CacheEntry(
204
- value=value,
205
- created_at=datetime.now(),
206
- expires_at=expires_at,
207
- access_count=0
208
- )
209
-
210
- with self._lock:
211
- # 全階層に設定
212
- self._l1_cache[key] = entry
213
- self._l2_cache[key] = entry
214
- self._l3_cache[key] = entry
215
-
216
- self._stats["sets"] += 1
217
- log_debug(f"Cache set: {key} (TTL={ttl}s)")
218
-
219
- def clear(self) -> None:
220
- """
221
- 全キャッシュをクリア
222
- """
223
- with self._lock:
224
- self._l1_cache.clear()
225
- self._l2_cache.clear()
226
- self._l3_cache.clear()
227
-
228
- # 統計をリセット
229
- for key in self._stats:
230
- self._stats[key] = 0
231
-
232
- log_info("All caches cleared")
233
-
234
- def size(self) -> int:
235
- """
236
- キャッシュサイズを取得
237
-
238
- Returns:
239
- L1キャッシュのサイズ(最も頻繁にアクセスされるアイテム数)
240
- """
241
- with self._lock:
242
- return len(self._l1_cache)
243
-
244
- def get_stats(self) -> Dict[str, Any]:
245
- """
246
- キャッシュ統計を取得
247
-
248
- Returns:
249
- 統計情報辞書
250
- """
251
- with self._lock:
252
- total_requests = self._stats["hits"] + self._stats["misses"]
253
- hit_rate = (
254
- self._stats["hits"] / total_requests
255
- if total_requests > 0 else 0.0
256
- )
257
-
258
- return {
259
- **self._stats,
260
- "hit_rate": hit_rate,
261
- "total_requests": total_requests,
262
- "l1_size": len(self._l1_cache),
263
- "l2_size": len(self._l2_cache),
264
- "l3_size": len(self._l3_cache)
265
- }
266
-
267
- def generate_cache_key(
268
- self,
269
- file_path: str,
270
- language: str,
271
- options: Dict[str, Any]
272
- ) -> str:
273
- """
274
- キャッシュキーを生成
275
-
276
- Args:
277
- file_path: ファイルパス
278
- language: プログラミング言語
279
- options: 解析オプション
280
-
281
- Returns:
282
- ハッシュ化されたキャッシュキー
283
- """
284
- # 一意なキーを生成するための文字列を構築
285
- key_components = [
286
- file_path,
287
- language,
288
- str(sorted(options.items())) # 辞書を安定した文字列に変換
289
- ]
290
-
291
- key_string = ":".join(key_components)
292
-
293
- # SHA256でハッシュ化
294
- return hashlib.sha256(key_string.encode('utf-8')).hexdigest()
295
-
296
- async def invalidate_pattern(self, pattern: str) -> int:
297
- """
298
- パターンに一致するキーを無効化
299
-
300
- Args:
301
- pattern: 無効化するキーのパターン
302
-
303
- Returns:
304
- 無効化されたキー数
305
- """
306
- invalidated_count = 0
307
-
308
- with self._lock:
309
- # 各階層からパターンに一致するキーを削除
310
- for cache in [self._l1_cache, self._l2_cache, self._l3_cache]:
311
- keys_to_remove = [
312
- key for key in cache.keys()
313
- if pattern in key
314
- ]
315
-
316
- for key in keys_to_remove:
317
- if key in cache:
318
- del cache[key]
319
- invalidated_count += 1
320
-
321
- log_info(f"Invalidated {invalidated_count} cache entries matching pattern: {pattern}")
322
- return invalidated_count
323
-
324
- def __del__(self) -> None:
325
- """デストラクタ - リソースクリーンアップ"""
326
- try:
327
- self.clear()
328
- log_debug("CacheService destroyed and cleaned up")
329
- except Exception as e:
330
- log_error(f"Error during CacheService cleanup: {e}")
1
+ #!/usr/bin/env python3
2
+ """
3
+ 統一キャッシュサービス - CLI・MCP共通キャッシュシステム
4
+
5
+ このモジュールは、メモリ効率的な階層キャッシュシステムを提供します。
6
+ L1(高速)、L2(中期)、L3(長期)の3層構造で最適なパフォーマンスを実現。
7
+
8
+ Roo Code規約準拠:
9
+ - 型ヒント: 全関数に型ヒント必須
10
+ - MCPログ: 各ステップでログ出力
11
+ - docstring: Google Style docstring
12
+ - パフォーマンス重視: メモリ効率とアクセス速度の最適化
13
+ """
14
+
15
+ import hashlib
16
+ import threading
17
+ from dataclasses import dataclass
18
+ from datetime import datetime, timedelta
19
+ from typing import Any
20
+
21
+ from cachetools import LRUCache, TTLCache
22
+
23
+ from ..utils import log_debug, log_error, log_info
24
+
25
+
26
+ @dataclass(frozen=True)
27
+ class CacheEntry:
28
+ """
29
+ キャッシュエントリ
30
+
31
+ キャッシュされた値とメタデータを保持するデータクラス。
32
+
33
+ Attributes:
34
+ value: キャッシュされた値
35
+ created_at: 作成日時
36
+ expires_at: 有効期限
37
+ access_count: アクセス回数
38
+ """
39
+
40
+ value: Any
41
+ created_at: datetime
42
+ expires_at: datetime | None = None
43
+ access_count: int = 0
44
+
45
+ def is_expired(self) -> bool:
46
+ """
47
+ 有効期限チェック
48
+
49
+ Returns:
50
+ bool: 期限切れの場合True
51
+ """
52
+ if self.expires_at is None:
53
+ return False
54
+ return datetime.now() > self.expires_at
55
+
56
+
57
+ class CacheService:
58
+ """
59
+ 統一キャッシュサービス
60
+
61
+ 階層化キャッシュシステムを提供し、CLI・MCP間でキャッシュを共有。
62
+ メモリ効率とアクセス速度を最適化した3層構造。
63
+
64
+ Attributes:
65
+ _l1_cache: L1キャッシュ(高速アクセス用)
66
+ _l2_cache: L2キャッシュ(中期保存用)
67
+ _l3_cache: L3キャッシュ(長期保存用)
68
+ _lock: スレッドセーフ用ロック
69
+ _stats: キャッシュ統計情報
70
+ """
71
+
72
+ def __init__(
73
+ self,
74
+ l1_maxsize: int = 100,
75
+ l2_maxsize: int = 1000,
76
+ l3_maxsize: int = 10000,
77
+ ttl_seconds: int = 3600,
78
+ ) -> None:
79
+ """
80
+ 初期化
81
+
82
+ Args:
83
+ l1_maxsize: L1キャッシュの最大サイズ
84
+ l2_maxsize: L2キャッシュの最大サイズ
85
+ l3_maxsize: L3キャッシュの最大サイズ
86
+ ttl_seconds: デフォルトTTL(秒)
87
+ """
88
+ # 階層化キャッシュの初期化
89
+ self._l1_cache: LRUCache[str, CacheEntry] = LRUCache(maxsize=l1_maxsize)
90
+ self._l2_cache: TTLCache[str, CacheEntry] = TTLCache(
91
+ maxsize=l2_maxsize, ttl=ttl_seconds
92
+ )
93
+ self._l3_cache: LRUCache[str, CacheEntry] = LRUCache(maxsize=l3_maxsize)
94
+
95
+ # スレッドセーフ用ロック
96
+ self._lock = threading.RLock()
97
+
98
+ # キャッシュ統計
99
+ self._stats = {
100
+ "hits": 0,
101
+ "misses": 0,
102
+ "l1_hits": 0,
103
+ "l2_hits": 0,
104
+ "l3_hits": 0,
105
+ "sets": 0,
106
+ "evictions": 0,
107
+ }
108
+
109
+ # デフォルト設定
110
+ self._default_ttl = ttl_seconds
111
+
112
+ log_info(
113
+ f"CacheService initialized: L1={l1_maxsize}, L2={l2_maxsize}, "
114
+ f"L3={l3_maxsize}, TTL={ttl_seconds}s"
115
+ )
116
+
117
+ async def get(self, key: str) -> Any | None:
118
+ """
119
+ キャッシュから値を取得
120
+
121
+ 階層キャッシュを順番にチェックし、見つかった場合は
122
+ 上位キャッシュに昇格させる。
123
+
124
+ Args:
125
+ key: キャッシュキー
126
+
127
+ Returns:
128
+ キャッシュされた値、見つからない場合はNone
129
+
130
+ Raises:
131
+ ValueError: 無効なキーの場合
132
+ """
133
+ if not key or key is None:
134
+ raise ValueError("Cache key cannot be empty or None")
135
+
136
+ with self._lock:
137
+ # L1キャッシュをチェック
138
+ entry = self._l1_cache.get(key)
139
+ if entry and not entry.is_expired():
140
+ self._stats["hits"] += 1
141
+ self._stats["l1_hits"] += 1
142
+ log_debug(f"Cache L1 hit: {key}")
143
+ return entry.value
144
+
145
+ # L2キャッシュをチェック
146
+ entry = self._l2_cache.get(key)
147
+ if entry and not entry.is_expired():
148
+ self._stats["hits"] += 1
149
+ self._stats["l2_hits"] += 1
150
+ # L1に昇格
151
+ self._l1_cache[key] = entry
152
+ log_debug(f"Cache L2 hit: {key} (promoted to L1)")
153
+ return entry.value
154
+
155
+ # L3キャッシュをチェック
156
+ entry = self._l3_cache.get(key)
157
+ if entry and not entry.is_expired():
158
+ self._stats["hits"] += 1
159
+ self._stats["l3_hits"] += 1
160
+ # L2とL1に昇格
161
+ self._l2_cache[key] = entry
162
+ self._l1_cache[key] = entry
163
+ log_debug(f"Cache L3 hit: {key} (promoted to L1/L2)")
164
+ return entry.value
165
+
166
+ # キャッシュミス
167
+ self._stats["misses"] += 1
168
+ log_debug(f"Cache miss: {key}")
169
+ return None
170
+
171
+ async def set(self, key: str, value: Any, ttl_seconds: int | None = None) -> None:
172
+ """
173
+ キャッシュに値を設定
174
+
175
+ Args:
176
+ key: キャッシュキー
177
+ value: キャッシュする値
178
+ ttl_seconds: TTL(秒)、Noneの場合はデフォルト値
179
+
180
+ Raises:
181
+ ValueError: 無効なキーの場合
182
+ TypeError: シリアライズできない値の場合
183
+ """
184
+ if not key or key is None:
185
+ raise ValueError("Cache key cannot be empty or None")
186
+
187
+ # シリアライズ可能性チェック
188
+ try:
189
+ import pickle
190
+
191
+ pickle.dumps(value)
192
+ except (pickle.PicklingError, TypeError) as e:
193
+ raise TypeError(f"Value is not serializable: {e}") from e
194
+
195
+ ttl = ttl_seconds or self._default_ttl
196
+ expires_at = datetime.now() + timedelta(seconds=ttl)
197
+
198
+ entry = CacheEntry(
199
+ value=value,
200
+ created_at=datetime.now(),
201
+ expires_at=expires_at,
202
+ access_count=0,
203
+ )
204
+
205
+ with self._lock:
206
+ # 全階層に設定
207
+ self._l1_cache[key] = entry
208
+ self._l2_cache[key] = entry
209
+ self._l3_cache[key] = entry
210
+
211
+ self._stats["sets"] += 1
212
+ log_debug(f"Cache set: {key} (TTL={ttl}s)")
213
+
214
+ def clear(self) -> None:
215
+ """
216
+ 全キャッシュをクリア
217
+ """
218
+ with self._lock:
219
+ self._l1_cache.clear()
220
+ self._l2_cache.clear()
221
+ self._l3_cache.clear()
222
+
223
+ # 統計をリセット
224
+ for key in self._stats:
225
+ self._stats[key] = 0
226
+
227
+ log_info("All caches cleared")
228
+
229
+ def size(self) -> int:
230
+ """
231
+ キャッシュサイズを取得
232
+
233
+ Returns:
234
+ L1キャッシュのサイズ(最も頻繁にアクセスされるアイテム数)
235
+ """
236
+ with self._lock:
237
+ return len(self._l1_cache)
238
+
239
+ def get_stats(self) -> dict[str, Any]:
240
+ """
241
+ キャッシュ統計を取得
242
+
243
+ Returns:
244
+ 統計情報辞書
245
+ """
246
+ with self._lock:
247
+ total_requests = self._stats["hits"] + self._stats["misses"]
248
+ hit_rate = (
249
+ self._stats["hits"] / total_requests if total_requests > 0 else 0.0
250
+ )
251
+
252
+ return {
253
+ **self._stats,
254
+ "hit_rate": hit_rate,
255
+ "total_requests": total_requests,
256
+ "l1_size": len(self._l1_cache),
257
+ "l2_size": len(self._l2_cache),
258
+ "l3_size": len(self._l3_cache),
259
+ }
260
+
261
+ def generate_cache_key(
262
+ self, file_path: str, language: str, options: dict[str, Any]
263
+ ) -> str:
264
+ """
265
+ キャッシュキーを生成
266
+
267
+ Args:
268
+ file_path: ファイルパス
269
+ language: プログラミング言語
270
+ options: 解析オプション
271
+
272
+ Returns:
273
+ ハッシュ化されたキャッシュキー
274
+ """
275
+ # 一意なキーを生成するための文字列を構築
276
+ key_components = [
277
+ file_path,
278
+ language,
279
+ str(sorted(options.items())), # 辞書を安定した文字列に変換
280
+ ]
281
+
282
+ key_string = ":".join(key_components)
283
+
284
+ # SHA256でハッシュ化
285
+ return hashlib.sha256(key_string.encode("utf-8")).hexdigest()
286
+
287
+ async def invalidate_pattern(self, pattern: str) -> int:
288
+ """
289
+ パターンに一致するキーを無効化
290
+
291
+ Args:
292
+ pattern: 無効化するキーのパターン
293
+
294
+ Returns:
295
+ 無効化されたキー数
296
+ """
297
+ invalidated_count = 0
298
+
299
+ with self._lock:
300
+ # 各階層からパターンに一致するキーを削除
301
+ for cache in [self._l1_cache, self._l2_cache, self._l3_cache]:
302
+ keys_to_remove = [key for key in cache.keys() if pattern in key]
303
+
304
+ for key in keys_to_remove:
305
+ if key in cache:
306
+ del cache[key]
307
+ invalidated_count += 1
308
+
309
+ log_info(
310
+ f"Invalidated {invalidated_count} cache entries matching pattern: {pattern}"
311
+ )
312
+ return invalidated_count
313
+
314
+ def __del__(self) -> None:
315
+ """デストラクタ - リソースクリーンアップ"""
316
+ try:
317
+ self.clear()
318
+ log_debug("CacheService destroyed and cleaned up")
319
+ except Exception as e:
320
+ log_error(f"Error during CacheService cleanup: {e}")