private boolean isMatch() {
            this.lock.lock();
            int isMatch = 0;
            try {
                TRACE_CONTEXT.set(new DebuggingTraceContext(expression, false, false));
                AlarmMQEVisitor visitor = new AlarmMQEVisitor(moduleManager, this.entity, this.values, this.endTime, this.additionalPeriod);
                ExpressionResult parseResult = visitor.visit(exprTree);
                if (StringUtil.isNotBlank(parseResult.getError())) {
                    log.error("expression:" + expression + " error: " + parseResult.getError());
                    return false;
                }
                if (!parseResult.isBoolResult() ||
                    ExpressionResultType.SINGLE_VALUE != parseResult.getType() ||
                    CollectionUtils.isEmpty(parseResult.getResults())) {
                    return false;
                }
                if (!parseResult.isLabeledResult()) {
                    MQEValues mqeValues = parseResult.getResults().get(0);
                    if (mqeValues != null &&
                        CollectionUtils.isNotEmpty(mqeValues.getValues()) &&
                        mqeValues.getValues().get(0) != null) {
                        isMatch = (int) mqeValues.getValues().get(0).getDoubleValue();
                    }
                } else {
                    // if the result has multiple labels, when there is one label match, then the result is match
                    // for example in 5 minutes, the sum(percentile{p='50,75'} > 1000) >= 3
                    // percentile{p='50,75'} result is:
                    // P50(1000,1100,1200,1000,500), > 1000 2 times
                    // P75(2000,1500,1200,1000,500), > 1000 3 times
                    // percentile{p='50,75'} > 1000 result is:
                    // P50(0,1,1,0,0)
                    // P75(1,1,1,0,0)
                    // sum(percentile{p='50,75'} > 1000) >= 3 result is:
                    // P50(0)
                    // P75(1)
                    // then the isMatch is 1
                    for (MQEValues mqeValues : parseResult.getResults()) {
                        if (mqeValues != null &&
                            CollectionUtils.isNotEmpty(mqeValues.getValues()) &&
                            mqeValues.getValues().get(0) != null) {
                            isMatch = (int) mqeValues.getValues().get(0).getDoubleValue();
                            if (isMatch == 1) {
                                break;
                            }
                        }
                    }
                }
                if (log.isTraceEnabled()) {
                    log.trace("Match expression is {}", expression);
                }
                this.mqeMetricsSnapshot = visitor.getMqeMetricsSnapshot();
                return isMatch == 1;
            } finally {
                this.lock.unlock();
                TRACE_CONTEXT.remove();
            }
        }
A metrics window, based on AlarmRule#period. This window slides with time, just keeps the recent N(period)
buckets.
oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java