diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md index 43402c4a01..3b4d290aa2 100644 --- a/docs/en/changes/changes.md +++ b/docs/en/changes/changes.md @@ -47,6 +47,7 @@ * BanyanDB: stream sort-by `time` query, use internal time-series rather than `index` to improve the query performance. * Bump up graphql-java to 21.5. * Add Unknown Node when receive Kubernetes peer address is not aware in current cluster. +* Fix CounterWindow concurrent increase cause NPE by PriorityQueue #### UI diff --git a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/counter/CounterWindow.java b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/counter/CounterWindow.java index b1e4eac68a..5e7e6039ee 100644 --- a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/counter/CounterWindow.java +++ b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/counter/CounterWindow.java @@ -48,25 +48,27 @@ public class CounterWindow { public Tuple2 increase(String name, ImmutableMap labels, Double value, long windowSize, long now) { ID id = new ID(name, labels); Queue> window = windows.computeIfAbsent(id, unused -> new PriorityQueue<>()); - window.offer(Tuple.of(now, value)); - long waterLevel = now - windowSize; - Tuple2 peek = window.peek(); - if (peek._1 > waterLevel) { + synchronized (window) { + window.offer(Tuple.of(now, value)); + long waterLevel = now - windowSize; + Tuple2 peek = window.peek(); + if (peek._1 > waterLevel) { + return peek; + } + + Tuple2 result = peek; + while (peek._1 < waterLevel) { + result = window.poll(); + peek = window.element(); + } + + // Choose the closed slot to the expected timestamp + if (waterLevel - result._1 <= peek._1 - waterLevel) { + return result; + } + return peek; } - - Tuple2 result = peek; - while (peek._1 < waterLevel) { - result = window.poll(); - peek = window.element(); - } - - // Choose the closed slot to the expected timestamp - if (waterLevel - result._1 <= peek._1 - waterLevel) { - return result; - } - - return peek; } public Tuple2 pop(String name, ImmutableMap labels, Double value, long now) {