org.apache.accumulo.test.functional.RegexGroupBalanceIT.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.accumulo.test.functional.RegexGroupBalanceIT.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.accumulo.test.functional;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.client.Scanner;
import org.apache.accumulo.core.client.TableNotFoundException;
import org.apache.accumulo.core.conf.Property;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.metadata.MetadataTable;
import org.apache.accumulo.core.metadata.schema.MetadataSchema;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.minicluster.impl.MiniAccumuloConfigImpl;
import org.apache.accumulo.server.master.balancer.RegexGroupBalancer;
import org.apache.accumulo.server.master.state.TServerInstance;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.hadoop.io.Text;
import org.junit.Test;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

public class RegexGroupBalanceIT extends ConfigurableMacBase {

    @Override
    public void beforeClusterStart(MiniAccumuloConfigImpl cfg) throws Exception {
        cfg.setNumTservers(4);
    }

    @Test(timeout = 120000)
    public void testBalancing() throws Exception {
        Connector conn = getConnector();
        String tablename = getUniqueNames(1)[0];
        conn.tableOperations().create(tablename);

        SortedSet<Text> splits = new TreeSet<>();
        splits.add(new Text("01a"));
        splits.add(new Text("01m"));
        splits.add(new Text("01z"));

        splits.add(new Text("02a"));
        splits.add(new Text("02f"));
        splits.add(new Text("02r"));
        splits.add(new Text("02z"));

        splits.add(new Text("03a"));
        splits.add(new Text("03f"));
        splits.add(new Text("03m"));
        splits.add(new Text("03r"));

        conn.tableOperations().setProperty(tablename, RegexGroupBalancer.REGEX_PROPERTY, "(\\d\\d).*");
        conn.tableOperations().setProperty(tablename, RegexGroupBalancer.DEFAUT_GROUP_PROPERTY, "03");
        conn.tableOperations().setProperty(tablename, RegexGroupBalancer.WAIT_TIME_PROPERTY, "50ms");
        conn.tableOperations().setProperty(tablename, Property.TABLE_LOAD_BALANCER.getKey(),
                RegexGroupBalancer.class.getName());

        conn.tableOperations().addSplits(tablename, splits);

        while (true) {
            Thread.sleep(250);

            Table<String, String, MutableInt> groupLocationCounts = getCounts(conn, tablename);

            boolean allGood = true;
            allGood &= checkGroup(groupLocationCounts, "01", 1, 1, 3);
            allGood &= checkGroup(groupLocationCounts, "02", 1, 1, 4);
            allGood &= checkGroup(groupLocationCounts, "03", 1, 2, 4);
            allGood &= checkTabletsPerTserver(groupLocationCounts, 3, 3, 4);

            if (allGood) {
                break;
            }
        }

        splits.clear();
        splits.add(new Text("01b"));
        splits.add(new Text("01f"));
        splits.add(new Text("01l"));
        splits.add(new Text("01r"));
        conn.tableOperations().addSplits(tablename, splits);

        while (true) {
            Thread.sleep(250);

            Table<String, String, MutableInt> groupLocationCounts = getCounts(conn, tablename);

            boolean allGood = true;
            allGood &= checkGroup(groupLocationCounts, "01", 1, 2, 4);
            allGood &= checkGroup(groupLocationCounts, "02", 1, 1, 4);
            allGood &= checkGroup(groupLocationCounts, "03", 1, 2, 4);
            allGood &= checkTabletsPerTserver(groupLocationCounts, 4, 4, 4);

            if (allGood) {
                break;
            }
        }

        // merge group 01 down to one tablet
        conn.tableOperations().merge(tablename, null, new Text("01z"));

        while (true) {
            Thread.sleep(250);

            Table<String, String, MutableInt> groupLocationCounts = getCounts(conn, tablename);

            boolean allGood = true;
            allGood &= checkGroup(groupLocationCounts, "01", 1, 1, 1);
            allGood &= checkGroup(groupLocationCounts, "02", 1, 1, 4);
            allGood &= checkGroup(groupLocationCounts, "03", 1, 2, 4);
            allGood &= checkTabletsPerTserver(groupLocationCounts, 2, 3, 4);

            if (allGood) {
                break;
            }
        }
    }

    private boolean checkTabletsPerTserver(Table<String, String, MutableInt> groupLocationCounts,
            int minTabletPerTserver, int maxTabletsPerTserver, int totalTservser) {
        // check that each tserver has between min and max tablets
        for (Map<String, MutableInt> groups : groupLocationCounts.columnMap().values()) {
            int sum = 0;
            for (MutableInt mi : groups.values()) {
                sum += mi.intValue();
            }

            if (sum < minTabletPerTserver || sum > maxTabletsPerTserver) {
                return false;
            }
        }

        return groupLocationCounts.columnKeySet().size() == totalTservser;
    }

    private boolean checkGroup(Table<String, String, MutableInt> groupLocationCounts, String group, int min,
            int max, int tsevers) {
        Collection<MutableInt> counts = groupLocationCounts.row(group).values();
        if (counts.size() == 0) {
            return min == 0 && max == 0 && tsevers == 0;
        }
        return min == Collections.min(counts).intValue() && max == Collections.max(counts).intValue()
                && counts.size() == tsevers;
    }

    private Table<String, String, MutableInt> getCounts(Connector conn, String tablename)
            throws TableNotFoundException {
        Scanner s = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
        s.fetchColumnFamily(MetadataSchema.TabletsSection.CurrentLocationColumnFamily.NAME);
        String tableId = conn.tableOperations().tableIdMap().get(tablename);
        s.setRange(MetadataSchema.TabletsSection.getRange(tableId));

        Table<String, String, MutableInt> groupLocationCounts = HashBasedTable.create();

        for (Entry<Key, Value> entry : s) {
            String group = entry.getKey().getRow().toString();
            if (group.endsWith("<")) {
                group = "03";
            } else {
                group = group.substring(tableId.length() + 1).substring(0, 2);
            }
            String loc = new TServerInstance(entry.getValue(), entry.getKey().getColumnQualifier()).toString();

            MutableInt count = groupLocationCounts.get(group, loc);
            if (count == null) {
                count = new MutableInt(0);
                groupLocationCounts.put(group, loc, count);
            }

            count.increment();
        }
        return groupLocationCounts;
    }
}