Package voldemort.store.routed.action

Source Code of voldemort.store.routed.action.PerformParallelGetAllRequests

/*
* Copyright 2010 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.store.routed.action;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang.mutable.MutableInt;
import org.apache.log4j.Level;

import voldemort.cluster.Node;
import voldemort.cluster.failuredetector.FailureDetector;
import voldemort.store.InvalidMetadataException;
import voldemort.store.nonblockingstore.NonblockingStore;
import voldemort.store.nonblockingstore.NonblockingStoreCallback;
import voldemort.store.routed.GetAllPipelineData;
import voldemort.store.routed.Pipeline;
import voldemort.store.routed.Pipeline.Event;
import voldemort.store.routed.Response;
import voldemort.utils.ByteArray;
import voldemort.versioning.Versioned;

import com.google.common.collect.Lists;

public class PerformParallelGetAllRequests
        extends
        AbstractAction<Iterable<ByteArray>, Map<ByteArray, List<Versioned<byte[]>>>, GetAllPipelineData> {

    private final long timeoutMs;

    private final Map<Integer, NonblockingStore> nonblockingStores;

    private final FailureDetector failureDetector;

    public PerformParallelGetAllRequests(GetAllPipelineData pipelineData,
                                         Event completeEvent,
                                         FailureDetector failureDetector,
                                         long timeoutMs,
                                         Map<Integer, NonblockingStore> nonblockingStores) {
        super(pipelineData, completeEvent);
        this.failureDetector = failureDetector;
        this.timeoutMs = timeoutMs;
        this.nonblockingStores = nonblockingStores;
    }

    @SuppressWarnings("unchecked")
    public void execute(final Pipeline pipeline) {
        int attempts = pipelineData.getNodeToKeysMap().size();
        final Map<Integer, Response<Iterable<ByteArray>, Object>> responses = new ConcurrentHashMap<Integer, Response<Iterable<ByteArray>, Object>>();
        final CountDownLatch latch = new CountDownLatch(attempts);

        if (logger.isTraceEnabled())
            logger.trace("Attempting " + attempts + " " + pipeline.getOperation().getSimpleName()
                         + " operations in parallel");

        Map<ByteArray, byte[]> transforms = pipelineData.getTransforms();

        final AtomicBoolean isResponseProcessed = new AtomicBoolean(false);

        for (Map.Entry<Node, List<ByteArray>> entry: pipelineData.getNodeToKeysMap().entrySet()) {
            final Node node = entry.getKey();
            final Collection<ByteArray> keys = entry.getValue();

            NonblockingStoreCallback callback = new NonblockingStoreCallback() {

                public void requestComplete(Object result, long requestTime) {
                    if (logger.isTraceEnabled())
                        logger.trace(pipeline.getOperation().getSimpleName()
                                     + " response received (" + requestTime + " ms.) from node "
                                     + node.getId());

                    Response<Iterable<ByteArray>, Object> response = new Response<Iterable<ByteArray>, Object>(node,
                                                                                                               keys,
                                                                                                               result,
                                                                                                               requestTime);
                    responses.put(node.getId(), response);
                    latch.countDown();
                    // TODO: There is inconsistency between the exceptions are treated here in the
                    // completion callback and in the application thread.
                    // They need a cleanup to make them consistent. Thought about handling
                    // them here, but it is the selector thread that is calling this completion method,
                    // handleResponseError has some synchronization, not sure about the effect, so reserving
                    // it for later.

                    // isResponseProcessed just reduces the time window during
                    // which a exception can go uncounted. When the parallel
                    // requests timeout and it is trying Serial timeout
                    // exceptions are lost and the node is never marked down.
                    // This reduces the window where an exception is lost
                    if (isResponseProcessed.get() && response.getValue() instanceof Exception)
                        if (response.getValue() instanceof InvalidMetadataException) {
                            pipelineData.reportException((InvalidMetadataException) response.getValue());
                            logger.warn("Received invalid metadata problem after a successful "
                                        + pipeline.getOperation().getSimpleName()
                                        + " call on node " + node.getId() + ", store '"
                                        + pipelineData.getStoreName() + "'");
                        } else {
                            handleResponseError(response, pipeline, failureDetector);
                        }
                }

            };

            if (logger.isTraceEnabled())
                logger.trace("Submitting " + pipeline.getOperation().getSimpleName()
                             + " request on node " + node.getId());

            NonblockingStore store = nonblockingStores.get(node.getId());
            store.submitGetAllRequest(keys, transforms, callback, timeoutMs);
        }

        try {
            latch.await(timeoutMs, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            if (logger.isEnabledFor(Level.WARN))
                logger.warn(e, e);
        }

        for (Response<Iterable<ByteArray>, Object> response: responses.values()) {
            if (response.getValue() instanceof Exception) {
                if (handleResponseError(response, pipeline, failureDetector))
                    return;
            } else {
                Map<ByteArray, List<Versioned<byte[]>>> values = (Map<ByteArray, List<Versioned<byte[]>>>) response.getValue();

                for (ByteArray key: response.getKey()) {
                    MutableInt successCount = pipelineData.getSuccessCount(key);
                    successCount.increment();

                    List<Versioned<byte[]>> retrieved = values.get(key);
                    /*
                     * retrieved can be null if there are no values for the key
                     * provided
                     */
                    if (retrieved != null) {
                        List<Versioned<byte[]>> existing = pipelineData.getResult().get(key);

                        if (existing == null)
                            pipelineData.getResult().put(key, Lists.newArrayList(retrieved));
                        else
                            existing.addAll(retrieved);
                    }

                    HashSet<Integer> zoneResponses = null;
                    if (pipelineData.getKeyToZoneResponse().containsKey(key)) {
                        zoneResponses = pipelineData.getKeyToZoneResponse().get(key);
                    } else {
                        zoneResponses = new HashSet<Integer>();
                        pipelineData.getKeyToZoneResponse().put(key, zoneResponses);
                    }
                    zoneResponses.add(response.getNode().getZoneId());
                }

                pipelineData.getResponses()
                            .add(new Response<Iterable<ByteArray>, Map<ByteArray, List<Versioned<byte[]>>>>(response.getNode(),
                                                                                                            response.getKey(),
                                                                                                            values,
                                                                                                            response.getRequestTime()));
                failureDetector.recordSuccess(response.getNode(), response.getRequestTime());
            }
        }
        isResponseProcessed.set(true);

        pipeline.addEvent(completeEvent);
    }
}
TOP

Related Classes of voldemort.store.routed.action.PerformParallelGetAllRequests

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.