com.alibaba.wasp.master.GeneralBulkAssigner.java Source code

Java tutorial

Introduction

Here is the source code for com.alibaba.wasp.master.GeneralBulkAssigner.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 com.alibaba.wasp.master;

import com.alibaba.wasp.EntityGroupInfo;
import com.alibaba.wasp.Server;
import com.alibaba.wasp.ServerName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Run bulk assign. Does one RCP per fserver passing a batch of entityGroups
 * using {@link SingleServerBulkAssigner}.
 */
public class GeneralBulkAssigner extends BulkAssigner {
    private static final Log LOG = LogFactory.getLog(GeneralBulkAssigner.class);

    private Map<ServerName, List<EntityGroupInfo>> failedPlans = new ConcurrentHashMap<ServerName, List<EntityGroupInfo>>();
    private ExecutorService pool;

    final Map<ServerName, List<EntityGroupInfo>> bulkPlan;
    final AssignmentManager assignmentManager;

    GeneralBulkAssigner(final Server server, final Map<ServerName, List<EntityGroupInfo>> bulkPlan,
            final AssignmentManager am) {
        super(server);
        this.bulkPlan = bulkPlan;
        this.assignmentManager = am;
    }

    @Override
    protected String getThreadNamePrefix() {
        return this.server.getServerName() + "-GeneralBulkAssigner";
    }

    @Override
    protected void populatePool(ExecutorService pool) {
        this.pool = pool; // shut it down later in case some assigner hangs
        for (Map.Entry<ServerName, List<EntityGroupInfo>> e : this.bulkPlan.entrySet()) {
            pool.execute(new SingleServerBulkAssigner(e.getKey(), e.getValue(), this.assignmentManager,
                    this.failedPlans));
        }
    }

    /**
     * 
     * @param timeout How long to wait.
     * @return true if done.
     */
    @Override
    protected boolean waitUntilDone(final long timeout) throws InterruptedException {
        Set<EntityGroupInfo> entityGroupSet = new HashSet<EntityGroupInfo>();
        for (List<EntityGroupInfo> entityGroupList : bulkPlan.values()) {
            entityGroupSet.addAll(entityGroupList);
        }

        pool.shutdown(); // no more task allowed
        int serverCount = bulkPlan.size();
        int entityGroupCount = entityGroupSet.size();
        long startTime = System.currentTimeMillis();
        long rpcWaitTime = startTime + timeout;
        while (!server.isStopped() && !pool.isTerminated() && rpcWaitTime > System.currentTimeMillis()) {
            if (failedPlans.isEmpty()) {
                pool.awaitTermination(100, TimeUnit.MILLISECONDS);
            } else {
                reassignFailedPlans();
            }
        }
        if (!pool.isTerminated()) {
            LOG.warn("bulk assigner is still running after " + (System.currentTimeMillis() - startTime)
                    + "ms, shut it down now");
            // some assigner hangs, can't wait any more, shutdown the pool now
            List<Runnable> notStarted = pool.shutdownNow();
            if (notStarted != null && !notStarted.isEmpty()) {
                server.abort("some single server assigner hasn't started yet" + " when the bulk assigner timed out",
                        null);
                return false;
            }
        }

        int reassigningEntityGroups = 0;
        if (!failedPlans.isEmpty() && !server.isStopped()) {
            reassigningEntityGroups = reassignFailedPlans();
        }

        Configuration conf = server.getConfiguration();
        long perEntityGroupOpenTimeGuesstimate = conf.getLong("wasp.bulk.assignment.perentityGroup.open.time",
                1000);
        long endTime = Math.max(System.currentTimeMillis(), rpcWaitTime)
                + perEntityGroupOpenTimeGuesstimate * (reassigningEntityGroups + 1);
        EntityGroupStates entityGroupStates = assignmentManager.getEntityGroupStates();
        // We're not synchronizing on entityGroupsInTransition now because we don't use
        // any iterator.
        while (!entityGroupSet.isEmpty() && !server.isStopped() && endTime > System.currentTimeMillis()) {
            Iterator<EntityGroupInfo> entityGroupInfoIterator = entityGroupSet.iterator();
            while (entityGroupInfoIterator.hasNext()) {
                EntityGroupInfo egi = entityGroupInfoIterator.next();
                EntityGroupState state = entityGroupStates.getEntityGroupState(egi);
                if ((!entityGroupStates.isEntityGroupInTransition(egi)
                        && entityGroupStates.isEntityGroupAssigned(egi)) || state.isSplit()
                        || state.isSplitting()) {
                    entityGroupInfoIterator.remove();
                }
            }
            if (!entityGroupSet.isEmpty()) {
                entityGroupStates.waitForUpdate(100);
            }
        }

        if (LOG.isDebugEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            String status = "successfully";
            if (!entityGroupSet.isEmpty()) {
                status = "with " + entityGroupSet.size() + " entityGroups still not assigned yet";
            }
            LOG.debug("bulk assigning total " + entityGroupCount + " entityGroups to " + serverCount
                    + " servers, took " + elapsedTime + "ms, " + status);
        }
        return entityGroupSet.isEmpty();
    }

    @Override
    protected long getTimeoutOnRIT() {
        // Guess timeout. Multiply the max number of entityGroups on a server
        // by how long we think one entityGroup takes opening.
        Configuration conf = server.getConfiguration();
        long perEntityGroupOpenTimeGuesstimate = conf.getLong("wasp.bulk.assignment.perentityGroup.open.time",
                1000);
        int maxEntityGroupsPerServer = 1;
        for (List<EntityGroupInfo> entityGroupList : bulkPlan.values()) {
            int size = entityGroupList.size();
            if (size > maxEntityGroupsPerServer) {
                maxEntityGroupsPerServer = size;
            }
        }
        long timeout = perEntityGroupOpenTimeGuesstimate * maxEntityGroupsPerServer
                + conf.getLong("wasp.fserver.rpc.startup.waittime", 60000)
                + conf.getLong("wasp.bulk.assignment.perfserver.rpc.waittime", 30000) * bulkPlan.size();
        LOG.debug("Timeout-on-RIT=" + timeout);
        return timeout;
    }

    @Override
    protected UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                LOG.warn("Assigning entityGroups in " + t.getName(), e);
            }
        };
    }

    private int reassignFailedPlans() {
        List<EntityGroupInfo> reassigningEntityGroups = new ArrayList<EntityGroupInfo>();
        for (Map.Entry<ServerName, List<EntityGroupInfo>> e : failedPlans.entrySet()) {
            LOG.info("Failed assigning " + e.getValue().size() + " entityGroups to server " + e.getKey()
                    + ", reassigning them");
            reassigningEntityGroups.addAll(failedPlans.remove(e.getKey()));
        }
        for (EntityGroupInfo entityGroup : reassigningEntityGroups) {
            assignmentManager.invokeAssign(entityGroup);
        }
        return reassigningEntityGroups.size();
    }

    /**
     * Manage bulk assigning to a server.
     */
    static class SingleServerBulkAssigner implements Runnable {
        private final ServerName fserver;
        private final List<EntityGroupInfo> entityGroups;
        private final AssignmentManager assignmentManager;
        private final Map<ServerName, List<EntityGroupInfo>> failedPlans;

        SingleServerBulkAssigner(final ServerName fserver, final List<EntityGroupInfo> entityGroups,
                final AssignmentManager am, final Map<ServerName, List<EntityGroupInfo>> failedPlans) {
            this.fserver = fserver;
            this.entityGroups = entityGroups;
            this.assignmentManager = am;
            this.failedPlans = failedPlans;
        }

        @Override
        public void run() {
            try {
                if (!assignmentManager.assign(fserver, entityGroups)) {
                    failedPlans.put(fserver, entityGroups);
                }
            } catch (Throwable t) {
                LOG.warn("Failed bulking assigning " + entityGroups.size() + " entityGroup(s) to "
                        + fserver.getServerName() + ", and continue to bulk assign others", t);
                failedPlans.put(fserver, entityGroups);
            }
        }
    }

}