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 should be also be tied to the span that represents the `SCAN` table operation. This accomplished by carefully passing the span instance around after it is created. Signed-off-by: Andrew Purtell <apurtell@apache.org> Signed-off-by: Duo Zhang <zhangduo@apache.org>
This commit is contained in:
parent
69ea6f579f
commit
235308d8bf
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -28,6 +28,9 @@ import static org.apache.hadoop.hbase.client.ConnectionUtils.isRemote;
|
|||
import static org.apache.hadoop.hbase.client.ConnectionUtils.timelineConsistentRead;
|
||||
import static org.apache.hadoop.hbase.util.FutureUtils.addListener;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -35,7 +38,9 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import org.apache.hadoop.hbase.HRegionLocation;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
|
||||
import org.apache.hadoop.hbase.client.trace.TableOperationSpanBuilder;
|
||||
import org.apache.hadoop.hbase.ipc.HBaseRpcController;
|
||||
import org.apache.hadoop.hbase.trace.TraceUtil;
|
||||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
|
||||
import org.apache.hbase.thirdparty.io.netty.util.Timer;
|
||||
|
@ -85,6 +90,8 @@ class AsyncClientScanner {
|
|||
|
||||
private final ScanResultCache resultCache;
|
||||
|
||||
private final Span span;
|
||||
|
||||
public AsyncClientScanner(Scan scan, AdvancedScanResultConsumer consumer, TableName tableName,
|
||||
AsyncConnectionImpl conn, Timer retryTimer, long pauseNs, long pauseForCQTBENs,
|
||||
int maxAttempts, long scanTimeoutNs, long rpcTimeoutNs, int startLogErrorsCnt) {
|
||||
|
@ -112,6 +119,18 @@ class AsyncClientScanner {
|
|||
} else {
|
||||
this.scanMetrics = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assumes that the `start()` method is called immediately after construction. If this is no
|
||||
* longer the case, for tracing correctness, we should move the start of the span into the
|
||||
* `start()` method. The cost of doing so would be making access to the `span` safe for
|
||||
* concurrent threads.
|
||||
*/
|
||||
span = new TableOperationSpanBuilder(conn).setTableName(tableName).setOperation(scan).build();
|
||||
if (consumer instanceof AsyncTableResultScanner) {
|
||||
AsyncTableResultScanner scanner = (AsyncTableResultScanner) consumer;
|
||||
scanner.setSpan(span);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class OpenScannerResponse {
|
||||
|
@ -140,6 +159,7 @@ class AsyncClientScanner {
|
|||
|
||||
private CompletableFuture<OpenScannerResponse> callOpenScanner(HBaseRpcController controller,
|
||||
HRegionLocation loc, ClientService.Interface stub) {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
boolean isRegionServerRemote = isRemote(loc.getHostname());
|
||||
incRPCCallsMetrics(scanMetrics, isRegionServerRemote);
|
||||
if (openScannerTries.getAndIncrement() > 1) {
|
||||
|
@ -147,20 +167,28 @@ class AsyncClientScanner {
|
|||
}
|
||||
CompletableFuture<OpenScannerResponse> future = new CompletableFuture<>();
|
||||
try {
|
||||
ScanRequest request = RequestConverter.buildScanRequest(loc.getRegion().getRegionName(), scan,
|
||||
scan.getCaching(), false);
|
||||
ScanRequest request = RequestConverter.buildScanRequest(loc.getRegion().getRegionName(),
|
||||
scan, scan.getCaching(), false);
|
||||
stub.scan(controller, request, resp -> {
|
||||
try (Scope ignored1 = span.makeCurrent()) {
|
||||
if (controller.failed()) {
|
||||
future.completeExceptionally(controller.getFailed());
|
||||
final IOException e = controller.getFailed();
|
||||
future.completeExceptionally(e);
|
||||
TraceUtil.setError(span, e);
|
||||
span.end();
|
||||
return;
|
||||
}
|
||||
future.complete(new OpenScannerResponse(loc, isRegionServerRemote, stub, controller, resp));
|
||||
future.complete(
|
||||
new OpenScannerResponse(loc, isRegionServerRemote, stub, controller, resp));
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
// span is closed by listener attached to the Future in `openScanner()`
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
private void startScan(OpenScannerResponse resp) {
|
||||
addListener(
|
||||
|
@ -173,26 +201,40 @@ class AsyncClientScanner {
|
|||
.pauseForCQTBE(pauseForCQTBENs, TimeUnit.NANOSECONDS).maxAttempts(maxAttempts)
|
||||
.startLogErrorsCnt(startLogErrorsCnt).start(resp.controller, resp.resp),
|
||||
(hasMore, error) -> {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
if (error != null) {
|
||||
try {
|
||||
consumer.onError(error);
|
||||
return;
|
||||
} finally {
|
||||
TraceUtil.setError(span, error);
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
if (hasMore) {
|
||||
openScanner();
|
||||
} else {
|
||||
try {
|
||||
consumer.onComplete();
|
||||
} finally {
|
||||
span.setStatus(StatusCode.OK);
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<OpenScannerResponse> openScanner(int replicaId) {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
return conn.callerFactory.<OpenScannerResponse> single().table(tableName)
|
||||
.row(scan.getStartRow()).replicaId(replicaId).locateType(getLocateType(scan))
|
||||
.priority(scan.getPriority())
|
||||
.rpcTimeout(rpcTimeoutNs, TimeUnit.NANOSECONDS)
|
||||
.operationTimeout(scanTimeoutNs, TimeUnit.NANOSECONDS).pause(pauseNs, TimeUnit.NANOSECONDS)
|
||||
.pauseForCQTBE(pauseForCQTBENs, TimeUnit.NANOSECONDS).maxAttempts(maxAttempts)
|
||||
.startLogErrorsCnt(startLogErrorsCnt).action(this::callOpenScanner).call();
|
||||
.priority(scan.getPriority()).rpcTimeout(rpcTimeoutNs, TimeUnit.NANOSECONDS)
|
||||
.operationTimeout(scanTimeoutNs, TimeUnit.NANOSECONDS)
|
||||
.pause(pauseNs, TimeUnit.NANOSECONDS).pauseForCQTBE(pauseForCQTBENs, TimeUnit.NANOSECONDS)
|
||||
.maxAttempts(maxAttempts).startLogErrorsCnt(startLogErrorsCnt)
|
||||
.action(this::callOpenScanner).call();
|
||||
}
|
||||
}
|
||||
|
||||
private long getPrimaryTimeoutNs() {
|
||||
|
@ -206,15 +248,24 @@ class AsyncClientScanner {
|
|||
addListener(timelineConsistentRead(conn.getLocator(), tableName, scan, scan.getStartRow(),
|
||||
getLocateType(scan), this::openScanner, rpcTimeoutNs, getPrimaryTimeoutNs(), retryTimer,
|
||||
conn.getConnectionMetrics()), (resp, error) -> {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
if (error != null) {
|
||||
try {
|
||||
consumer.onError(error);
|
||||
return;
|
||||
} finally {
|
||||
TraceUtil.setError(span, error);
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
startScan(resp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void start() {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
openScanner();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -28,6 +28,8 @@ import static org.apache.hadoop.hbase.client.ConnectionUtils.translateException;
|
|||
import static org.apache.hadoop.hbase.client.ConnectionUtils.updateResultsMetrics;
|
||||
import static org.apache.hadoop.hbase.client.ConnectionUtils.updateServerSideMetrics;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -170,8 +172,8 @@ class AsyncScanSingleRegionRpcRetryingCaller {
|
|||
|
||||
private void preCheck() {
|
||||
Preconditions.checkState(Thread.currentThread() == callerThread,
|
||||
"The current thread is %s, expected thread is %s, " +
|
||||
"you should not call this method outside onNext or onHeartbeat",
|
||||
"The current thread is %s, expected thread is %s, "
|
||||
+ "you should not call this method outside onNext or onHeartbeat",
|
||||
Thread.currentThread(), callerThread);
|
||||
Preconditions.checkState(state.equals(ScanControllerState.INITIALIZED),
|
||||
"Invalid Stopper state %s", state);
|
||||
|
@ -352,9 +354,9 @@ class AsyncScanSingleRegionRpcRetryingCaller {
|
|||
ScanRequest req = RequestConverter.buildScanRequest(this.scannerId, 0, true, false);
|
||||
stub.scan(controller, req, resp -> {
|
||||
if (controller.failed()) {
|
||||
LOG.warn("Call to " + loc.getServerName() + " for closing scanner id = " + scannerId +
|
||||
" for " + loc.getRegion().getEncodedName() + " of " +
|
||||
loc.getRegion().getTable() + " failed, ignore, probably already closed",
|
||||
LOG.warn("Call to " + loc.getServerName() + " for closing scanner id = " + scannerId
|
||||
+ " for " + loc.getRegion().getEncodedName() + " of " + loc.getRegion().getTable()
|
||||
+ " failed, ignore, probably already closed",
|
||||
controller.getFailed());
|
||||
}
|
||||
});
|
||||
|
@ -392,16 +394,16 @@ class AsyncScanSingleRegionRpcRetryingCaller {
|
|||
private void onError(Throwable error) {
|
||||
error = translateException(error);
|
||||
if (tries > startLogErrorsCnt) {
|
||||
LOG.warn("Call to " + loc.getServerName() + " for scanner id = " + scannerId + " for " +
|
||||
loc.getRegion().getEncodedName() + " of " + loc.getRegion().getTable() +
|
||||
" failed, , tries = " + tries + ", maxAttempts = " + maxAttempts + ", timeout = " +
|
||||
TimeUnit.NANOSECONDS.toMillis(scanTimeoutNs) + " ms, time elapsed = " + elapsedMs() +
|
||||
" ms",
|
||||
LOG.warn("Call to " + loc.getServerName() + " for scanner id = " + scannerId + " for "
|
||||
+ loc.getRegion().getEncodedName() + " of " + loc.getRegion().getTable()
|
||||
+ " failed, , tries = " + tries + ", maxAttempts = " + maxAttempts + ", timeout = "
|
||||
+ TimeUnit.NANOSECONDS.toMillis(scanTimeoutNs) + " ms, time elapsed = " + elapsedMs()
|
||||
+ " ms",
|
||||
error);
|
||||
}
|
||||
boolean scannerClosed =
|
||||
error instanceof UnknownScannerException || error instanceof NotServingRegionException ||
|
||||
error instanceof RegionServerStoppedException || error instanceof ScannerResetException;
|
||||
boolean scannerClosed = error instanceof UnknownScannerException
|
||||
|| error instanceof NotServingRegionException
|
||||
|| error instanceof RegionServerStoppedException || error instanceof ScannerResetException;
|
||||
RetriesExhaustedException.ThrowableWithExtraContext qt =
|
||||
new RetriesExhaustedException.ThrowableWithExtraContext(error,
|
||||
EnvironmentEdgeManager.currentTime(), "");
|
||||
|
@ -573,7 +575,12 @@ class AsyncScanSingleRegionRpcRetryingCaller {
|
|||
resetController(controller, callTimeoutNs, priority);
|
||||
ScanRequest req = RequestConverter.buildScanRequest(scannerId, scan.getCaching(), false,
|
||||
nextCallSeq, scan.isScanMetricsEnabled(), false, scan.getLimit());
|
||||
stub.scan(controller, req, resp -> onComplete(controller, resp));
|
||||
final Context context = Context.current();
|
||||
stub.scan(controller, req, resp -> {
|
||||
try (Scope ignored = context.makeCurrent()) {
|
||||
onComplete(controller, resp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void next() {
|
||||
|
|
|
@ -18,8 +18,11 @@
|
|||
package org.apache.hadoop.hbase.client;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.google.protobuf.RpcChannel;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
@ -177,8 +180,7 @@ class AsyncTableImpl implements AsyncTable<ScanResultConsumer> {
|
|||
public CheckAndMutateWithFilterBuilder checkAndMutate(byte[] row, Filter filter) {
|
||||
return new CheckAndMutateWithFilterBuilder() {
|
||||
|
||||
private final CheckAndMutateWithFilterBuilder builder =
|
||||
rawTable.checkAndMutate(row, filter);
|
||||
private final CheckAndMutateWithFilterBuilder builder = rawTable.checkAndMutate(row, filter);
|
||||
|
||||
@Override
|
||||
public CheckAndMutateWithFilterBuilder timeRange(TimeRange timeRange) {
|
||||
|
@ -209,10 +211,9 @@ class AsyncTableImpl implements AsyncTable<ScanResultConsumer> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<CompletableFuture<CheckAndMutateResult>> checkAndMutate(
|
||||
List<CheckAndMutate> checkAndMutates) {
|
||||
return rawTable.checkAndMutate(checkAndMutates).stream()
|
||||
.map(this::wrap).collect(toList());
|
||||
public List<CompletableFuture<CheckAndMutateResult>>
|
||||
checkAndMutate(List<CheckAndMutate> checkAndMutates) {
|
||||
return rawTable.checkAndMutate(checkAndMutates).stream().map(this::wrap).collect(toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -231,7 +232,10 @@ class AsyncTableImpl implements AsyncTable<ScanResultConsumer> {
|
|||
}
|
||||
|
||||
private void scan0(Scan scan, ScanResultConsumer consumer) {
|
||||
try (ResultScanner scanner = getScanner(scan)) {
|
||||
Span span = null;
|
||||
try (AsyncTableResultScanner scanner = rawTable.getScanner(scan)) {
|
||||
span = scanner.getSpan();
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
consumer.onScanMetricsCreated(scanner.getScanMetrics());
|
||||
for (Result result; (result = scanner.next()) != null;) {
|
||||
if (!consumer.onNext(result)) {
|
||||
|
@ -239,14 +243,18 @@ class AsyncTableImpl implements AsyncTable<ScanResultConsumer> {
|
|||
}
|
||||
}
|
||||
consumer.onComplete();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
consumer.onError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scan(Scan scan, ScanResultConsumer consumer) {
|
||||
pool.execute(() -> scan0(scan, consumer));
|
||||
final Context context = Context.current();
|
||||
pool.execute(context.wrap(() -> scan0(scan, consumer)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.client;
|
|||
|
||||
import static org.apache.hadoop.hbase.client.ConnectionUtils.calcEstimatedSize;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.ArrayDeque;
|
||||
|
@ -58,6 +59,9 @@ class AsyncTableResultScanner implements ResultScanner, AdvancedScanResultConsum
|
|||
|
||||
private ScanResumer resumer;
|
||||
|
||||
// Used to pass the span instance to the `AsyncTableImpl` from its underlying `rawAsyncTable`.
|
||||
private Span span = null;
|
||||
|
||||
public AsyncTableResultScanner(TableName tableName, Scan scan, long maxCacheSize) {
|
||||
this.tableName = tableName;
|
||||
this.maxCacheSize = maxCacheSize;
|
||||
|
@ -71,14 +75,22 @@ class AsyncTableResultScanner implements ResultScanner, AdvancedScanResultConsum
|
|||
|
||||
private void stopPrefetch(ScanController controller) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("{} stop prefetching when scanning {} as the cache size {}" +
|
||||
" is greater than the maxCacheSize {}",
|
||||
String.format("0x%x", System.identityHashCode(this)), tableName, cacheSize,
|
||||
maxCacheSize);
|
||||
LOG.debug(
|
||||
"{} stop prefetching when scanning {} as the cache size {}"
|
||||
+ " is greater than the maxCacheSize {}",
|
||||
String.format("0x%x", System.identityHashCode(this)), tableName, cacheSize, maxCacheSize);
|
||||
}
|
||||
resumer = controller.suspend();
|
||||
}
|
||||
|
||||
Span getSpan() {
|
||||
return span;
|
||||
}
|
||||
|
||||
void setSpan(final Span span) {
|
||||
this.span = span;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onNext(Result[] results, ScanController controller) {
|
||||
assert results.length > 0;
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
package org.apache.hadoop.hbase.client;
|
||||
|
||||
import static org.apache.hadoop.hbase.client.ConnectionUtils.calcEstimatedSize;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.Queue;
|
||||
|
@ -36,14 +39,13 @@ import org.apache.hadoop.hbase.util.Threads;
|
|||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
|
||||
/**
|
||||
* ClientAsyncPrefetchScanner implements async scanner behaviour.
|
||||
* Specifically, the cache used by this scanner is a concurrent queue which allows both
|
||||
* the producer (hbase client) and consumer (application) to access the queue in parallel.
|
||||
* The number of rows returned in a prefetch is defined by the caching factor and the result size
|
||||
* factor.
|
||||
* This class allocates a buffer cache, whose size is a function of both factors.
|
||||
* The prefetch is invoked when the cache is halffilled, instead of waiting for it to be empty.
|
||||
* This is defined in the method {@link ClientAsyncPrefetchScanner#prefetchCondition()}.
|
||||
* ClientAsyncPrefetchScanner implements async scanner behaviour. Specifically, the cache used by
|
||||
* this scanner is a concurrent queue which allows both the producer (hbase client) and consumer
|
||||
* (application) to access the queue in parallel. The number of rows returned in a prefetch is
|
||||
* defined by the caching factor and the result size factor. This class allocates a buffer cache,
|
||||
* whose size is a function of both factors. The prefetch is invoked when the cache is half-filled,
|
||||
* instead of waiting for it to be empty. This is defined in the method
|
||||
* {@link ClientAsyncPrefetchScanner#prefetchCondition()}.
|
||||
*/
|
||||
@InterfaceAudience.Private
|
||||
public class ClientAsyncPrefetchScanner extends ClientSimpleScanner {
|
||||
|
@ -66,7 +68,9 @@ public class ClientAsyncPrefetchScanner extends ClientSimpleScanner {
|
|||
super(configuration, scan, name, connection, rpcCallerFactory, rpcControllerFactory, pool,
|
||||
replicaCallTimeoutMicroSecondScan);
|
||||
exceptionsQueue = new ConcurrentLinkedQueue<>();
|
||||
Threads.setDaemonThreadRunning(new Thread(new PrefetchRunnable()), name + ".asyncPrefetcher");
|
||||
final Context context = Context.current();
|
||||
final Runnable runnable = context.wrap(new PrefetchRunnable());
|
||||
Threads.setDaemonThreadRunning(new Thread(runnable), name + ".asyncPrefetcher");
|
||||
}
|
||||
|
||||
void setPrefetchListener(Consumer<Boolean> prefetchListener) {
|
||||
|
@ -88,7 +92,7 @@ public class ClientAsyncPrefetchScanner extends ClientSimpleScanner {
|
|||
|
||||
@Override
|
||||
public Result next() throws IOException {
|
||||
try {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
lock.lock();
|
||||
while (cache.isEmpty()) {
|
||||
handleException();
|
||||
|
@ -98,6 +102,7 @@ public class ClientAsyncPrefetchScanner extends ClientSimpleScanner {
|
|||
try {
|
||||
notEmpty.await();
|
||||
} catch (InterruptedException e) {
|
||||
span.recordException(e);
|
||||
throw new InterruptedIOException("Interrupted when wait to load cache");
|
||||
}
|
||||
}
|
||||
|
@ -132,8 +137,8 @@ public class ClientAsyncPrefetchScanner extends ClientSimpleScanner {
|
|||
}
|
||||
|
||||
private void handleException() throws IOException {
|
||||
//The prefetch task running in the background puts any exception it
|
||||
//catches into this exception queue.
|
||||
// The prefetch task running in the background puts any exception it
|
||||
// catches into this exception queue.
|
||||
// Rethrow the exception so the application can handle it.
|
||||
while (!exceptionsQueue.isEmpty()) {
|
||||
Exception first = exceptionsQueue.peek();
|
||||
|
@ -171,6 +176,7 @@ public class ClientAsyncPrefetchScanner extends ClientSimpleScanner {
|
|||
succeed = true;
|
||||
} catch (Exception e) {
|
||||
exceptionsQueue.add(e);
|
||||
span.recordException(e);
|
||||
} finally {
|
||||
notEmpty.signalAll();
|
||||
lock.unlock();
|
||||
|
@ -180,7 +186,6 @@ public class ClientAsyncPrefetchScanner extends ClientSimpleScanner {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -21,6 +21,9 @@ import static org.apache.hadoop.hbase.client.ConnectionUtils.calcEstimatedSize;
|
|||
import static org.apache.hadoop.hbase.client.ConnectionUtils.createScanResultCache;
|
||||
import static org.apache.hadoop.hbase.client.ConnectionUtils.incRegionCountMetrics;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.ArrayDeque;
|
||||
|
@ -40,13 +43,14 @@ import org.apache.hadoop.hbase.exceptions.ScannerResetException;
|
|||
import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
|
||||
import org.apache.hadoop.hbase.regionserver.LeaseException;
|
||||
import org.apache.hadoop.hbase.regionserver.RegionServerStoppedException;
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
|
||||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||
|
||||
/**
|
||||
* Implements the scanner interface for the HBase client. If there are multiple regions in a table,
|
||||
* this scanner will iterate through them all.
|
||||
|
@ -76,6 +80,7 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
protected RpcRetryingCaller<Result[]> caller;
|
||||
protected RpcControllerFactory rpcControllerFactory;
|
||||
protected Configuration conf;
|
||||
protected final Span span;
|
||||
// The timeout on the primary. Applicable if there are multiple replicas for a region
|
||||
// In that case, we will only wait for this much timeout on the primary before going
|
||||
// to the replicas and trying the same scan. Note that the retries will still happen
|
||||
|
@ -92,7 +97,6 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
* @param scan {@link Scan} to use in this scanner
|
||||
* @param tableName The table that we wish to scan
|
||||
* @param connection Connection identifying the cluster
|
||||
* @throws IOException
|
||||
*/
|
||||
public ClientScanner(final Configuration conf, final Scan scan, final TableName tableName,
|
||||
ClusterConnection connection, RpcRetryingCallerFactory rpcFactory,
|
||||
|
@ -134,14 +138,14 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
this.rpcControllerFactory = controllerFactory;
|
||||
|
||||
this.conf = conf;
|
||||
this.span = Span.current();
|
||||
|
||||
this.scanResultCache = createScanResultCache(scan);
|
||||
initCache();
|
||||
}
|
||||
|
||||
protected final int getScanReplicaId() {
|
||||
return scan.getReplicaId() >= RegionReplicaUtil.DEFAULT_REPLICA_ID ? scan.getReplicaId() :
|
||||
RegionReplicaUtil.DEFAULT_REPLICA_ID;
|
||||
return Math.max(scan.getReplicaId(), RegionReplicaUtil.DEFAULT_REPLICA_ID);
|
||||
}
|
||||
|
||||
protected ClusterConnection getConnection() {
|
||||
|
@ -238,8 +242,8 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
if (LOG.isDebugEnabled() && this.currentRegion != null) {
|
||||
// Only worth logging if NOT first region in scan.
|
||||
LOG.debug(
|
||||
"Advancing internal scanner to startKey at '" + Bytes.toStringBinary(scan.getStartRow()) +
|
||||
"', " + (scan.includeStartRow() ? "inclusive" : "exclusive"));
|
||||
"Advancing internal scanner to startKey at '" + Bytes.toStringBinary(scan.getStartRow())
|
||||
+ "', " + (scan.includeStartRow() ? "inclusive" : "exclusive"));
|
||||
}
|
||||
// clear the current region, we will set a new value to it after the first call of the new
|
||||
// callable.
|
||||
|
@ -331,8 +335,8 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
// old time we always return empty result for a open scanner operation so we add a check here to
|
||||
// keep compatible with the old logic. Should remove the isOpenScanner in the future.
|
||||
// 2. Server tells us that it has no more results for this region.
|
||||
return (values.length == 0 && !callable.isHeartbeatMessage()) ||
|
||||
callable.moreResultsInRegion() == MoreResults.NO;
|
||||
return (values.length == 0 && !callable.isHeartbeatMessage())
|
||||
|| callable.moreResultsInRegion() == MoreResults.NO;
|
||||
}
|
||||
|
||||
private void closeScannerIfExhausted(boolean exhausted) throws IOException {
|
||||
|
@ -362,10 +366,10 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
// If exception is any but the list below throw it back to the client; else setup
|
||||
// the scanner and retry.
|
||||
Throwable cause = e.getCause();
|
||||
if ((cause != null && cause instanceof NotServingRegionException) ||
|
||||
(cause != null && cause instanceof RegionServerStoppedException) ||
|
||||
e instanceof OutOfOrderScannerNextException || e instanceof UnknownScannerException ||
|
||||
e instanceof ScannerResetException || e instanceof LeaseException) {
|
||||
if ((cause != null && cause instanceof NotServingRegionException)
|
||||
|| (cause != null && cause instanceof RegionServerStoppedException)
|
||||
|| e instanceof OutOfOrderScannerNextException || e instanceof UnknownScannerException
|
||||
|| e instanceof ScannerResetException || e instanceof LeaseException) {
|
||||
// Pass. It is easier writing the if loop test as list of what is allowed rather than
|
||||
// as a list of what is not allowed... so if in here, it means we do not throw.
|
||||
if (retriesLeft <= 0) {
|
||||
|
@ -489,8 +493,8 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
// processing of the scan is taking a long time server side. Rather than continue to
|
||||
// loop until a limit (e.g. size or caching) is reached, break out early to avoid causing
|
||||
// unnecesary delays to the caller
|
||||
LOG.trace("Heartbeat message received and cache contains Results. " +
|
||||
"Breaking out of scan loop");
|
||||
LOG.trace("Heartbeat message received and cache contains Results. "
|
||||
+ "Breaking out of scan loop");
|
||||
// we know that the region has not been exhausted yet so just break without calling
|
||||
// closeScannerIfExhausted
|
||||
break;
|
||||
|
@ -546,7 +550,10 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
|
||||
@Override
|
||||
public void close() {
|
||||
if (!scanMetricsPublished) writeScanMetrics();
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
if (!scanMetricsPublished) {
|
||||
writeScanMetrics();
|
||||
}
|
||||
if (callable != null) {
|
||||
callable.setClose();
|
||||
try {
|
||||
|
@ -559,14 +566,21 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
} catch (IOException e) {
|
||||
/* An exception other than UnknownScanner is unexpected. */
|
||||
LOG.warn("scanner failed to close.", e);
|
||||
span.recordException(e);
|
||||
span.setStatus(StatusCode.ERROR);
|
||||
}
|
||||
callable = null;
|
||||
}
|
||||
closed = true;
|
||||
span.setStatus(StatusCode.OK);
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renewLease() {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
if (callable == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -577,11 +591,13 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.debug("scanner failed to renew lease", e);
|
||||
span.recordException(e);
|
||||
return false;
|
||||
} finally {
|
||||
callable.setRenew(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void initCache() {
|
||||
initSyncCache();
|
||||
|
@ -589,6 +605,8 @@ public abstract class ClientScanner extends AbstractClientScanner {
|
|||
|
||||
@Override
|
||||
public Result next() throws IOException {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
return nextWithSyncCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/**
|
||||
*
|
||||
/*
|
||||
* 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
|
||||
|
@ -30,6 +29,8 @@ import static org.apache.hadoop.hbase.util.ConcurrentMapUtils.computeIfAbsent;
|
|||
import static org.apache.hadoop.hbase.util.ConcurrentMapUtils.computeIfAbsentEx;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.Nullable;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
@ -69,6 +70,7 @@ import org.apache.hadoop.hbase.ZooKeeperConnectionException;
|
|||
import org.apache.hadoop.hbase.client.Scan.ReadType;
|
||||
import org.apache.hadoop.hbase.client.backoff.ClientBackoffPolicy;
|
||||
import org.apache.hadoop.hbase.client.backoff.ClientBackoffPolicyFactory;
|
||||
import org.apache.hadoop.hbase.client.trace.TableOperationSpanBuilder;
|
||||
import org.apache.hadoop.hbase.exceptions.ClientExceptionsUtil;
|
||||
import org.apache.hadoop.hbase.exceptions.ConnectionClosedException;
|
||||
import org.apache.hadoop.hbase.exceptions.RegionMovedException;
|
||||
|
@ -163,12 +165,12 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.ReplicationProtos.Updat
|
|||
import org.apache.hadoop.hbase.shaded.protobuf.generated.ReplicationProtos.UpdateReplicationPeerConfigResponse;
|
||||
|
||||
/**
|
||||
* Main implementation of {@link Connection} and {@link ClusterConnection} interfaces.
|
||||
* Encapsulates connection to zookeeper and regionservers.
|
||||
* Main implementation of {@link Connection} and {@link ClusterConnection} interfaces. Encapsulates
|
||||
* connection to zookeeper and regionservers.
|
||||
*/
|
||||
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
|
||||
value="AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION",
|
||||
justification="Access to the conncurrent hash map is under a lock so should be fine.")
|
||||
value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION",
|
||||
justification = "Access to the conncurrent hash map is under a lock so should be fine.")
|
||||
@InterfaceAudience.Private
|
||||
public class ConnectionImplementation implements ClusterConnection, Closeable {
|
||||
public static final String RETRIES_BY_SERVER_KEY = "hbase.client.retries.by.server";
|
||||
|
@ -186,8 +188,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
final int rpcTimeout;
|
||||
|
||||
/**
|
||||
* Global nonceGenerator shared per client.Currently there's no reason to limit its scope.
|
||||
* Once it's set under nonceGeneratorCreateLock, it is never unset or changed.
|
||||
* Global nonceGenerator shared per client.Currently there's no reason to limit its scope. Once
|
||||
* it's set under nonceGeneratorCreateLock, it is never unset or changed.
|
||||
*/
|
||||
private static volatile NonceGenerator nonceGenerator = null;
|
||||
/** The nonce generator lock. Only taken when creating Connection, which gets a private copy. */
|
||||
|
@ -243,8 +245,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
private final ClientBackoffPolicy backoffPolicy;
|
||||
|
||||
/**
|
||||
* Allow setting an alternate BufferedMutator implementation via
|
||||
* config. If null, use default.
|
||||
* Allow setting an alternate BufferedMutator implementation via config. If null, use default.
|
||||
*/
|
||||
private final String alternateBufferedMutatorClassName;
|
||||
|
||||
|
@ -274,8 +275,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
this.batchPool = (ThreadPoolExecutor) pool;
|
||||
this.connectionConfig = new ConnectionConfiguration(conf);
|
||||
this.closed = false;
|
||||
this.pause = conf.getLong(HConstants.HBASE_CLIENT_PAUSE,
|
||||
HConstants.DEFAULT_HBASE_CLIENT_PAUSE);
|
||||
this.pause = conf.getLong(HConstants.HBASE_CLIENT_PAUSE, HConstants.DEFAULT_HBASE_CLIENT_PAUSE);
|
||||
long configuredPauseForCQTBE = conf.getLong(HConstants.HBASE_CLIENT_PAUSE_FOR_CQTBE, pause);
|
||||
if (configuredPauseForCQTBE < pause) {
|
||||
LOG.warn("The " + HConstants.HBASE_CLIENT_PAUSE_FOR_CQTBE + " setting: "
|
||||
|
@ -290,9 +290,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
|
||||
// how many times to try, one more than max *retry* time
|
||||
this.numTries = retries2Attempts(connectionConfig.getRetriesNumber());
|
||||
this.rpcTimeout = conf.getInt(
|
||||
HConstants.HBASE_RPC_TIMEOUT_KEY,
|
||||
HConstants.DEFAULT_HBASE_RPC_TIMEOUT);
|
||||
this.rpcTimeout =
|
||||
conf.getInt(HConstants.HBASE_RPC_TIMEOUT_KEY, HConstants.DEFAULT_HBASE_RPC_TIMEOUT);
|
||||
if (conf.getBoolean(NonceGenerator.CLIENT_NONCES_ENABLED_KEY, true)) {
|
||||
synchronized (nonceGeneratorCreateLock) {
|
||||
if (nonceGenerator == null) {
|
||||
|
@ -317,16 +316,14 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
this.metaCache = new MetaCache(this.metrics);
|
||||
|
||||
boolean shouldListen = conf.getBoolean(HConstants.STATUS_PUBLISHED,
|
||||
HConstants.STATUS_PUBLISHED_DEFAULT);
|
||||
Class<? extends ClusterStatusListener.Listener> listenerClass =
|
||||
conf.getClass(ClusterStatusListener.STATUS_LISTENER_CLASS,
|
||||
ClusterStatusListener.DEFAULT_STATUS_LISTENER_CLASS,
|
||||
ClusterStatusListener.Listener.class);
|
||||
boolean shouldListen =
|
||||
conf.getBoolean(HConstants.STATUS_PUBLISHED, HConstants.STATUS_PUBLISHED_DEFAULT);
|
||||
Class<? extends ClusterStatusListener.Listener> listenerClass = conf.getClass(
|
||||
ClusterStatusListener.STATUS_LISTENER_CLASS,
|
||||
ClusterStatusListener.DEFAULT_STATUS_LISTENER_CLASS, ClusterStatusListener.Listener.class);
|
||||
|
||||
// Is there an alternate BufferedMutator to use?
|
||||
this.alternateBufferedMutatorClassName =
|
||||
this.conf.get(BufferedMutator.CLASSNAME_KEY);
|
||||
this.alternateBufferedMutatorClassName = this.conf.get(BufferedMutator.CLASSNAME_KEY);
|
||||
|
||||
try {
|
||||
if (registry == null) {
|
||||
|
@ -341,11 +338,11 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
// Do we publish the status?
|
||||
if (shouldListen) {
|
||||
if (listenerClass == null) {
|
||||
LOG.warn(HConstants.STATUS_PUBLISHED + " is true, but " +
|
||||
ClusterStatusListener.STATUS_LISTENER_CLASS + " is not set - not listening status");
|
||||
LOG.warn(HConstants.STATUS_PUBLISHED + " is true, but "
|
||||
+ ClusterStatusListener.STATUS_LISTENER_CLASS + " is not set - not listening status");
|
||||
} else {
|
||||
clusterStatusListener = new ClusterStatusListener(
|
||||
new ClusterStatusListener.DeadServerHandler() {
|
||||
clusterStatusListener =
|
||||
new ClusterStatusListener(new ClusterStatusListener.DeadServerHandler() {
|
||||
@Override
|
||||
public void newDead(ServerName sn) {
|
||||
clearCaches(sn);
|
||||
|
@ -362,21 +359,21 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
// Get the region locator's meta replica mode.
|
||||
this.metaReplicaMode = CatalogReplicaMode.fromString(conf.get(LOCATOR_META_REPLICAS_MODE,
|
||||
CatalogReplicaMode.NONE.toString()));
|
||||
this.metaReplicaMode = CatalogReplicaMode
|
||||
.fromString(conf.get(LOCATOR_META_REPLICAS_MODE, CatalogReplicaMode.NONE.toString()));
|
||||
|
||||
switch (this.metaReplicaMode) {
|
||||
case LOAD_BALANCE:
|
||||
String replicaSelectorClass = conf.get(
|
||||
RegionLocator.LOCATOR_META_REPLICAS_MODE_LOADBALANCE_SELECTOR,
|
||||
String replicaSelectorClass =
|
||||
conf.get(RegionLocator.LOCATOR_META_REPLICAS_MODE_LOADBALANCE_SELECTOR,
|
||||
CatalogReplicaLoadBalanceSimpleSelector.class.getName());
|
||||
|
||||
this.metaReplicaSelector = CatalogReplicaLoadBalanceSelectorFactory.createSelector(
|
||||
replicaSelectorClass, META_TABLE_NAME, getChoreService(), () -> {
|
||||
this.metaReplicaSelector = CatalogReplicaLoadBalanceSelectorFactory
|
||||
.createSelector(replicaSelectorClass, META_TABLE_NAME, getChoreService(), () -> {
|
||||
int numOfReplicas = 1;
|
||||
try {
|
||||
RegionLocations metaLocations = this.registry.getMetaRegionLocations().get(
|
||||
connectionConfig.getReadRpcTimeout(), TimeUnit.MILLISECONDS);
|
||||
RegionLocations metaLocations = this.registry.getMetaRegionLocations()
|
||||
.get(connectionConfig.getReadRpcTimeout(), TimeUnit.MILLISECONDS);
|
||||
numOfReplicas = metaLocations.size();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to get table {}'s region replication, ", META_TABLE_NAME, e);
|
||||
|
@ -387,8 +384,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
case NONE:
|
||||
// If user does not configure LOCATOR_META_REPLICAS_MODE, let's check the legacy config.
|
||||
|
||||
boolean useMetaReplicas = conf.getBoolean(USE_META_REPLICAS,
|
||||
DEFAULT_USE_META_REPLICAS);
|
||||
boolean useMetaReplicas = conf.getBoolean(USE_META_REPLICAS, DEFAULT_USE_META_REPLICAS);
|
||||
if (useMetaReplicas) {
|
||||
this.metaReplicaMode = CatalogReplicaMode.HEDGED_READ;
|
||||
}
|
||||
|
@ -408,12 +404,10 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
* @param cnm Replaces the nonce generator used, for testing.
|
||||
* @return old nonce generator.
|
||||
*/
|
||||
static NonceGenerator injectNonceGeneratorForTesting(
|
||||
ClusterConnection conn, NonceGenerator cnm) {
|
||||
ConnectionImplementation connImpl = (ConnectionImplementation)conn;
|
||||
static NonceGenerator injectNonceGeneratorForTesting(ClusterConnection conn, NonceGenerator cnm) {
|
||||
ConnectionImplementation connImpl = (ConnectionImplementation) conn;
|
||||
NonceGenerator ng = connImpl.getNonceGenerator();
|
||||
LOG.warn("Nonce generator is being replaced by test code for "
|
||||
+ cnm.getClass().getName());
|
||||
LOG.warn("Nonce generator is being replaced by test code for " + cnm.getClass().getName());
|
||||
nonceGenerator = cnm;
|
||||
return ng;
|
||||
}
|
||||
|
@ -464,7 +458,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
return new BufferedMutatorImpl(this, rpcCallerFactory, rpcControllerFactory, params);
|
||||
}
|
||||
try {
|
||||
return (BufferedMutator)ReflectionUtils.newInstance(Class.forName(implementationClassName),
|
||||
return (BufferedMutator) ReflectionUtils.newInstance(Class.forName(implementationClassName),
|
||||
this, rpcCallerFactory, rpcControllerFactory, params);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
@ -552,10 +546,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
long keepAliveTime = conf.getLong("hbase.hconnection.threads.keepalivetime", 60);
|
||||
BlockingQueue<Runnable> workQueue = passedWorkQueue;
|
||||
if (workQueue == null) {
|
||||
workQueue =
|
||||
new LinkedBlockingQueue<>(maxThreads *
|
||||
conf.getInt(HConstants.HBASE_CLIENT_MAX_TOTAL_TASKS,
|
||||
HConstants.DEFAULT_HBASE_CLIENT_MAX_TOTAL_TASKS));
|
||||
workQueue = new LinkedBlockingQueue<>(maxThreads * conf.getInt(
|
||||
HConstants.HBASE_CLIENT_MAX_TOTAL_TASKS, HConstants.DEFAULT_HBASE_CLIENT_MAX_TOTAL_TASKS));
|
||||
coreThreads = maxThreads;
|
||||
}
|
||||
ThreadPoolExecutor tpe =
|
||||
|
@ -570,15 +562,13 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
if (this.metaLookupPool == null) {
|
||||
synchronized (this) {
|
||||
if (this.metaLookupPool == null) {
|
||||
//Some of the threads would be used for meta replicas
|
||||
//To start with, threads.max.core threads can hit the meta (including replicas).
|
||||
//After that, requests will get queued up in the passed queue, and only after
|
||||
//the queue is full, a new thread will be started
|
||||
// Some of the threads would be used for meta replicas
|
||||
// To start with, threads.max.core threads can hit the meta (including replicas).
|
||||
// After that, requests will get queued up in the passed queue, and only after
|
||||
// the queue is full, a new thread will be started
|
||||
int threads = conf.getInt("hbase.hconnection.meta.lookup.threads.max", 128);
|
||||
this.metaLookupPool = getThreadPool(
|
||||
threads,
|
||||
threads,
|
||||
"-metaLookup-shared-", new LinkedBlockingQueue<>());
|
||||
this.metaLookupPool =
|
||||
getThreadPool(threads, threads, "-metaLookup-shared-", new LinkedBlockingQueue<>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -624,7 +614,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
* An identifier that will remain the same for a given connection.
|
||||
*/
|
||||
@Override
|
||||
public String toString(){
|
||||
public String toString() {
|
||||
return "hconnection-0x" + Integer.toHexString(hashCode());
|
||||
}
|
||||
|
||||
|
@ -668,9 +658,9 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Like {@link ConnectionClosedException} but thrown from the checkClosed call which looks
|
||||
* at the local this.closed flag. We use this rather than {@link ConnectionClosedException}
|
||||
* because the latter does not inherit from DoNotRetryIOE (it should. TODO).
|
||||
* Like {@link ConnectionClosedException} but thrown from the checkClosed call which looks at the
|
||||
* local this.closed flag. We use this rather than {@link ConnectionClosedException} because the
|
||||
* latter does not inherit from DoNotRetryIOE (it should. TODO).
|
||||
*/
|
||||
private static class LocalConnectionClosedException extends DoNotRetryIOException {
|
||||
LocalConnectionClosedException(String message) {
|
||||
|
@ -705,7 +695,6 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
return reload ? relocateRegion(tableName, row) : locateRegion(tableName, row);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isTableEnabled(TableName tableName) throws IOException {
|
||||
return getTableState(tableName).inStates(TableState.State.ENABLED);
|
||||
|
@ -740,8 +729,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
LOG.debug("Table {} has not deployed region {}", tableName,
|
||||
pair.getFirst().getEncodedName());
|
||||
notDeployed++;
|
||||
} else if (splitKeys != null
|
||||
&& !Bytes.equals(info.getStartKey(), HConstants.EMPTY_BYTE_ARRAY)) {
|
||||
} else
|
||||
if (splitKeys != null && !Bytes.equals(info.getStartKey(), HConstants.EMPTY_BYTE_ARRAY)) {
|
||||
for (byte[] splitKey : splitKeys) {
|
||||
// Just check if the splitkey is available
|
||||
if (Bytes.equals(info.getStartKey(), splitKey)) {
|
||||
|
@ -838,8 +827,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public RegionLocations relocateRegion(final TableName tableName,
|
||||
final byte [] row, int replicaId) throws IOException{
|
||||
public RegionLocations relocateRegion(final TableName tableName, final byte[] row, int replicaId)
|
||||
throws IOException {
|
||||
// Since this is an explicit request not to use any caching, finding
|
||||
// disabled tables should not be desirable. This will ensure that an exception is thrown when
|
||||
// the first time a disabled table is interacted with.
|
||||
|
@ -871,8 +860,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
}
|
||||
|
||||
private RegionLocations locateMeta(final TableName tableName,
|
||||
boolean useCache, int replicaId) throws IOException {
|
||||
private RegionLocations locateMeta(final TableName tableName, boolean useCache, int replicaId)
|
||||
throws IOException {
|
||||
// HBASE-10785: We cache the location of the META itself, so that we are not overloading
|
||||
// zookeeper with one request for every region lookup. We cache the META with empty row
|
||||
// key in MetaCache.
|
||||
|
@ -931,8 +920,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
|
||||
switch (this.metaReplicaMode) {
|
||||
case LOAD_BALANCE:
|
||||
int metaReplicaId = this.metaReplicaSelector.select(tableName, row,
|
||||
RegionLocateType.CURRENT);
|
||||
int metaReplicaId =
|
||||
this.metaReplicaSelector.select(tableName, row, RegionLocateType.CURRENT);
|
||||
if (metaReplicaId != RegionInfo.DEFAULT_REPLICA_ID) {
|
||||
// If the selector gives a non-primary meta replica region, then go with it.
|
||||
// Otherwise, just go to primary in non-hedgedRead mode.
|
||||
|
@ -948,7 +937,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
int maxAttempts = (retry ? numTries : 1);
|
||||
boolean relocateMeta = false;
|
||||
for (int tries = 0; ; tries++) {
|
||||
for (int tries = 0;; tries++) {
|
||||
if (tries >= maxAttempts) {
|
||||
throw new NoServerForRegionException("Unable to find region for "
|
||||
+ Bytes.toStringBinary(row) + " in " + tableName + " after " + tries + " tries.");
|
||||
|
@ -981,9 +970,12 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
RegionInfo.DEFAULT_REPLICA_ID);
|
||||
}
|
||||
s.resetMvccReadPoint();
|
||||
try (ReversedClientScanner rcs =
|
||||
new ReversedClientScanner(conf, s, TableName.META_TABLE_NAME, this, rpcCallerFactory,
|
||||
rpcControllerFactory, getMetaLookupPool(), metaReplicaCallTimeoutScanInMicroSecond)) {
|
||||
final Span span = new TableOperationSpanBuilder(this)
|
||||
.setTableName(TableName.META_TABLE_NAME).setOperation(s).build();
|
||||
try (Scope ignored = span.makeCurrent();
|
||||
ReversedClientScanner rcs = new ReversedClientScanner(conf, s,
|
||||
TableName.META_TABLE_NAME, this, rpcCallerFactory, rpcControllerFactory,
|
||||
getMetaLookupPool(), metaReplicaCallTimeoutScanInMicroSecond)) {
|
||||
boolean tableNotFound = true;
|
||||
for (;;) {
|
||||
Result regionInfoRow = rcs.next();
|
||||
|
@ -1003,8 +995,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
RegionInfo regionInfo = locations.getRegionLocation(replicaId).getRegion();
|
||||
if (regionInfo == null) {
|
||||
throw new IOException("RegionInfo null or empty in " + TableName.META_TABLE_NAME +
|
||||
", row=" + regionInfoRow);
|
||||
throw new IOException("RegionInfo null or empty in " + TableName.META_TABLE_NAME
|
||||
+ ", row=" + regionInfoRow);
|
||||
}
|
||||
// See HBASE-20182. It is possible that we locate to a split parent even after the
|
||||
// children are online, so here we need to skip this region and go to the next one.
|
||||
|
@ -1012,8 +1004,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
continue;
|
||||
}
|
||||
if (regionInfo.isOffline()) {
|
||||
throw new RegionOfflineException("Region offline; disable table call? " +
|
||||
regionInfo.getRegionNameAsString());
|
||||
throw new RegionOfflineException(
|
||||
"Region offline; disable table call? " + regionInfo.getRegionNameAsString());
|
||||
}
|
||||
// It is possible that the split children have not been online yet and we have skipped
|
||||
// the parent in the above condition, so we may have already reached a region which does
|
||||
|
@ -1024,14 +1016,14 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
ServerName serverName = locations.getRegionLocation(replicaId).getServerName();
|
||||
if (serverName == null) {
|
||||
throw new NoServerForRegionException("No server address listed in " +
|
||||
TableName.META_TABLE_NAME + " for region " + regionInfo.getRegionNameAsString() +
|
||||
" containing row " + Bytes.toStringBinary(row));
|
||||
throw new NoServerForRegionException("No server address listed in "
|
||||
+ TableName.META_TABLE_NAME + " for region " + regionInfo.getRegionNameAsString()
|
||||
+ " containing row " + Bytes.toStringBinary(row));
|
||||
}
|
||||
if (isDeadServer(serverName)) {
|
||||
throw new RegionServerStoppedException(
|
||||
"hbase:meta says the region " + regionInfo.getRegionNameAsString() +
|
||||
" is managed by the server " + serverName + ", but it is dead.");
|
||||
"hbase:meta says the region " + regionInfo.getRegionNameAsString()
|
||||
+ " is managed by the server " + serverName + ", but it is dead.");
|
||||
}
|
||||
// Instantiate the location
|
||||
cacheLocation(tableName, locations);
|
||||
|
@ -1050,15 +1042,17 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
} catch (IOException e) {
|
||||
ExceptionUtil.rethrowIfInterrupt(e);
|
||||
if (e instanceof RemoteException) {
|
||||
e = ((RemoteException)e).unwrapRemoteException();
|
||||
e = ((RemoteException) e).unwrapRemoteException();
|
||||
}
|
||||
if (e instanceof CallQueueTooBigException) {
|
||||
// Give a special check on CallQueueTooBigException, see #HBASE-17114
|
||||
pauseBase = this.pauseForCQTBE;
|
||||
}
|
||||
if (tries < maxAttempts - 1) {
|
||||
LOG.debug("locateRegionInMeta parentTable='{}', attempt={} of {} failed; retrying " +
|
||||
"after sleep of {}", TableName.META_TABLE_NAME, tries, maxAttempts, maxAttempts, e);
|
||||
LOG.debug(
|
||||
"locateRegionInMeta parentTable='{}', attempt={} of {} failed; retrying "
|
||||
+ "after sleep of {}",
|
||||
TableName.META_TABLE_NAME, tries, maxAttempts, maxAttempts, e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
@ -1068,11 +1062,11 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
} finally {
|
||||
userRegionLock.unlock();
|
||||
}
|
||||
try{
|
||||
try {
|
||||
Thread.sleep(ConnectionUtils.getPauseTime(pauseBase, tries));
|
||||
} catch (InterruptedException e) {
|
||||
throw new InterruptedIOException("Giving up trying to location region in " +
|
||||
"meta: thread is interrupted.");
|
||||
throw new InterruptedIOException(
|
||||
"Giving up trying to location region in " + "meta: thread is interrupted.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1081,8 +1075,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
try {
|
||||
long waitTime = connectionConfig.getMetaOperationTimeout();
|
||||
if (!userRegionLock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {
|
||||
throw new LockTimeoutException("Failed to get user region lock in"
|
||||
+ waitTime + " ms. " + " for accessing meta region server.");
|
||||
throw new LockTimeoutException("Failed to get user region lock in" + waitTime + " ms. "
|
||||
+ " for accessing meta region server.");
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
LOG.error("Interrupted while waiting for a lock", ie);
|
||||
|
@ -1101,12 +1095,11 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Search the cache for a location that fits our table and row key.
|
||||
* Return null if no suitable region is located.
|
||||
* Search the cache for a location that fits our table and row key. Return null if no suitable
|
||||
* region is located.
|
||||
* @return Null or region location found in cache.
|
||||
*/
|
||||
RegionLocations getCachedLocation(final TableName tableName,
|
||||
final byte [] row) {
|
||||
RegionLocations getCachedLocation(final TableName tableName, final byte[] row) {
|
||||
return metaCache.getCachedLocation(tableName, row);
|
||||
}
|
||||
|
||||
|
@ -1180,7 +1173,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
} catch (Exception e) {
|
||||
throw ProtobufUtil.handleRemoteException(e);
|
||||
}
|
||||
return response != null? response.getIsMasterRunning(): false;
|
||||
return response != null ? response.getIsMasterRunning() : false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1189,7 +1182,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
*/
|
||||
static class ServerErrorTracker {
|
||||
// We need a concurrent map here, as we could have multiple threads updating it in parallel.
|
||||
private final ConcurrentMap<ServerName, ServerErrors> errorsByServer = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<ServerName, ServerErrors> errorsByServer =
|
||||
new ConcurrentHashMap<>();
|
||||
private final long canRetryUntil;
|
||||
private final int maxTries;// max number to try
|
||||
private final long startTrackingTime;
|
||||
|
@ -1211,13 +1205,12 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
*/
|
||||
boolean canTryMore(int numAttempt) {
|
||||
// If there is a single try we must not take into account the time.
|
||||
return numAttempt < maxTries || (maxTries > 1 &&
|
||||
EnvironmentEdgeManager.currentTime() < this.canRetryUntil);
|
||||
return numAttempt < maxTries
|
||||
|| (maxTries > 1 && EnvironmentEdgeManager.currentTime() < this.canRetryUntil);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the back-off time for a retrying request to a particular server.
|
||||
*
|
||||
* @param server The server in question.
|
||||
* @param basePause The default hci pause.
|
||||
* @return The time to wait before sending next request.
|
||||
|
@ -1292,8 +1285,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
throw new MasterNotRunningException(sn + " is dead.");
|
||||
}
|
||||
// Use the security info interface name as our stub key
|
||||
String key =
|
||||
getStubKey(MasterProtos.MasterService.getDescriptor().getName(), sn);
|
||||
String key = getStubKey(MasterProtos.MasterService.getDescriptor().getName(), sn);
|
||||
MasterProtos.MasterService.BlockingInterface stub =
|
||||
(MasterProtos.MasterService.BlockingInterface) computeIfAbsentEx(stubs, key, () -> {
|
||||
BlockingRpcChannel channel = rpcClient.createBlockingRpcChannel(sn, user, rpcTimeout);
|
||||
|
@ -1355,8 +1347,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
if (isDeadServer(serverName)) {
|
||||
throw new RegionServerStoppedException(serverName + " is dead.");
|
||||
}
|
||||
String key = getStubKey(ClientProtos.ClientService.BlockingInterface.class.getName(),
|
||||
serverName);
|
||||
String key =
|
||||
getStubKey(ClientProtos.ClientService.BlockingInterface.class.getName(), serverName);
|
||||
return (ClientProtos.ClientService.BlockingInterface) computeIfAbsentEx(stubs, key, () -> {
|
||||
BlockingRpcChannel channel =
|
||||
this.rpcClient.createBlockingRpcChannel(serverName, user, rpcTimeout);
|
||||
|
@ -1389,44 +1381,38 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
MasterServiceState mss = masterServiceState;
|
||||
|
||||
@Override
|
||||
public MasterProtos.AbortProcedureResponse abortProcedure(
|
||||
RpcController controller,
|
||||
public MasterProtos.AbortProcedureResponse abortProcedure(RpcController controller,
|
||||
MasterProtos.AbortProcedureRequest request) throws ServiceException {
|
||||
return stub.abortProcedure(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.GetProceduresResponse getProcedures(
|
||||
RpcController controller,
|
||||
public MasterProtos.GetProceduresResponse getProcedures(RpcController controller,
|
||||
MasterProtos.GetProceduresRequest request) throws ServiceException {
|
||||
return stub.getProcedures(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.GetLocksResponse getLocks(
|
||||
RpcController controller,
|
||||
public MasterProtos.GetLocksResponse getLocks(RpcController controller,
|
||||
MasterProtos.GetLocksRequest request) throws ServiceException {
|
||||
return stub.getLocks(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.AddColumnResponse addColumn(
|
||||
RpcController controller,
|
||||
public MasterProtos.AddColumnResponse addColumn(RpcController controller,
|
||||
MasterProtos.AddColumnRequest request) throws ServiceException {
|
||||
return stub.addColumn(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.DeleteColumnResponse deleteColumn(RpcController controller,
|
||||
MasterProtos.DeleteColumnRequest request)
|
||||
throws ServiceException {
|
||||
MasterProtos.DeleteColumnRequest request) throws ServiceException {
|
||||
return stub.deleteColumn(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.ModifyColumnResponse modifyColumn(RpcController controller,
|
||||
MasterProtos.ModifyColumnRequest request)
|
||||
throws ServiceException {
|
||||
MasterProtos.ModifyColumnRequest request) throws ServiceException {
|
||||
return stub.modifyColumn(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1437,9 +1423,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.MergeTableRegionsResponse mergeTableRegions(
|
||||
RpcController controller, MasterProtos.MergeTableRegionsRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.MergeTableRegionsResponse mergeTableRegions(RpcController controller,
|
||||
MasterProtos.MergeTableRegionsRequest request) throws ServiceException {
|
||||
return stub.mergeTableRegions(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1517,8 +1502,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
|
||||
@Override
|
||||
public MasterProtos.IsInMaintenanceModeResponse isMasterInMaintenanceMode(
|
||||
final RpcController controller,
|
||||
final MasterProtos.IsInMaintenanceModeRequest request) throws ServiceException {
|
||||
final RpcController controller, final MasterProtos.IsInMaintenanceModeRequest request)
|
||||
throws ServiceException {
|
||||
return stub.isMasterInMaintenanceMode(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1529,22 +1514,20 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.SetBalancerRunningResponse setBalancerRunning(
|
||||
RpcController controller, MasterProtos.SetBalancerRunningRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.SetBalancerRunningResponse setBalancerRunning(RpcController controller,
|
||||
MasterProtos.SetBalancerRunningRequest request) throws ServiceException {
|
||||
return stub.setBalancerRunning(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NormalizeResponse normalize(RpcController controller,
|
||||
NormalizeRequest request) throws ServiceException {
|
||||
public NormalizeResponse normalize(RpcController controller, NormalizeRequest request)
|
||||
throws ServiceException {
|
||||
return stub.normalize(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetNormalizerRunningResponse setNormalizerRunning(
|
||||
RpcController controller, SetNormalizerRunningRequest request)
|
||||
throws ServiceException {
|
||||
public SetNormalizerRunningResponse setNormalizerRunning(RpcController controller,
|
||||
SetNormalizerRunningRequest request) throws ServiceException {
|
||||
return stub.setNormalizerRunning(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1570,8 +1553,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
|
||||
@Override
|
||||
public MasterProtos.RunCleanerChoreResponse runCleanerChore(RpcController controller,
|
||||
MasterProtos.RunCleanerChoreRequest request)
|
||||
throws ServiceException {
|
||||
MasterProtos.RunCleanerChoreRequest request) throws ServiceException {
|
||||
return stub.runCleanerChore(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1590,9 +1572,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ClientProtos.CoprocessorServiceResponse execMasterService(
|
||||
RpcController controller, ClientProtos.CoprocessorServiceRequest request)
|
||||
throws ServiceException {
|
||||
public ClientProtos.CoprocessorServiceResponse execMasterService(RpcController controller,
|
||||
ClientProtos.CoprocessorServiceRequest request) throws ServiceException {
|
||||
return stub.execMasterService(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1622,16 +1603,14 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.RestoreSnapshotResponse restoreSnapshot(
|
||||
RpcController controller, MasterProtos.RestoreSnapshotRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.RestoreSnapshotResponse restoreSnapshot(RpcController controller,
|
||||
MasterProtos.RestoreSnapshotRequest request) throws ServiceException {
|
||||
return stub.restoreSnapshot(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.SetSnapshotCleanupResponse switchSnapshotCleanup(
|
||||
RpcController controller, MasterProtos.SetSnapshotCleanupRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.SetSnapshotCleanupResponse switchSnapshotCleanup(RpcController controller,
|
||||
MasterProtos.SetSnapshotCleanupRequest request) throws ServiceException {
|
||||
return stub.switchSnapshotCleanup(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1643,16 +1622,14 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.ExecProcedureResponse execProcedure(
|
||||
RpcController controller, MasterProtos.ExecProcedureRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.ExecProcedureResponse execProcedure(RpcController controller,
|
||||
MasterProtos.ExecProcedureRequest request) throws ServiceException {
|
||||
return stub.execProcedure(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.ExecProcedureResponse execProcedureWithRet(
|
||||
RpcController controller, MasterProtos.ExecProcedureRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.ExecProcedureResponse execProcedureWithRet(RpcController controller,
|
||||
MasterProtos.ExecProcedureRequest request) throws ServiceException {
|
||||
return stub.execProcedureWithRet(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1669,51 +1646,46 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.IsMasterRunningResponse isMasterRunning(
|
||||
RpcController controller, MasterProtos.IsMasterRunningRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.IsMasterRunningResponse isMasterRunning(RpcController controller,
|
||||
MasterProtos.IsMasterRunningRequest request) throws ServiceException {
|
||||
return stub.isMasterRunning(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.ModifyNamespaceResponse modifyNamespace(RpcController controller,
|
||||
MasterProtos.ModifyNamespaceRequest request)
|
||||
throws ServiceException {
|
||||
MasterProtos.ModifyNamespaceRequest request) throws ServiceException {
|
||||
return stub.modifyNamespace(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.CreateNamespaceResponse createNamespace(
|
||||
RpcController controller,
|
||||
public MasterProtos.CreateNamespaceResponse createNamespace(RpcController controller,
|
||||
MasterProtos.CreateNamespaceRequest request) throws ServiceException {
|
||||
return stub.createNamespace(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.DeleteNamespaceResponse deleteNamespace(
|
||||
RpcController controller,
|
||||
public MasterProtos.DeleteNamespaceResponse deleteNamespace(RpcController controller,
|
||||
MasterProtos.DeleteNamespaceRequest request) throws ServiceException {
|
||||
return stub.deleteNamespace(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.ListNamespacesResponse listNamespaces(
|
||||
RpcController controller,
|
||||
public MasterProtos.ListNamespacesResponse listNamespaces(RpcController controller,
|
||||
MasterProtos.ListNamespacesRequest request) throws ServiceException {
|
||||
return stub.listNamespaces(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.GetNamespaceDescriptorResponse getNamespaceDescriptor(
|
||||
RpcController controller,
|
||||
MasterProtos.GetNamespaceDescriptorRequest request) throws ServiceException {
|
||||
RpcController controller, MasterProtos.GetNamespaceDescriptorRequest request)
|
||||
throws ServiceException {
|
||||
return stub.getNamespaceDescriptor(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.ListNamespaceDescriptorsResponse listNamespaceDescriptors(
|
||||
RpcController controller,
|
||||
MasterProtos.ListNamespaceDescriptorsRequest request) throws ServiceException {
|
||||
RpcController controller, MasterProtos.ListNamespaceDescriptorsRequest request)
|
||||
throws ServiceException {
|
||||
return stub.listNamespaceDescriptors(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1732,9 +1704,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.GetTableStateResponse getTableState(
|
||||
RpcController controller, MasterProtos.GetTableStateRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.GetTableStateResponse getTableState(RpcController controller,
|
||||
MasterProtos.GetTableStateRequest request) throws ServiceException {
|
||||
return stub.getTableState(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1751,30 +1722,26 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.GetTableDescriptorsResponse getTableDescriptors(
|
||||
RpcController controller, MasterProtos.GetTableDescriptorsRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.GetTableDescriptorsResponse getTableDescriptors(RpcController controller,
|
||||
MasterProtos.GetTableDescriptorsRequest request) throws ServiceException {
|
||||
return stub.getTableDescriptors(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.GetTableNamesResponse getTableNames(
|
||||
RpcController controller, MasterProtos.GetTableNamesRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.GetTableNamesResponse getTableNames(RpcController controller,
|
||||
MasterProtos.GetTableNamesRequest request) throws ServiceException {
|
||||
return stub.getTableNames(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.GetClusterStatusResponse getClusterStatus(
|
||||
RpcController controller, MasterProtos.GetClusterStatusRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.GetClusterStatusResponse getClusterStatus(RpcController controller,
|
||||
MasterProtos.GetClusterStatusRequest request) throws ServiceException {
|
||||
return stub.getClusterStatus(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterProtos.SetQuotaResponse setQuota(
|
||||
RpcController controller, MasterProtos.SetQuotaRequest request)
|
||||
throws ServiceException {
|
||||
public MasterProtos.SetQuotaResponse setQuota(RpcController controller,
|
||||
MasterProtos.SetQuotaRequest request) throws ServiceException {
|
||||
return stub.setQuota(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1849,8 +1816,9 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ListDecommissionedRegionServersResponse listDecommissionedRegionServers(RpcController controller,
|
||||
ListDecommissionedRegionServersRequest request) throws ServiceException {
|
||||
public ListDecommissionedRegionServersResponse listDecommissionedRegionServers(
|
||||
RpcController controller, ListDecommissionedRegionServersRequest request)
|
||||
throws ServiceException {
|
||||
return stub.listDecommissionedRegionServers(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1861,9 +1829,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public RecommissionRegionServerResponse recommissionRegionServer(
|
||||
RpcController controller, RecommissionRegionServerRequest request)
|
||||
throws ServiceException {
|
||||
public RecommissionRegionServerResponse recommissionRegionServer(RpcController controller,
|
||||
RecommissionRegionServerRequest request) throws ServiceException {
|
||||
return stub.recommissionRegionServer(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1887,15 +1854,14 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GetSpaceQuotaRegionSizesResponse getSpaceQuotaRegionSizes(
|
||||
RpcController controller, GetSpaceQuotaRegionSizesRequest request)
|
||||
throws ServiceException {
|
||||
public GetSpaceQuotaRegionSizesResponse getSpaceQuotaRegionSizes(RpcController controller,
|
||||
GetSpaceQuotaRegionSizesRequest request) throws ServiceException {
|
||||
return stub.getSpaceQuotaRegionSizes(controller, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetQuotaStatesResponse getQuotaStates(
|
||||
RpcController controller, GetQuotaStatesRequest request) throws ServiceException {
|
||||
public GetQuotaStatesResponse getQuotaStates(RpcController controller,
|
||||
GetQuotaStatesRequest request) throws ServiceException {
|
||||
return stub.getQuotaStates(controller, request);
|
||||
}
|
||||
|
||||
|
@ -1971,12 +1937,12 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
|
||||
private static void release(MasterServiceState mss) {
|
||||
if (mss != null && mss.connection != null) {
|
||||
((ConnectionImplementation)mss.connection).releaseMaster(mss);
|
||||
((ConnectionImplementation) mss.connection).releaseMaster(mss);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isKeepAliveMasterConnectedAndRunning(MasterServiceState mss) {
|
||||
if (mss.getStub() == null){
|
||||
if (mss.getStub() == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
|
@ -2030,19 +1996,19 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Update the location with the new value (if the exception is a RegionMovedException)
|
||||
* or delete it from the cache. Does nothing if we can be sure from the exception that
|
||||
* the location is still accurate, or if the cache has already been updated.
|
||||
* @param exception an object (to simplify user code) on which we will try to find a nested
|
||||
* or wrapped or both RegionMovedException
|
||||
* Update the location with the new value (if the exception is a RegionMovedException) or delete
|
||||
* it from the cache. Does nothing if we can be sure from the exception that the location is still
|
||||
* accurate, or if the cache has already been updated.
|
||||
* @param exception an object (to simplify user code) on which we will try to find a nested or
|
||||
* wrapped or both RegionMovedException
|
||||
* @param source server that is the source of the location update.
|
||||
*/
|
||||
@Override
|
||||
public void updateCachedLocations(final TableName tableName, byte[] regionName, byte[] rowkey,
|
||||
final Object exception, final ServerName source) {
|
||||
if (rowkey == null || tableName == null) {
|
||||
LOG.warn("Coding error, see method javadoc. row=" + (rowkey == null ? "null" : rowkey) +
|
||||
", tableName=" + (tableName == null ? "null" : tableName));
|
||||
LOG.warn("Coding error, see method javadoc. row=" + (rowkey == null ? "null" : rowkey)
|
||||
+ ", tableName=" + (tableName == null ? "null" : tableName));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2083,14 +2049,12 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
if (cause instanceof RegionMovedException) {
|
||||
RegionMovedException rme = (RegionMovedException) cause;
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Region " + regionInfo.getRegionNameAsString() + " moved to " +
|
||||
rme.getHostname() + ":" + rme.getPort() +
|
||||
" according to " + source.getAddress());
|
||||
LOG.trace("Region " + regionInfo.getRegionNameAsString() + " moved to "
|
||||
+ rme.getHostname() + ":" + rme.getPort() + " according to " + source.getAddress());
|
||||
}
|
||||
// We know that the region is not anymore on this region server, but we know
|
||||
// the new location.
|
||||
updateCachedLocation(
|
||||
regionInfo, source, rme.getServerName(), rme.getLocationSeqNum());
|
||||
updateCachedLocation(regionInfo, source, rme.getServerName(), rme.getLocationSeqNum());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2127,8 +2091,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
/*
|
||||
* Return the number of cached region for a table. It will only be called
|
||||
* from a unit test.
|
||||
* Return the number of cached region for a table. It will only be called from a unit test.
|
||||
*/
|
||||
int getNumberOfCachedRegionLocations(final TableName tableName) {
|
||||
return metaCache.getNumberOfCachedRegionLocations(tableName);
|
||||
|
@ -2152,7 +2115,7 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isAborted(){
|
||||
public boolean isAborted() {
|
||||
return this.aborted;
|
||||
}
|
||||
|
||||
|
@ -2187,12 +2150,11 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Close the connection for good. On the off chance that someone is unable to close
|
||||
* the connection, perhaps because it bailed out prematurely, the method
|
||||
* below will ensure that this instance is cleaned up.
|
||||
* Caveat: The JVM may take an unknown amount of time to call finalize on an
|
||||
* unreachable object, so our hope is that every consumer cleans up after
|
||||
* itself, like any good citizen.
|
||||
* Close the connection for good. On the off chance that someone is unable to close the
|
||||
* connection, perhaps because it bailed out prematurely, the method below will ensure that this
|
||||
* instance is cleaned up. Caveat: The JVM may take an unknown amount of time to call finalize on
|
||||
* an unreachable object, so our hope is that every consumer cleans up after itself, like any good
|
||||
* citizen.
|
||||
*/
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
|
@ -2217,8 +2179,8 @@ public class ConnectionImplementation implements ClusterConnection, Closeable {
|
|||
|
||||
@Override
|
||||
public RpcRetryingCallerFactory getNewRpcRetryingCallerFactory(Configuration conf) {
|
||||
return RpcRetryingCallerFactory
|
||||
.instantiate(conf, this.interceptor, this.getStatisticsTracker());
|
||||
return RpcRetryingCallerFactory.instantiate(conf, this.interceptor,
|
||||
this.getStatisticsTracker());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,6 +26,7 @@ import static org.apache.hadoop.hbase.client.ConnectionUtils.validatePutsInRowMu
|
|||
import static org.apache.hadoop.hbase.trace.TraceUtil.tracedFuture;
|
||||
import static org.apache.hadoop.hbase.trace.TraceUtil.tracedFutures;
|
||||
import static org.apache.hadoop.hbase.util.FutureUtils.addListener;
|
||||
|
||||
import com.google.protobuf.RpcChannel;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
|
@ -58,9 +59,11 @@ import org.apache.hadoop.hbase.util.ReflectionUtils;
|
|||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
|
||||
import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
|
||||
import org.apache.hbase.thirdparty.io.netty.util.Timer;
|
||||
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.ResponseConverter;
|
||||
|
@ -127,8 +130,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
this.pauseNs = builder.pauseNs;
|
||||
if (builder.pauseForCQTBENs < builder.pauseNs) {
|
||||
LOG.warn(
|
||||
"Configured value of pauseForCQTBENs is {} ms, which is less than" +
|
||||
" the normal pause value {} ms, use the greater one instead",
|
||||
"Configured value of pauseForCQTBENs is {} ms, which is less than"
|
||||
+ " the normal pause value {} ms, use the greater one instead",
|
||||
TimeUnit.NANOSECONDS.toMillis(builder.pauseForCQTBENs),
|
||||
TimeUnit.NANOSECONDS.toMillis(builder.pauseNs));
|
||||
this.pauseForCQTBENs = builder.pauseNs;
|
||||
|
@ -137,8 +140,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
}
|
||||
this.maxAttempts = builder.maxAttempts;
|
||||
this.startLogErrorsCnt = builder.startLogErrorsCnt;
|
||||
this.defaultScannerCaching = tableName.isSystemTable() ? conn.connConf.getMetaScannerCaching() :
|
||||
conn.connConf.getScannerCaching();
|
||||
this.defaultScannerCaching = tableName.isSystemTable() ? conn.connConf.getMetaScannerCaching()
|
||||
: conn.connConf.getScannerCaching();
|
||||
this.defaultScannerMaxResultSize = conn.connConf.getScannerMaxResultSize();
|
||||
}
|
||||
|
||||
|
@ -266,8 +269,7 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
|
||||
@Override
|
||||
public CompletableFuture<Result> get(Get get) {
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(get);
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(get);
|
||||
return tracedFuture(
|
||||
() -> timelineConsistentRead(conn.getLocator(), tableName, get, get.getRow(),
|
||||
RegionLocateType.CURRENT, replicaId -> get(get, replicaId), readRpcTimeoutNs,
|
||||
|
@ -278,20 +280,18 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
@Override
|
||||
public CompletableFuture<Void> put(Put put) {
|
||||
validatePut(put, conn.connConf.getMaxKeyValueSize());
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(put);
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(put);
|
||||
return tracedFuture(() -> this.<Void, Put> newCaller(put, writeRpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> RawAsyncTableImpl.<Put> voidMutate(controller, loc, stub,
|
||||
put, RequestConverter::buildMutateRequest))
|
||||
.call(), supplier);
|
||||
.call(),
|
||||
supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> delete(Delete delete) {
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(delete);
|
||||
return tracedFuture(
|
||||
() -> this.<Void, Delete> newCaller(delete, writeRpcTimeoutNs)
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(delete);
|
||||
return tracedFuture(() -> this.<Void, Delete> newCaller(delete, writeRpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> RawAsyncTableImpl.<Delete> voidMutate(controller, loc,
|
||||
stub, delete, RequestConverter::buildMutateRequest))
|
||||
.call(),
|
||||
|
@ -301,8 +301,7 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
@Override
|
||||
public CompletableFuture<Result> append(Append append) {
|
||||
checkHasFamilies(append);
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(append);
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(append);
|
||||
return tracedFuture(() -> {
|
||||
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
||||
long nonce = conn.getNonceGenerator().newNonce();
|
||||
|
@ -317,14 +316,13 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
@Override
|
||||
public CompletableFuture<Result> increment(Increment increment) {
|
||||
checkHasFamilies(increment);
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(increment);
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(increment);
|
||||
return tracedFuture(() -> {
|
||||
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
||||
long nonce = conn.getNonceGenerator().newNonce();
|
||||
return this.<Result, Increment> newCaller(increment, rpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> this.<Increment, Result> noncedMutate(nonceGroup, nonce,
|
||||
controller, loc, stub, increment, RequestConverter::buildMutateRequest,
|
||||
.action((controller, loc, stub) -> this.<Increment, Result> noncedMutate(nonceGroup,
|
||||
nonce, controller, loc, stub, increment, RequestConverter::buildMutateRequest,
|
||||
RawAsyncTableImpl::toResult))
|
||||
.call();
|
||||
}, supplier);
|
||||
|
@ -351,8 +349,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
|
||||
@Override
|
||||
public CheckAndMutateBuilder qualifier(byte[] qualifier) {
|
||||
this.qualifier = Preconditions.checkNotNull(qualifier, "qualifier is null. Consider using" +
|
||||
" an empty byte array, or just do not call this method if you want a null qualifier");
|
||||
this.qualifier = Preconditions.checkNotNull(qualifier, "qualifier is null. Consider using"
|
||||
+ " an empty byte array, or just do not call this method if you want a null qualifier");
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -377,8 +375,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
}
|
||||
|
||||
private void preCheck() {
|
||||
Preconditions.checkNotNull(op, "condition is null. You need to specify the condition by" +
|
||||
" calling ifNotExists/ifEquals/ifMatches before executing the request");
|
||||
Preconditions.checkNotNull(op, "condition is null. You need to specify the condition by"
|
||||
+ " calling ifNotExists/ifEquals/ifMatches before executing the request");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -404,8 +402,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE)
|
||||
.setContainerOperations(delete);
|
||||
return tracedFuture(
|
||||
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
|
||||
return tracedFuture(() -> RawAsyncTableImpl.this
|
||||
.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, delete,
|
||||
(rn, d) -> RequestConverter.buildMutateRequest(rn, row, family, qualifier, op, value,
|
||||
null, timeRange, d, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||
|
@ -421,8 +419,7 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE)
|
||||
.setContainerOperations(mutations);
|
||||
return tracedFuture(
|
||||
() -> RawAsyncTableImpl.this
|
||||
return tracedFuture(() -> RawAsyncTableImpl.this
|
||||
.<Boolean> newCaller(row, mutations.getMaxPriority(), rpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> RawAsyncTableImpl.this.mutateRow(controller, loc, stub,
|
||||
mutations,
|
||||
|
@ -465,12 +462,11 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE)
|
||||
.setContainerOperations(put);
|
||||
return tracedFuture(
|
||||
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, put.getPriority(), rpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc,
|
||||
stub, put,
|
||||
(rn, p) -> RequestConverter.buildMutateRequest(rn, row, null, null, null, null,
|
||||
filter, timeRange, p, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||
return tracedFuture(() -> RawAsyncTableImpl.this
|
||||
.<Boolean> newCaller(row, put.getPriority(), rpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, put,
|
||||
(rn, p) -> RequestConverter.buildMutateRequest(rn, row, null, null, null, null, filter,
|
||||
timeRange, p, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||
(c, r) -> r.getProcessed()))
|
||||
.call(),
|
||||
supplier);
|
||||
|
@ -481,8 +477,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE)
|
||||
.setContainerOperations(delete);
|
||||
return tracedFuture(
|
||||
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
|
||||
return tracedFuture(() -> RawAsyncTableImpl.this
|
||||
.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, delete,
|
||||
(rn, d) -> RequestConverter.buildMutateRequest(rn, row, null, null, null, null, filter,
|
||||
timeRange, d, HConstants.NO_NONCE, HConstants.NO_NONCE),
|
||||
|
@ -497,8 +493,7 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE)
|
||||
.setContainerOperations(mutations);
|
||||
return tracedFuture(
|
||||
() -> RawAsyncTableImpl.this
|
||||
return tracedFuture(() -> RawAsyncTableImpl.this
|
||||
.<Boolean> newCaller(row, mutations.getMaxPriority(), rpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> RawAsyncTableImpl.this.mutateRow(controller, loc, stub,
|
||||
mutations,
|
||||
|
@ -517,14 +512,12 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
|
||||
@Override
|
||||
public CompletableFuture<CheckAndMutateResult> checkAndMutate(CheckAndMutate checkAndMutate) {
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(checkAndMutate)
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(checkAndMutate)
|
||||
.setContainerOperations(checkAndMutate.getAction());
|
||||
return tracedFuture(() -> {
|
||||
if (checkAndMutate.getAction() instanceof Put ||
|
||||
checkAndMutate.getAction() instanceof Delete ||
|
||||
checkAndMutate.getAction() instanceof Increment ||
|
||||
checkAndMutate.getAction() instanceof Append) {
|
||||
if (checkAndMutate.getAction() instanceof Put || checkAndMutate.getAction() instanceof Delete
|
||||
|| checkAndMutate.getAction() instanceof Increment
|
||||
|| checkAndMutate.getAction() instanceof Append) {
|
||||
Mutation mutation = (Mutation) checkAndMutate.getAction();
|
||||
if (mutation instanceof Put) {
|
||||
validatePut((Put) mutation, conn.connConf.getMaxKeyValueSize());
|
||||
|
@ -548,15 +541,16 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
||||
long nonce = conn.getNonceGenerator().newNonce();
|
||||
return RawAsyncTableImpl.this
|
||||
.<CheckAndMutateResult> newCaller(checkAndMutate.getRow(), rowMutations.getMaxPriority(),
|
||||
rpcTimeoutNs)
|
||||
.<CheckAndMutateResult> newCaller(checkAndMutate.getRow(),
|
||||
rowMutations.getMaxPriority(), rpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> RawAsyncTableImpl.this
|
||||
.<CheckAndMutateResult, CheckAndMutateResult> mutateRow(controller, loc, stub,
|
||||
rowMutations,
|
||||
(rn, rm) -> RequestConverter.buildMultiRequest(rn, checkAndMutate.getRow(),
|
||||
checkAndMutate.getFamily(), checkAndMutate.getQualifier(),
|
||||
checkAndMutate.getCompareOp(), checkAndMutate.getValue(),
|
||||
checkAndMutate.getFilter(), checkAndMutate.getTimeRange(), rm, nonceGroup, nonce),
|
||||
checkAndMutate.getFilter(), checkAndMutate.getTimeRange(), rm, nonceGroup,
|
||||
nonce),
|
||||
resp -> resp))
|
||||
.call();
|
||||
} else {
|
||||
|
@ -571,11 +565,9 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
@Override
|
||||
public List<CompletableFuture<CheckAndMutateResult>>
|
||||
checkAndMutate(List<CheckAndMutate> checkAndMutates) {
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(checkAndMutates)
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(checkAndMutates)
|
||||
.setContainerOperations(checkAndMutates);
|
||||
return tracedFutures(
|
||||
() -> batch(checkAndMutates, rpcTimeoutNs).stream()
|
||||
return tracedFutures(() -> batch(checkAndMutates, rpcTimeoutNs).stream()
|
||||
.map(f -> f.thenApply(r -> (CheckAndMutateResult) r)).collect(toList()),
|
||||
supplier);
|
||||
}
|
||||
|
@ -604,9 +596,11 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
loc.getServerName(), multiResp);
|
||||
Throwable ex = multiResp.getException(regionName);
|
||||
if (ex != null) {
|
||||
future.completeExceptionally(ex instanceof IOException ? ex :
|
||||
new IOException(
|
||||
"Failed to mutate row: " + Bytes.toStringBinary(mutation.getRow()), ex));
|
||||
future
|
||||
.completeExceptionally(ex instanceof IOException ? ex
|
||||
: new IOException(
|
||||
"Failed to mutate row: " + Bytes.toStringBinary(mutation.getRow()),
|
||||
ex));
|
||||
} else {
|
||||
future.complete(
|
||||
respConverter.apply((RES) multiResp.getResults().get(regionName).result.get(0)));
|
||||
|
@ -628,11 +622,9 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
validatePutsInRowMutations(mutations, conn.connConf.getMaxKeyValueSize());
|
||||
long nonceGroup = conn.getNonceGenerator().getNonceGroup();
|
||||
long nonce = conn.getNonceGenerator().newNonce();
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(mutations)
|
||||
.setContainerOperations(mutations);
|
||||
return tracedFuture(
|
||||
() -> this
|
||||
final Supplier<Span> supplier =
|
||||
newTableOperationSpanBuilder().setOperation(mutations).setContainerOperations(mutations);
|
||||
return tracedFuture(() -> this
|
||||
.<Result> newCaller(mutations.getRow(), mutations.getMaxPriority(), writeRpcTimeoutNs)
|
||||
.action((controller, loc, stub) -> this.<Result, Result> mutateRow(controller, loc, stub,
|
||||
mutations, (rn, rm) -> RequestConverter.buildMultiRequest(rn, rm, nonceGroup, nonce),
|
||||
|
@ -678,9 +670,6 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
|
||||
@Override
|
||||
public CompletableFuture<List<Result>> scanAll(Scan scan) {
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(scan);
|
||||
return tracedFuture(() -> {
|
||||
CompletableFuture<List<Result>> future = new CompletableFuture<>();
|
||||
List<Result> scanResults = new ArrayList<>();
|
||||
scan(scan, new AdvancedScanResultConsumer() {
|
||||
|
@ -701,38 +690,33 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
}
|
||||
});
|
||||
return future;
|
||||
}, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompletableFuture<Result>> get(List<Get> gets) {
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(gets)
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(gets)
|
||||
.setContainerOperations(HBaseSemanticAttributes.Operation.GET);
|
||||
return tracedFutures(() -> batch(gets, readRpcTimeoutNs), supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompletableFuture<Void>> put(List<Put> puts) {
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(puts)
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(puts)
|
||||
.setContainerOperations(HBaseSemanticAttributes.Operation.PUT);
|
||||
return tracedFutures(() -> voidMutate(puts), supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompletableFuture<Void>> delete(List<Delete> deletes) {
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(deletes)
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder().setOperation(deletes)
|
||||
.setContainerOperations(HBaseSemanticAttributes.Operation.DELETE);
|
||||
return tracedFutures(() -> voidMutate(deletes), supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<CompletableFuture<T>> batch(List<? extends Row> actions) {
|
||||
final Supplier<Span> supplier = newTableOperationSpanBuilder()
|
||||
.setOperation(actions)
|
||||
.setContainerOperations(actions);
|
||||
final Supplier<Span> supplier =
|
||||
newTableOperationSpanBuilder().setOperation(actions).setContainerOperations(actions);
|
||||
return tracedFutures(() -> batch(actions, rpcTimeoutNs), supplier);
|
||||
}
|
||||
|
||||
|
@ -853,10 +837,8 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
if (locateFinished(region, endKey, endKeyInclusive)) {
|
||||
locateFinished.set(true);
|
||||
} else {
|
||||
addListener(
|
||||
conn.getLocator().getRegionLocation(tableName, region.getEndKey(), RegionLocateType.CURRENT,
|
||||
operationTimeoutNs),
|
||||
(l, e) -> {
|
||||
addListener(conn.getLocator().getRegionLocation(tableName, region.getEndKey(),
|
||||
RegionLocateType.CURRENT, operationTimeoutNs), (l, e) -> {
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
onLocateComplete(stubMaker, callable, callback, locs, endKey, endKeyInclusive,
|
||||
locateFinished, unfinishedRequest, l, e);
|
||||
|
@ -904,9 +886,9 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
@Override
|
||||
public CoprocessorServiceBuilderImpl<S, R> fromRow(byte[] startKey, boolean inclusive) {
|
||||
this.startKey = Preconditions.checkNotNull(startKey,
|
||||
"startKey is null. Consider using" +
|
||||
" an empty byte array, or just do not call this method if you want to start selection" +
|
||||
" from the first region");
|
||||
"startKey is null. Consider using"
|
||||
+ " an empty byte array, or just do not call this method if you want to start selection"
|
||||
+ " from the first region");
|
||||
this.startKeyInclusive = inclusive;
|
||||
return this;
|
||||
}
|
||||
|
@ -914,9 +896,9 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
@Override
|
||||
public CoprocessorServiceBuilderImpl<S, R> toRow(byte[] endKey, boolean inclusive) {
|
||||
this.endKey = Preconditions.checkNotNull(endKey,
|
||||
"endKey is null. Consider using" +
|
||||
" an empty byte array, or just do not call this method if you want to continue" +
|
||||
" selection to the last region");
|
||||
"endKey is null. Consider using"
|
||||
+ " an empty byte array, or just do not call this method if you want to continue"
|
||||
+ " selection to the last region");
|
||||
this.endKeyInclusive = inclusive;
|
||||
return this;
|
||||
}
|
||||
|
@ -924,12 +906,10 @@ class RawAsyncTableImpl implements AsyncTable<AdvancedScanResultConsumer> {
|
|||
@Override
|
||||
public void execute() {
|
||||
final Span span = newTableOperationSpanBuilder()
|
||||
.setOperation(HBaseSemanticAttributes.Operation.COPROC_EXEC)
|
||||
.build();
|
||||
.setOperation(HBaseSemanticAttributes.Operation.COPROC_EXEC).build();
|
||||
try (Scope ignored = span.makeCurrent()) {
|
||||
final RegionLocateType regionLocateType = startKeyInclusive
|
||||
? RegionLocateType.CURRENT
|
||||
: RegionLocateType.AFTER;
|
||||
final RegionLocateType regionLocateType =
|
||||
startKeyInclusive ? RegionLocateType.CURRENT : RegionLocateType.AFTER;
|
||||
final CompletableFuture<HRegionLocation> future = conn.getLocator()
|
||||
.getRegionLocation(tableName, startKey, regionLocateType, operationTimeoutNs);
|
||||
addListener(future, (loc, error) -> {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/**
|
||||
*
|
||||
/*
|
||||
* 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
|
||||
|
@ -24,9 +23,8 @@ import java.io.UncheckedIOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
|
||||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
|
||||
/**
|
||||
* Interface for client-side scanning. Go to {@link Table} to obtain instances.
|
||||
|
@ -50,7 +48,8 @@ public interface ResultScanner extends Closeable, Iterable<Result> {
|
|||
return true;
|
||||
}
|
||||
try {
|
||||
return (next = ResultScanner.this.next()) != null;
|
||||
next = ResultScanner.this.next();
|
||||
return next != null;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
@ -89,7 +88,6 @@ public interface ResultScanner extends Closeable, Iterable<Result> {
|
|||
* @param nbRows number of rows to return
|
||||
* @return Between zero and nbRows rowResults. Scan is done if returned array is of zero-length
|
||||
* (We never return null).
|
||||
* @throws IOException
|
||||
*/
|
||||
default Result[] next(int nbRows) throws IOException {
|
||||
List<Result> resultSets = new ArrayList<>(nbRows);
|
||||
|
|
|
@ -28,6 +28,8 @@ import static org.apache.hadoop.hbase.client.trace.hamcrest.TraceTestUtil.buildT
|
|||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.junit.Assert.fail;
|
||||
|
@ -36,6 +38,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
|||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule;
|
||||
|
@ -44,8 +47,10 @@ import java.io.IOException;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.hbase.Cell;
|
||||
|
@ -75,8 +80,10 @@ import org.junit.Test;
|
|||
import org.junit.experimental.categories.Category;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
|
||||
import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
|
||||
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService;
|
||||
|
@ -105,7 +112,7 @@ public class TestAsyncTableTracing {
|
|||
|
||||
private AsyncConnectionImpl conn;
|
||||
|
||||
private AsyncTable<?> table;
|
||||
private AsyncTable<ScanResultConsumer> table;
|
||||
|
||||
@Rule
|
||||
public OpenTelemetryRule traceRule = OpenTelemetryRule.create();
|
||||
|
@ -175,9 +182,9 @@ public class TestAsyncTableTracing {
|
|||
case INCREMENT:
|
||||
ColumnValue value = req.getColumnValue(0);
|
||||
QualifierValue qvalue = value.getQualifierValue(0);
|
||||
Cell cell = CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
|
||||
.setType(Cell.Type.Put).setRow(req.getRow().toByteArray())
|
||||
.setFamily(value.getFamily().toByteArray())
|
||||
Cell cell =
|
||||
CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY).setType(Cell.Type.Put)
|
||||
.setRow(req.getRow().toByteArray()).setFamily(value.getFamily().toByteArray())
|
||||
.setQualifier(qvalue.getQualifier().toByteArray())
|
||||
.setValue(qvalue.getValue().toByteArray()).build();
|
||||
resp = MutateResponse.newBuilder()
|
||||
|
@ -202,8 +209,7 @@ public class TestAsyncTableTracing {
|
|||
}
|
||||
}).when(stub).get(any(HBaseRpcController.class), any(GetRequest.class), any());
|
||||
final User user = UserProvider.instantiate(CONF).getCurrent();
|
||||
conn = new AsyncConnectionImpl(CONF, new DoNothingConnectionRegistry(CONF), "test",
|
||||
user) {
|
||||
conn = new AsyncConnectionImpl(CONF, new DoNothingConnectionRegistry(CONF), "test", user) {
|
||||
|
||||
@Override
|
||||
AsyncRegionLocator getLocator() {
|
||||
|
@ -249,26 +255,19 @@ public class TestAsyncTableTracing {
|
|||
// n.b. this method implementation must match the one of the same name found in
|
||||
// TestHTableTracing
|
||||
final TableName tableName = table.getName();
|
||||
final Matcher<SpanData> spanLocator = allOf(
|
||||
hasName(containsString(tableOperation)), hasEnded());
|
||||
final Matcher<SpanData> spanLocator =
|
||||
allOf(hasName(containsString(tableOperation)), hasEnded());
|
||||
final String expectedName = tableOperation + " " + tableName.getNameWithNamespaceInclAsString();
|
||||
|
||||
Waiter.waitFor(CONF, 1000, new MatcherPredicate<>(
|
||||
"waiting for span to emit",
|
||||
Waiter.waitFor(CONF, 1000, new MatcherPredicate<>("waiting for span to emit",
|
||||
() -> traceRule.getSpans(), hasItem(spanLocator)));
|
||||
List<SpanData> candidateSpans = traceRule.getSpans()
|
||||
.stream()
|
||||
.filter(spanLocator::matches)
|
||||
.collect(Collectors.toList());
|
||||
List<SpanData> candidateSpans =
|
||||
traceRule.getSpans().stream().filter(spanLocator::matches).collect(Collectors.toList());
|
||||
assertThat(candidateSpans, hasSize(1));
|
||||
SpanData data = candidateSpans.iterator().next();
|
||||
assertThat(data, allOf(
|
||||
hasName(expectedName),
|
||||
hasKind(SpanKind.CLIENT),
|
||||
hasStatusWithCode(StatusCode.OK),
|
||||
buildConnectionAttributesMatcher(conn),
|
||||
buildTableAttributesMatcher(tableName),
|
||||
matcher));
|
||||
assertThat(data,
|
||||
allOf(hasName(expectedName), hasKind(SpanKind.CLIENT), hasStatusWithCode(StatusCode.OK),
|
||||
buildConnectionAttributesMatcher(conn), buildTableAttributesMatcher(tableName), matcher));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -341,9 +340,9 @@ public class TestAsyncTableTracing {
|
|||
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
|
||||
.build(new Delete(Bytes.toBytes(0))))).toArray(new CompletableFuture[0]))
|
||||
.join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf(
|
||||
"db.hbase.container_operations", "CHECK_AND_MUTATE", "DELETE")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations",
|
||||
"CHECK_AND_MUTATE", "DELETE")));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -351,15 +350,14 @@ public class TestAsyncTableTracing {
|
|||
table.checkAndMutateAll(Arrays.asList(CheckAndMutate.newBuilder(Bytes.toBytes(0))
|
||||
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
|
||||
.build(new Delete(Bytes.toBytes(0))))).join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf(
|
||||
"db.hbase.container_operations", "CHECK_AND_MUTATE", "DELETE")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations",
|
||||
"CHECK_AND_MUTATE", "DELETE")));
|
||||
}
|
||||
|
||||
private void testCheckAndMutateBuilder(Row op) {
|
||||
AsyncTable.CheckAndMutateBuilder builder =
|
||||
table.checkAndMutate(Bytes.toBytes(0), Bytes.toBytes("cf"))
|
||||
.qualifier(Bytes.toBytes("cq"))
|
||||
table.checkAndMutate(Bytes.toBytes(0), Bytes.toBytes("cf")).qualifier(Bytes.toBytes("cq"))
|
||||
.ifEquals(Bytes.toBytes("v"));
|
||||
if (op instanceof Put) {
|
||||
Put put = (Put) op;
|
||||
|
@ -378,8 +376,8 @@ public class TestAsyncTableTracing {
|
|||
|
||||
@Test
|
||||
public void testCheckAndMutateBuilderThenPut() {
|
||||
Put put = new Put(Bytes.toBytes(0))
|
||||
.addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"), Bytes.toBytes("v"));
|
||||
Put put = new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"),
|
||||
Bytes.toBytes("v"));
|
||||
testCheckAndMutateBuilder(put);
|
||||
}
|
||||
|
||||
|
@ -390,9 +388,10 @@ public class TestAsyncTableTracing {
|
|||
|
||||
@Test
|
||||
public void testCheckAndMutateBuilderThenMutations() throws IOException {
|
||||
RowMutations mutations = new RowMutations(Bytes.toBytes(0))
|
||||
.add((Mutation) (new Put(Bytes.toBytes(0))
|
||||
.addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"), Bytes.toBytes("v"))))
|
||||
RowMutations mutations =
|
||||
new RowMutations(Bytes.toBytes(0))
|
||||
.add((Mutation) (new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("f"),
|
||||
Bytes.toBytes("cq"), Bytes.toBytes("v"))))
|
||||
.add((Mutation) new Delete(Bytes.toBytes(0)));
|
||||
testCheckAndMutateBuilder(mutations);
|
||||
}
|
||||
|
@ -418,8 +417,8 @@ public class TestAsyncTableTracing {
|
|||
|
||||
@Test
|
||||
public void testCheckAndMutateWithFilterBuilderThenPut() {
|
||||
Put put = new Put(Bytes.toBytes(0))
|
||||
.addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"), Bytes.toBytes("v"));
|
||||
Put put = new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"),
|
||||
Bytes.toBytes("v"));
|
||||
testCheckAndMutateWithFilterBuilder(put);
|
||||
}
|
||||
|
||||
|
@ -430,18 +429,20 @@ public class TestAsyncTableTracing {
|
|||
|
||||
@Test
|
||||
public void testCheckAndMutateWithFilterBuilderThenMutations() throws IOException {
|
||||
RowMutations mutations = new RowMutations(Bytes.toBytes(0))
|
||||
.add((Mutation) new Put(Bytes.toBytes(0))
|
||||
.addColumn(Bytes.toBytes("f"), Bytes.toBytes("cq"), Bytes.toBytes("v")))
|
||||
RowMutations mutations =
|
||||
new RowMutations(Bytes.toBytes(0))
|
||||
.add((Mutation) new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("f"),
|
||||
Bytes.toBytes("cq"), Bytes.toBytes("v")))
|
||||
.add((Mutation) new Delete(Bytes.toBytes(0)));
|
||||
testCheckAndMutateWithFilterBuilder(mutations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMutateRow() throws IOException {
|
||||
final RowMutations mutations = new RowMutations(Bytes.toBytes(0))
|
||||
.add((Mutation) new Put(Bytes.toBytes(0))
|
||||
.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v")))
|
||||
final RowMutations mutations =
|
||||
new RowMutations(Bytes.toBytes(0))
|
||||
.add((Mutation) new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"),
|
||||
Bytes.toBytes("cq"), Bytes.toBytes("v")))
|
||||
.add((Mutation) new Delete(Bytes.toBytes(0)));
|
||||
table.mutateRow(mutations).join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
|
@ -454,37 +455,88 @@ public class TestAsyncTableTracing {
|
|||
assertTrace("SCAN");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScan() throws Throwable {
|
||||
final CountDownLatch doneSignal = new CountDownLatch(1);
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
final AtomicReference<Throwable> throwable = new AtomicReference<>();
|
||||
final Scan scan = new Scan().setCaching(1).setMaxResultSize(1).setLimit(1);
|
||||
table.scan(scan, new ScanResultConsumer() {
|
||||
@Override
|
||||
public boolean onNext(Result result) {
|
||||
if (result.getRow() != null) {
|
||||
count.incrementAndGet();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable error) {
|
||||
throwable.set(error);
|
||||
doneSignal.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
doneSignal.countDown();
|
||||
}
|
||||
});
|
||||
doneSignal.await();
|
||||
if (throwable.get() != null) {
|
||||
throw throwable.get();
|
||||
}
|
||||
assertThat("user code did not run. check test setup.", count.get(), greaterThan(0));
|
||||
assertTrace("SCAN");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetScanner() {
|
||||
final Scan scan = new Scan().setCaching(1).setMaxResultSize(1).setLimit(1);
|
||||
try (ResultScanner scanner = table.getScanner(scan)) {
|
||||
int count = 0;
|
||||
for (Result result : scanner) {
|
||||
if (result.getRow() != null) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
// do something with it.
|
||||
assertThat(count, greaterThanOrEqualTo(0));
|
||||
}
|
||||
assertTrace("SCAN");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExistsList() {
|
||||
CompletableFuture
|
||||
.allOf(
|
||||
table.exists(Arrays.asList(new Get(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
||||
.join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExistsAll() {
|
||||
table.existsAll(Arrays.asList(new Get(Bytes.toBytes(0)))).join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetList() {
|
||||
CompletableFuture
|
||||
.allOf(table.get(Arrays.asList(new Get(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
||||
.allOf(
|
||||
table.get(Arrays.asList(new Get(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
||||
.join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAll() {
|
||||
table.getAll(Arrays.asList(new Get(Bytes.toBytes(0)))).join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -493,49 +545,47 @@ public class TestAsyncTableTracing {
|
|||
.allOf(table.put(Arrays.asList(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"),
|
||||
Bytes.toBytes("cq"), Bytes.toBytes("v")))).toArray(new CompletableFuture[0]))
|
||||
.join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "PUT")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "PUT")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutAll() {
|
||||
table.putAll(Arrays.asList(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"),
|
||||
Bytes.toBytes("cq"), Bytes.toBytes("v")))).join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "PUT")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "PUT")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteList() {
|
||||
CompletableFuture
|
||||
.allOf(
|
||||
CompletableFuture.allOf(
|
||||
table.delete(Arrays.asList(new Delete(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
||||
.join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAll() {
|
||||
table.deleteAll(Arrays.asList(new Delete(Bytes.toBytes(0)))).join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatch() {
|
||||
CompletableFuture
|
||||
.allOf(
|
||||
CompletableFuture.allOf(
|
||||
table.batch(Arrays.asList(new Delete(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
|
||||
.join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchAll() {
|
||||
table.batchAll(Arrays.asList(new Delete(Bytes.toBytes(0)))).join();
|
||||
assertTrace("BATCH", hasAttributes(
|
||||
containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
|
||||
assertTrace("BATCH",
|
||||
hasAttributes(containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,15 +17,19 @@
|
|||
*/
|
||||
package org.apache.hadoop.hbase.client.trace.hamcrest;
|
||||
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.AttributesMatchers.containsEntry;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.sdk.trace.data.EventData;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.FeatureMatcher;
|
||||
import org.hamcrest.Matcher;
|
||||
|
@ -36,21 +40,22 @@ import org.hamcrest.TypeSafeMatcher;
|
|||
*/
|
||||
public final class SpanDataMatchers {
|
||||
|
||||
private SpanDataMatchers() { }
|
||||
private SpanDataMatchers() {
|
||||
}
|
||||
|
||||
public static Matcher<SpanData> hasAttributes(Matcher<Attributes> matcher) {
|
||||
return new FeatureMatcher<SpanData, Attributes>(
|
||||
matcher, "SpanData having attributes that ", "attributes"
|
||||
) {
|
||||
@Override protected Attributes featureValueOf(SpanData item) {
|
||||
return new FeatureMatcher<SpanData, Attributes>(matcher, "SpanData having attributes that ",
|
||||
"attributes") {
|
||||
@Override
|
||||
protected Attributes featureValueOf(SpanData item) {
|
||||
return item.getAttributes();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<SpanData> hasDuration(Matcher<Duration> matcher) {
|
||||
return new FeatureMatcher<SpanData, Duration>(
|
||||
matcher, "SpanData having duration that ", "duration") {
|
||||
return new FeatureMatcher<SpanData, Duration>(matcher, "SpanData having duration that ",
|
||||
"duration") {
|
||||
@Override
|
||||
protected Duration featureValueOf(SpanData item) {
|
||||
return Duration.ofNanos(item.getEndEpochNanos() - item.getStartEpochNanos());
|
||||
|
@ -60,28 +65,49 @@ public final class SpanDataMatchers {
|
|||
|
||||
public static Matcher<SpanData> hasEnded() {
|
||||
return new TypeSafeMatcher<SpanData>() {
|
||||
@Override protected boolean matchesSafely(SpanData item) {
|
||||
@Override
|
||||
protected boolean matchesSafely(SpanData item) {
|
||||
return item.hasEnded();
|
||||
}
|
||||
@Override public void describeTo(Description description) {
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("SpanData that hasEnded");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<SpanData> hasEvents(Matcher<Iterable<? super EventData>> matcher) {
|
||||
return new FeatureMatcher<SpanData, Iterable<? super EventData>>(
|
||||
matcher, "SpanData having events that", "events") {
|
||||
@Override protected Iterable<? super EventData> featureValueOf(SpanData item) {
|
||||
return new FeatureMatcher<SpanData, Iterable<? super EventData>>(matcher,
|
||||
"SpanData having events that", "events") {
|
||||
@Override
|
||||
protected Iterable<? super EventData> featureValueOf(SpanData item) {
|
||||
return item.getEvents();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<SpanData> hasExceptionWithType(Matcher<? super String> matcher) {
|
||||
return hasException(containsEntry(is(SemanticAttributes.EXCEPTION_TYPE), matcher));
|
||||
}
|
||||
|
||||
public static Matcher<SpanData> hasException(Matcher<? super Attributes> matcher) {
|
||||
return new FeatureMatcher<SpanData, Attributes>(matcher,
|
||||
"SpanData having Exception with Attributes that", "exception attributes") {
|
||||
@Override
|
||||
protected Attributes featureValueOf(SpanData actual) {
|
||||
return actual.getEvents().stream()
|
||||
.filter(e -> Objects.equals(SemanticAttributes.EXCEPTION_EVENT_NAME, e.getName()))
|
||||
.map(EventData::getAttributes).findFirst().orElse(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<SpanData> hasKind(SpanKind kind) {
|
||||
return new FeatureMatcher<SpanData, SpanKind>(
|
||||
equalTo(kind), "SpanData with kind that", "SpanKind") {
|
||||
@Override protected SpanKind featureValueOf(SpanData item) {
|
||||
return new FeatureMatcher<SpanData, SpanKind>(equalTo(kind), "SpanData with kind that",
|
||||
"SpanKind") {
|
||||
@Override
|
||||
protected SpanKind featureValueOf(SpanData item) {
|
||||
return item.getKind();
|
||||
}
|
||||
};
|
||||
|
@ -93,7 +119,8 @@ public final class SpanDataMatchers {
|
|||
|
||||
public static Matcher<SpanData> hasName(Matcher<String> matcher) {
|
||||
return new FeatureMatcher<SpanData, String>(matcher, "SpanKind with a name that", "name") {
|
||||
@Override protected String featureValueOf(SpanData item) {
|
||||
@Override
|
||||
protected String featureValueOf(SpanData item) {
|
||||
return item.getName();
|
||||
}
|
||||
};
|
||||
|
@ -109,9 +136,9 @@ public final class SpanDataMatchers {
|
|||
|
||||
public static Matcher<SpanData> hasParentSpanId(Matcher<String> matcher) {
|
||||
return new FeatureMatcher<SpanData, String>(matcher, "SpanKind with a parentSpanId that",
|
||||
"parentSpanId"
|
||||
) {
|
||||
@Override protected String featureValueOf(SpanData item) {
|
||||
"parentSpanId") {
|
||||
@Override
|
||||
protected String featureValueOf(SpanData item) {
|
||||
return item.getParentSpanId();
|
||||
}
|
||||
};
|
||||
|
@ -120,13 +147,15 @@ public final class SpanDataMatchers {
|
|||
public static Matcher<SpanData> hasStatusWithCode(StatusCode statusCode) {
|
||||
final Matcher<StatusCode> matcher = is(equalTo(statusCode));
|
||||
return new TypeSafeMatcher<SpanData>() {
|
||||
@Override protected boolean matchesSafely(SpanData item) {
|
||||
@Override
|
||||
protected boolean matchesSafely(SpanData item) {
|
||||
final StatusData statusData = item.getStatus();
|
||||
return statusData != null
|
||||
&& statusData.getStatusCode() != null
|
||||
return statusData != null && statusData.getStatusCode() != null
|
||||
&& matcher.matches(statusData.getStatusCode());
|
||||
}
|
||||
@Override public void describeTo(Description description) {
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("SpanData with StatusCode that ").appendDescriptionOf(matcher);
|
||||
}
|
||||
};
|
||||
|
@ -137,9 +166,10 @@ public final class SpanDataMatchers {
|
|||
}
|
||||
|
||||
public static Matcher<SpanData> hasTraceId(Matcher<String> matcher) {
|
||||
return new FeatureMatcher<SpanData, String>(
|
||||
matcher, "SpanData with a traceId that ", "traceId") {
|
||||
@Override protected String featureValueOf(SpanData item) {
|
||||
return new FeatureMatcher<SpanData, String>(matcher, "SpanData with a traceId that ",
|
||||
"traceId") {
|
||||
@Override
|
||||
protected String featureValueOf(SpanData item) {
|
||||
return item.getTraceId();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/**
|
||||
*
|
||||
/*
|
||||
* 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
|
||||
|
@ -20,7 +19,6 @@ package org.apache.hadoop.hbase;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hadoop.hbase.master.HMaster;
|
||||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
|
@ -28,10 +26,9 @@ import org.apache.yetus.audience.InterfaceAudience;
|
|||
/**
|
||||
* Options for starting up a mini cluster (including an hbase, dfs and zookeeper clusters) in test.
|
||||
* The options include HDFS options to build mini dfs cluster, Zookeeper options to build mini zk
|
||||
* cluster, and mostly HBase options to build mini hbase cluster.
|
||||
* cluster, and mostly HBase options to build mini hbase cluster. To create an object, use a
|
||||
* {@link Builder}. Example usage:
|
||||
*
|
||||
* To create an object, use a {@link Builder}.
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* StartMiniClusterOption option = StartMiniClusterOption.builder().
|
||||
* .numMasters(3).rsClass(MyRegionServer.class).createWALDir(true).build();
|
||||
|
@ -42,8 +39,8 @@ import org.apache.yetus.audience.InterfaceAudience;
|
|||
@InterfaceAudience.Public
|
||||
public final class StartMiniClusterOption {
|
||||
/**
|
||||
* Number of masters to start up. We'll start this many hbase masters. If numMasters > 1, you
|
||||
* can find the active/primary master with {@link MiniHBaseCluster#getMaster()}.
|
||||
* Number of masters to start up. We'll start this many hbase masters. If numMasters > 1, you can
|
||||
* find the active/primary master with {@link MiniHBaseCluster#getMaster()}.
|
||||
*/
|
||||
private final int numMasters;
|
||||
|
||||
|
@ -60,9 +57,8 @@ public final class StartMiniClusterOption {
|
|||
private final Class<? extends HMaster> masterClass;
|
||||
|
||||
/**
|
||||
* Number of region servers to start up.
|
||||
* If this value is > 1, then make sure config "hbase.regionserver.info.port" is -1
|
||||
* (i.e. no ui per regionserver) otherwise bind errors.
|
||||
* Number of region servers to start up. If this value is > 1, then make sure config
|
||||
* "hbase.regionserver.info.port" is -1 (i.e. no ui per regionserver) otherwise bind errors.
|
||||
*/
|
||||
private final int numRegionServers;
|
||||
/**
|
||||
|
@ -172,9 +168,9 @@ public final class StartMiniClusterOption {
|
|||
public String toString() {
|
||||
return "StartMiniClusterOption{" + "numMasters=" + numMasters + ", masterClass=" + masterClass
|
||||
+ ", numRegionServers=" + numRegionServers + ", rsPorts=" + StringUtils.join(rsPorts)
|
||||
+ ", rsClass=" + rsClass + ", numDataNodes=" + numDataNodes
|
||||
+ ", dataNodeHosts=" + Arrays.toString(dataNodeHosts) + ", numZkServers=" + numZkServers
|
||||
+ ", createRootDir=" + createRootDir + ", createWALDir=" + createWALDir + '}';
|
||||
+ ", rsClass=" + rsClass + ", numDataNodes=" + numDataNodes + ", dataNodeHosts="
|
||||
+ Arrays.toString(dataNodeHosts) + ", numZkServers=" + numZkServers + ", createRootDir="
|
||||
+ createRootDir + ", createWALDir=" + createWALDir + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,10 +181,9 @@ public final class StartMiniClusterOption {
|
|||
}
|
||||
|
||||
/**
|
||||
* Builder pattern for creating an {@link StartMiniClusterOption}.
|
||||
*
|
||||
* The default values of its fields should be considered public and constant. Changing the default
|
||||
* values may cause other tests fail.
|
||||
* Builder pattern for creating an {@link StartMiniClusterOption}. The default values of its
|
||||
* fields should be considered public and constant. Changing the default values may cause other
|
||||
* tests fail.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private int numMasters = 1;
|
||||
|
@ -210,7 +205,7 @@ public final class StartMiniClusterOption {
|
|||
if (dataNodeHosts != null && dataNodeHosts.length != 0) {
|
||||
numDataNodes = dataNodeHosts.length;
|
||||
}
|
||||
return new StartMiniClusterOption(numMasters,numAlwaysStandByMasters, masterClass,
|
||||
return new StartMiniClusterOption(numMasters, numAlwaysStandByMasters, masterClass,
|
||||
numRegionServers, rsPorts, rsClass, numDataNodes, dataNodeHosts, numZkServers,
|
||||
createRootDir, createWALDir);
|
||||
}
|
||||
|
@ -260,6 +255,10 @@ public final class StartMiniClusterOption {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder numWorkers(int numWorkers) {
|
||||
return numDataNodes(numWorkers).numRegionServers(numWorkers);
|
||||
}
|
||||
|
||||
public Builder createRootDir(boolean createRootDir) {
|
||||
this.createRootDir = createRootDir;
|
||||
return this;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -17,30 +17,91 @@
|
|||
*/
|
||||
package org.apache.hadoop.hbase.client;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
import static org.hamcrest.Matchers.isA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.hbase.ConnectionRule;
|
||||
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||
import org.apache.hadoop.hbase.MatcherPredicate;
|
||||
import org.apache.hadoop.hbase.MiniClusterRule;
|
||||
import org.apache.hadoop.hbase.StartMiniClusterOption;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.Waiter;
|
||||
import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException;
|
||||
import org.apache.hadoop.hbase.trace.OpenTelemetryClassRule;
|
||||
import org.apache.hadoop.hbase.trace.OpenTelemetryTestRule;
|
||||
import org.apache.hadoop.hbase.trace.TraceUtil;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
import org.apache.hadoop.hbase.util.JVMClusterUtil;
|
||||
import org.apache.hadoop.hbase.util.Pair;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.junit.rules.RuleChain;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.rules.TestRule;
|
||||
|
||||
public abstract class AbstractTestAsyncTableScan {
|
||||
|
||||
protected static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||
protected static final OpenTelemetryClassRule otelClassRule = OpenTelemetryClassRule.create();
|
||||
protected static final MiniClusterRule miniClusterRule = MiniClusterRule.newBuilder()
|
||||
.setMiniClusterOption(StartMiniClusterOption.builder().numWorkers(3).build()).build();
|
||||
|
||||
protected static final ConnectionRule connectionRule =
|
||||
ConnectionRule.createAsyncConnectionRule(miniClusterRule::createAsyncConnection);
|
||||
|
||||
private static final class Setup extends ExternalResource {
|
||||
@Override
|
||||
protected void before() throws Throwable {
|
||||
final HBaseTestingUtility testingUtil = miniClusterRule.getTestingUtility();
|
||||
final AsyncConnection conn = connectionRule.getAsyncConnection();
|
||||
|
||||
byte[][] splitKeys = new byte[8][];
|
||||
for (int i = 111; i < 999; i += 111) {
|
||||
splitKeys[i / 111 - 1] = Bytes.toBytes(String.format("%03d", i));
|
||||
}
|
||||
testingUtil.createTable(TABLE_NAME, FAMILY, splitKeys);
|
||||
testingUtil.waitTableAvailable(TABLE_NAME);
|
||||
conn.getTable(TABLE_NAME)
|
||||
.putAll(IntStream.range(0, COUNT)
|
||||
.mapToObj(i -> new Put(Bytes.toBytes(String.format("%03d", i)))
|
||||
.addColumn(FAMILY, CQ1, Bytes.toBytes(i))
|
||||
.addColumn(FAMILY, CQ2, Bytes.toBytes(i * i)))
|
||||
.collect(Collectors.toList()))
|
||||
.get();
|
||||
}
|
||||
}
|
||||
|
||||
@ClassRule
|
||||
public static final TestRule classRule = RuleChain.outerRule(otelClassRule)
|
||||
.around(miniClusterRule).around(connectionRule).around(new Setup());
|
||||
|
||||
@Rule
|
||||
public final OpenTelemetryTestRule otelTestRule = new OpenTelemetryTestRule(otelClassRule);
|
||||
|
||||
@Rule
|
||||
public final TestName testName = new TestName();
|
||||
|
||||
protected static TableName TABLE_NAME = TableName.valueOf("async");
|
||||
|
||||
|
@ -52,53 +113,29 @@ public abstract class AbstractTestAsyncTableScan {
|
|||
|
||||
protected static int COUNT = 1000;
|
||||
|
||||
protected static AsyncConnection ASYNC_CONN;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() throws Exception {
|
||||
TEST_UTIL.startMiniCluster(3);
|
||||
byte[][] splitKeys = new byte[8][];
|
||||
for (int i = 111; i < 999; i += 111) {
|
||||
splitKeys[i / 111 - 1] = Bytes.toBytes(String.format("%03d", i));
|
||||
}
|
||||
TEST_UTIL.createTable(TABLE_NAME, FAMILY, splitKeys);
|
||||
TEST_UTIL.waitTableAvailable(TABLE_NAME);
|
||||
ASYNC_CONN = ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get();
|
||||
ASYNC_CONN.getTable(TABLE_NAME).putAll(IntStream.range(0, COUNT)
|
||||
.mapToObj(i -> new Put(Bytes.toBytes(String.format("%03d", i)))
|
||||
.addColumn(FAMILY, CQ1, Bytes.toBytes(i)).addColumn(FAMILY, CQ2, Bytes.toBytes(i * i)))
|
||||
.collect(Collectors.toList())).get();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() throws Exception {
|
||||
ASYNC_CONN.close();
|
||||
TEST_UTIL.shutdownMiniCluster();
|
||||
}
|
||||
|
||||
protected static Scan createNormalScan() {
|
||||
private static Scan createNormalScan() {
|
||||
return new Scan();
|
||||
}
|
||||
|
||||
protected static Scan createBatchScan() {
|
||||
private static Scan createBatchScan() {
|
||||
return new Scan().setBatch(1);
|
||||
}
|
||||
|
||||
// set a small result size for testing flow control
|
||||
protected static Scan createSmallResultSizeScan() {
|
||||
private static Scan createSmallResultSizeScan() {
|
||||
return new Scan().setMaxResultSize(1);
|
||||
}
|
||||
|
||||
protected static Scan createBatchSmallResultSizeScan() {
|
||||
private static Scan createBatchSmallResultSizeScan() {
|
||||
return new Scan().setBatch(1).setMaxResultSize(1);
|
||||
}
|
||||
|
||||
protected static AsyncTable<?> getRawTable() {
|
||||
return ASYNC_CONN.getTable(TABLE_NAME);
|
||||
private static AsyncTable<?> getRawTable() {
|
||||
return connectionRule.getAsyncConnection().getTable(TABLE_NAME);
|
||||
}
|
||||
|
||||
protected static AsyncTable<?> getTable() {
|
||||
return ASYNC_CONN.getTable(TABLE_NAME, ForkJoinPool.commonPool());
|
||||
private static AsyncTable<?> getTable() {
|
||||
return connectionRule.getAsyncConnection().getTable(TABLE_NAME, ForkJoinPool.commonPool());
|
||||
}
|
||||
|
||||
private static List<Pair<String, Supplier<Scan>>> getScanCreator() {
|
||||
|
@ -132,8 +169,18 @@ public abstract class AbstractTestAsyncTableScan {
|
|||
|
||||
protected abstract List<Result> doScan(Scan scan, int closeAfter) throws Exception;
|
||||
|
||||
/**
|
||||
* Used by implementation classes to assert the correctness of spans produced under test.
|
||||
*/
|
||||
protected abstract void assertTraceContinuity();
|
||||
|
||||
/**
|
||||
* Used by implementation classes to assert the correctness of spans having errors.
|
||||
*/
|
||||
protected abstract void assertTraceError(final Matcher<String> exceptionTypeNameMatcher);
|
||||
|
||||
protected final List<Result> convertFromBatchResult(List<Result> results) {
|
||||
assertTrue(results.size() % 2 == 0);
|
||||
assertEquals(0, results.size() % 2);
|
||||
return IntStream.range(0, results.size() / 2).mapToObj(i -> {
|
||||
try {
|
||||
return Result
|
||||
|
@ -144,15 +191,21 @@ public abstract class AbstractTestAsyncTableScan {
|
|||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected static void waitForSpan(final Matcher<SpanData> parentSpanMatcher) {
|
||||
final Configuration conf = miniClusterRule.getTestingUtility().getConfiguration();
|
||||
Waiter.waitFor(conf, TimeUnit.SECONDS.toMillis(5), new MatcherPredicate<>(
|
||||
"Span for test failed to complete.", otelClassRule::getSpans, hasItem(parentSpanMatcher)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScanAll() throws Exception {
|
||||
List<Result> results = doScan(createScan(), -1);
|
||||
// make sure all scanners are closed at RS side
|
||||
TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream().map(t -> t.getRegionServer())
|
||||
.forEach(
|
||||
rs -> assertEquals(
|
||||
"The scanner count of " + rs.getServerName() + " is " +
|
||||
rs.getRSRpcServices().getScannersCount(),
|
||||
miniClusterRule.getTestingUtility().getHBaseCluster().getRegionServerThreads().stream()
|
||||
.map(JVMClusterUtil.RegionServerThread::getRegionServer)
|
||||
.forEach(rs -> assertEquals(
|
||||
"The scanner count of " + rs.getServerName() + " is "
|
||||
+ rs.getRSRpcServices().getScannersCount(),
|
||||
0, rs.getRSRpcServices().getScannersCount()));
|
||||
assertEquals(COUNT, results.size());
|
||||
IntStream.range(0, COUNT).forEach(i -> {
|
||||
|
@ -170,37 +223,54 @@ public abstract class AbstractTestAsyncTableScan {
|
|||
|
||||
@Test
|
||||
public void testReversedScanAll() throws Exception {
|
||||
List<Result> results = doScan(createScan().setReversed(true), -1);
|
||||
List<Result> results =
|
||||
TraceUtil.trace(() -> doScan(createScan().setReversed(true), -1), testName.getMethodName());
|
||||
assertEquals(COUNT, results.size());
|
||||
IntStream.range(0, COUNT).forEach(i -> assertResultEquals(results.get(i), COUNT - i - 1));
|
||||
assertTraceContinuity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScanNoStopKey() throws Exception {
|
||||
int start = 345;
|
||||
List<Result> results =
|
||||
doScan(createScan().withStartRow(Bytes.toBytes(String.format("%03d", start))), -1);
|
||||
List<Result> results = TraceUtil.trace(
|
||||
() -> doScan(createScan().withStartRow(Bytes.toBytes(String.format("%03d", start))), -1),
|
||||
testName.getMethodName());
|
||||
assertEquals(COUNT - start, results.size());
|
||||
IntStream.range(0, COUNT - start).forEach(i -> assertResultEquals(results.get(i), start + i));
|
||||
assertTraceContinuity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReverseScanNoStopKey() throws Exception {
|
||||
int start = 765;
|
||||
List<Result> results = doScan(
|
||||
createScan().withStartRow(Bytes.toBytes(String.format("%03d", start))).setReversed(true), -1);
|
||||
final Scan scan =
|
||||
createScan().withStartRow(Bytes.toBytes(String.format("%03d", start))).setReversed(true);
|
||||
List<Result> results = TraceUtil.trace(() -> doScan(scan, -1), testName.getMethodName());
|
||||
assertEquals(start + 1, results.size());
|
||||
IntStream.range(0, start + 1).forEach(i -> assertResultEquals(results.get(i), start - i));
|
||||
assertTraceContinuity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScanWrongColumnFamily() throws Exception {
|
||||
try {
|
||||
doScan(createScan().addFamily(Bytes.toBytes("WrongColumnFamily")), -1);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NoSuchColumnFamilyException ||
|
||||
e.getCause() instanceof NoSuchColumnFamilyException);
|
||||
public void testScanWrongColumnFamily() {
|
||||
final Exception e = assertThrows(Exception.class,
|
||||
() -> TraceUtil.trace(
|
||||
() -> doScan(createScan().addFamily(Bytes.toBytes("WrongColumnFamily")), -1),
|
||||
testName.getMethodName()));
|
||||
// hamcrest generic enforcement for `anyOf` is a pain; skip it
|
||||
// but -- don't we always unwrap ExecutionExceptions -- bug?
|
||||
if (e instanceof NoSuchColumnFamilyException) {
|
||||
final NoSuchColumnFamilyException ex = (NoSuchColumnFamilyException) e;
|
||||
assertThat(ex, isA(NoSuchColumnFamilyException.class));
|
||||
} else if (e instanceof ExecutionException) {
|
||||
final ExecutionException ex = (ExecutionException) e;
|
||||
assertThat(ex, allOf(isA(ExecutionException.class),
|
||||
hasProperty("cause", isA(NoSuchColumnFamilyException.class))));
|
||||
} else {
|
||||
fail("Found unexpected Exception " + e);
|
||||
}
|
||||
assertTraceError(endsWith(NoSuchColumnFamilyException.class.getName()));
|
||||
}
|
||||
|
||||
private void testScan(int start, boolean startInclusive, int stop, boolean stopInclusive,
|
||||
|
@ -232,8 +302,8 @@ public abstract class AbstractTestAsyncTableScan {
|
|||
|
||||
private void testReversedScan(int start, boolean startInclusive, int stop, boolean stopInclusive,
|
||||
int limit) throws Exception {
|
||||
Scan scan =
|
||||
createScan().withStartRow(Bytes.toBytes(String.format("%03d", start)), startInclusive)
|
||||
Scan scan = createScan()
|
||||
.withStartRow(Bytes.toBytes(String.format("%03d", start)), startInclusive)
|
||||
.withStopRow(Bytes.toBytes(String.format("%03d", stop)), stopInclusive).setReversed(true);
|
||||
if (limit > 0) {
|
||||
scan.setLimit(limit);
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.hbase.client;
|
||||
|
||||
/**
|
||||
* Advise the scanning infrastructure to collect up to {@code limit} results.
|
||||
*/
|
||||
class LimitedScanResultConsumer extends SimpleScanResultConsumerImpl {
|
||||
|
||||
private final int limit;
|
||||
|
||||
public LimitedScanResultConsumer(int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean onNext(Result result) {
|
||||
return super.onNext(result) && results.size() < limit;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -17,59 +17,15 @@
|
|||
*/
|
||||
package org.apache.hadoop.hbase.client;
|
||||
|
||||
import org.apache.hbase.thirdparty.com.google.common.base.Throwables;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
|
||||
|
||||
final class SimpleScanResultConsumer implements ScanResultConsumer {
|
||||
/**
|
||||
* A simplistic {@link ScanResultConsumer} for use in tests.
|
||||
*/
|
||||
public interface SimpleScanResultConsumer extends ScanResultConsumer {
|
||||
|
||||
private ScanMetrics scanMetrics;
|
||||
List<Result> getAll() throws Exception;
|
||||
|
||||
private final List<Result> results = new ArrayList<>();
|
||||
|
||||
private Throwable error;
|
||||
|
||||
private boolean finished = false;
|
||||
|
||||
@Override
|
||||
public void onScanMetricsCreated(ScanMetrics scanMetrics) {
|
||||
this.scanMetrics = scanMetrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean onNext(Result result) {
|
||||
results.add(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onError(Throwable error) {
|
||||
this.error = error;
|
||||
finished = true;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onComplete() {
|
||||
finished = true;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
public synchronized List<Result> getAll() throws Exception {
|
||||
while (!finished) {
|
||||
wait();
|
||||
}
|
||||
if (error != null) {
|
||||
Throwables.propagateIfPossible(error, Exception.class);
|
||||
throw new Exception(error);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public ScanMetrics getScanMetrics() {
|
||||
return scanMetrics;
|
||||
}
|
||||
ScanMetrics getScanMetrics();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.hbase.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
|
||||
|
||||
import org.apache.hbase.thirdparty.com.google.common.base.Throwables;
|
||||
|
||||
class SimpleScanResultConsumerImpl implements SimpleScanResultConsumer {
|
||||
|
||||
private ScanMetrics scanMetrics;
|
||||
|
||||
protected final List<Result> results = new ArrayList<>();
|
||||
|
||||
private Throwable error;
|
||||
|
||||
private boolean finished = false;
|
||||
|
||||
@Override
|
||||
public void onScanMetricsCreated(ScanMetrics scanMetrics) {
|
||||
this.scanMetrics = scanMetrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean onNext(Result result) {
|
||||
results.add(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onError(Throwable error) {
|
||||
this.error = error;
|
||||
finished = true;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onComplete() {
|
||||
finished = true;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Result> getAll() throws Exception {
|
||||
while (!finished) {
|
||||
wait();
|
||||
}
|
||||
if (error != null) {
|
||||
Throwables.propagateIfPossible(error, Exception.class);
|
||||
throw new Exception(error);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScanMetrics getScanMetrics() {
|
||||
return scanMetrics;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -17,24 +17,41 @@
|
|||
*/
|
||||
package org.apache.hadoop.hbase.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasEnded;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasExceptionWithType;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasName;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasParentSpanId;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasStatusWithCode;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||
import org.apache.hadoop.hbase.client.trace.StringTraceRenderer;
|
||||
import org.apache.hadoop.hbase.testclassification.ClientTests;
|
||||
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.apache.hbase.thirdparty.com.google.common.base.Throwables;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
@Category({ LargeTests.class, ClientTests.class })
|
||||
public class TestAsyncTableScan extends AbstractTestAsyncTableScan {
|
||||
private static final Logger logger = LoggerFactory.getLogger(TestAsyncTableScan.class);
|
||||
|
||||
@ClassRule
|
||||
public static final HBaseClassTestRule CLASS_RULE =
|
||||
|
@ -59,7 +76,7 @@ public class TestAsyncTableScan extends AbstractTestAsyncTableScan {
|
|||
@Override
|
||||
protected List<Result> doScan(Scan scan, int closeAfter) throws Exception {
|
||||
AsyncTable<ScanResultConsumer> table =
|
||||
ASYNC_CONN.getTable(TABLE_NAME, ForkJoinPool.commonPool());
|
||||
connectionRule.getAsyncConnection().getTable(TABLE_NAME, ForkJoinPool.commonPool());
|
||||
List<Result> results;
|
||||
if (closeAfter > 0) {
|
||||
// these tests batch settings with the sample data result in each result being
|
||||
|
@ -68,11 +85,13 @@ public class TestAsyncTableScan extends AbstractTestAsyncTableScan {
|
|||
if (scan.getBatch() > 0) {
|
||||
closeAfter = closeAfter * 2;
|
||||
}
|
||||
LimitedScanResultConsumer consumer = new LimitedScanResultConsumer(closeAfter);
|
||||
TracedScanResultConsumer consumer =
|
||||
new TracedScanResultConsumer(new LimitedScanResultConsumer(closeAfter));
|
||||
table.scan(scan, consumer);
|
||||
results = consumer.getAll();
|
||||
} else {
|
||||
SimpleScanResultConsumer consumer = new SimpleScanResultConsumer();
|
||||
TracedScanResultConsumer consumer =
|
||||
new TracedScanResultConsumer(new SimpleScanResultConsumerImpl());
|
||||
table.scan(scan, consumer);
|
||||
results = consumer.getAll();
|
||||
}
|
||||
|
@ -82,49 +101,77 @@ public class TestAsyncTableScan extends AbstractTestAsyncTableScan {
|
|||
return results;
|
||||
}
|
||||
|
||||
private static class LimitedScanResultConsumer implements ScanResultConsumer {
|
||||
@Override
|
||||
protected void assertTraceContinuity() {
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher =
|
||||
allOf(hasName(parentSpanName), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
private final int limit;
|
||||
|
||||
public LimitedScanResultConsumer(int limit) {
|
||||
this.limit = limit;
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (logger.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(logger::debug);
|
||||
}
|
||||
|
||||
private final List<Result> results = new ArrayList<>();
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
private Throwable error;
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
final String scanOperationSpanId = spans.stream().filter(scanOperationSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
private boolean finished = false;
|
||||
final Matcher<SpanData> onScanMetricsCreatedMatcher =
|
||||
hasName("TracedScanResultConsumer#onScanMetricsCreated");
|
||||
assertThat(spans, hasItem(onScanMetricsCreatedMatcher));
|
||||
spans.stream().filter(onScanMetricsCreatedMatcher::matches).forEach(span -> assertThat(span,
|
||||
allOf(onScanMetricsCreatedMatcher, hasParentSpanId(scanOperationSpanId), hasEnded())));
|
||||
|
||||
@Override
|
||||
public synchronized boolean onNext(Result result) {
|
||||
results.add(result);
|
||||
return results.size() < limit;
|
||||
final Matcher<SpanData> onNextMatcher = hasName("TracedScanResultConsumer#onNext");
|
||||
assertThat(spans, hasItem(onNextMatcher));
|
||||
spans.stream().filter(onNextMatcher::matches)
|
||||
.forEach(span -> assertThat(span, allOf(onNextMatcher, hasParentSpanId(scanOperationSpanId),
|
||||
hasStatusWithCode(StatusCode.OK), hasEnded())));
|
||||
|
||||
final Matcher<SpanData> onCompleteMatcher = hasName("TracedScanResultConsumer#onComplete");
|
||||
assertThat(spans, hasItem(onCompleteMatcher));
|
||||
spans.stream().filter(onCompleteMatcher::matches)
|
||||
.forEach(span -> assertThat(span, allOf(onCompleteMatcher,
|
||||
hasParentSpanId(scanOperationSpanId), hasStatusWithCode(StatusCode.OK), hasEnded())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onError(Throwable error) {
|
||||
this.error = error;
|
||||
finished = true;
|
||||
notifyAll();
|
||||
protected void assertTraceError(Matcher<String> exceptionTypeNameMatcher) {
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher = allOf(hasName(parentSpanName), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (logger.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(logger::debug);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onComplete() {
|
||||
finished = true;
|
||||
notifyAll();
|
||||
}
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
public synchronized List<Result> getAll() throws Exception {
|
||||
while (!finished) {
|
||||
wait();
|
||||
}
|
||||
if (error != null) {
|
||||
Throwables.propagateIfPossible(error, Exception.class);
|
||||
throw new Exception(error);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.ERROR),
|
||||
hasExceptionWithType(exceptionTypeNameMatcher), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
final String scanOperationSpanId = spans.stream().filter(scanOperationSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> onErrorMatcher = hasName("TracedScanResultConsumer#onError");
|
||||
assertThat(spans, hasItem(onErrorMatcher));
|
||||
spans.stream().filter(onErrorMatcher::matches)
|
||||
.forEach(span -> assertThat(span, allOf(onErrorMatcher,
|
||||
hasParentSpanId(scanOperationSpanId), hasStatusWithCode(StatusCode.OK), hasEnded())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,21 +17,40 @@
|
|||
*/
|
||||
package org.apache.hadoop.hbase.client;
|
||||
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasEnded;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasExceptionWithType;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasName;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasParentSpanId;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasStatusWithCode;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||
import org.apache.hadoop.hbase.client.trace.StringTraceRenderer;
|
||||
import org.apache.hadoop.hbase.testclassification.ClientTests;
|
||||
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
@Category({ LargeTests.class, ClientTests.class })
|
||||
public class TestAsyncTableScanAll extends AbstractTestAsyncTableScan {
|
||||
private static final Logger logger = LoggerFactory.getLogger(TestAsyncTableScanAll.class);
|
||||
|
||||
@ClassRule
|
||||
public static final HBaseClassTestRule CLASS_RULE =
|
||||
|
@ -72,4 +91,50 @@ public class TestAsyncTableScanAll extends AbstractTestAsyncTableScan {
|
|||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertTraceContinuity() {
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher =
|
||||
allOf(hasName(parentSpanName), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (logger.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(logger::debug);
|
||||
}
|
||||
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertTraceError(Matcher<String> exceptionTypeNameMatcher) {
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher = allOf(hasName(parentSpanName), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (logger.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(logger::debug);
|
||||
}
|
||||
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.ERROR),
|
||||
hasExceptionWithType(exceptionTypeNameMatcher), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -123,7 +123,7 @@ public class TestAsyncTableScanMetrics {
|
|||
|
||||
private static Pair<List<Result>, ScanMetrics> doScanWithAsyncTableScan(Scan scan)
|
||||
throws Exception {
|
||||
SimpleScanResultConsumer consumer = new SimpleScanResultConsumer();
|
||||
SimpleScanResultConsumerImpl consumer = new SimpleScanResultConsumerImpl();
|
||||
CONN.getTable(TABLE_NAME, ForkJoinPool.commonPool()).scan(scan, consumer);
|
||||
return Pair.newPair(consumer.getAll(), consumer.getScanMetrics());
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -17,23 +17,42 @@
|
|||
*/
|
||||
package org.apache.hadoop.hbase.client;
|
||||
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasEnded;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasExceptionWithType;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasName;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasParentSpanId;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasStatusWithCode;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||
import org.apache.hadoop.hbase.client.trace.StringTraceRenderer;
|
||||
import org.apache.hadoop.hbase.testclassification.ClientTests;
|
||||
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
@Category({ LargeTests.class, ClientTests.class })
|
||||
public class TestAsyncTableScanner extends AbstractTestAsyncTableScan {
|
||||
private static final Logger logger = LoggerFactory.getLogger(TestAsyncTableScanner.class);
|
||||
|
||||
@ClassRule
|
||||
public static final HBaseClassTestRule CLASS_RULE =
|
||||
|
@ -63,7 +82,8 @@ public class TestAsyncTableScanner extends AbstractTestAsyncTableScan {
|
|||
|
||||
@Override
|
||||
protected List<Result> doScan(Scan scan, int closeAfter) throws Exception {
|
||||
AsyncTable<?> table = ASYNC_CONN.getTable(TABLE_NAME, ForkJoinPool.commonPool());
|
||||
AsyncTable<?> table =
|
||||
connectionRule.getAsyncConnection().getTable(TABLE_NAME, ForkJoinPool.commonPool());
|
||||
List<Result> results = new ArrayList<>();
|
||||
// these tests batch settings with the sample data result in each result being
|
||||
// split in two. so we must allow twice the expected results in order to reach
|
||||
|
@ -84,4 +104,49 @@ public class TestAsyncTableScanner extends AbstractTestAsyncTableScan {
|
|||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertTraceContinuity() {
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher =
|
||||
allOf(hasName(parentSpanName), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (logger.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(logger::debug);
|
||||
}
|
||||
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
assertThat(spans,
|
||||
hasItem(allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.OK), hasEnded())));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertTraceError(Matcher<String> exceptionTypeNameMatcher) {
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher = allOf(hasName(parentSpanName), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (logger.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(logger::debug);
|
||||
}
|
||||
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.ERROR),
|
||||
hasExceptionWithType(exceptionTypeNameMatcher), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
* 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
|
||||
|
@ -17,22 +17,42 @@
|
|||
*/
|
||||
package org.apache.hadoop.hbase.client;
|
||||
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasEnded;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasExceptionWithType;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasName;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasParentSpanId;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasStatusWithCode;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||
import org.apache.hadoop.hbase.client.trace.StringTraceRenderer;
|
||||
import org.apache.hadoop.hbase.testclassification.ClientTests;
|
||||
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
@Category({ LargeTests.class, ClientTests.class })
|
||||
public class TestRawAsyncTableScan extends AbstractTestAsyncTableScan {
|
||||
private static final Logger logger = LoggerFactory.getLogger(TestRawAsyncTableScan.class);
|
||||
|
||||
@ClassRule
|
||||
public static final HBaseClassTestRule CLASS_RULE =
|
||||
|
@ -56,8 +76,8 @@ public class TestRawAsyncTableScan extends AbstractTestAsyncTableScan {
|
|||
|
||||
@Override
|
||||
protected List<Result> doScan(Scan scan, int closeAfter) throws Exception {
|
||||
BufferingScanResultConsumer scanConsumer = new BufferingScanResultConsumer();
|
||||
ASYNC_CONN.getTable(TABLE_NAME).scan(scan, scanConsumer);
|
||||
TracedAdvancedScanResultConsumer scanConsumer = new TracedAdvancedScanResultConsumer();
|
||||
connectionRule.getAsyncConnection().getTable(TABLE_NAME).scan(scan, scanConsumer);
|
||||
List<Result> results = new ArrayList<>();
|
||||
// these tests batch settings with the sample data result in each result being
|
||||
// split in two. so we must allow twice the expected results in order to reach
|
||||
|
@ -76,4 +96,79 @@ public class TestRawAsyncTableScan extends AbstractTestAsyncTableScan {
|
|||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertTraceContinuity() {
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher =
|
||||
allOf(hasName(parentSpanName), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (logger.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(logger::debug);
|
||||
}
|
||||
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
final String scanOperationSpanId = spans.stream().filter(scanOperationSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
// RawAsyncTableImpl never invokes the callback to `onScanMetricsCreated` -- bug?
|
||||
final Matcher<SpanData> onScanMetricsCreatedMatcher =
|
||||
hasName("TracedAdvancedScanResultConsumer#onScanMetricsCreated");
|
||||
assertThat(spans, not(hasItem(onScanMetricsCreatedMatcher)));
|
||||
|
||||
final Matcher<SpanData> onNextMatcher = hasName("TracedAdvancedScanResultConsumer#onNext");
|
||||
assertThat(spans, hasItem(onNextMatcher));
|
||||
spans.stream().filter(onNextMatcher::matches)
|
||||
.forEach(span -> assertThat(span, hasParentSpanId(scanOperationSpanId)));
|
||||
assertThat(spans, hasItem(allOf(onNextMatcher, hasParentSpanId(scanOperationSpanId),
|
||||
hasStatusWithCode(StatusCode.OK), hasEnded())));
|
||||
|
||||
final Matcher<SpanData> onCompleteMatcher =
|
||||
hasName("TracedAdvancedScanResultConsumer#onComplete");
|
||||
assertThat(spans, hasItem(onCompleteMatcher));
|
||||
spans.stream().filter(onCompleteMatcher::matches)
|
||||
.forEach(span -> assertThat(span, allOf(onCompleteMatcher,
|
||||
hasParentSpanId(scanOperationSpanId), hasStatusWithCode(StatusCode.OK), hasEnded())));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertTraceError(Matcher<String> exceptionTypeNameMatcher) {
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher = allOf(hasName(parentSpanName), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (logger.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(logger::debug);
|
||||
}
|
||||
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.ERROR),
|
||||
hasExceptionWithType(exceptionTypeNameMatcher), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
final String scanOperationSpanId = spans.stream().filter(scanOperationSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> onCompleteMatcher = hasName("TracedAdvancedScanResultConsumer#onError");
|
||||
assertThat(spans, hasItem(onCompleteMatcher));
|
||||
spans.stream().filter(onCompleteMatcher::matches)
|
||||
.forEach(span -> assertThat(span, allOf(onCompleteMatcher,
|
||||
hasParentSpanId(scanOperationSpanId), hasStatusWithCode(StatusCode.OK), hasEnded())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* 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.hbase.client;
|
||||
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasEnded;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasName;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasParentSpanId;
|
||||
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasStatusWithCode;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.emptyIterable;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.hbase.ConnectionRule;
|
||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||
import org.apache.hadoop.hbase.MatcherPredicate;
|
||||
import org.apache.hadoop.hbase.MiniClusterRule;
|
||||
import org.apache.hadoop.hbase.StartMiniClusterOption;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.Waiter;
|
||||
import org.apache.hadoop.hbase.client.trace.StringTraceRenderer;
|
||||
import org.apache.hadoop.hbase.testclassification.ClientTests;
|
||||
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||
import org.apache.hadoop.hbase.trace.OpenTelemetryClassRule;
|
||||
import org.apache.hadoop.hbase.trace.OpenTelemetryTestRule;
|
||||
import org.apache.hadoop.hbase.trace.TraceUtil;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.junit.rules.RuleChain;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Category({ LargeTests.class, ClientTests.class })
|
||||
public class TestResultScannerTracing {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TestResultScannerTracing.class);
|
||||
|
||||
@ClassRule
|
||||
public static final HBaseClassTestRule CLASS_RULE =
|
||||
HBaseClassTestRule.forClass(TestResultScannerTracing.class);
|
||||
|
||||
private static final TableName TABLE_NAME =
|
||||
TableName.valueOf(TestResultScannerTracing.class.getSimpleName());
|
||||
private static final byte[] FAMILY = Bytes.toBytes("f");
|
||||
private static final byte[] CQ = Bytes.toBytes("q");
|
||||
private static final int COUNT = 1000;
|
||||
|
||||
private static final OpenTelemetryClassRule otelClassRule = OpenTelemetryClassRule.create();
|
||||
private static final MiniClusterRule miniClusterRule = MiniClusterRule.newBuilder()
|
||||
.setMiniClusterOption(StartMiniClusterOption.builder().numRegionServers(3).build()).build();
|
||||
|
||||
private static final ConnectionRule connectionRule =
|
||||
ConnectionRule.createConnectionRule(miniClusterRule::createConnection);
|
||||
|
||||
private static final class Setup extends ExternalResource {
|
||||
|
||||
private Connection conn;
|
||||
|
||||
@Override
|
||||
protected void before() throws Throwable {
|
||||
final HBaseTestingUtility testUtil = miniClusterRule.getTestingUtility();
|
||||
conn = testUtil.getConnection();
|
||||
|
||||
byte[][] splitKeys = new byte[8][];
|
||||
for (int i = 111; i < 999; i += 111) {
|
||||
splitKeys[i / 111 - 1] = Bytes.toBytes(String.format("%03d", i));
|
||||
}
|
||||
testUtil.createTable(TABLE_NAME, FAMILY, splitKeys);
|
||||
testUtil.waitTableAvailable(TABLE_NAME);
|
||||
try (final Table table = conn.getTable(TABLE_NAME)) {
|
||||
table.put(
|
||||
IntStream.range(0, COUNT).mapToObj(i -> new Put(Bytes.toBytes(String.format("%03d", i)))
|
||||
.addColumn(FAMILY, CQ, Bytes.toBytes(i))).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void after() {
|
||||
try (Admin admin = conn.getAdmin()) {
|
||||
if (!admin.tableExists(TABLE_NAME)) {
|
||||
return;
|
||||
}
|
||||
admin.disableTable(TABLE_NAME);
|
||||
admin.deleteTable(TABLE_NAME);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ClassRule
|
||||
public static final TestRule classRule = RuleChain.outerRule(otelClassRule)
|
||||
.around(miniClusterRule).around(connectionRule).around(new Setup());
|
||||
|
||||
@Rule
|
||||
public final OpenTelemetryTestRule otelTestRule = new OpenTelemetryTestRule(otelClassRule);
|
||||
|
||||
@Rule
|
||||
public final TestName testName = new TestName();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
final Connection conn = connectionRule.getConnection();
|
||||
try (final RegionLocator locator = conn.getRegionLocator(TABLE_NAME)) {
|
||||
locator.clearRegionLocationCache();
|
||||
}
|
||||
}
|
||||
|
||||
private static void waitForSpan(final Matcher<SpanData> parentSpanMatcher) {
|
||||
final Configuration conf = miniClusterRule.getTestingUtility().getConfiguration();
|
||||
Waiter.waitFor(conf, TimeUnit.SECONDS.toMillis(5), new MatcherPredicate<>(
|
||||
"Span for test failed to complete.", otelClassRule::getSpans, hasItem(parentSpanMatcher)));
|
||||
}
|
||||
|
||||
private Scan buildDefaultScan() {
|
||||
return new Scan().withStartRow(Bytes.toBytes(String.format("%03d", 1)))
|
||||
.withStopRow(Bytes.toBytes(String.format("%03d", 998)));
|
||||
}
|
||||
|
||||
private void assertDefaultScan(final Scan scan) {
|
||||
assertThat(scan.isReversed(), is(false));
|
||||
assertThat(scan.isAsyncPrefetch(), nullValue());
|
||||
}
|
||||
|
||||
private Scan buildAsyncPrefetchScan() {
|
||||
return new Scan().withStartRow(Bytes.toBytes(String.format("%03d", 1)))
|
||||
.withStopRow(Bytes.toBytes(String.format("%03d", 998))).setAsyncPrefetch(true);
|
||||
}
|
||||
|
||||
private void assertAsyncPrefetchScan(final Scan scan) {
|
||||
assertThat(scan.isReversed(), is(false));
|
||||
assertThat(scan.isAsyncPrefetch(), is(true));
|
||||
}
|
||||
|
||||
private Scan buildReversedScan() {
|
||||
return new Scan().withStartRow(Bytes.toBytes(String.format("%03d", 998)))
|
||||
.withStopRow(Bytes.toBytes(String.format("%03d", 1))).setReversed(true);
|
||||
}
|
||||
|
||||
private void assertReversedScan(final Scan scan) {
|
||||
assertThat(scan.isReversed(), is(true));
|
||||
assertThat(scan.isAsyncPrefetch(), nullValue());
|
||||
}
|
||||
|
||||
private void doScan(final Supplier<Scan> spanSupplier, final Consumer<Scan> scanAssertions)
|
||||
throws Exception {
|
||||
final Connection conn = connectionRule.getConnection();
|
||||
final Scan scan = spanSupplier.get();
|
||||
scanAssertions.accept(scan);
|
||||
try (final Table table = conn.getTable(TABLE_NAME);
|
||||
final ResultScanner scanner = table.getScanner(scan)) {
|
||||
final List<Result> results = new ArrayList<>(COUNT);
|
||||
scanner.forEach(results::add);
|
||||
assertThat(results, not(emptyIterable()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalScan() throws Exception {
|
||||
TraceUtil.trace(() -> doScan(this::buildDefaultScan, this::assertDefaultScan),
|
||||
testName.getMethodName());
|
||||
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher =
|
||||
allOf(hasName(parentSpanName), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (LOG.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(LOG::debug);
|
||||
}
|
||||
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
final String scanOperationSpanId = spans.stream().filter(scanOperationSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> childMetaScanSpanMatcher = allOf(hasName(startsWith("SCAN hbase:meta")),
|
||||
hasParentSpanId(scanOperationSpanId), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
assertThat("expected a scan of hbase:meta", spans, hasItem(childMetaScanSpanMatcher));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAsyncPrefetchScan() throws Exception {
|
||||
TraceUtil.trace(() -> doScan(this::buildAsyncPrefetchScan, this::assertAsyncPrefetchScan),
|
||||
testName.getMethodName());
|
||||
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher =
|
||||
allOf(hasName(parentSpanName), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (LOG.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(LOG::debug);
|
||||
}
|
||||
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
final String scanOperationSpanId = spans.stream().filter(scanOperationSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> childMetaScanSpanMatcher = allOf(hasName(startsWith("SCAN hbase:meta")),
|
||||
hasParentSpanId(scanOperationSpanId), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
assertThat("expected a scan of hbase:meta", spans, hasItem(childMetaScanSpanMatcher));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReversedScan() throws Exception {
|
||||
TraceUtil.trace(() -> doScan(this::buildReversedScan, this::assertReversedScan),
|
||||
testName.getMethodName());
|
||||
|
||||
final String parentSpanName = testName.getMethodName();
|
||||
final Matcher<SpanData> parentSpanMatcher =
|
||||
allOf(hasName(parentSpanName), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
waitForSpan(parentSpanMatcher);
|
||||
|
||||
final List<SpanData> spans =
|
||||
otelClassRule.getSpans().stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (LOG.isDebugEnabled()) {
|
||||
StringTraceRenderer stringTraceRenderer = new StringTraceRenderer(spans);
|
||||
stringTraceRenderer.render(LOG::debug);
|
||||
}
|
||||
|
||||
final String parentSpanId = spans.stream().filter(parentSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> scanOperationSpanMatcher =
|
||||
allOf(hasName(startsWith("SCAN " + TABLE_NAME.getNameWithNamespaceInclAsString())),
|
||||
hasParentSpanId(parentSpanId), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
assertThat(spans, hasItem(scanOperationSpanMatcher));
|
||||
final String scanOperationSpanId = spans.stream().filter(scanOperationSpanMatcher::matches)
|
||||
.map(SpanData::getSpanId).findAny().orElseThrow(AssertionError::new);
|
||||
|
||||
final Matcher<SpanData> childMetaScanSpanMatcher = allOf(hasName(startsWith("SCAN hbase:meta")),
|
||||
hasParentSpanId(scanOperationSpanId), hasStatusWithCode(StatusCode.OK), hasEnded());
|
||||
assertThat("expected a scan of hbase:meta", spans, hasItem(childMetaScanSpanMatcher));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.hbase.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
|
||||
import org.apache.hadoop.hbase.trace.TraceUtil;
|
||||
|
||||
/**
|
||||
* A drop-in replacement for {@link BufferingScanResultConsumer} that adds tracing spans to its
|
||||
* implementation of the {@link AdvancedScanResultConsumer} API.
|
||||
*/
|
||||
public class TracedAdvancedScanResultConsumer implements AdvancedScanResultConsumer {
|
||||
|
||||
private final BufferingScanResultConsumer delegate = new BufferingScanResultConsumer();
|
||||
|
||||
@Override
|
||||
public void onScanMetricsCreated(ScanMetrics scanMetrics) {
|
||||
TraceUtil.trace(() -> delegate.onScanMetricsCreated(scanMetrics),
|
||||
"TracedAdvancedScanResultConsumer#onScanMetricsCreated");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(Result[] results, ScanController controller) {
|
||||
TraceUtil.trace(() -> delegate.onNext(results, controller),
|
||||
"TracedAdvancedScanResultConsumer#onNext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable error) {
|
||||
TraceUtil.trace(() -> delegate.onError(error), "TracedAdvancedScanResultConsumer#onError");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
TraceUtil.trace(delegate::onComplete, "TracedAdvancedScanResultConsumer#onComplete");
|
||||
}
|
||||
|
||||
public Result take() throws IOException, InterruptedException {
|
||||
return delegate.take();
|
||||
}
|
||||
|
||||
public ScanMetrics getScanMetrics() {
|
||||
return delegate.getScanMetrics();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.hbase.client;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
|
||||
import org.apache.hadoop.hbase.trace.TraceUtil;
|
||||
|
||||
/**
|
||||
* A wrapper over {@link SimpleScanResultConsumer} that adds tracing of spans to its implementation.
|
||||
*/
|
||||
class TracedScanResultConsumer implements SimpleScanResultConsumer {
|
||||
|
||||
private final SimpleScanResultConsumer delegate;
|
||||
|
||||
public TracedScanResultConsumer(final SimpleScanResultConsumer delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScanMetricsCreated(ScanMetrics scanMetrics) {
|
||||
TraceUtil.trace(() -> delegate.onScanMetricsCreated(scanMetrics),
|
||||
"TracedScanResultConsumer#onScanMetricsCreated");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNext(Result result) {
|
||||
return TraceUtil.trace(() -> delegate.onNext(result), "TracedScanResultConsumer#onNext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable error) {
|
||||
TraceUtil.trace(() -> delegate.onError(error), "TracedScanResultConsumer#onError");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
TraceUtil.trace(delegate::onComplete, "TracedScanResultConsumer#onComplete");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Result> getAll() throws Exception {
|
||||
return delegate.getAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScanMetrics getScanMetrics() {
|
||||
return delegate.getScanMetrics();
|
||||
}
|
||||
}
|
3
pom.xml
3
pom.xml
|
@ -692,7 +692,8 @@
|
|||
<hbase-surefire.cygwin-argLine>-enableassertions -Xmx${surefire.cygwinXmx}
|
||||
-Djava.security.egd=file:/dev/./urandom -Djava.net.preferIPv4Stack=true
|
||||
"-Djava.library.path=${hadoop.library.path};${java.library.path}"
|
||||
-Dorg.apache.hbase.thirdparty.io.netty.leakDetection.level=advanced</hbase-surefire.cygwin-argLine>
|
||||
-Dorg.apache.hbase.thirdparty.io.netty.leakDetection.level=advanced
|
||||
-Dio.opentelemetry.context.enableStrictContext=true</hbase-surefire.cygwin-argLine>
|
||||
<!-- Surefire argLine defaults to Linux, cygwin argLine is used in the os.windows profile -->
|
||||
<argLine>${hbase-surefire.argLine}</argLine>
|
||||
<jacoco.version>0.7.5.201505241946</jacoco.version>
|
||||
|
|
Loading…
Reference in New Issue