This is an automated email from the ASF dual-hosted git repository.
dsmiley pushed a commit to branch feature/SOLR-17458-rebased
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/feature/SOLR-17458-rebased by
this push:
new 315bf57ee49 SOLR-17865: Support aggregateNodeLevelMetricsEnabled
(#3734)
315bf57ee49 is described below
commit 315bf57ee4937830f1314f51b2ddda1ae3fed092
Author: Matthew Biscocho <[email protected]>
AuthorDate: Mon Oct 13 23:09:09 2025 -0400
SOLR-17865: Support aggregateNodeLevelMetricsEnabled (#3734)
Aggregates some core metrics to the node level.
---------
Co-authored-by: Matthew Biscocho <[email protected]>
---
.../apache/solr/handler/RequestHandlerBase.java | 95 +++++------
.../solr/handler/component/SearchHandler.java | 5 +-
.../otel/instruments/AttributedDoubleCounter.java | 2 +-
.../instruments/AttributedDoubleUpDownCounter.java | 4 +-
.../instruments/AttributedInstrumentFactory.java | 160 ++++++++++++++++++
.../otel/instruments/AttributedLongCounter.java | 2 +-
.../instruments/AttributedLongUpDownCounter.java | 4 +-
...java => DualRegistryAttributedLongCounter.java} | 28 ++--
...r.java => DualRegistryAttributedLongTimer.java} | 32 ++--
...> DualRegistryAttributedLongUpDownCounter.java} | 32 ++--
.../apache/solr/update/DirectUpdateHandler2.java | 175 ++++++++++----------
.../conf/solrconfig.xml | 4 +-
.../solr/handler/RequestHandlerBaseTest.java | 3 +-
.../solr/handler/RequestHandlerMetricsTest.java | 183 +++++++++------------
14 files changed, 433 insertions(+), 296 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
index f726842d773..f2407a4273e 100644
--- a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
+++ b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
@@ -21,8 +21,6 @@ import static
org.apache.solr.response.SolrQueryResponse.haveCompleteResults;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
-import io.opentelemetry.api.metrics.LongCounter;
-import io.opentelemetry.api.metrics.LongHistogram;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
@@ -41,11 +39,10 @@ import org.apache.solr.core.PluginBag;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrInfoBean;
-import org.apache.solr.metrics.SolrDelegateRegistryMetricsContext;
import org.apache.solr.metrics.SolrMetricManager;
-import org.apache.solr.metrics.SolrMetricProducer;
import org.apache.solr.metrics.SolrMetricsContext;
import org.apache.solr.metrics.otel.OtelUnit;
+import org.apache.solr.metrics.otel.instruments.AttributedInstrumentFactory;
import org.apache.solr.metrics.otel.instruments.AttributedLongCounter;
import org.apache.solr.metrics.otel.instruments.AttributedLongTimer;
import org.apache.solr.request.SolrQueryRequest;
@@ -72,6 +69,7 @@ public abstract class RequestHandlerBase
PermissionNameProvider {
public static final String REQUEST_CPU_TIMER_CONTEXT = "publishCpuTime";
+ public static final AttributeKey<String> SOURCE_ATTR =
AttributeKey.stringKey("source");
protected NamedList<?> initArgs = null;
protected SolrParams defaults;
protected SolrParams appends;
@@ -167,21 +165,13 @@ public abstract class RequestHandlerBase
@Override
public void initializeMetrics(
SolrMetricsContext parentContext, Attributes attributes, String scope) {
- if (aggregateNodeLevelMetricsEnabled) {
- this.solrMetricsContext =
- new SolrDelegateRegistryMetricsContext(
- parentContext.getMetricManager(),
- parentContext.getRegistryName(),
- SolrMetricProducer.getUniqueMetricTag(this,
parentContext.getTag()),
- SolrMetricManager.getRegistryName(SolrInfoBean.Group.node));
- } else {
- this.solrMetricsContext = parentContext.getChildContext(this);
- }
+ this.solrMetricsContext = parentContext.getChildContext(this);
metrics =
new HandlerMetrics(
solrMetricsContext,
- attributes.toBuilder().put(CATEGORY_ATTR,
getCategory().toString()).build());
+ attributes.toBuilder().put(CATEGORY_ATTR,
getCategory().toString()).build(),
+ aggregateNodeLevelMetricsEnabled);
}
/** Metrics for this handler. */
@@ -189,7 +179,8 @@ public abstract class RequestHandlerBase
public static final HandlerMetrics NO_OP =
new HandlerMetrics(
new SolrMetricsContext(new SolrMetricManager(null), "NO_OP",
"NO_OP"),
- Attributes.empty());
+ Attributes.empty(),
+ false);
public AttributedLongCounter requests;
public AttributedLongCounter numServerErrors;
@@ -197,53 +188,41 @@ public abstract class RequestHandlerBase
public AttributedLongCounter numTimeouts;
public AttributedLongTimer requestTimes;
- public HandlerMetrics(SolrMetricsContext solrMetricsContext, Attributes
attributes) {
- LongCounter requestMetric;
- LongCounter errorRequestMetric;
- LongCounter timeoutRequestMetric;
- LongHistogram requestTimeMetric;
-
- if (solrMetricsContext.getRegistryName().equals("solr.node")) {
- requestMetric =
- solrMetricsContext.longCounter("solr_node_requests", "Http Solr
node requests");
- errorRequestMetric =
- solrMetricsContext.longCounter(
- "solr_node_requests_errors", "HTTP Solr node request errors");
- timeoutRequestMetric =
- solrMetricsContext.longCounter(
- "solr_node_requests_timeout", "HTTP Solr node request
timeouts");
- requestTimeMetric =
- solrMetricsContext.longHistogram(
- "solr_node_requests_times", "HTTP Solr node request times",
OtelUnit.MILLISECONDS);
- } else {
- requestMetric =
- solrMetricsContext.longCounter("solr_core_requests", "HTTP Solr
core requests");
- errorRequestMetric =
- solrMetricsContext.longCounter(
- "solr_core_requests_errors", "HTTP Solr core request errors");
- timeoutRequestMetric =
- solrMetricsContext.longCounter(
- "solr_core_requests_timeout", "HTTP Solr core request
timeouts");
- requestTimeMetric =
- solrMetricsContext.longHistogram(
- "solr_core_requests_times", "HTTP Solr core request times",
OtelUnit.MILLISECONDS);
- }
+ public HandlerMetrics(
+ SolrMetricsContext solrMetricsContext,
+ Attributes coreAttributes,
+ boolean aggregateNodeLevelMetricsEnabled) {
- requests = new AttributedLongCounter(requestMetric, attributes);
+ AttributedInstrumentFactory factory =
+ new AttributedInstrumentFactory(
+ solrMetricsContext, coreAttributes,
aggregateNodeLevelMetricsEnabled);
+
+ requests =
+ factory.attributedLongCounter(
+ "solr_core_requests", "HTTP Solr requests", Attributes.empty());
numServerErrors =
- new AttributedLongCounter(
- errorRequestMetric,
- attributes.toBuilder().put(AttributeKey.stringKey("source"),
"server").build());
+ factory.attributedLongCounter(
+ "solr_core_requests_errors",
+ "HTTP Solr request errors",
+ Attributes.of(SOURCE_ATTR, "server"));
numClientErrors =
- new AttributedLongCounter(
- errorRequestMetric,
- attributes.toBuilder().put(AttributeKey.stringKey("source"),
"client").build());
-
- numTimeouts = new AttributedLongCounter(timeoutRequestMetric,
attributes);
-
- requestTimes = new AttributedLongTimer(requestTimeMetric, attributes);
+ factory.attributedLongCounter(
+ "solr_core_requests_errors",
+ "HTTP Solr request errors",
+ Attributes.of(SOURCE_ATTR, "client"));
+
+ numTimeouts =
+ factory.attributedLongCounter(
+ "solr_core_requests_timeout", "HTTP Solr request timeouts",
Attributes.empty());
+
+ requestTimes =
+ factory.attributedLongTimer(
+ "solr_core_requests_times",
+ "HTTP Solr request times",
+ OtelUnit.MILLISECONDS,
+ Attributes.empty());
}
}
diff --git
a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
index b42e62d187b..cc7ad157651 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java
@@ -98,8 +98,6 @@ public class SearchHandler extends RequestHandlerBase
static final String INIT_FIRST_COMPONENTS = "first-components";
static final String INIT_LAST_COMPONENTS = "last-components";
- protected static final String SHARD_HANDLER_SUFFIX = "[shard]";
-
private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/**
@@ -171,7 +169,8 @@ public class SearchHandler extends RequestHandlerBase
.putAll(attributes)
.put(CATEGORY_ATTR, getCategory().toString())
.put(INTERNAL_ATTR, true)
- .build());
+ .build(),
+ false);
}
@Override
diff --git
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedDoubleCounter.java
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedDoubleCounter.java
index 43adf8ad087..e2f28293e4a 100644
---
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedDoubleCounter.java
+++
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedDoubleCounter.java
@@ -29,7 +29,7 @@ public class AttributedDoubleCounter {
this.attributes = attributes;
}
- public void inc() {
+ public final void inc() {
add(1.0);
}
diff --git
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedDoubleUpDownCounter.java
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedDoubleUpDownCounter.java
index 23c0d3b9a53..ca2808a596f 100644
---
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedDoubleUpDownCounter.java
+++
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedDoubleUpDownCounter.java
@@ -29,11 +29,11 @@ public class AttributedDoubleUpDownCounter {
this.attributes = attributes;
}
- public void inc() {
+ public final void inc() {
add(1.0);
}
- public void dec() {
+ public final void dec() {
add(-1.0);
}
diff --git
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedInstrumentFactory.java
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedInstrumentFactory.java
new file mode 100644
index 00000000000..a443eab92b0
--- /dev/null
+++
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedInstrumentFactory.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.metrics.otel.instruments;
+
+import static org.apache.solr.handler.component.SearchHandler.INTERNAL_ATTR;
+import static org.apache.solr.metrics.SolrCoreMetricManager.COLLECTION_ATTR;
+import static org.apache.solr.metrics.SolrCoreMetricManager.CORE_ATTR;
+import static org.apache.solr.metrics.SolrCoreMetricManager.REPLICA_TYPE_ATTR;
+import static org.apache.solr.metrics.SolrCoreMetricManager.SHARD_ATTR;
+
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.metrics.LongCounter;
+import io.opentelemetry.api.metrics.LongHistogram;
+import io.opentelemetry.api.metrics.LongUpDownCounter;
+import java.util.Set;
+import org.apache.solr.core.SolrInfoBean;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricsContext;
+import org.apache.solr.metrics.otel.OtelUnit;
+
+/**
+ * Factory for creating metrics instruments that can write to either single or
dual registries (core
+ * and node).
+ */
+public class AttributedInstrumentFactory {
+
+ private static final Set<AttributeKey<?>> FILTER_ATTRS_SET =
+ Set.of(COLLECTION_ATTR, CORE_ATTR, SHARD_ATTR, REPLICA_TYPE_ATTR,
INTERNAL_ATTR);
+ private final SolrMetricsContext primaryMetricsContext;
+ private final Attributes primaryAttributes;
+ private final boolean aggregateToNodeRegistry;
+ private final boolean primaryIsNodeRegistry;
+ private SolrMetricsContext nodeMetricsContext = null;
+ private Attributes nodeAttributes = null;
+
+ public AttributedInstrumentFactory(
+ SolrMetricsContext primaryMetricsContext,
+ Attributes primaryAttributes,
+ boolean aggregateToNodeRegistry) {
+ this.primaryMetricsContext = primaryMetricsContext;
+ this.primaryAttributes = primaryAttributes;
+ this.aggregateToNodeRegistry = aggregateToNodeRegistry;
+
+ // Primary could be a node
+ this.primaryIsNodeRegistry =
+ primaryMetricsContext
+ .getRegistryName()
+
.equals(SolrMetricManager.getRegistryName(SolrInfoBean.Group.node));
+
+ // Only create node registry if we want dual registry mode AND primary is
not already a node
+ // registry
+ if (aggregateToNodeRegistry && !primaryIsNodeRegistry) {
+ this.nodeMetricsContext =
+ new SolrMetricsContext(
+ primaryMetricsContext.getMetricManager(),
+ SolrMetricManager.getRegistryName(SolrInfoBean.Group.node),
+ null);
+ this.nodeAttributes = createNodeAttributes(primaryAttributes);
+ }
+ }
+
+ public AttributedLongCounter attributedLongCounter(
+ String metricName, String description, Attributes additionalAttributes) {
+ Attributes finalPrimaryAttrs = appendAttributes(primaryAttributes,
additionalAttributes);
+
+ if (aggregateToNodeRegistry && nodeMetricsContext != null) {
+ Attributes finalNodeAttrs = appendAttributes(nodeAttributes,
additionalAttributes);
+
+ LongCounter primaryCounter =
primaryMetricsContext.longCounter(metricName, description);
+ LongCounter nodeCounter =
+ nodeMetricsContext.longCounter(toNodeMetricName(metricName),
description);
+ return new DualRegistryAttributedLongCounter(
+ primaryCounter, finalPrimaryAttrs, nodeCounter, finalNodeAttrs);
+ } else {
+ String finalMetricName = primaryIsNodeRegistry ?
toNodeMetricName(metricName) : metricName;
+ LongCounter counter = primaryMetricsContext.longCounter(finalMetricName,
description);
+ return new AttributedLongCounter(counter, finalPrimaryAttrs);
+ }
+ }
+
+ public AttributedLongUpDownCounter attributedLongUpDownCounter(
+ String metricName, String description, Attributes additionalAttributes) {
+ Attributes finalPrimaryAttrs = appendAttributes(primaryAttributes,
additionalAttributes);
+
+ if (aggregateToNodeRegistry && nodeMetricsContext != null) {
+ Attributes finalNodeAttrs = appendAttributes(nodeAttributes,
additionalAttributes);
+
+ LongUpDownCounter primaryCounter =
+ primaryMetricsContext.longUpDownCounter(metricName, description);
+ LongUpDownCounter nodeCounter =
+ nodeMetricsContext.longUpDownCounter(toNodeMetricName(metricName),
description);
+ return new DualRegistryAttributedLongUpDownCounter(
+ primaryCounter, finalPrimaryAttrs, nodeCounter, finalNodeAttrs);
+ } else {
+ String finalMetricName = primaryIsNodeRegistry ?
toNodeMetricName(metricName) : metricName;
+ LongUpDownCounter counter =
+ primaryMetricsContext.longUpDownCounter(finalMetricName,
description);
+ return new AttributedLongUpDownCounter(counter, finalPrimaryAttrs);
+ }
+ }
+
+ public AttributedLongTimer attributedLongTimer(
+ String metricName, String description, OtelUnit unit, Attributes
additionalAttributes) {
+ Attributes finalPrimaryAttrs = appendAttributes(primaryAttributes,
additionalAttributes);
+
+ if (aggregateToNodeRegistry && nodeMetricsContext != null) {
+ Attributes finalNodeAttrs = appendAttributes(nodeAttributes,
additionalAttributes);
+ LongHistogram primaryHistogram =
+ primaryMetricsContext.longHistogram(metricName, description, unit);
+ LongHistogram nodeHistogram =
+ nodeMetricsContext.longHistogram(toNodeMetricName(metricName),
description, unit);
+ return new DualRegistryAttributedLongTimer(
+ primaryHistogram, finalPrimaryAttrs, nodeHistogram, finalNodeAttrs);
+ } else {
+ String finalMetricName = primaryIsNodeRegistry ?
toNodeMetricName(metricName) : metricName;
+ LongHistogram histogram =
+ primaryMetricsContext.longHistogram(finalMetricName, description,
unit);
+ return new AttributedLongTimer(histogram, finalPrimaryAttrs);
+ }
+ }
+
+ /** Replace core metric name prefix to node prefix */
+ private String toNodeMetricName(String coreMetricName) {
+ return coreMetricName.replace("solr_core", "solr_node");
+ }
+
+ /** Filter out core attributes and keep all others for node-level metrics */
+ @SuppressWarnings("unchecked")
+ private Attributes createNodeAttributes(Attributes coreAttributes) {
+ var builder = Attributes.builder();
+
+ coreAttributes.forEach(
+ (key, value) -> {
+ if (!FILTER_ATTRS_SET.contains(key)) {
+ builder.put((AttributeKey<Object>) key, value);
+ }
+ });
+
+ return builder.build();
+ }
+
+ private Attributes appendAttributes(Attributes base, Attributes additional) {
+ return base.toBuilder().putAll(additional).build();
+ }
+}
diff --git
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
index f33b4784c53..e2a477eac35 100644
---
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
+++
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
@@ -29,7 +29,7 @@ public class AttributedLongCounter {
this.attributes = attributes;
}
- public void inc() {
+ public final void inc() {
add(1L);
}
diff --git
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongUpDownCounter.java
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongUpDownCounter.java
index 91487c9e677..e3ae3e98edd 100644
---
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongUpDownCounter.java
+++
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongUpDownCounter.java
@@ -29,11 +29,11 @@ public class AttributedLongUpDownCounter {
this.attributes = attributes;
}
- public void inc() {
+ public final void inc() {
add(1L);
}
- public void dec() {
+ public final void dec() {
add(-1L);
}
diff --git
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/DualRegistryAttributedLongCounter.java
similarity index 60%
copy from
solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
copy to
solr/core/src/java/org/apache/solr/metrics/otel/instruments/DualRegistryAttributedLongCounter.java
index f33b4784c53..15fc27b85c5 100644
---
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
+++
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/DualRegistryAttributedLongCounter.java
@@ -19,21 +19,27 @@ package org.apache.solr.metrics.otel.instruments;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.LongCounter;
-public class AttributedLongCounter {
-
- private final LongCounter baseCounter;
- private final io.opentelemetry.api.common.Attributes attributes;
+/**
+ * An AttributedLongCounter that writes to both core and node registries with
corresponding
+ * attributes.
+ */
+public class DualRegistryAttributedLongCounter extends AttributedLongCounter {
- public AttributedLongCounter(LongCounter baseCounter, Attributes attributes)
{
- this.baseCounter = baseCounter;
- this.attributes = attributes;
- }
+ private final AttributedLongCounter nodeCounter;
- public void inc() {
- add(1L);
+ public DualRegistryAttributedLongCounter(
+ LongCounter coreCounter,
+ Attributes coreAttributes,
+ LongCounter nodeCounter,
+ Attributes nodeAttributes) {
+ super(coreCounter, coreAttributes);
+ assert coreCounter != nodeCounter;
+ this.nodeCounter = new AttributedLongCounter(nodeCounter, nodeAttributes);
}
+ @Override
public void add(Long value) {
- baseCounter.add(value, attributes);
+ super.add(value);
+ nodeCounter.add(value);
}
}
diff --git
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/DualRegistryAttributedLongTimer.java
similarity index 55%
copy from
solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
copy to
solr/core/src/java/org/apache/solr/metrics/otel/instruments/DualRegistryAttributedLongTimer.java
index f33b4784c53..b42d869892c 100644
---
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongCounter.java
+++
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/DualRegistryAttributedLongTimer.java
@@ -17,23 +17,29 @@
package org.apache.solr.metrics.otel.instruments;
import io.opentelemetry.api.common.Attributes;
-import io.opentelemetry.api.metrics.LongCounter;
+import io.opentelemetry.api.metrics.LongHistogram;
-public class AttributedLongCounter {
-
- private final LongCounter baseCounter;
- private final io.opentelemetry.api.common.Attributes attributes;
+/**
+ * An AttributedLongTimer that records to both core and node registries with
corresponding
+ * attributes.
+ */
+public class DualRegistryAttributedLongTimer extends AttributedLongTimer {
- public AttributedLongCounter(LongCounter baseCounter, Attributes attributes)
{
- this.baseCounter = baseCounter;
- this.attributes = attributes;
- }
+ private final AttributedLongTimer nodeTimer;
- public void inc() {
- add(1L);
+ public DualRegistryAttributedLongTimer(
+ LongHistogram coreHistogram,
+ Attributes coreAttributes,
+ LongHistogram nodeHistogram,
+ Attributes nodeAttributes) {
+ super(coreHistogram, coreAttributes);
+ assert coreHistogram != nodeHistogram;
+ this.nodeTimer = new AttributedLongTimer(nodeHistogram, nodeAttributes);
}
- public void add(Long value) {
- baseCounter.add(value, attributes);
+ @Override
+ public void record(Long value) {
+ super.record(value);
+ nodeTimer.record(value);
}
}
diff --git
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongUpDownCounter.java
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/DualRegistryAttributedLongUpDownCounter.java
similarity index 57%
copy from
solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongUpDownCounter.java
copy to
solr/core/src/java/org/apache/solr/metrics/otel/instruments/DualRegistryAttributedLongUpDownCounter.java
index 91487c9e677..6cf505fb54e 100644
---
a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedLongUpDownCounter.java
+++
b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/DualRegistryAttributedLongUpDownCounter.java
@@ -19,25 +19,27 @@ package org.apache.solr.metrics.otel.instruments;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.LongUpDownCounter;
-public class AttributedLongUpDownCounter {
-
- private final LongUpDownCounter upDownCounter;
- private final Attributes attributes;
-
- public AttributedLongUpDownCounter(LongUpDownCounter upDownCounter,
Attributes attributes) {
- this.upDownCounter = upDownCounter;
- this.attributes = attributes;
- }
+/**
+ * An AttributedLongUpDownCounter that writes to both core and node registries
with corresponding
+ * attributes.
+ */
+public class DualRegistryAttributedLongUpDownCounter extends
AttributedLongUpDownCounter {
- public void inc() {
- add(1L);
- }
+ private final AttributedLongUpDownCounter nodeUpDownCounter;
- public void dec() {
- add(-1L);
+ public DualRegistryAttributedLongUpDownCounter(
+ LongUpDownCounter coreUpDownCounter,
+ Attributes coreAttributes,
+ LongUpDownCounter nodeUpDownCounter,
+ Attributes nodeAttributes) {
+ super(coreUpDownCounter, coreAttributes);
+ assert coreUpDownCounter != nodeUpDownCounter;
+ this.nodeUpDownCounter = new
AttributedLongUpDownCounter(nodeUpDownCounter, nodeAttributes);
}
+ @Override
public void add(Long value) {
- upDownCounter.add(value, attributes);
+ super.add(value);
+ nodeUpDownCounter.add(value);
}
}
diff --git
a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
index 0a027282c46..dc802afc2b7 100644
--- a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
+++ b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
@@ -53,11 +53,9 @@ import org.apache.solr.common.util.IOUtils;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrConfig.UpdateHandlerInfo;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoBean;
-import org.apache.solr.metrics.SolrDelegateRegistryMetricsContext;
-import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricProducer;
import org.apache.solr.metrics.SolrMetricsContext;
+import org.apache.solr.metrics.otel.instruments.AttributedInstrumentFactory;
import org.apache.solr.metrics.otel.instruments.AttributedLongCounter;
import org.apache.solr.metrics.otel.instruments.AttributedLongUpDownCounter;
import org.apache.solr.request.LocalSolrQueryRequest;
@@ -227,84 +225,121 @@ public class DirectUpdateHandler2 extends UpdateHandler
@Override
public void initializeMetrics(
SolrMetricsContext parentContext, Attributes attributes, String scope) {
- if
(core.getSolrConfig().getUpdateHandlerInfo().aggregateNodeLevelMetricsEnabled) {
- this.solrMetricsContext =
- new SolrDelegateRegistryMetricsContext(
- parentContext.getMetricManager(),
- parentContext.getRegistryName(),
- SolrMetricProducer.getUniqueMetricTag(this,
parentContext.getTag()),
- SolrMetricManager.getRegistryName(SolrInfoBean.Group.node));
- } else {
- this.solrMetricsContext = parentContext.getChildContext(this);
- }
- final List<AutoCloseable> observables = new ArrayList<>();
+ this.solrMetricsContext = parentContext.getChildContext(this);
var baseAttributes =
attributes.toBuilder()
.put(AttributeKey.stringKey("category"), getCategory().toString())
.build();
- var baseCommandsMetric =
- solrMetricsContext.longUpDownCounter(
- "solr_core_update_cumulative_ops",
- "Cumulative number of update commands processed. Cumulative can
decrease from rollback command");
+ boolean aggregateNodeLevelMetricsEnabled =
+
core.getSolrConfig().getUpdateHandlerInfo().aggregateNodeLevelMetricsEnabled;
+
+ createMetrics(baseAttributes, aggregateNodeLevelMetricsEnabled);
+ }
+
+ private void createMetrics(Attributes baseAttributes, boolean
aggregateToNodeRegistry) {
+ final List<AutoCloseable> observables = new ArrayList<>();
+
+ AttributedInstrumentFactory factory =
+ new AttributedInstrumentFactory(
+ solrMetricsContext, baseAttributes, aggregateToNodeRegistry);
addCommandsCumulative =
- new AttributedLongUpDownCounter(
- baseCommandsMetric, baseAttributes.toBuilder().put(OPERATION_ATTR,
"adds").build());
+ factory.attributedLongUpDownCounter(
+ "solr_core_update_cumulative_ops",
+ "Cumulative number of update commands processed. Cumulative can
decrease from rollback command",
+ Attributes.of(OPERATION_ATTR, "adds"));
deleteByIdCommandsCumulative =
- new AttributedLongUpDownCounter(
- baseCommandsMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"deletes_by_id").build());
+ factory.attributedLongUpDownCounter(
+ "solr_core_update_cumulative_ops",
+ "Cumulative number of update commands processed. Cumulative can
decrease from rollback command",
+ Attributes.of(OPERATION_ATTR, "deletes_by_id"));
deleteByQueryCommandsCumulative =
- new AttributedLongUpDownCounter(
- baseCommandsMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"deletes_by_query").build());
-
- var baseCommitOpsMetric =
- solrMetricsContext.longCounter(
- "solr_core_update_commit_ops", "Total number of commit
operations");
+ factory.attributedLongUpDownCounter(
+ "solr_core_update_cumulative_ops",
+ "Cumulative number of update commands processed. Cumulative can
decrease from rollback command",
+ Attributes.of(OPERATION_ATTR, "deletes_by_query"));
commitCommands =
- new AttributedLongCounter(
- baseCommitOpsMetric,
baseAttributes.toBuilder().put(OPERATION_ATTR, "commits").build());
+ factory.attributedLongCounter(
+ "solr_core_update_commit_ops",
+ "Total number of commit operations",
+ Attributes.of(OPERATION_ATTR, "commits"));
optimizeCommands =
- new AttributedLongCounter(
- baseCommitOpsMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"optimize").build());
+ factory.attributedLongCounter(
+ "solr_core_update_commit_ops",
+ "Total number of commit operations",
+ Attributes.of(OPERATION_ATTR, "optimize"));
mergeIndexesCommands =
- new AttributedLongCounter(
- baseCommitOpsMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"merge_indexes").build());
+ factory.attributedLongCounter(
+ "solr_core_update_commit_ops",
+ "Total number of commit operations",
+ Attributes.of(OPERATION_ATTR, "merge_indexes"));
expungeDeleteCommands =
- new AttributedLongCounter(
- baseCommitOpsMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"expunge_deletes").build());
-
- var baseMaintenanceMetric =
- solrMetricsContext.longCounter(
- "solr_core_update_maintenance_ops", "Total number of maintenance
operations");
+ factory.attributedLongCounter(
+ "solr_core_update_commit_ops",
+ "Total number of commit operations",
+ Attributes.of(OPERATION_ATTR, "expunge_deletes"));
rollbackCommands =
- new AttributedLongCounter(
- baseMaintenanceMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"rollback").build());
+ factory.attributedLongCounter(
+ "solr_core_update_maintenance_ops",
+ "Total number of maintenance operations",
+ Attributes.of(OPERATION_ATTR, "rollback"));
splitCommands =
- new AttributedLongCounter(
- baseMaintenanceMetric,
baseAttributes.toBuilder().put(OPERATION_ATTR, "split").build());
-
- var baseErrorsMetric =
- solrMetricsContext.longCounter("solr_core_update_errors", "Total
number of update errors");
+ factory.attributedLongCounter(
+ "solr_core_update_maintenance_ops",
+ "Total number of maintenance operations",
+ Attributes.of(OPERATION_ATTR, "split"));
numErrorsCumulative =
- new AttributedLongCounter(baseErrorsMetric,
baseAttributes.toBuilder().build());
+ factory.attributedLongCounter(
+ "solr_core_update_errors", "Total number of update errors",
Attributes.empty());
+
+ submittedAdds =
+ factory.attributedLongCounter(
+ "solr_core_update_submitted_ops",
+ "Total number of submitted update operations",
+ Attributes.of(OPERATION_ATTR, "adds"));
+
+ submittedDeleteById =
+ factory.attributedLongCounter(
+ "solr_core_update_submitted_ops",
+ "Total number of submitted update operations",
+ Attributes.of(OPERATION_ATTR, "deletes_by_id"));
+ submittedDeleteByQuery =
+ factory.attributedLongCounter(
+ "solr_core_update_submitted_ops",
+ "Total number of submitted update operations",
+ Attributes.of(OPERATION_ATTR, "deletes_by_query"));
+
+ committedAdds =
+ factory.attributedLongCounter(
+ "solr_core_update_committed_ops",
+ "Total number of committed update operations",
+ Attributes.of(OPERATION_ATTR, "adds"));
+
+ committedDeleteById =
+ factory.attributedLongCounter(
+ "solr_core_update_committed_ops",
+ "Total number of committed update operations",
+ Attributes.of(OPERATION_ATTR, "deletes_by_id"));
+
+ committedDeleteByQuery =
+ factory.attributedLongCounter(
+ "solr_core_update_committed_ops",
+ "Total number of committed update operations",
+ Attributes.of(OPERATION_ATTR, "deletes_by_query"));
+
+ // Create observable metrics only for core registry
observables.add(
solrMetricsContext.observableLongCounter(
"solr_core_update_auto_commits",
@@ -361,38 +396,6 @@ public class DirectUpdateHandler2 extends UpdateHandler
}));
this.toClose = Collections.unmodifiableList(observables);
-
- var baseSubmittedOpsMetric =
- solrMetricsContext.longCounter(
- "solr_core_update_submitted_ops", "Total number of submitted
update operations");
-
- var baseCommittedOpsMetric =
- solrMetricsContext.longCounter(
- "solr_core_update_committed_ops", "Total number of committed
update operations");
-
- submittedAdds =
- new AttributedLongCounter(
- baseSubmittedOpsMetric,
baseAttributes.toBuilder().put(OPERATION_ATTR, "adds").build());
- submittedDeleteById =
- new AttributedLongCounter(
- baseSubmittedOpsMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"deletes_by_id").build());
- submittedDeleteByQuery =
- new AttributedLongCounter(
- baseSubmittedOpsMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"deletes_by_query").build());
-
- committedAdds =
- new AttributedLongCounter(
- baseCommittedOpsMetric,
baseAttributes.toBuilder().put(OPERATION_ATTR, "adds").build());
- committedDeleteById =
- new AttributedLongCounter(
- baseCommittedOpsMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"deletes_by_id").build());
- committedDeleteByQuery =
- new AttributedLongCounter(
- baseCommittedOpsMetric,
- baseAttributes.toBuilder().put(OPERATION_ATTR,
"deletes_by_query").build());
}
private void deleteAll() throws IOException {
diff --git
a/solr/core/src/test-files/solr/configsets/cloud-aggregate-node-metrics/conf/solrconfig.xml
b/solr/core/src/test-files/solr/configsets/cloud-aggregate-node-metrics/conf/solrconfig.xml
index f23456d060a..2b1586ae253 100644
---
a/solr/core/src/test-files/solr/configsets/cloud-aggregate-node-metrics/conf/solrconfig.xml
+++
b/solr/core/src/test-files/solr/configsets/cloud-aggregate-node-metrics/conf/solrconfig.xml
@@ -29,7 +29,7 @@
<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
- <updateHandler class="solr.DirectUpdateHandler2">
+ <updateHandler class="solr.DirectUpdateHandler2"
aggregateNodeLevelMetricsEnabled="true">
<commitWithin>
<softCommit>${solr.commitwithin.softcommit:true}</softCommit>
</commitWithin>
@@ -52,4 +52,4 @@
<indexConfig>
<mergeScheduler
class="${solr.mscheduler:org.apache.lucene.index.ConcurrentMergeScheduler}"/>
</indexConfig>
-</config>
\ No newline at end of file
+</config>
diff --git
a/solr/core/src/test/org/apache/solr/handler/RequestHandlerBaseTest.java
b/solr/core/src/test/org/apache/solr/handler/RequestHandlerBaseTest.java
index 74d3d6b2510..2320b526b08 100644
--- a/solr/core/src/test/org/apache/solr/handler/RequestHandlerBaseTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/RequestHandlerBaseTest.java
@@ -17,6 +17,7 @@
package org.apache.solr.handler;
+import static org.apache.solr.metrics.SolrMetricProducer.HANDLER_ATTR;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
@@ -196,6 +197,6 @@ public class RequestHandlerBaseTest extends SolrTestCaseJ4 {
when(metricsContext.longHistogram(any(),
any())).thenReturn(mockLongHistogram);
return new RequestHandlerBase.HandlerMetrics(
- metricsContext, Attributes.of(AttributeKey.stringKey("/handler"),
"/someBaseMetricPath"));
+ metricsContext, Attributes.of(HANDLER_ATTR, "/someBaseMetricPath"),
false);
}
}
diff --git
a/solr/core/src/test/org/apache/solr/handler/RequestHandlerMetricsTest.java
b/solr/core/src/test/org/apache/solr/handler/RequestHandlerMetricsTest.java
index e9618297760..e338939b30c 100644
--- a/solr/core/src/test/org/apache/solr/handler/RequestHandlerMetricsTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/RequestHandlerMetricsTest.java
@@ -16,19 +16,17 @@
*/
package org.apache.solr.handler;
+import io.prometheus.metrics.model.snapshots.CounterSnapshot;
+import io.prometheus.metrics.model.snapshots.Labels;
import java.io.IOException;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
import org.apache.solr.client.solrj.SolrQuery;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.SolrInputDocument;
-import org.apache.solr.common.util.NamedList;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.util.SolrMetricTestUtils;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -54,10 +52,7 @@ public class RequestHandlerMetricsTest extends
SolrCloudTestCase {
System.clearProperty("metricsEnabled");
}
- // TODO: Migrate aggregateNodeLevelMetricsEnabled for OTEL metrics
@Test
- @AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/SOLR-17865")
- @SuppressWarnings({"unchecked"})
public void testAggregateNodeLevelMetrics() throws SolrServerException,
IOException {
String collection1 = "testRequestHandlerMetrics1";
String collection2 = "testRequestHandlerMetrics2";
@@ -82,97 +77,83 @@ public class RequestHandlerMetricsTest extends
SolrCloudTestCase {
cloudClient.query(collection1, solrQuery);
cloudClient.query(collection2, solrQuery);
- NamedList<Object> response =
- cloudClient.request(
- new GenericSolrRequest(
- SolrRequest.METHOD.GET, "/admin/metrics",
SolrRequest.SolrRequestType.ADMIN));
-
- NamedList<Object> metrics = (NamedList<Object>) response.get("metrics");
-
- final double[] minQueryTime = {Double.MAX_VALUE};
- final double[] maxQueryTime = {-1.0};
- final double[] minUpdateTime = {Double.MAX_VALUE};
- final double[] maxUpdateTime = {-1.0};
- Set<NamedList<Object>> coreMetrics = new HashSet<>();
- metrics.forEach(
- (key, coreMetric) -> {
- if (key.startsWith("solr.core.testRequestHandlerMetrics")) {
- coreMetrics.add((NamedList<Object>) coreMetric);
- }
- });
- assertEquals(2, coreMetrics.size());
- coreMetrics.forEach(
- metric -> {
- assertEquals(
- 1L,
- ((Map<String, Number>) metric.get("QUERY./select.requestTimes"))
- .get("count")
- .longValue());
- minQueryTime[0] =
- Math.min(
- minQueryTime[0],
- ((Map<String, Number>)
metric.get("QUERY./select.requestTimes"))
- .get("min_ms")
- .doubleValue());
- maxQueryTime[0] =
- Math.max(
- maxQueryTime[0],
- ((Map<String, Number>)
metric.get("QUERY./select.requestTimes"))
- .get("max_ms")
- .doubleValue());
- assertEquals(
- 1L,
- ((Map<String, Number>) metric.get("UPDATE./update.requestTimes"))
- .get("count")
- .longValue());
- minUpdateTime[0] =
- Math.min(
- minUpdateTime[0],
- ((Map<String, Number>)
metric.get("UPDATE./update.requestTimes"))
- .get("min_ms")
- .doubleValue());
- maxUpdateTime[0] =
- Math.max(
- maxUpdateTime[0],
- ((Map<String, Number>)
metric.get("UPDATE./update.requestTimes"))
- .get("max_ms")
- .doubleValue());
- });
-
- NamedList<Object> nodeMetrics = (NamedList<Object>)
metrics.get("solr.node");
- assertEquals(
- 2L,
- ((Map<String, Number>) nodeMetrics.get("QUERY./select.requestTimes"))
- .get("count")
- .longValue());
- assertEquals(
- minQueryTime[0],
- ((Map<String, Number>) nodeMetrics.get("QUERY./select.requestTimes"))
- .get("min_ms")
- .doubleValue(),
- 0.0);
- assertEquals(
- maxQueryTime[0],
- ((Map<String, Number>) nodeMetrics.get("QUERY./select.requestTimes"))
- .get("max_ms")
- .doubleValue(),
- 0.0);
- assertEquals(
- 2L,
- ((Map<String, Number>) nodeMetrics.get("UPDATE./update.requestTimes"))
- .get("count")
- .longValue());
- assertEquals(
- minUpdateTime[0],
- ((Map<String, Number>) nodeMetrics.get("UPDATE./update.requestTimes"))
- .get("min_ms")
- .doubleValue(),
- 0.0);
- assertEquals(
- maxUpdateTime[0],
- ((Map<String, Number>) nodeMetrics.get("UPDATE./update.requestTimes"))
- .get("max_ms")
- .doubleValue(),
- 0.0);
+ var coreContainer =
cluster.getJettySolrRunners().get(0).getCoreContainer();
+
+ try (SolrCore core1 =
coreContainer.getCore(coreContainer.getAllCoreNames().get(0));
+ SolrCore core2 =
coreContainer.getCore(coreContainer.getAllCoreNames().get(1))) {
+
+ CounterSnapshot.CounterDataPointSnapshot actualCore1Selects =
+ SolrMetricTestUtils.newCloudSelectRequestsDatapoint(core1);
+ CounterSnapshot.CounterDataPointSnapshot actualCore1Updates =
+ SolrMetricTestUtils.newCloudUpdateRequestsDatapoint(core1);
+ CounterSnapshot.CounterDataPointSnapshot actualCore2Selects =
+ SolrMetricTestUtils.newCloudSelectRequestsDatapoint(core2);
+ CounterSnapshot.CounterDataPointSnapshot actualCore2Updates =
+ SolrMetricTestUtils.newCloudUpdateRequestsDatapoint(core2);
+ CounterSnapshot.CounterDataPointSnapshot actualCore1SubmittedOps =
+ SolrMetricTestUtils.getCounterDatapoint(
+ core1,
+ "solr_core_update_submitted_ops",
+ SolrMetricTestUtils.newCloudLabelsBuilder(core1)
+ .label("category", "UPDATE")
+ .label("ops", "adds")
+ .build());
+ CounterSnapshot.CounterDataPointSnapshot actualCore2SubmittedOps =
+ SolrMetricTestUtils.getCounterDatapoint(
+ core2,
+ "solr_core_update_submitted_ops",
+ SolrMetricTestUtils.newCloudLabelsBuilder(core2)
+ .label("category", "UPDATE")
+ .label("ops", "adds")
+ .build());
+
+ assertEquals(1.0, actualCore1Selects.getValue(), 0.0);
+ assertEquals(1.0, actualCore1Updates.getValue(), 0.0);
+ assertEquals(1.0, actualCore2Updates.getValue(), 0.0);
+ assertEquals(1.0, actualCore2Selects.getValue(), 0.0);
+ assertEquals(1.0, actualCore1SubmittedOps.getValue(), 0.0);
+ assertEquals(1.0, actualCore2SubmittedOps.getValue(), 0.0);
+
+ // Get node metrics and the select/update requests should be the sum of
both cores requests
+ var nodeReader =
SolrMetricTestUtils.getPrometheusMetricReader(coreContainer, "solr.node");
+
+ CounterSnapshot.CounterDataPointSnapshot nodeSelectRequests =
+ (CounterSnapshot.CounterDataPointSnapshot)
+ SolrMetricTestUtils.getDataPointSnapshot(
+ nodeReader,
+ "solr_node_requests",
+ Labels.builder()
+ .label("category", "QUERY")
+ .label("handler", "/select")
+ .label("otel_scope_name", "org.apache.solr")
+ .build());
+ CounterSnapshot.CounterDataPointSnapshot nodeUpdateRequests =
+ (CounterSnapshot.CounterDataPointSnapshot)
+ SolrMetricTestUtils.getDataPointSnapshot(
+ nodeReader,
+ "solr_node_requests",
+ Labels.builder()
+ .label("category", "UPDATE")
+ .label("handler", "/update")
+ .label("otel_scope_name", "org.apache.solr")
+ .build());
+ CounterSnapshot.CounterDataPointSnapshot nodeSubmittedOps =
+ (CounterSnapshot.CounterDataPointSnapshot)
+ SolrMetricTestUtils.getDataPointSnapshot(
+ nodeReader,
+ "solr_node_update_submitted_ops",
+ Labels.builder()
+ .label("category", "UPDATE")
+ .label("ops", "adds")
+ .label("otel_scope_name", "org.apache.solr")
+ .build());
+
+ assertNotNull("Node select requests should be recorded",
nodeSelectRequests);
+ assertNotNull("Node update requests should be recorded",
nodeUpdateRequests);
+ assertNotNull("Node submitted update operations should be recorded",
nodeSubmittedOps);
+ assertEquals(2.0, nodeSelectRequests.getValue(), 0.0);
+ assertEquals(2.0, nodeUpdateRequests.getValue(), 0.0);
+ assertEquals(2.0, nodeSubmittedOps.getValue(), 0.0);
+ }
}
}