001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.client; 019 020import static org.apache.hadoop.hbase.client.trace.hamcrest.AttributesMatchers.containsEntry; 021import static org.apache.hadoop.hbase.client.trace.hamcrest.AttributesMatchers.containsEntryWithStringValuesOf; 022import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasAttributes; 023import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasEnded; 024import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasKind; 025import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasName; 026import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasStatusWithCode; 027import static org.apache.hadoop.hbase.client.trace.hamcrest.TraceTestUtil.buildConnectionAttributesMatcher; 028import static org.apache.hadoop.hbase.client.trace.hamcrest.TraceTestUtil.buildTableAttributesMatcher; 029import static org.hamcrest.MatcherAssert.assertThat; 030import static org.hamcrest.Matchers.allOf; 031import static org.hamcrest.Matchers.containsInAnyOrder; 032import static org.hamcrest.Matchers.hasItem; 033 034import io.opentelemetry.api.trace.SpanKind; 035import io.opentelemetry.api.trace.StatusCode; 036import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; 037import io.opentelemetry.sdk.trace.data.SpanData; 038import java.io.IOException; 039import java.util.Arrays; 040import java.util.concurrent.CompletableFuture; 041import java.util.concurrent.TimeUnit; 042import org.apache.hadoop.conf.Configuration; 043import org.apache.hadoop.hbase.HBaseConfiguration; 044import org.apache.hadoop.hbase.HConstants; 045import org.apache.hadoop.hbase.HRegionLocation; 046import org.apache.hadoop.hbase.MatcherPredicate; 047import org.apache.hadoop.hbase.RegionLocations; 048import org.apache.hadoop.hbase.ServerName; 049import org.apache.hadoop.hbase.TableName; 050import org.apache.hadoop.hbase.Waiter; 051import org.apache.hadoop.hbase.security.User; 052import org.apache.hadoop.hbase.security.UserProvider; 053import org.apache.hadoop.hbase.testclassification.ClientTests; 054import org.apache.hadoop.hbase.testclassification.MediumTests; 055import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 056import org.hamcrest.Matcher; 057import org.junit.jupiter.api.AfterEach; 058import org.junit.jupiter.api.BeforeEach; 059import org.junit.jupiter.api.Tag; 060import org.junit.jupiter.api.Test; 061import org.junit.jupiter.api.extension.RegisterExtension; 062import org.slf4j.Logger; 063import org.slf4j.LoggerFactory; 064 065import org.apache.hbase.thirdparty.com.google.common.io.Closeables; 066 067@Tag(ClientTests.TAG) 068@Tag(MediumTests.TAG) 069public class TestAsyncRegionLocatorTracing { 070 private static final Logger LOG = LoggerFactory.getLogger(TestAsyncRegionLocatorTracing.class); 071 072 private static final Configuration CONF = HBaseConfiguration.create(); 073 074 private AsyncConnectionImpl conn; 075 076 private RegionLocations locs; 077 078 @RegisterExtension 079 public static final OpenTelemetryExtension traceRule = OpenTelemetryExtension.create(); 080 081 @BeforeEach 082 public void setUp() throws IOException { 083 RegionInfo metaRegionInfo = RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME).build(); 084 locs = new RegionLocations( 085 new HRegionLocation(metaRegionInfo, 086 ServerName.valueOf("127.0.0.1", 12345, EnvironmentEdgeManager.currentTime())), 087 new HRegionLocation(RegionReplicaUtil.getRegionInfoForReplica(metaRegionInfo, 1), 088 ServerName.valueOf("127.0.0.2", 12345, EnvironmentEdgeManager.currentTime())), 089 new HRegionLocation(RegionReplicaUtil.getRegionInfoForReplica(metaRegionInfo, 2), 090 ServerName.valueOf("127.0.0.3", 12345, EnvironmentEdgeManager.currentTime()))); 091 User user = UserProvider.instantiate(CONF).getCurrent(); 092 conn = new AsyncConnectionImpl(CONF, new DoNothingConnectionRegistry(CONF, user) { 093 094 @Override 095 public CompletableFuture<RegionLocations> getMetaRegionLocations() { 096 return CompletableFuture.completedFuture(locs); 097 } 098 }, "test", null, user); 099 } 100 101 @AfterEach 102 public void tearDown() throws IOException { 103 Closeables.close(conn, true); 104 } 105 106 private SpanData waitSpan(String name) { 107 return waitSpan(hasName(name)); 108 } 109 110 private SpanData waitSpan(Matcher<SpanData> matcher) { 111 Matcher<SpanData> spanLocator = allOf(matcher, hasEnded()); 112 try { 113 Waiter.waitFor(CONF, 1000, new MatcherPredicate<>("waiting for span", 114 () -> traceRule.getSpans(), hasItem(spanLocator))); 115 } catch (AssertionError e) { 116 LOG.error("AssertionError while waiting for matching span. Span reservoir contains: {}", 117 traceRule.getSpans()); 118 throw e; 119 } 120 return traceRule.getSpans().stream().filter(spanLocator::matches).findFirst() 121 .orElseThrow(AssertionError::new); 122 } 123 124 @Test 125 public void testClearCache() { 126 conn.getLocator().clearCache(); 127 SpanData span = waitSpan("AsyncRegionLocator.clearCache"); 128 assertThat(span, allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 129 buildConnectionAttributesMatcher(conn))); 130 } 131 132 @Test 133 public void testClearCacheServerName() { 134 ServerName sn = ServerName.valueOf("127.0.0.1", 12345, EnvironmentEdgeManager.currentTime()); 135 conn.getLocator().clearCache(sn); 136 SpanData span = waitSpan("AsyncRegionLocator.clearCache"); 137 assertThat(span, 138 allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 139 buildConnectionAttributesMatcher(conn), 140 hasAttributes(containsEntry("db.hbase.server.name", sn.getServerName())))); 141 } 142 143 @Test 144 public void testClearCacheTableName() { 145 conn.getLocator().clearCache(TableName.META_TABLE_NAME); 146 SpanData span = waitSpan("AsyncRegionLocator.clearCache"); 147 assertThat(span, 148 allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 149 buildConnectionAttributesMatcher(conn), 150 buildTableAttributesMatcher(TableName.META_TABLE_NAME))); 151 } 152 153 @Test 154 public void testGetRegionLocation() { 155 conn.getLocator().getRegionLocation(TableName.META_TABLE_NAME, HConstants.EMPTY_START_ROW, 156 RegionLocateType.CURRENT, TimeUnit.SECONDS.toNanos(1)).join(); 157 SpanData span = waitSpan("AsyncRegionLocator.getRegionLocation"); 158 assertThat(span, 159 allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 160 buildConnectionAttributesMatcher(conn), 161 buildTableAttributesMatcher(TableName.META_TABLE_NAME), 162 hasAttributes(containsEntryWithStringValuesOf("db.hbase.regions", 163 locs.getDefaultRegionLocation().getRegion().getRegionNameAsString())))); 164 } 165 166 @Test 167 public void testGetRegionLocations() { 168 conn.getLocator().getRegionLocations(TableName.META_TABLE_NAME, HConstants.EMPTY_START_ROW, 169 RegionLocateType.CURRENT, false, TimeUnit.SECONDS.toNanos(1)).join(); 170 SpanData span = waitSpan("AsyncRegionLocator.getRegionLocations"); 171 String[] expectedRegions = 172 Arrays.stream(locs.getRegionLocations()).map(HRegionLocation::getRegion) 173 .map(RegionInfo::getRegionNameAsString).toArray(String[]::new); 174 assertThat(span, allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 175 buildConnectionAttributesMatcher(conn), 176 buildTableAttributesMatcher(TableName.META_TABLE_NAME), hasAttributes( 177 containsEntryWithStringValuesOf("db.hbase.regions", containsInAnyOrder(expectedRegions))))); 178 } 179}