Skip to content

Commit ac1cfbb

Browse files
committed
HBASE-26473 Introduce db.hbase.container_operations span attribute
For batch operations, collect and annotate the associated span with the set of all operations contained in the batch.
1 parent 84ea8e2 commit ac1cfbb

File tree

5 files changed

+156
-32
lines changed

5 files changed

+156
-32
lines changed

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

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ public CompletableFuture<Boolean> thenPut(Put put) {
350350
preCheck();
351351
final Supplier<Span> supplier = new TableOperationSpanBuilder()
352352
.setTableName(tableName)
353-
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
353+
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE)
354+
.setContainerOperations(put);
354355
return tracedFuture(
355356
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, put.getPriority(), rpcTimeoutNs)
356357
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, put,
@@ -366,7 +367,8 @@ public CompletableFuture<Boolean> thenDelete(Delete delete) {
366367
preCheck();
367368
final Supplier<Span> supplier = new TableOperationSpanBuilder()
368369
.setTableName(tableName)
369-
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
370+
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE)
371+
.setContainerOperations(delete);
370372
return tracedFuture(
371373
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
372374
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, delete,
@@ -383,7 +385,8 @@ public CompletableFuture<Boolean> thenMutate(RowMutations mutations) {
383385
validatePutsInRowMutations(mutations, conn.connConf.getMaxKeyValueSize());
384386
final Supplier<Span> supplier = new TableOperationSpanBuilder()
385387
.setTableName(tableName)
386-
.setOperation(HBaseSemanticAttributes.Operation.BATCH);
388+
.setOperation(HBaseSemanticAttributes.Operation.BATCH)
389+
.setContainerOperations(mutations);
387390
return tracedFuture(
388391
() -> RawAsyncTableImpl.this
389392
.<Boolean> newCaller(row, mutations.getMaxPriority(), rpcTimeoutNs)
@@ -427,7 +430,8 @@ public CompletableFuture<Boolean> thenPut(Put put) {
427430
validatePut(put, conn.connConf.getMaxKeyValueSize());
428431
final Supplier<Span> supplier = new TableOperationSpanBuilder()
429432
.setTableName(tableName)
430-
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
433+
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE)
434+
.setContainerOperations(put);
431435
return tracedFuture(
432436
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, put.getPriority(), rpcTimeoutNs)
433437
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc,
@@ -443,7 +447,8 @@ public CompletableFuture<Boolean> thenPut(Put put) {
443447
public CompletableFuture<Boolean> thenDelete(Delete delete) {
444448
final Supplier<Span> supplier = new TableOperationSpanBuilder()
445449
.setTableName(tableName)
446-
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE);
450+
.setOperation(HBaseSemanticAttributes.Operation.CHECK_AND_MUTATE)
451+
.setContainerOperations(delete);
447452
return tracedFuture(
448453
() -> RawAsyncTableImpl.this.<Boolean> newCaller(row, delete.getPriority(), rpcTimeoutNs)
449454
.action((controller, loc, stub) -> RawAsyncTableImpl.mutate(controller, loc, stub, delete,
@@ -459,7 +464,8 @@ public CompletableFuture<Boolean> thenMutate(RowMutations mutations) {
459464
validatePutsInRowMutations(mutations, conn.connConf.getMaxKeyValueSize());
460465
final Supplier<Span> supplier = new TableOperationSpanBuilder()
461466
.setTableName(tableName)
462-
.setOperation(HBaseSemanticAttributes.Operation.BATCH);
467+
.setOperation(HBaseSemanticAttributes.Operation.BATCH)
468+
.setContainerOperations(mutations);
463469
return tracedFuture(
464470
() -> RawAsyncTableImpl.this
465471
.<Boolean> newCaller(row, mutations.getMaxPriority(), rpcTimeoutNs)
@@ -482,7 +488,8 @@ public CheckAndMutateWithFilterBuilder checkAndMutate(byte[] row, Filter filter)
482488
public CompletableFuture<CheckAndMutateResult> checkAndMutate(CheckAndMutate checkAndMutate) {
483489
final Supplier<Span> supplier = new TableOperationSpanBuilder()
484490
.setTableName(tableName)
485-
.setOperation(checkAndMutate);
491+
.setOperation(checkAndMutate)
492+
.setContainerOperations(checkAndMutate.getAction());
486493
return tracedFuture(() -> {
487494
if (checkAndMutate.getAction() instanceof Put ||
488495
checkAndMutate.getAction() instanceof Delete ||
@@ -536,7 +543,8 @@ public CompletableFuture<CheckAndMutateResult> checkAndMutate(CheckAndMutate che
536543
checkAndMutate(List<CheckAndMutate> checkAndMutates) {
537544
final Supplier<Span> supplier = new TableOperationSpanBuilder()
538545
.setTableName(tableName)
539-
.setOperation(HBaseSemanticAttributes.Operation.BATCH);
546+
.setOperation(HBaseSemanticAttributes.Operation.BATCH)
547+
.setContainerOperations(checkAndMutates);
540548
return tracedFutures(
541549
() -> batch(checkAndMutates, rpcTimeoutNs).stream()
542550
.map(f -> f.thenApply(r -> (CheckAndMutateResult) r)).collect(toList()),
@@ -593,7 +601,8 @@ public CompletableFuture<Result> mutateRow(RowMutations mutations) {
593601
long nonce = conn.getNonceGenerator().newNonce();
594602
final Supplier<Span> supplier = new TableOperationSpanBuilder()
595603
.setTableName(tableName)
596-
.setOperation(HBaseSemanticAttributes.Operation.BATCH);
604+
.setOperation(HBaseSemanticAttributes.Operation.BATCH)
605+
.setContainerOperations(mutations);
597606
return tracedFuture(
598607
() -> this
599608
.<Result> newCaller(mutations.getRow(), mutations.getMaxPriority(), writeRpcTimeoutNs)
@@ -668,31 +677,35 @@ public void onComplete() {
668677
public List<CompletableFuture<Result>> get(List<Get> gets) {
669678
final Supplier<Span> supplier = new TableOperationSpanBuilder()
670679
.setTableName(tableName)
671-
.setOperation(HBaseSemanticAttributes.Operation.BATCH);
680+
.setOperation(HBaseSemanticAttributes.Operation.BATCH)
681+
.setContainerOperations(HBaseSemanticAttributes.Operation.GET);
672682
return tracedFutures(() -> batch(gets, readRpcTimeoutNs), supplier);
673683
}
674684

675685
@Override
676686
public List<CompletableFuture<Void>> put(List<Put> puts) {
677687
final Supplier<Span> supplier = new TableOperationSpanBuilder()
678688
.setTableName(tableName)
679-
.setOperation(HBaseSemanticAttributes.Operation.BATCH);
689+
.setOperation(HBaseSemanticAttributes.Operation.BATCH)
690+
.setContainerOperations(HBaseSemanticAttributes.Operation.PUT);
680691
return tracedFutures(() -> voidMutate(puts), supplier);
681692
}
682693

683694
@Override
684695
public List<CompletableFuture<Void>> delete(List<Delete> deletes) {
685696
final Supplier<Span> supplier = new TableOperationSpanBuilder()
686697
.setTableName(tableName)
687-
.setOperation(HBaseSemanticAttributes.Operation.BATCH);
698+
.setOperation(HBaseSemanticAttributes.Operation.BATCH)
699+
.setContainerOperations(HBaseSemanticAttributes.Operation.DELETE);
688700
return tracedFutures(() -> voidMutate(deletes), supplier);
689701
}
690702

691703
@Override
692704
public <T> List<CompletableFuture<T>> batch(List<? extends Row> actions) {
693705
final Supplier<Span> supplier = new TableOperationSpanBuilder()
694706
.setTableName(tableName)
695-
.setOperation(HBaseSemanticAttributes.Operation.BATCH);
707+
.setOperation(HBaseSemanticAttributes.Operation.BATCH)
708+
.setContainerOperations(actions);
696709
return tracedFutures(() -> batch(actions, rpcTimeoutNs), supplier);
697710
}
698711

hbase-client/src/main/java/org/apache/hadoop/hbase/client/trace/TableOperationSpanBuilder.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
package org.apache.hadoop.hbase.client.trace;
2020

21+
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.CONTAINER_DB_OPERATIONS_KEY;
2122
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.DB_NAME;
2223
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.DB_OPERATION;
2324
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.NAMESPACE_KEY;
@@ -26,9 +27,16 @@
2627
import io.opentelemetry.api.trace.Span;
2728
import io.opentelemetry.api.trace.SpanBuilder;
2829
import io.opentelemetry.api.trace.SpanKind;
30+
import java.util.Arrays;
31+
import java.util.Collection;
2932
import java.util.HashMap;
33+
import java.util.HashSet;
34+
import java.util.List;
3035
import java.util.Map;
36+
import java.util.Set;
3137
import java.util.function.Supplier;
38+
import java.util.stream.Collectors;
39+
import java.util.stream.Stream;
3240
import org.apache.hadoop.hbase.TableName;
3341
import org.apache.hadoop.hbase.client.Append;
3442
import org.apache.hadoop.hbase.client.CheckAndMutate;
@@ -76,6 +84,72 @@ public TableOperationSpanBuilder setOperation(final Operation operation) {
7684
return this;
7785
}
7886

87+
// `setContainerOperations` perform a recursive descent expansion of all the operations
88+
// contained within the provided "batch" object.
89+
90+
public TableOperationSpanBuilder setContainerOperations(final RowMutations mutations) {
91+
final Operation[] ops = mutations.getMutations()
92+
.stream()
93+
.flatMap(row -> Stream.concat(Stream.of(valueFrom(row)), unpackRowOperations(row).stream()))
94+
.toArray(Operation[]::new);
95+
return setContainerOperations(ops);
96+
}
97+
98+
public TableOperationSpanBuilder setContainerOperations(final Row row) {
99+
final Operation[] ops =
100+
Stream.concat(Stream.of(valueFrom(row)), unpackRowOperations(row).stream())
101+
.toArray(Operation[]::new);
102+
return setContainerOperations(ops);
103+
}
104+
105+
public TableOperationSpanBuilder setContainerOperations(
106+
final Collection<? extends Row> operations
107+
) {
108+
final Operation[] ops = operations.stream()
109+
.flatMap(row -> Stream.concat(Stream.of(valueFrom(row)), unpackRowOperations(row).stream()))
110+
.toArray(Operation[]::new);
111+
return setContainerOperations(ops);
112+
}
113+
114+
private static Set<Operation> unpackRowOperations(final Row row) {
115+
final Set<Operation> ops = new HashSet<>();
116+
if (row instanceof CheckAndMutate) {
117+
final CheckAndMutate cam = (CheckAndMutate) row;
118+
ops.addAll(unpackRowOperations(cam));
119+
}
120+
if (row instanceof RowMutations) {
121+
final RowMutations mutations = (RowMutations) row;
122+
ops.addAll(unpackRowOperations(mutations));
123+
}
124+
return ops;
125+
}
126+
127+
private static Set<Operation> unpackRowOperations(final CheckAndMutate cam) {
128+
final Set<Operation> ops = new HashSet<>();
129+
final Operation op = valueFrom(cam.getAction());
130+
switch (op) {
131+
case BATCH:
132+
case CHECK_AND_MUTATE:
133+
ops.addAll(unpackRowOperations(cam.getAction()));
134+
break;
135+
default:
136+
ops.add(op);
137+
}
138+
return ops;
139+
}
140+
141+
public TableOperationSpanBuilder setContainerOperations(
142+
final Operation... operations
143+
) {
144+
final List<String> ops = Arrays.stream(operations)
145+
.map(op -> op == null ? unknown : op.name())
146+
.sorted()
147+
.distinct()
148+
.collect(Collectors.toList());
149+
attributes.put(CONTAINER_DB_OPERATIONS_KEY, ops);
150+
return this;
151+
}
152+
79153
public TableOperationSpanBuilder setTableName(final TableName tableName) {
80154
this.tableName = tableName;
81155
attributes.put(NAMESPACE_KEY, tableName.getNamespaceAsString());

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

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

2020
import static org.apache.hadoop.hbase.client.trace.hamcrest.AttributesMatchers.containsEntry;
21+
import static org.apache.hadoop.hbase.client.trace.hamcrest.AttributesMatchers.containsEntryWithStringValuesOf;
2122
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasAttributes;
2223
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasEnded;
2324
import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasKind;
@@ -144,11 +145,17 @@ public Void answer(InvocationOnMock invocation) throws Throwable {
144145

145146
@Override
146147
public Void answer(InvocationOnMock invocation) throws Throwable {
147-
ClientProtos.MultiResponse resp =
148-
ClientProtos.MultiResponse.newBuilder()
149-
.addRegionActionResult(RegionActionResult.newBuilder().addResultOrException(
150-
ResultOrException.newBuilder().setResult(ProtobufUtil.toResult(new Result()))))
151-
.build();
148+
ClientProtos.MultiRequest req = invocation.getArgument(1);
149+
ClientProtos.MultiResponse.Builder builder = ClientProtos.MultiResponse.newBuilder();
150+
for (ClientProtos.RegionAction regionAction : req.getRegionActionList()) {
151+
RegionActionResult.Builder raBuilder = RegionActionResult.newBuilder();
152+
for (ClientProtos.Action ignored : regionAction.getActionList()) {
153+
raBuilder.addResultOrException(
154+
ResultOrException.newBuilder().setResult(ProtobufUtil.toResult(new Result())));
155+
}
156+
builder.addRegionActionResult(raBuilder);
157+
}
158+
ClientProtos.MultiResponse resp = builder.build();
152159
RpcCallback<ClientProtos.MultiResponse> done = invocation.getArgument(2);
153160
ForkJoinPool.commonPool().execute(() -> done.run(resp));
154161
return null;
@@ -335,21 +342,30 @@ public void testCheckAndMutateList() {
335342
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
336343
.build(new Delete(Bytes.toBytes(0))))).toArray(new CompletableFuture[0]))
337344
.join();
338-
assertTrace("BATCH");
345+
assertTrace("BATCH", hasAttributes(
346+
containsEntryWithStringValuesOf(
347+
"db.hbase.container_operations", "CHECK_AND_MUTATE", "DELETE")));
339348
}
340349

341350
@Test
342351
public void testCheckAndMutateAll() {
343352
table.checkAndMutateAll(Arrays.asList(CheckAndMutate.newBuilder(Bytes.toBytes(0))
344353
.ifEquals(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v"))
345354
.build(new Delete(Bytes.toBytes(0))))).join();
346-
assertTrace("BATCH");
355+
assertTrace("BATCH", hasAttributes(
356+
containsEntryWithStringValuesOf(
357+
"db.hbase.container_operations", "CHECK_AND_MUTATE", "DELETE")));
347358
}
348359

349360
@Test
350361
public void testMutateRow() throws IOException {
351-
table.mutateRow(new RowMutations(Bytes.toBytes(0)).add(new Delete(Bytes.toBytes(0))));
352-
assertTrace("BATCH");
362+
final RowMutations mutations = new RowMutations(Bytes.toBytes(0))
363+
.add(new Put(Bytes.toBytes(0))
364+
.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("cq"), Bytes.toBytes("v")))
365+
.add(new Delete(Bytes.toBytes(0)));
366+
table.mutateRow(mutations).join();
367+
assertTrace("BATCH", hasAttributes(
368+
containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE", "PUT")));
353369
}
354370

355371
@Test
@@ -364,27 +380,31 @@ public void testExistsList() {
364380
.allOf(
365381
table.exists(Arrays.asList(new Get(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
366382
.join();
367-
assertTrace("BATCH");
383+
assertTrace("BATCH", hasAttributes(
384+
containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
368385
}
369386

370387
@Test
371388
public void testExistsAll() {
372389
table.existsAll(Arrays.asList(new Get(Bytes.toBytes(0)))).join();
373-
assertTrace("BATCH");
390+
assertTrace("BATCH", hasAttributes(
391+
containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
374392
}
375393

376394
@Test
377395
public void testGetList() {
378396
CompletableFuture
379397
.allOf(table.get(Arrays.asList(new Get(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
380398
.join();
381-
assertTrace("BATCH");
399+
assertTrace("BATCH", hasAttributes(
400+
containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
382401
}
383402

384403
@Test
385404
public void testGetAll() {
386405
table.getAll(Arrays.asList(new Get(Bytes.toBytes(0)))).join();
387-
assertTrace("BATCH");
406+
assertTrace("BATCH", hasAttributes(
407+
containsEntryWithStringValuesOf("db.hbase.container_operations", "GET")));
388408
}
389409

390410
@Test
@@ -393,14 +413,16 @@ public void testPutList() {
393413
.allOf(table.put(Arrays.asList(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"),
394414
Bytes.toBytes("cq"), Bytes.toBytes("v")))).toArray(new CompletableFuture[0]))
395415
.join();
396-
assertTrace("BATCH");
416+
assertTrace("BATCH", hasAttributes(
417+
containsEntryWithStringValuesOf("db.hbase.container_operations", "PUT")));
397418
}
398419

399420
@Test
400421
public void testPutAll() {
401422
table.putAll(Arrays.asList(new Put(Bytes.toBytes(0)).addColumn(Bytes.toBytes("cf"),
402423
Bytes.toBytes("cq"), Bytes.toBytes("v")))).join();
403-
assertTrace("BATCH");
424+
assertTrace("BATCH", hasAttributes(
425+
containsEntryWithStringValuesOf("db.hbase.container_operations", "PUT")));
404426
}
405427

406428
@Test
@@ -409,13 +431,15 @@ public void testDeleteList() {
409431
.allOf(
410432
table.delete(Arrays.asList(new Delete(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
411433
.join();
412-
assertTrace("BATCH");
434+
assertTrace("BATCH", hasAttributes(
435+
containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
413436
}
414437

415438
@Test
416439
public void testDeleteAll() {
417440
table.deleteAll(Arrays.asList(new Delete(Bytes.toBytes(0)))).join();
418-
assertTrace("BATCH");
441+
assertTrace("BATCH", hasAttributes(
442+
containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
419443
}
420444

421445
@Test
@@ -424,13 +448,15 @@ public void testBatch() {
424448
.allOf(
425449
table.batch(Arrays.asList(new Delete(Bytes.toBytes(0)))).toArray(new CompletableFuture[0]))
426450
.join();
427-
assertTrace("BATCH");
451+
assertTrace("BATCH", hasAttributes(
452+
containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
428453
}
429454

430455
@Test
431456
public void testBatchAll() {
432457
table.batchAll(Arrays.asList(new Delete(Bytes.toBytes(0)))).join();
433-
assertTrace("BATCH");
458+
assertTrace("BATCH", hasAttributes(
459+
containsEntryWithStringValuesOf("db.hbase.container_operations", "DELETE")));
434460
}
435461

436462
@Test

0 commit comments

Comments
 (0)