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.junit4.OpenTelemetryRule;
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.HBaseClassTestRule;
044import org.apache.hadoop.hbase.HBaseConfiguration;
045import org.apache.hadoop.hbase.HConstants;
046import org.apache.hadoop.hbase.HRegionLocation;
047import org.apache.hadoop.hbase.MatcherPredicate;
048import org.apache.hadoop.hbase.RegionLocations;
049import org.apache.hadoop.hbase.ServerName;
050import org.apache.hadoop.hbase.TableName;
051import org.apache.hadoop.hbase.Waiter;
052import org.apache.hadoop.hbase.security.User;
053import org.apache.hadoop.hbase.security.UserProvider;
054import org.apache.hadoop.hbase.testclassification.ClientTests;
055import org.apache.hadoop.hbase.testclassification.MediumTests;
056import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
057import org.hamcrest.Matcher;
058import org.junit.After;
059import org.junit.Before;
060import org.junit.ClassRule;
061import org.junit.Rule;
062import org.junit.Test;
063import org.junit.experimental.categories.Category;
064import org.slf4j.Logger;
065import org.slf4j.LoggerFactory;
066
067import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
068
069@Category({ ClientTests.class, MediumTests.class })
070public class TestAsyncRegionLocatorTracing {
071  private static final Logger LOG = LoggerFactory.getLogger(TestAsyncRegionLocatorTracing.class);
072
073  @ClassRule
074  public static final HBaseClassTestRule CLASS_RULE =
075    HBaseClassTestRule.forClass(TestAsyncRegionLocatorTracing.class);
076
077  private static final Configuration CONF = HBaseConfiguration.create();
078
079  private AsyncConnectionImpl conn;
080
081  private RegionLocations locs;
082
083  @Rule
084  public OpenTelemetryRule traceRule = OpenTelemetryRule.create();
085
086  @Before
087  public void setUp() throws IOException {
088    RegionInfo metaRegionInfo = RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME).build();
089    locs = new RegionLocations(
090      new HRegionLocation(metaRegionInfo,
091        ServerName.valueOf("127.0.0.1", 12345, EnvironmentEdgeManager.currentTime())),
092      new HRegionLocation(RegionReplicaUtil.getRegionInfoForReplica(metaRegionInfo, 1),
093        ServerName.valueOf("127.0.0.2", 12345, EnvironmentEdgeManager.currentTime())),
094      new HRegionLocation(RegionReplicaUtil.getRegionInfoForReplica(metaRegionInfo, 2),
095        ServerName.valueOf("127.0.0.3", 12345, EnvironmentEdgeManager.currentTime())));
096    User user = UserProvider.instantiate(CONF).getCurrent();
097    conn = new AsyncConnectionImpl(CONF, new DoNothingConnectionRegistry(CONF, user) {
098
099      @Override
100      public CompletableFuture<RegionLocations> getMetaRegionLocations() {
101        return CompletableFuture.completedFuture(locs);
102      }
103    }, "test", null, user);
104  }
105
106  @After
107  public void tearDown() throws IOException {
108    Closeables.close(conn, true);
109  }
110
111  private SpanData waitSpan(String name) {
112    return waitSpan(hasName(name));
113  }
114
115  private SpanData waitSpan(Matcher<SpanData> matcher) {
116    Matcher<SpanData> spanLocator = allOf(matcher, hasEnded());
117    try {
118      Waiter.waitFor(CONF, 1000, new MatcherPredicate<>("waiting for span",
119        () -> traceRule.getSpans(), hasItem(spanLocator)));
120    } catch (AssertionError e) {
121      LOG.error("AssertionError while waiting for matching span. Span reservoir contains: {}",
122        traceRule.getSpans());
123      throw e;
124    }
125    return traceRule.getSpans().stream().filter(spanLocator::matches).findFirst()
126      .orElseThrow(AssertionError::new);
127  }
128
129  @Test
130  public void testClearCache() {
131    conn.getLocator().clearCache();
132    SpanData span = waitSpan("AsyncRegionLocator.clearCache");
133    assertThat(span, allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL),
134      buildConnectionAttributesMatcher(conn)));
135  }
136
137  @Test
138  public void testClearCacheServerName() {
139    ServerName sn = ServerName.valueOf("127.0.0.1", 12345, EnvironmentEdgeManager.currentTime());
140    conn.getLocator().clearCache(sn);
141    SpanData span = waitSpan("AsyncRegionLocator.clearCache");
142    assertThat(span,
143      allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL),
144        buildConnectionAttributesMatcher(conn),
145        hasAttributes(containsEntry("db.hbase.server.name", sn.getServerName()))));
146  }
147
148  @Test
149  public void testClearCacheTableName() {
150    conn.getLocator().clearCache(TableName.META_TABLE_NAME);
151    SpanData span = waitSpan("AsyncRegionLocator.clearCache");
152    assertThat(span,
153      allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL),
154        buildConnectionAttributesMatcher(conn),
155        buildTableAttributesMatcher(TableName.META_TABLE_NAME)));
156  }
157
158  @Test
159  public void testGetRegionLocation() {
160    conn.getLocator().getRegionLocation(TableName.META_TABLE_NAME, HConstants.EMPTY_START_ROW,
161      RegionLocateType.CURRENT, TimeUnit.SECONDS.toNanos(1)).join();
162    SpanData span = waitSpan("AsyncRegionLocator.getRegionLocation");
163    assertThat(span,
164      allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL),
165        buildConnectionAttributesMatcher(conn),
166        buildTableAttributesMatcher(TableName.META_TABLE_NAME),
167        hasAttributes(containsEntryWithStringValuesOf("db.hbase.regions",
168          locs.getDefaultRegionLocation().getRegion().getRegionNameAsString()))));
169  }
170
171  @Test
172  public void testGetRegionLocations() {
173    conn.getLocator().getRegionLocations(TableName.META_TABLE_NAME, HConstants.EMPTY_START_ROW,
174      RegionLocateType.CURRENT, false, TimeUnit.SECONDS.toNanos(1)).join();
175    SpanData span = waitSpan("AsyncRegionLocator.getRegionLocations");
176    String[] expectedRegions =
177      Arrays.stream(locs.getRegionLocations()).map(HRegionLocation::getRegion)
178        .map(RegionInfo::getRegionNameAsString).toArray(String[]::new);
179    assertThat(span, allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL),
180      buildConnectionAttributesMatcher(conn),
181      buildTableAttributesMatcher(TableName.META_TABLE_NAME), hasAttributes(
182        containsEntryWithStringValuesOf("db.hbase.regions", containsInAnyOrder(expectedRegions)))));
183  }
184}