This is an automated email from the ASF dual-hosted git repository.
adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new d499272132c HDDS-14814. Unify fragmented traces for Freon randomkeys
command (#9957)
d499272132c is described below
commit d499272132c1e3eaaca974c836abf80bf8c10ac8
Author: sravani <[email protected]>
AuthorDate: Thu Mar 26 11:57:23 2026 +0530
HDDS-14814. Unify fragmented traces for Freon randomkeys command (#9957)
---
.../apache/hadoop/hdds/tracing/LoopSampler.java | 46 +++++++
.../apache/hadoop/hdds/tracing/SpanSampler.java | 90 +++++++++++++
.../apache/hadoop/hdds/tracing/TracingUtil.java | 76 ++++++++++-
.../hadoop/hdds/tracing/TestSpanSampling.java | 144 +++++++++++++++++++++
hadoop-ozone/freon/pom.xml | 4 +
.../java/org/apache/hadoop/ozone/freon/Freon.java | 3 +-
.../hadoop/ozone/freon/RandomKeyGenerator.java | 34 +++--
7 files changed, 383 insertions(+), 14 deletions(-)
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/LoopSampler.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/LoopSampler.java
new file mode 100644
index 00000000000..d7a044d2a4f
--- /dev/null
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/LoopSampler.java
@@ -0,0 +1,46 @@
+/*
+ * 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.hadoop.hdds.tracing;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * Probability-based span sampler that samples spans independently.
+ * Uses ThreadLocalRandom for probability decisions.
+ */
+public final class LoopSampler {
+ private final double probability;
+
+ public LoopSampler(double ratio) {
+ if (ratio < 0) {
+ throw new IllegalArgumentException("Sampling ratio cannot be negative: "
+ ratio);
+ }
+ // Cap at 1.0 to prevent logic errors
+ this.probability = Math.min(ratio, 1.0);
+ }
+
+ public boolean shouldSample() {
+ if (probability <= 0) {
+ return false;
+ }
+ if (probability >= 1.0) {
+ return true;
+ }
+ return ThreadLocalRandom.current().nextDouble() < probability;
+ }
+}
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/SpanSampler.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/SpanSampler.java
new file mode 100644
index 00000000000..317573a5e19
--- /dev/null
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/SpanSampler.java
@@ -0,0 +1,90 @@
+/*
+ * 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.hadoop.hdds.tracing;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.sdk.trace.data.LinkData;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import io.opentelemetry.sdk.trace.samplers.SamplingResult;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Custom Sampler that applies span-level sampling for configured
+ * span names, and delegates to parent-based strategy otherwise.
+ * When a span name is in the configured spanMap, uses LoopSampler for
+ * probabilistic sampling, otherwise follows the parent span's
+ * sampling decision.
+ */
+public final class SpanSampler implements Sampler {
+
+ private final Sampler rootSampler;
+ private final Map<String, LoopSampler> spanMap;
+
+ public SpanSampler(Sampler rootSampler,
+ Map<String, LoopSampler> spanMap) {
+ this.rootSampler = rootSampler;
+ this.spanMap = spanMap;
+ }
+
+ @Override
+ public SamplingResult shouldSample(
+ Context parentContext,
+ String traceId,
+ String spanName,
+ SpanKind spanKind,
+ Attributes attributes,
+ List<LinkData> parentLinks) {
+
+ Span parentSpan = Span.fromContext(parentContext);
+
+ // check if we have a valid parent span
+ if (!parentSpan.getSpanContext().isValid()) {
+ // Root span: always delegate to trace-level sampler
+ // This ensures OTEL_TRACES_SAMPLER_ARG is respected
+ return rootSampler.shouldSample(parentContext, traceId, spanName,
+ spanKind, attributes, parentLinks);
+ }
+
+ // Child span: check parent's sampling status first
+ // after the process of sampling trace / parent span then check if it is
sampled or not.
+ if (!parentSpan.getSpanContext().isSampled()) {
+ // Parent was not sampled, so this child should not be sampled either
+ // This prevents orphaned spans
+ return SamplingResult.drop();
+ }
+
+ // Parent was sampled, now check if this span has explicit sampling config
+ LoopSampler loopSampler = spanMap.get(spanName);
+ if (loopSampler != null) {
+ boolean sample = loopSampler.shouldSample();
+ return sample ? SamplingResult.recordAndSample() : SamplingResult.drop();
+ }
+
+ // No explicit config for this span, follow parent's sampling decision
+ return SamplingResult.recordAndSample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "SpanSampler(spanMap=" + spanMap.keySet() + ")";
+ }
+}
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java
index 8d6e0fd240f..0f8aa4561f1 100644
---
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/tracing/TracingUtil.java
@@ -33,6 +33,7 @@
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.lang.reflect.Proxy;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
@@ -52,6 +53,8 @@ public final class TracingUtil {
private static final String OTEL_EXPORTER_OTLP_ENDPOINT_DEFAULT =
"http://localhost:4317";
private static final String OTEL_TRACES_SAMPLER_ARG =
"OTEL_TRACES_SAMPLER_ARG";
private static final double OTEL_TRACES_SAMPLER_RATIO_DEFAULT = 1.0;
+ private static final String OTEL_SPAN_SAMPLING_ARG =
"OTEL_SPAN_SAMPLING_ARG";
+ private static final String OTEL_TRACES_SAMPLER_CONFIG_DEFAULT = "";
private static volatile boolean isInit = false;
private static Tracer tracer = OpenTelemetry.noop().getTracer("noop");
@@ -88,21 +91,50 @@ private static void initialize(String serviceName) {
String sampleStrRatio = System.getenv(OTEL_TRACES_SAMPLER_ARG);
if (sampleStrRatio != null && !sampleStrRatio.isEmpty()) {
samplerRatio =
Double.parseDouble(System.getenv(OTEL_TRACES_SAMPLER_ARG));
+ LOG.info("Sampling Trace Config = '{}'", samplerRatio);
}
} catch (NumberFormatException ex) {
- // ignore and use the default value.
+ // log and use the default value.
+ LOG.warn("Invalid value for {}: '{}'. Falling back to default: {}",
+ OTEL_TRACES_SAMPLER_ARG, System.getenv(OTEL_TRACES_SAMPLER_ARG),
OTEL_TRACES_SAMPLER_RATIO_DEFAULT, ex);
}
+ String spanSamplingConfig = OTEL_TRACES_SAMPLER_CONFIG_DEFAULT;
+ try {
+ String spanStrConfig = System.getenv(OTEL_SPAN_SAMPLING_ARG);
+ if (spanStrConfig != null && !spanStrConfig.isEmpty()) {
+ spanSamplingConfig = spanStrConfig;
+ }
+ LOG.info("Sampling Span Config = '{}'", spanSamplingConfig);
+ } catch (Exception ex) {
+ // Log and use the default value.
+ LOG.warn("Failed to process {}. Falling back to default configuration:
{}",
+ OTEL_SPAN_SAMPLING_ARG, OTEL_TRACES_SAMPLER_CONFIG_DEFAULT, ex);
+ }
+ // Pass the config to parseSpanSamplingConfig to get spans to be sampled.
+ Map<String, LoopSampler> spanMap =
parseSpanSamplingConfig(spanSamplingConfig);
+
Resource resource =
Resource.create(Attributes.of(AttributeKey.stringKey("service.name"),
serviceName));
OtlpGrpcSpanExporter spanExporter = OtlpGrpcSpanExporter.builder()
.setEndpoint(otelEndPoint)
.build();
SimpleSpanProcessor spanProcessor =
SimpleSpanProcessor.builder(spanExporter).build();
+
+ // Choose sampler based on span sampling config. If it is empty use trace
based sampling only.
+ // else use custom SpanSampler.
+ Sampler sampler;
+ if (spanMap.isEmpty()) {
+ sampler = Sampler.traceIdRatioBased(samplerRatio);
+ } else {
+ Sampler rootSampler = Sampler.traceIdRatioBased(samplerRatio);
+ sampler = new SpanSampler(rootSampler, spanMap);
+ }
+
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(spanProcessor)
.setResource(resource)
- .setSampler(Sampler.traceIdRatioBased(samplerRatio))
+ .setSampler(sampler)
.build();
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
@@ -133,7 +165,6 @@ public static String exportCurrentSpan() {
*
* @param name name of the newly created scope
* @param encodedParent Encoded parent span (could be null or empty)
- *
* @return Tracing scope.
*/
public static Span importAndCreateSpan(String name, String encodedParent) {
@@ -177,6 +208,44 @@ public static boolean isTracingEnabled(
ScmConfigKeys.HDDS_TRACING_ENABLED_DEFAULT);
}
+ /**
+ * Function to parse span sampling config. The input is in the form
<span_name>:<sample_rate>.
+ * The sample rate must be a number between 0 and 1. Any value other than
that will LOG an error.
+ */
+ static Map<String, LoopSampler> parseSpanSamplingConfig(String configStr) {
+ Map<String, LoopSampler> result = new HashMap<>();
+ if (configStr == null || configStr.isEmpty()) {
+ return Collections.emptyMap();
+ }
+
+ for (String entry : configStr.split(",")) {
+ String trimmed = entry.trim();
+ int colon = trimmed.indexOf(':');
+
+ if (colon <= 0 || colon >= trimmed.length() - 1) {
+ continue;
+ }
+
+ String name = trimmed.substring(0, colon).trim();
+ String val = trimmed.substring(colon + 1).trim();
+
+ try {
+ double rate = Double.parseDouble(val);
+ //if the rate is less than or equal to zero , no sampling config is
taken for that key value pair.
+ if (rate > 0) {
+ // cap it at 1.0 when a number greater than 1 is entered
+ double effectiveRate = Math.min(rate, 1.0);
+ result.put(name, new LoopSampler(effectiveRate));
+ } else {
+ LOG.warn("rate for span '{}' is 0 or less, ignoring sample
configuration", name);
+ }
+ } catch (NumberFormatException e) {
+ LOG.error("Invalid rate '{}' for span '{}', ignoring sample
configuration", val, name);
+ }
+ }
+ return result;
+ }
+
/**
* Execute {@code runnable} inside an activated new span.
* If a parent span exists in the current context, this becomes a child span.
@@ -198,6 +267,7 @@ public static <R, E extends Exception> R
executeInNewSpan(String spanName,
/**
* Execute {@code supplier} in the given {@code span}.
+ *
* @return the value returned by {@code supplier}
*/
private static <R, E extends Exception> R executeInSpan(Span span,
diff --git
a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestSpanSampling.java
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestSpanSampling.java
new file mode 100644
index 00000000000..f46eb2855bb
--- /dev/null
+++
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/tracing/TestSpanSampling.java
@@ -0,0 +1,144 @@
+/*
+ * 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.hadoop.hdds.tracing;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.api.trace.TraceFlags;
+import io.opentelemetry.api.trace.TraceState;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import io.opentelemetry.sdk.trace.samplers.SamplingDecision;
+import io.opentelemetry.sdk.trace.samplers.SamplingResult;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test cases for span sampling functionality.
+ */
+public class TestSpanSampling {
+
+ /**
+ * Tests that valid configuration strings result in a Map
+ * containing the correct LoopSampler objects.
+ */
+ @Test
+ public void testParseSpanSamplingConfigValid() throws Exception {
+ String config = "createVolume:0.25,createBucket:0.5,createKey:0.75";
+ Map<String, LoopSampler> result =
TracingUtil.parseSpanSamplingConfig(config);
+
+ assertThat(result)
+ .hasSize(3)
+ .containsKeys("createVolume", "createBucket", "createKey");
+
+ }
+
+ /**
+ * Tests that invalid entries (zeros, negative numbers, non-numeric) are
caught
+ * by the try-catch blocks and excluded from the resulting Map.
+ */
+ @Test
+ public void testParseSpanSamplingConfigInvalid() throws Exception {
+ String config =
"createVolume:0,createBucket:-0.5,createKey:invalid,writeKey:-1";
+ Map<String, LoopSampler> result =
TracingUtil.parseSpanSamplingConfig(config);
+
+ assertThat(result).as("The map should be empty as all inputs were
invalid").isEmpty();
+ }
+
+ /**
+ * Tests a mixed configuration to ensure valid entries are
+ * preserved while invalid ones are skipped.
+ */
+ @Test
+ public void testParseSpanSamplingConfigMixed() throws Exception {
+ String config = "createVolume:0.75,createBucket:0,createKey:-5";
+ Map<String, LoopSampler> result =
TracingUtil.parseSpanSamplingConfig(config);
+
+ assertThat(result)
+ .hasSize(1)
+ .containsKey("createVolume")
+ .doesNotContainKeys("createBucket", "createKey");
+ }
+
+ /**
+ * Test to show sampling of span only if trace is sampled.
+ * Trace is always sampled and span name is not mentioned in config, Hence
it will be sampled.
+ */
+ @Test
+ public void testSpanSamplingWithTraceSampled() {
+ Map<String, LoopSampler> spanMap = new HashMap<>();
+ spanMap.put("createKey", new LoopSampler(0.5));
+
+ Sampler rootSampler = Sampler.alwaysOn();
+ SpanSampler customSampler = new SpanSampler(rootSampler, spanMap);
+ Context parentContext = Context.current();
+ SamplingResult result = customSampler.shouldSample(parentContext,
"trace1", "unknownSpan",
+ SpanKind.INTERNAL, Attributes.empty(), Collections.emptyList());
+
+ // Since no parent and not configured, should use root sampler and sample
span.
+ assertEquals(SamplingDecision.RECORD_AND_SAMPLE, result.getDecision());
+ }
+
+ /**
+ * Test to show dropping of span only if trace is not sample sampled.
+ * This shows priority given to Trace.
+ * */
+ @Test
+ public void testSpanSamplingWithTraceNotSampled() {
+ Map<String, LoopSampler> spanMap = new HashMap<>();
+ Sampler rootSampler = Sampler.alwaysOff();
+ SpanSampler customSampler = new SpanSampler(rootSampler, spanMap);
+ Context parentContext = Context.current();
+
+ SamplingResult result = customSampler.shouldSample(parentContext,
"trace1", "rootSpan",
+ SpanKind.INTERNAL, Attributes.empty(), Collections.emptyList());
+
+ // Root span with alwaysOff should not be sampled.
+ assertEquals(SamplingDecision.DROP, result.getDecision());
+ }
+
+ /**
+ * Test to show child span is not sampled when parent span is also not
sampled.
+ */
+ @Test
+ public void testChildDropsWhenParentIsNotSampled() {
+ Map<String, LoopSampler> spanMap = new HashMap<>();
+ spanMap.put("createKey", new LoopSampler(1.0));
+
+ SpanSampler customSampler = new SpanSampler(Sampler.alwaysOn(), spanMap);
+
+ io.opentelemetry.api.trace.Span parentSpan =
io.opentelemetry.api.trace.Span.wrap(
+ io.opentelemetry.api.trace.SpanContext.create(
+ "ff000000000000000000000000000041",
+ "ff00000000000042",
+ TraceFlags.getDefault(),
+ TraceState.getDefault()));
+
+ Context parentContext = Context.root().with(parentSpan);
+
+ SamplingResult result = customSampler.shouldSample(parentContext,
"trace1", "createKey",
+ SpanKind.INTERNAL, Attributes.empty(), Collections.emptyList());
+
+ assertEquals(SamplingDecision.DROP, result.getDecision());
+ }
+}
diff --git a/hadoop-ozone/freon/pom.xml b/hadoop-ozone/freon/pom.xml
index 71a9b1c1165..08bbdcd3eac 100644
--- a/hadoop-ozone/freon/pom.xml
+++ b/hadoop-ozone/freon/pom.xml
@@ -70,6 +70,10 @@
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-context</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
diff --git
a/hadoop-ozone/freon/src/main/java/org/apache/hadoop/ozone/freon/Freon.java
b/hadoop-ozone/freon/src/main/java/org/apache/hadoop/ozone/freon/Freon.java
index b2ed1eb8069..c6e21cf7a95 100644
--- a/hadoop-ozone/freon/src/main/java/org/apache/hadoop/ozone/freon/Freon.java
+++ b/hadoop-ozone/freon/src/main/java/org/apache/hadoop/ozone/freon/Freon.java
@@ -58,7 +58,8 @@ public int execute(String[] argv) {
conf = getOzoneConf();
HddsServerUtil.initializeMetrics(conf, "ozone-freon");
TracingUtil.initTracing("freon", conf);
- return super.execute(argv);
+ String spanName = "ozone freon " + String.join(" ", argv);
+ return TracingUtil.executeInNewSpan(spanName, () -> super.execute(argv));
}
@Override
diff --git
a/hadoop-ozone/freon/src/main/java/org/apache/hadoop/ozone/freon/RandomKeyGenerator.java
b/hadoop-ozone/freon/src/main/java/org/apache/hadoop/ozone/freon/RandomKeyGenerator.java
index 87ebf95f0b0..5fe14774159 100644
---
a/hadoop-ozone/freon/src/main/java/org/apache/hadoop/ozone/freon/RandomKeyGenerator.java
+++
b/hadoop-ozone/freon/src/main/java/org/apache/hadoop/ozone/freon/RandomKeyGenerator.java
@@ -27,6 +27,8 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.google.common.annotations.VisibleForTesting;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.context.Scope;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
@@ -311,8 +313,8 @@ public Void call() throws Exception {
if (validateWrites) {
commonInitialMD = DigestUtils.getDigest(DIGEST_ALGORITHM);
for (long nrRemaining = keySize.toBytes(); nrRemaining > 0;
- nrRemaining -= bufferSize) {
- int curSize = (int)Math.min(bufferSize, nrRemaining);
+ nrRemaining -= bufferSize) {
+ int curSize = (int) Math.min(bufferSize, nrRemaining);
commonInitialMD.update(keyValueBuffer, 0, curSize);
}
}
@@ -333,8 +335,10 @@ public Void call() throws Exception {
LOG.info("validateWrites : {}", validateWrites);
LOG.info("Number of Validate Threads: {}", numOfValidateThreads);
LOG.info("cleanObjects : {}", cleanObjects);
+
+ Span currentSpan = TracingUtil.getActiveSpan();
for (int i = 0; i < numOfThreads; i++) {
- executor.execute(new ObjectCreator());
+ executor.execute(new ObjectCreator(currentSpan));
}
ExecutorService validateExecutor = null;
@@ -360,7 +364,7 @@ public Void call() throws Exception {
// wait until all keys are added or exception occurred.
while ((numberOfKeysAdded.get() != totalKeyCount)
- && exception == null) {
+ && exception == null) {
Thread.sleep(CHECK_INTERVAL_MILLIS);
}
executor.shutdown();
@@ -689,9 +693,9 @@ private static class KeyValidate {
/**
* Constructs a new ozone keyValidate.
*
- * @param bucket bucket part
- * @param keyName key part
- * @param digest digest of this key's full value
+ * @param bucket bucket part
+ * @param keyName key part
+ * @param digest digest of this key's full value
*/
KeyValidate(OzoneBucket bucket, String keyName, byte[] digest) {
this.bucket = bucket;
@@ -701,22 +705,32 @@ private static class KeyValidate {
}
private class ObjectCreator implements Runnable {
+ private final Span parentSpan;
+
+ ObjectCreator(Span parentSpan) {
+ this.parentSpan = parentSpan;
+ }
+
@Override
public void run() {
+ try (Scope scope = parentSpan.makeCurrent()) {
+ createObjects();
+ }
+ }
+
+ private void createObjects() {
int v;
while ((v = volumeCounter.getAndIncrement()) < numOfVolumes) {
if (!createVolume(v)) {
return;
}
}
-
int b;
while ((b = bucketCounter.getAndIncrement()) < totalBucketCount) {
if (!createBucket(b)) {
return;
}
}
-
long k;
while ((k = keyCounter.getAndIncrement()) < totalKeyCount) {
if (!createKey(k)) {
@@ -919,7 +933,7 @@ OzoneBucket getBucket(Integer bucketNumber) {
* threads).
*
* @return may return null if this thread is interrupted, or if any other
- * thread encounters an exception (and stores it to {@code exception})
+ * thread encounters an exception (and stores it to {@code exception})
*/
private <T> T waitUntilAddedToMap(Map<Integer, T> map, Integer i) {
while (exception == null && !map.containsKey(i)) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]