Search in sources :

Example 16 with Slave

use of org.neo4j.kernel.ha.com.master.Slave in project neo4j by neo4j.

the class TransactionPropagator method committed.

/**
     *
     * @param txId transaction id to replicate
     * @param authorId author id for such transaction id
     * @return the number of missed replicas (e.g., desired replication factor - number of successful replications)
     */
public int committed(long txId, int authorId) {
    int replicationFactor = desiredReplicationFactor;
    // If the author is not this instance, then we need to push to one less - the committer already has it
    boolean isAuthoredBySlave = config.getServerId().toIntegerIndex() != authorId;
    if (isAuthoredBySlave) {
        replicationFactor--;
    }
    if (replicationFactor == 0) {
        return replicationFactor;
    }
    Collection<ReplicationContext> committers = new HashSet<>();
    try {
        // TODO: Move this logic into {@link CommitPusher}
        // Commit at the configured amount of slaves in parallel.
        int successfulReplications = 0;
        Iterator<Slave> slaveList = filter(replicationStrategy.prioritize(slaves.getSlaves()).iterator(), authorId);
        CompletionNotifier notifier = new CompletionNotifier();
        // Start as many initial committers as needed
        for (int i = 0; i < replicationFactor && slaveList.hasNext(); i++) {
            Slave slave = slaveList.next();
            Callable<Void> slaveCommitter = slaveCommitter(slave, txId, notifier);
            committers.add(new ReplicationContext(slaveCommitters.submit(slaveCommitter), slave));
        }
        // Wait for them and perhaps spawn new ones for failing committers until we're done
        // or until we have no more slaves to try out.
        Collection<ReplicationContext> toAdd = new ArrayList<>();
        Collection<ReplicationContext> toRemove = new ArrayList<>();
        while (!committers.isEmpty() && successfulReplications < replicationFactor) {
            toAdd.clear();
            toRemove.clear();
            for (ReplicationContext context : committers) {
                if (!context.future.isDone()) {
                    continue;
                }
                if (isSuccessful(context)) // This committer was successful, increment counter
                {
                    successfulReplications++;
                } else if (slaveList.hasNext()) // This committer failed, spawn another one
                {
                    Slave newSlave = slaveList.next();
                    Callable<Void> slaveCommitter;
                    try {
                        slaveCommitter = slaveCommitter(newSlave, txId, notifier);
                    } catch (Throwable t) {
                        log.error("Unknown error commit master transaction at slave", t);
                        return desiredReplicationFactor;
                    }
                    toAdd.add(new ReplicationContext(slaveCommitters.submit(slaveCommitter), newSlave));
                }
                toRemove.add(context);
            }
            // Incorporate the results into committers collection
            if (!toAdd.isEmpty()) {
                committers.addAll(toAdd);
            }
            if (!toRemove.isEmpty()) {
                committers.removeAll(toRemove);
            }
            if (!committers.isEmpty()) // There are committers doing work right now, so go and wait for
            // any of the committers to be done so that we can reevaluate
            // the situation again.
            {
                notifier.waitForAnyCompletion();
            }
        }
        // We did the best we could, have we committed successfully on enough slaves?
        if (successfulReplications < replicationFactor) {
            pushedToTooFewSlaveLogger.info("Transaction " + txId + " couldn't commit on enough slaves, desired " + replicationFactor + ", but could only commit at " + successfulReplications);
        }
        return replicationFactor - successfulReplications;
    } finally {
        // Cancel all ongoing committers in the executor
        for (ReplicationContext committer : committers) {
            committer.future.cancel(false);
        }
    }
}
Also used : ArrayList(java.util.ArrayList) Callable(java.util.concurrent.Callable) Slave(org.neo4j.kernel.ha.com.master.Slave) HashSet(java.util.HashSet)

Aggregations

Slave (org.neo4j.kernel.ha.com.master.Slave)16 Test (org.junit.Test)13 TransactionPropagator (org.neo4j.kernel.ha.transaction.TransactionPropagator)6 Cluster (org.neo4j.cluster.protocol.cluster.Cluster)4 HostnamePort (org.neo4j.helpers.HostnamePort)4 DefaultSlaveFactory (org.neo4j.kernel.ha.com.master.DefaultSlaveFactory)4 SlaveFactory (org.neo4j.kernel.ha.com.master.SlaveFactory)3 SlavePriority (org.neo4j.kernel.ha.com.master.SlavePriority)3 LifeSupport (org.neo4j.kernel.lifecycle.LifeSupport)3 ArrayList (java.util.ArrayList)2 Configuration (org.neo4j.kernel.ha.transaction.TransactionPropagator.Configuration)2 URI (java.net.URI)1 HashSet (java.util.HashSet)1 Callable (java.util.concurrent.Callable)1 ExecutorService (java.util.concurrent.ExecutorService)1 ClusterListener (org.neo4j.cluster.protocol.cluster.ClusterListener)1 TransactionObligationFulfiller (org.neo4j.com.storecopy.TransactionObligationFulfiller)1 UpdatePullerScheduler (org.neo4j.kernel.ha.UpdatePullerScheduler)1 MasterClient (org.neo4j.kernel.ha.com.slave.MasterClient)1 SlaveImpl (org.neo4j.kernel.ha.com.slave.SlaveImpl)1