001package gudusoft.gsqlparser.sqlenv.catalog;
002
003import java.util.concurrent.atomic.AtomicLong;
004
005/**
006 * Catalog 监控指标(Phase 2: Read Switching)
007 *
008 * <p>用于监控读取路径的命中率和回退率,帮助评估新实现的质量。
009 *
010 * @since 3.2.0 (Phase 2)
011 */
012public class CatalogMetrics {
013
014    private final AtomicLong newHitCount = new AtomicLong(0);
015    private final AtomicLong missCount = new AtomicLong(0);
016    private final AtomicLong fallbackCount = new AtomicLong(0);
017    private final AtomicLong legacyHitCount = new AtomicLong(0);
018
019    /**
020     * 记录新实现命中
021     */
022    public void recordNewHit() {
023        newHitCount.incrementAndGet();
024    }
025
026    /**
027     * 记录未找到(miss)
028     */
029    public void recordMiss() {
030        missCount.incrementAndGet();
031    }
032
033    /**
034     * 记录回退到旧实现
035     */
036    public void recordFallback() {
037        fallbackCount.incrementAndGet();
038    }
039
040    /**
041     * 记录旧实现命中
042     */
043    public void recordLegacyHit() {
044        legacyHitCount.incrementAndGet();
045    }
046
047    /**
048     * 计算新实现命中率
049     *
050     * @return 命中率 (0.0 到 1.0)
051     */
052    public double getNewHitRate() {
053        long total = newHitCount.get() + missCount.get() + fallbackCount.get();
054        if (total == 0) {
055            return 0.0;
056        }
057        return (double) newHitCount.get() / total;
058    }
059
060    /**
061     * 计算回退率
062     *
063     * @return 回退率 (0.0 到 1.0)
064     */
065    public double getFallbackRate() {
066        long total = newHitCount.get() + missCount.get() + fallbackCount.get();
067        if (total == 0) {
068            return 0.0;
069        }
070        return (double) fallbackCount.get() / total;
071    }
072
073    /**
074     * 计算总命中率(包括新实现和回退)
075     *
076     * @return 总命中率 (0.0 到 1.0)
077     */
078    public double getTotalHitRate() {
079        long total = newHitCount.get() + missCount.get() + fallbackCount.get();
080        if (total == 0) {
081            return 0.0;
082        }
083        return (double) (newHitCount.get() + fallbackCount.get()) / total;
084    }
085
086    /**
087     * 获取新实现命中数
088     *
089     * @return 命中数
090     */
091    public long getNewHitCount() {
092        return newHitCount.get();
093    }
094
095    /**
096     * 获取未找到数
097     *
098     * @return 未找到数
099     */
100    public long getMissCount() {
101        return missCount.get();
102    }
103
104    /**
105     * 获取回退数
106     *
107     * @return 回退数
108     */
109    public long getFallbackCount() {
110        return fallbackCount.get();
111    }
112
113    /**
114     * 获取旧实现命中数
115     *
116     * @return 旧实现命中数
117     */
118    public long getLegacyHitCount() {
119        return legacyHitCount.get();
120    }
121
122    /**
123     * 获取总操作数
124     *
125     * @return 总操作数
126     */
127    public long getTotalOperations() {
128        return newHitCount.get() + missCount.get() + fallbackCount.get() + legacyHitCount.get();
129    }
130
131    /**
132     * 重置所有计数器
133     */
134    public void reset() {
135        newHitCount.set(0);
136        missCount.set(0);
137        fallbackCount.set(0);
138        legacyHitCount.set(0);
139    }
140
141    /**
142     * 生成监控报告
143     *
144     * @return 报告字符串
145     */
146    public String generateReport() {
147        StringBuilder sb = new StringBuilder();
148        sb.append("CatalogMetrics Report:\n");
149        sb.append("==================================================\n");
150        sb.append(String.format("New Implementation Hits:    %,d%n", newHitCount.get()));
151        sb.append(String.format("Misses (not found):         %,d%n", missCount.get()));
152        sb.append(String.format("Fallbacks to Legacy:        %,d%n", fallbackCount.get()));
153        sb.append(String.format("Legacy Direct Hits:         %,d%n", legacyHitCount.get()));
154        sb.append("==================================================\n");
155        sb.append(String.format("Total Operations:           %,d%n", getTotalOperations()));
156        sb.append(String.format("New Hit Rate:               %.2f%%%n", getNewHitRate() * 100));
157        sb.append(String.format("Fallback Rate:              %.2f%%%n", getFallbackRate() * 100));
158        sb.append(String.format("Total Hit Rate:             %.2f%%%n", getTotalHitRate() * 100));
159        sb.append("==================================================\n");
160
161        // Quality assessment
162        if (getNewHitRate() >= 0.99) {
163            sb.append("✅ Quality: EXCELLENT (Ready for Phase 3)\n");
164        } else if (getNewHitRate() >= 0.95) {
165            sb.append("⚠️  Quality: GOOD (Minor issues, investigate misses)\n");
166        } else if (getNewHitRate() >= 0.90) {
167            sb.append("⚠️  Quality: ACCEPTABLE (Some issues, review needed)\n");
168        } else {
169            sb.append("❌ Quality: POOR (Significant issues, rollback recommended)\n");
170        }
171
172        return sb.toString();
173    }
174
175    /**
176     * 检查是否准备好进入 Phase 3
177     *
178     * @return true 如果新实现命中率 >= 99%
179     */
180    public boolean isReadyForPhase3() {
181        return getNewHitRate() >= 0.99 && getFallbackRate() < 0.01;
182    }
183
184    /**
185     * 生成简短状态摘要
186     *
187     * @return 状态摘要
188     */
189    public String getShortSummary() {
190        return String.format("NewHit=%d, Miss=%d, Fallback=%d, HitRate=%.2f%%",
191            newHitCount.get(), missCount.get(), fallbackCount.get(), getNewHitRate() * 100);
192    }
193}