Skip to content

Commit ad27bcb

Browse files
committed
HBASE-26545 Implement tracing of scan
* on `AsyncTable`, both `scan` and `scanAll` methods should result in `SCAN` table operations. * the span of the `SCAN` table operation should have children representing all the RPC calls involved in servicing the scan. * when a user provides custom implementation of `AdvancedScanResultConsumer`, any spans emitted from the callback methods should also be tied to the span that represents the `SCAN` table operation. This is easily done because these callbacks are executed on the RPC thread. * when a user provides a custom implementation of `ScanResultConsumer`, any spans emitted from the callback methods are tied to the context of user application code. We could `link` them to the `SCAN` table operation, except that we have no means of passing that span along.
1 parent 85fadfd commit ad27bcb

17 files changed

Lines changed: 839 additions & 92 deletions

hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncClientScanner.java

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/*
22
* Licensed to the Apache Software Foundation (ASF) under one
33
* or more contributor license agreements. See the NOTICE file
44
* distributed with this work for additional information
@@ -27,19 +27,22 @@
2727
import static org.apache.hadoop.hbase.client.ConnectionUtils.isRemote;
2828
import static org.apache.hadoop.hbase.client.ConnectionUtils.timelineConsistentRead;
2929
import static org.apache.hadoop.hbase.util.FutureUtils.addListener;
30-
30+
import io.opentelemetry.api.trace.Span;
31+
import io.opentelemetry.context.Context;
32+
import io.opentelemetry.context.Scope;
3133
import java.io.IOException;
3234
import java.util.concurrent.CompletableFuture;
3335
import java.util.concurrent.TimeUnit;
3436
import java.util.concurrent.atomic.AtomicInteger;
37+
import java.util.function.Supplier;
3538
import org.apache.hadoop.hbase.HRegionLocation;
3639
import org.apache.hadoop.hbase.TableName;
3740
import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
41+
import org.apache.hadoop.hbase.client.trace.TableOperationSpanBuilder;
3842
import org.apache.hadoop.hbase.ipc.HBaseRpcController;
43+
import org.apache.hadoop.hbase.trace.TraceUtil;
3944
import org.apache.yetus.audience.InterfaceAudience;
40-
4145
import org.apache.hbase.thirdparty.io.netty.util.Timer;
42-
4346
import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
4447
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService;
4548
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService.Interface;
@@ -163,6 +166,7 @@ private CompletableFuture<OpenScannerResponse> callOpenScanner(HBaseRpcControlle
163166
}
164167

165168
private void startScan(OpenScannerResponse resp) {
169+
final Context context = Context.current();
166170
addListener(
167171
conn.callerFactory.scanSingleRegion().id(resp.resp.getScannerId()).location(resp.loc)
168172
.remote(resp.isRegionServerRemote)
@@ -173,14 +177,16 @@ private void startScan(OpenScannerResponse resp) {
173177
.pauseForCQTBE(pauseForCQTBENs, TimeUnit.NANOSECONDS).maxAttempts(maxAttempts)
174178
.startLogErrorsCnt(startLogErrorsCnt).start(resp.controller, resp.resp),
175179
(hasMore, error) -> {
176-
if (error != null) {
177-
consumer.onError(error);
178-
return;
179-
}
180-
if (hasMore) {
181-
openScanner();
182-
} else {
183-
consumer.onComplete();
180+
try (Scope ignored = context.makeCurrent()) {
181+
if (error != null) {
182+
consumer.onError(error);
183+
return;
184+
}
185+
if (hasMore) {
186+
openScanner();
187+
} else {
188+
consumer.onComplete();
189+
}
184190
}
185191
});
186192
}
@@ -202,18 +208,24 @@ private long getPrimaryTimeoutNs() {
202208
private void openScanner() {
203209
incRegionCountMetrics(scanMetrics);
204210
openScannerTries.set(1);
211+
final Context context = Context.current();
205212
addListener(timelineConsistentRead(conn.getLocator(), tableName, scan, scan.getStartRow(),
206213
getLocateType(scan), this::openScanner, rpcTimeoutNs, getPrimaryTimeoutNs(), retryTimer,
207214
conn.getConnectionMetrics()), (resp, error) -> {
208-
if (error != null) {
209-
consumer.onError(error);
210-
return;
215+
try (Scope ignored = context.makeCurrent()) {
216+
if (error != null) {
217+
consumer.onError(error);
218+
return;
219+
}
220+
startScan(resp);
211221
}
212-
startScan(resp);
213222
});
214223
}
215224

216225
public void start() {
217-
openScanner();
226+
final Supplier<Span> spanSupplier = new TableOperationSpanBuilder(conn)
227+
.setTableName(tableName)
228+
.setOperation(scan);
229+
TraceUtil.trace(() -> openScanner(), spanSupplier);
218230
}
219231
}

hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncScanSingleRegionRpcRetryingCaller.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static org.apache.hadoop.hbase.client.ConnectionUtils.updateResultsMetrics;
2929
import static org.apache.hadoop.hbase.client.ConnectionUtils.updateServerSideMetrics;
3030

31+
import io.opentelemetry.context.Context;
3132
import java.io.IOException;
3233
import java.util.ArrayList;
3334
import java.util.List;
@@ -572,7 +573,8 @@ private void call() {
572573
resetController(controller, callTimeoutNs, priority);
573574
ScanRequest req = RequestConverter.buildScanRequest(scannerId, scan.getCaching(), false,
574575
nextCallSeq, scan.isScanMetricsEnabled(), false, scan.getLimit());
575-
stub.scan(controller, req, resp -> onComplete(controller, resp));
576+
Context context = Context.current();
577+
stub.scan(controller, req, resp -> context.wrap(() -> onComplete(controller, resp)).run());
576578
}
577579

578580
private void next() {

hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncTableImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
package org.apache.hadoop.hbase.client;
1919

2020
import static java.util.stream.Collectors.toList;
21-
21+
import io.opentelemetry.context.Context;
2222
import java.io.IOException;
2323
import java.util.List;
2424
import java.util.concurrent.CompletableFuture;
@@ -32,7 +32,6 @@
3232
import org.apache.hadoop.hbase.io.TimeRange;
3333
import org.apache.hadoop.hbase.util.FutureUtils;
3434
import org.apache.yetus.audience.InterfaceAudience;
35-
3635
import org.apache.hbase.thirdparty.com.google.protobuf.RpcChannel;
3736

3837
/**
@@ -248,7 +247,8 @@ private void scan0(Scan scan, ScanResultConsumer consumer) {
248247

249248
@Override
250249
public void scan(Scan scan, ScanResultConsumer consumer) {
251-
pool.execute(() -> scan0(scan, consumer));
250+
final Context context = Context.current();
251+
pool.execute(context.wrap(() -> scan0(scan, consumer)));
252252
}
253253

254254
@Override

hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncTableImpl.java

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -636,30 +636,26 @@ public ResultScanner getScanner(Scan scan) {
636636

637637
@Override
638638
public CompletableFuture<List<Result>> scanAll(Scan scan) {
639-
final Supplier<Span> supplier = newTableOperationSpanBuilder()
640-
.setOperation(scan);
641-
return tracedFuture(() -> {
642-
CompletableFuture<List<Result>> future = new CompletableFuture<>();
643-
List<Result> scanResults = new ArrayList<>();
644-
scan(scan, new AdvancedScanResultConsumer() {
639+
CompletableFuture<List<Result>> future = new CompletableFuture<>();
640+
List<Result> scanResults = new ArrayList<>();
641+
scan(scan, new AdvancedScanResultConsumer() {
645642

646-
@Override
647-
public void onNext(Result[] results, ScanController controller) {
648-
scanResults.addAll(Arrays.asList(results));
649-
}
643+
@Override
644+
public void onNext(Result[] results, ScanController controller) {
645+
scanResults.addAll(Arrays.asList(results));
646+
}
650647

651-
@Override
652-
public void onError(Throwable error) {
653-
future.completeExceptionally(error);
654-
}
648+
@Override
649+
public void onError(Throwable error) {
650+
future.completeExceptionally(error);
651+
}
655652

656-
@Override
657-
public void onComplete() {
658-
future.complete(scanResults);
659-
}
660-
});
661-
return future;
662-
}, supplier);
653+
@Override
654+
public void onComplete() {
655+
future.complete(scanResults);
656+
}
657+
});
658+
return future;
663659
}
664660

665661
@Override

hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestAsyncTableTracing.java

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import static org.hamcrest.MatcherAssert.assertThat;
2929
import static org.hamcrest.Matchers.allOf;
3030
import static org.hamcrest.Matchers.containsString;
31+
import static org.hamcrest.Matchers.greaterThan;
32+
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
3133
import static org.hamcrest.Matchers.hasItem;
3234
import static org.hamcrest.Matchers.hasSize;
3335
import static org.junit.Assert.fail;
@@ -44,9 +46,11 @@
4446
import java.util.Arrays;
4547
import java.util.List;
4648
import java.util.concurrent.CompletableFuture;
49+
import java.util.concurrent.CountDownLatch;
4750
import java.util.concurrent.ForkJoinPool;
4851
import java.util.concurrent.atomic.AtomicInteger;
4952
import java.util.stream.Collectors;
53+
import java.util.concurrent.atomic.AtomicReference;
5054
import org.apache.hadoop.conf.Configuration;
5155
import org.apache.hadoop.hbase.Cell;
5256
import org.apache.hadoop.hbase.Cell.Type;
@@ -76,6 +80,8 @@
7680
import org.junit.experimental.categories.Category;
7781
import org.mockito.invocation.InvocationOnMock;
7882
import org.mockito.stubbing.Answer;
83+
import org.slf4j.Logger;
84+
import org.slf4j.LoggerFactory;
7985
import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
8086
import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
8187
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
@@ -95,6 +101,7 @@
95101

96102
@Category({ ClientTests.class, MediumTests.class })
97103
public class TestAsyncTableTracing {
104+
private static final Logger logger = LoggerFactory.getLogger(TestAsyncTableTracing.class);
98105

99106
@ClassRule
100107
public static final HBaseClassTestRule CLASS_RULE =
@@ -106,7 +113,7 @@ public class TestAsyncTableTracing {
106113

107114
private AsyncConnectionImpl conn;
108115

109-
private AsyncTable<?> table;
116+
private AsyncTable<ScanResultConsumer> table;
110117

111118
@Rule
112119
public OpenTelemetryRule traceRule = OpenTelemetryRule.create();
@@ -452,6 +459,53 @@ public void testScanAll() {
452459
assertTrace("SCAN");
453460
}
454461

462+
@Test
463+
public void testScan() throws Throwable {
464+
final CountDownLatch doneSignal = new CountDownLatch(1);
465+
final AtomicInteger count = new AtomicInteger();
466+
final AtomicReference<Throwable> throwable = new AtomicReference<>();
467+
final Scan scan = new Scan().setCaching(1).setMaxResultSize(1).setLimit(1);
468+
table.scan(scan, new ScanResultConsumer() {
469+
@Override public boolean onNext(Result result) {
470+
if (result.getRow() != null) {
471+
count.incrementAndGet();
472+
}
473+
return true;
474+
}
475+
476+
@Override public void onError(Throwable error) {
477+
throwable.set(error);
478+
doneSignal.countDown();
479+
}
480+
481+
@Override public void onComplete() {
482+
doneSignal.countDown();
483+
}
484+
});
485+
doneSignal.await();
486+
if (throwable.get() != null) {
487+
throw throwable.get();
488+
}
489+
assertThat("user code did not run. check test setup.", count.get(), greaterThan(0));
490+
assertTrace("SCAN");
491+
}
492+
493+
@Test
494+
public void testGetScanner() {
495+
final Scan scan = new Scan().setCaching(1).setMaxResultSize(1).setLimit(1);
496+
try (ResultScanner scanner = table.getScanner(scan)) {
497+
int count = 0;
498+
for (Result result : scanner) {
499+
if (result.getRow() != null) {
500+
count++;
501+
}
502+
}
503+
// do something with it.
504+
assertThat(count, greaterThanOrEqualTo(0));
505+
}
506+
assertTrace("SCAN");
507+
}
508+
455509
@Test
456510
public void testExistsList() {
457511
CompletableFuture

0 commit comments

Comments
 (0)