org.apache.hadoop.hbase.client.TestAsyncNonMetaRegionLocator.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.client.TestAsyncNonMetaRegionLocator.java

Source

/**
 * 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 java.util.stream.Collectors.toList;
import static org.apache.hadoop.hbase.HConstants.EMPTY_END_ROW;
import static org.apache.hadoop.hbase.HConstants.EMPTY_START_ROW;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.IntStream;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.NotServingRegionException;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.testclassification.ClientTests;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;

@Category({ MediumTests.class, ClientTests.class })
public class TestAsyncNonMetaRegionLocator {

    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();

    private static TableName TABLE_NAME = TableName.valueOf("async");

    private static byte[] FAMILY = Bytes.toBytes("cf");

    private static AsyncConnectionImpl CONN;

    private static AsyncNonMetaRegionLocator LOCATOR;

    private static byte[][] SPLIT_KEYS;

    @BeforeClass
    public static void setUp() throws Exception {
        TEST_UTIL.startMiniCluster(3);
        TEST_UTIL.getAdmin().setBalancerRunning(false, true);
        AsyncRegistry registry = AsyncRegistryFactory.getRegistry(TEST_UTIL.getConfiguration());
        CONN = new AsyncConnectionImpl(TEST_UTIL.getConfiguration(), registry, registry.getClusterId().get(),
                User.getCurrent());
        LOCATOR = new AsyncNonMetaRegionLocator(CONN);
        SPLIT_KEYS = new byte[8][];
        for (int i = 111; i < 999; i += 111) {
            SPLIT_KEYS[i / 111 - 1] = Bytes.toBytes(String.format("%03d", i));
        }
    }

    @AfterClass
    public static void tearDown() throws Exception {
        IOUtils.closeQuietly(CONN);
        TEST_UTIL.shutdownMiniCluster();
    }

    @After
    public void tearDownAfterTest() throws IOException {
        Admin admin = TEST_UTIL.getAdmin();
        if (admin.tableExists(TABLE_NAME)) {
            if (admin.isTableEnabled(TABLE_NAME)) {
                TEST_UTIL.getAdmin().disableTable(TABLE_NAME);
            }
            TEST_UTIL.getAdmin().deleteTable(TABLE_NAME);
        }
        LOCATOR.clearCache(TABLE_NAME);
    }

    private void createSingleRegionTable() throws IOException, InterruptedException {
        TEST_UTIL.createTable(TABLE_NAME, FAMILY);
        TEST_UTIL.waitTableAvailable(TABLE_NAME);
    }

    @Test
    public void testNoTable() throws InterruptedException {
        for (RegionLocateType locateType : RegionLocateType.values()) {
            try {
                LOCATOR.getRegionLocation(TABLE_NAME, EMPTY_START_ROW, locateType).get();
            } catch (ExecutionException e) {
                assertThat(e.getCause(), instanceOf(TableNotFoundException.class));
            }
        }
    }

    @Test
    public void testDisableTable() throws IOException, InterruptedException {
        createSingleRegionTable();
        TEST_UTIL.getAdmin().disableTable(TABLE_NAME);
        for (RegionLocateType locateType : RegionLocateType.values()) {
            try {
                LOCATOR.getRegionLocation(TABLE_NAME, EMPTY_START_ROW, locateType).get();
            } catch (ExecutionException e) {
                assertThat(e.getCause(), instanceOf(TableNotFoundException.class));
            }
        }
    }

    private void assertLocEquals(byte[] startKey, byte[] endKey, ServerName serverName, HRegionLocation loc) {
        HRegionInfo info = loc.getRegionInfo();
        assertEquals(TABLE_NAME, info.getTable());
        assertArrayEquals(startKey, info.getStartKey());
        assertArrayEquals(endKey, info.getEndKey());
        assertEquals(serverName, loc.getServerName());
    }

    @Test
    public void testSingleRegionTable() throws IOException, InterruptedException, ExecutionException {
        createSingleRegionTable();
        ServerName serverName = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName();
        for (RegionLocateType locateType : RegionLocateType.values()) {
            assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, serverName,
                    LOCATOR.getRegionLocation(TABLE_NAME, EMPTY_START_ROW, locateType).get());
        }
        byte[] randKey = new byte[ThreadLocalRandom.current().nextInt(128)];
        ThreadLocalRandom.current().nextBytes(randKey);
        for (RegionLocateType locateType : RegionLocateType.values()) {
            assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, serverName,
                    LOCATOR.getRegionLocation(TABLE_NAME, randKey, locateType).get());
        }
    }

    private void createMultiRegionTable() throws IOException, InterruptedException {
        TEST_UTIL.createTable(TABLE_NAME, FAMILY, SPLIT_KEYS);
        TEST_UTIL.waitTableAvailable(TABLE_NAME);
    }

    private static byte[][] getStartKeys() {
        byte[][] startKeys = new byte[SPLIT_KEYS.length + 1][];
        startKeys[0] = EMPTY_START_ROW;
        System.arraycopy(SPLIT_KEYS, 0, startKeys, 1, SPLIT_KEYS.length);
        return startKeys;
    }

    private static byte[][] getEndKeys() {
        byte[][] endKeys = Arrays.copyOf(SPLIT_KEYS, SPLIT_KEYS.length + 1);
        endKeys[endKeys.length - 1] = EMPTY_START_ROW;
        return endKeys;
    }

    private ServerName[] getLocations(byte[][] startKeys) {
        ServerName[] serverNames = new ServerName[startKeys.length];
        TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream().map(t -> t.getRegionServer()).forEach(rs -> {
            rs.getOnlineRegions(TABLE_NAME).forEach(r -> {
                serverNames[Arrays.binarySearch(startKeys, r.getRegionInfo().getStartKey(), Bytes::compareTo)] = rs
                        .getServerName();
            });
        });
        return serverNames;
    }

    @Test
    public void testMultiRegionTable() throws IOException, InterruptedException {
        createMultiRegionTable();
        byte[][] startKeys = getStartKeys();
        ServerName[] serverNames = getLocations(startKeys);
        IntStream.range(0, 2).forEach(n -> IntStream.range(0, startKeys.length).forEach(i -> {
            try {
                assertLocEquals(startKeys[i], i == startKeys.length - 1 ? EMPTY_END_ROW : startKeys[i + 1],
                        serverNames[i],
                        LOCATOR.getRegionLocation(TABLE_NAME, startKeys[i], RegionLocateType.CURRENT).get());
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }));

        LOCATOR.clearCache(TABLE_NAME);
        IntStream.range(0, 2).forEach(n -> IntStream.range(0, startKeys.length).forEach(i -> {
            try {
                assertLocEquals(startKeys[i], i == startKeys.length - 1 ? EMPTY_END_ROW : startKeys[i + 1],
                        serverNames[i],
                        LOCATOR.getRegionLocation(TABLE_NAME, startKeys[i], RegionLocateType.AFTER).get());
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }));
        LOCATOR.clearCache(TABLE_NAME);
        byte[][] endKeys = getEndKeys();
        IntStream.range(0, 2)
                .forEach(n -> IntStream.range(0, endKeys.length).map(i -> endKeys.length - 1 - i).forEach(i -> {
                    try {
                        assertLocEquals(i == 0 ? EMPTY_START_ROW : endKeys[i - 1], endKeys[i], serverNames[i],
                                LOCATOR.getRegionLocation(TABLE_NAME, endKeys[i], RegionLocateType.BEFORE).get());
                    } catch (InterruptedException | ExecutionException e) {
                        throw new RuntimeException(e);
                    }
                }));
    }

    @Test
    public void testRegionMove() throws IOException, InterruptedException, ExecutionException {
        createSingleRegionTable();
        ServerName serverName = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName();
        HRegionLocation loc = LOCATOR.getRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT)
                .get();
        assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, serverName, loc);
        ServerName newServerName = TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream()
                .map(t -> t.getRegionServer().getServerName()).filter(sn -> !sn.equals(serverName)).findAny().get();

        TEST_UTIL.getAdmin().move(Bytes.toBytes(loc.getRegionInfo().getEncodedName()),
                Bytes.toBytes(newServerName.getServerName()));
        while (!TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName().equals(newServerName)) {
            Thread.sleep(100);
        }
        // Should be same as it is in cache
        assertSame(loc, LOCATOR.getRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT).get());
        LOCATOR.updateCachedLocation(loc, null);
        // null error will not trigger a cache cleanup
        assertSame(loc, LOCATOR.getRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT).get());
        LOCATOR.updateCachedLocation(loc, new NotServingRegionException());
        assertLocEquals(EMPTY_START_ROW, EMPTY_END_ROW, newServerName,
                LOCATOR.getRegionLocation(TABLE_NAME, EMPTY_START_ROW, RegionLocateType.CURRENT).get());
    }

    // usually locate after will return the same result, so we add a test to make it return different
    // result.
    @Test
    public void testLocateAfter() throws IOException, InterruptedException, ExecutionException {
        byte[] row = Bytes.toBytes("1");
        byte[] splitKey = Arrays.copyOf(row, 2);
        TEST_UTIL.createTable(TABLE_NAME, FAMILY, new byte[][] { splitKey });
        TEST_UTIL.waitTableAvailable(TABLE_NAME);
        HRegionLocation currentLoc = LOCATOR.getRegionLocation(TABLE_NAME, row, RegionLocateType.CURRENT).get();
        ServerName currentServerName = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME).getServerName();
        assertLocEquals(EMPTY_START_ROW, splitKey, currentServerName, currentLoc);

        HRegionLocation afterLoc = LOCATOR.getRegionLocation(TABLE_NAME, row, RegionLocateType.AFTER).get();
        ServerName afterServerName = TEST_UTIL.getHBaseCluster().getRegionServerThreads().stream()
                .map(t -> t.getRegionServer())
                .filter(rs -> rs.getOnlineRegions(TABLE_NAME).stream()
                        .anyMatch(r -> Bytes.equals(splitKey, r.getRegionInfo().getStartKey())))
                .findAny().get().getServerName();
        assertLocEquals(splitKey, EMPTY_END_ROW, afterServerName, afterLoc);

        assertSame(afterLoc, LOCATOR.getRegionLocation(TABLE_NAME, row, RegionLocateType.AFTER).get());
    }

    // For HBASE-17402
    @Test
    public void testConcurrentLocate() throws IOException, InterruptedException, ExecutionException {
        createMultiRegionTable();
        byte[][] startKeys = getStartKeys();
        byte[][] endKeys = getEndKeys();
        ServerName[] serverNames = getLocations(startKeys);
        for (int i = 0; i < 100; i++) {
            LOCATOR.clearCache(TABLE_NAME);
            List<CompletableFuture<HRegionLocation>> futures = IntStream.range(0, 1000)
                    .mapToObj(n -> String.format("%03d", n)).map(s -> Bytes.toBytes(s))
                    .map(r -> LOCATOR.getRegionLocation(TABLE_NAME, r, RegionLocateType.CURRENT)).collect(toList());
            for (int j = 0; j < 1000; j++) {
                int index = Math.min(8, j / 111);
                assertLocEquals(startKeys[index], endKeys[index], serverNames[index], futures.get(j).get());
            }
        }
    }
}