Package voldemort.server.rebalance.async

Source Code of voldemort.server.rebalance.async.StealerBasedRebalanceAsyncOperation

/*
* Copyright 2011-2013 LinkedIn, Inc
*
* Licensed 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 voldemort.server.rebalance.async;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.rebalance.RebalanceTaskInfo;
import voldemort.server.VoldemortConfig;
import voldemort.server.rebalance.Rebalancer;
import voldemort.server.rebalance.VoldemortRebalancingException;
import voldemort.store.metadata.MetadataStore;
import voldemort.store.readonly.ReadOnlyStorageConfiguration;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

/**
* Individual rebalancing operation run on the server side as an async
* operation. This is run on the stealer node
*/
public class StealerBasedRebalanceAsyncOperation extends RebalanceAsyncOperation {

    private List<Integer> rebalanceStatusList;

    private final RebalanceTaskInfo stealInfo;
    private final int partitionStoreCount;

    public StealerBasedRebalanceAsyncOperation(Rebalancer rebalancer,
                                               VoldemortConfig voldemortConfig,
                                               MetadataStore metadataStore,
                                               int requestId,
                                               RebalanceTaskInfo stealInfo) {
        super(rebalancer,
              voldemortConfig,
              metadataStore,
              requestId,
              "Stealer based rebalance of " + stealInfo.getPartitionStoreCount()
                      + " partition-stores.");
        this.rebalancer = rebalancer;
        this.stealInfo = stealInfo;
        this.rebalanceStatusList = new ArrayList<Integer>();
        this.partitionStoreCount = stealInfo.getPartitionStoreCount();
    }

    @Override
    public void operate() throws Exception {
        adminClient = AdminClient.createTempAdminClient(voldemortConfig,
                                                           metadataStore.getCluster(),
                                                           voldemortConfig.getMaxParallelStoresRebalancing());
        final List<Exception> failures = new ArrayList<Exception>();
        final ConcurrentLinkedQueue<String> storesRebalancing = new ConcurrentLinkedQueue<String>();
        final AtomicInteger completedStoresCount = new AtomicInteger(0);
        final int totalStoresCount = stealInfo.getPartitionStores().size();

        try {

            for (final String storeName : ImmutableList.copyOf(stealInfo.getPartitionStores())) {

                executors.submit(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            boolean isReadOnlyStore = metadataStore.getStoreDef(storeName)
                                                                   .getType()
                                                                   .compareTo(ReadOnlyStorageConfiguration.TYPE_NAME) == 0;

                            // Add the store to the rebalancing list
                            storesRebalancing.add(storeName);
                            updateStatus(getHeader(stealInfo) + "Completed working on "
                                         + completedStoresCount.get() + " out of "
                                         + totalStoresCount + " stores. Still rebalancing "
                                         + storesRebalancing);

                            // Start the rebalance..
                            rebalanceStore(storeName, adminClient, stealInfo, isReadOnlyStore);

                            // We finished the store, delete it
                            stealInfo.removeStore(storeName);
                            storesRebalancing.remove(storeName);

                            // Increment the store count
                            completedStoresCount.getAndIncrement();

                            updateStatus(getHeader(stealInfo) + "Completed working on "
                                         + completedStoresCount.get() + " out of "
                                         + totalStoresCount + " stores. Still rebalancing "
                                         + storesRebalancing);

                        } catch(Exception e) {
                            logger.error(getHeader(stealInfo)
                                         + "Error while rebalancing for store " + storeName + " - "
                                         + e.getMessage(), e);
                            failures.add(e);
                        }
                    }
                });

            }

            waitForShutdown();

            // If empty, clean state
            List<String> unbalancedStores = Lists.newArrayList(stealInfo.getPartitionStores());
            if(unbalancedStores.isEmpty()) {
                logger.info(getHeader(stealInfo) + "Rebalance of " + stealInfo
                            + " completed successfully for all " + totalStoresCount + " stores");
                updateStatus(getHeader(stealInfo) + "Rebalance of " + partitionStoreCount
                             + " partition-stores completed successfully for all "
                             + totalStoresCount + " stores");
                metadataStore.deleteRebalancingState(stealInfo);
            } else {
                throw new VoldemortRebalancingException(getHeader(stealInfo)
                                                        + "Failed to rebalance task " + stealInfo
                                                        + ". Could only complete "
                                                        + completedStoresCount.get() + " out of "
                                                        + totalStoresCount + " stores", failures);
            }

        } finally {
            // free the permit in all cases.
            logger.info(getHeader(stealInfo) + "Releasing permit for donor node "
                        + stealInfo.getDonorId());

            rebalancer.releaseRebalancingPermit(stealInfo.getDonorId());
            adminClient.close();
            adminClient = null;
        }
    }

    @Override
    public void stop() {
        updateStatus(getHeader(stealInfo) + "Stop called on rebalance operation");
        if(null != adminClient) {
            for(int asyncID: rebalanceStatusList) {
                adminClient.rpcOps.stopAsyncRequest(metadataStore.getNodeId(), asyncID);
            }
        }

        executors.shutdownNow();
    }

    private String getHeader(RebalanceTaskInfo stealInfo) {
        return "Stealer " + stealInfo.getStealerId() + ", Donor " + stealInfo.getDonorId() + "] ";
    }

    /**
     * Blocking function which completes the migration of one store
     *
     * @param storeName The name of the store
     * @param adminClient Admin client used to initiate the copying of data
     * @param stealInfo The steal information
     * @param isReadOnlyStore Boolean indicating that this is a read-only store
     */
    private void rebalanceStore(String storeName,
                                final AdminClient adminClient,
                                RebalanceTaskInfo stealInfo,
                                boolean isReadOnlyStore) {
        // Move partitions
        if (stealInfo.getPartitionIds(storeName) != null && stealInfo.getPartitionIds(storeName).size() > 0) {

            logger.info(getHeader(stealInfo) + "Starting partitions migration for store "
                        + storeName + " from donor node " + stealInfo.getDonorId());

            int asyncId = adminClient.storeMntOps.migratePartitions(stealInfo.getDonorId(),
                                                                    metadataStore.getNodeId(),
                                                                    storeName,
                                                                    stealInfo.getPartitionIds(storeName),
                                                                    null,
                                                                    stealInfo.getInitialCluster());
            rebalanceStatusList.add(asyncId);

            if(logger.isDebugEnabled()) {
                logger.debug(getHeader(stealInfo) + "Waiting for completion for " + storeName
                             + " with async id " + asyncId);
            }
            adminClient.rpcOps.waitForCompletion(metadataStore.getNodeId(),
                                                 asyncId,
                                                 voldemortConfig.getRebalancingTimeoutSec(),
                                                 TimeUnit.SECONDS,
                                                 getStatus());

            rebalanceStatusList.remove((Object) asyncId);

            logger.info(getHeader(stealInfo) + "Completed partition migration for store "
                        + storeName + " from donor node " + stealInfo.getDonorId());
        }

        logger.info(getHeader(stealInfo) + "Finished all migration for store " + storeName);
    }
}
TOP

Related Classes of voldemort.server.rebalance.async.StealerBasedRebalanceAsyncOperation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.