Package org.apache.cassandra.repair

Source Code of org.apache.cassandra.repair.RepairJob

/*
* 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.cassandra.repair;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.cassandra.concurrent.Stage;
import org.apache.cassandra.concurrent.StageManager;
import org.apache.cassandra.db.SnapshotCommand;
import org.apache.cassandra.db.Keyspace;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.net.IAsyncCallback;
import org.apache.cassandra.net.MessageIn;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.repair.messages.ValidationRequest;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.MerkleTree;
import org.apache.cassandra.utils.SimpleCondition;

/**
* RepairJob runs repair on given ColumnFamily.
*/
public class RepairJob
{
    private static Logger logger = LoggerFactory.getLogger(RepairJob.class);

    public final RepairJobDesc desc;
    private final boolean isSequential;
    // first we send tree requests. this tracks the endpoints remaining to hear from
    private final RequestCoordinator<InetAddress> treeRequests;
    // tree responses are then tracked here
    private final List<TreeResponse> trees = new ArrayList<>();
    // once all responses are received, each tree is compared with each other, and differencer tasks
    // are submitted. the job is done when all differencers are complete.
    private final RequestCoordinator<Differencer> differencers;
    private final Condition requestsSent = new SimpleCondition();
    private CountDownLatch snapshotLatch = null;
    private int gcBefore = -1;

    private volatile boolean failed = false;

    /**
     * Create repair job to run on specific columnfamily
     */
    public RepairJob(UUID parentSessionId, UUID sessionId, String keyspace, String columnFamily, Range<Token> range, boolean isSequential)
    {
        this.desc = new RepairJobDesc(parentSessionId, sessionId, keyspace, columnFamily, range);
        this.isSequential = isSequential;
        this.treeRequests = new RequestCoordinator<InetAddress>(isSequential)
        {
            public void send(InetAddress endpoint)
            {
                ValidationRequest request = new ValidationRequest(desc, gcBefore);
                MessagingService.instance().sendOneWay(request.createMessage(), endpoint);
            }
        };
        this.differencers = new RequestCoordinator<Differencer>(isSequential)
        {
            public void send(Differencer d)
            {
                StageManager.getStage(Stage.ANTI_ENTROPY).execute(d);
            }
        };
    }

    /**
     * @return true if this job failed
     */
    public boolean isFailed()
    {
        return failed;
    }

    /**
     * Send merkle tree request to every involved neighbor.
     */
    public void sendTreeRequests(Collection<InetAddress> endpoints)
    {
        // send requests to all nodes
        List<InetAddress> allEndpoints = new ArrayList<>(endpoints);
        allEndpoints.add(FBUtilities.getBroadcastAddress());

        if (isSequential)
            makeSnapshots(endpoints);

        this.gcBefore = Keyspace.open(desc.keyspace).getColumnFamilyStore(desc.columnFamily).gcBefore(System.currentTimeMillis());

        for (InetAddress endpoint : allEndpoints)
            treeRequests.add(endpoint);

        logger.info(String.format("[repair #%s] requesting merkle trees for %s (to %s)", desc.sessionId, desc.columnFamily, allEndpoints));
        treeRequests.start();
        requestsSent.signalAll();
    }

    public void makeSnapshots(Collection<InetAddress> endpoints)
    {
        try
        {
            snapshotLatch = new CountDownLatch(endpoints.size());
            IAsyncCallback callback = new IAsyncCallback()
            {
                public boolean isLatencyForSnitch()
                {
                    return false;
                }

                public void response(MessageIn msg)
                {
                    RepairJob.this.snapshotLatch.countDown();
                }
            };
            for (InetAddress endpoint : endpoints)
                MessagingService.instance().sendRR(new SnapshotCommand(desc.keyspace, desc.columnFamily, desc.sessionId.toString(), false).createMessage(), endpoint, callback);
            snapshotLatch.await();
            snapshotLatch = null;
        }
        catch (InterruptedException e)
        {
            throw new RuntimeException(e);
        }
    }

    /**
     * Add a new received tree and return the number of remaining tree to
     * be received for the job to be complete.
     *
     * Callers may assume exactly one addTree call will result in zero remaining endpoints.
     *
     * @param endpoint address of the endpoint that sent response
     * @param tree sent Merkle tree or null if validation failed on endpoint
     * @return the number of responses waiting to receive
     */
    public synchronized int addTree(InetAddress endpoint, MerkleTree tree)
    {
        // Wait for all request to have been performed (see #3400)
        try
        {
            requestsSent.await();
        }
        catch (InterruptedException e)
        {
            throw new AssertionError("Interrupted while waiting for requests to be sent");
        }

        if (tree == null)
            failed = true;
        else
            trees.add(new TreeResponse(endpoint, tree));
        return treeRequests.completed(endpoint);
    }

    /**
     * Submit differencers for running.
     * All tree *must* have been received before this is called.
     */
    public void submitDifferencers()
    {
        assert !failed;

        // We need to difference all trees one against another
        for (int i = 0; i < trees.size() - 1; ++i)
        {
            TreeResponse r1 = trees.get(i);
            for (int j = i + 1; j < trees.size(); ++j)
            {
                TreeResponse r2 = trees.get(j);
                Differencer differencer = new Differencer(desc, r1, r2);
                logger.debug("Queueing comparison {}", differencer);
                differencers.add(differencer);
            }
        }
        differencers.start();
        trees.clear(); // allows gc to do its thing
    }

    /**
     * @return true if the given node pair was the last remaining
     */
    synchronized boolean completedSynchronization(NodePair nodes, boolean success)
    {
        if (!success)
            failed = true;
        Differencer completed = new Differencer(desc, new TreeResponse(nodes.endpoint1, null), new TreeResponse(nodes.endpoint2, null));
        return differencers.completed(completed) == 0;
    }

    /**
     * terminate this job.
     */
    public void terminate()
    {
        if (snapshotLatch != null)
        {
            while (snapshotLatch.getCount() > 0)
                snapshotLatch.countDown();
        }
    }
}
TOP

Related Classes of org.apache.cassandra.repair.RepairJob

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.