Search in sources :

Example 11 with QuorumVerifier

use of org.apache.zookeeper.server.quorum.flexible.QuorumVerifier in project zookeeper by apache.

the class Learner method syncWithLeader.

/**
     * Finally, synchronize our history with the Leader. 
     * @param newLeaderZxid
     * @throws IOException
     * @throws InterruptedException
     */
protected void syncWithLeader(long newLeaderZxid) throws Exception {
    QuorumPacket ack = new QuorumPacket(Leader.ACK, 0, null, null);
    QuorumPacket qp = new QuorumPacket();
    long newEpoch = ZxidUtils.getEpochFromZxid(newLeaderZxid);
    QuorumVerifier newLeaderQV = null;
    // In the DIFF case we don't need to do a snapshot because the transactions will sync on top of any existing snapshot
    // For SNAP and TRUNC the snapshot is needed to save that history
    boolean snapshotNeeded = true;
    readPacket(qp);
    LinkedList<Long> packetsCommitted = new LinkedList<Long>();
    LinkedList<PacketInFlight> packetsNotCommitted = new LinkedList<PacketInFlight>();
    synchronized (zk) {
        if (qp.getType() == Leader.DIFF) {
            LOG.info("Getting a diff from the leader 0x{}", Long.toHexString(qp.getZxid()));
            snapshotNeeded = false;
        } else if (qp.getType() == Leader.SNAP) {
            LOG.info("Getting a snapshot from leader");
            // The leader is going to dump the database
            // db is clear as part of deserializeSnapshot()
            zk.getZKDatabase().deserializeSnapshot(leaderIs);
            String signature = leaderIs.readString("signature");
            if (!signature.equals("BenWasHere")) {
                LOG.error("Missing signature. Got " + signature);
                throw new IOException("Missing signature");
            }
        } else if (qp.getType() == Leader.TRUNC) {
            //we need to truncate the log to the lastzxid of the leader
            LOG.warn("Truncating log to get in sync with the leader 0x" + Long.toHexString(qp.getZxid()));
            boolean truncated = zk.getZKDatabase().truncateLog(qp.getZxid());
            if (!truncated) {
                // not able to truncate the log
                LOG.error("Not able to truncate the log " + Long.toHexString(qp.getZxid()));
                System.exit(13);
            }
        } else {
            LOG.error("Got unexpected packet from leader: {}, exiting ... ", LearnerHandler.packetToString(qp));
            System.exit(13);
        }
        zk.getZKDatabase().initConfigInZKDatabase(self.getQuorumVerifier());
        zk.getZKDatabase().setlastProcessedZxid(qp.getZxid());
        zk.createSessionTracker();
        long lastQueued = 0;
        // in Zab V1.0 (ZK 3.4+) we might take a snapshot when we get the NEWLEADER message, but in pre V1.0
        // we take the snapshot on the UPDATE message, since Zab V1.0 also gets the UPDATE (after the NEWLEADER)
        // we need to make sure that we don't take the snapshot twice.
        boolean isPreZAB1_0 = true;
        //If we are not going to take the snapshot be sure the transactions are not applied in memory
        // but written out to the transaction log
        boolean writeToTxnLog = !snapshotNeeded;
        // we are now going to start getting transactions to apply followed by an UPTODATE
        outerLoop: while (self.isRunning()) {
            readPacket(qp);
            switch(qp.getType()) {
                case Leader.PROPOSAL:
                    PacketInFlight pif = new PacketInFlight();
                    pif.hdr = new TxnHeader();
                    pif.rec = SerializeUtils.deserializeTxn(qp.getData(), pif.hdr);
                    if (pif.hdr.getZxid() != lastQueued + 1) {
                        LOG.warn("Got zxid 0x" + Long.toHexString(pif.hdr.getZxid()) + " expected 0x" + Long.toHexString(lastQueued + 1));
                    }
                    lastQueued = pif.hdr.getZxid();
                    if (pif.hdr.getType() == OpCode.reconfig) {
                        SetDataTxn setDataTxn = (SetDataTxn) pif.rec;
                        QuorumVerifier qv = self.configFromString(new String(setDataTxn.getData()));
                        self.setLastSeenQuorumVerifier(qv, true);
                    }
                    packetsNotCommitted.add(pif);
                    break;
                case Leader.COMMIT:
                case Leader.COMMITANDACTIVATE:
                    pif = packetsNotCommitted.peekFirst();
                    if (pif.hdr.getZxid() == qp.getZxid() && qp.getType() == Leader.COMMITANDACTIVATE) {
                        QuorumVerifier qv = self.configFromString(new String(((SetDataTxn) pif.rec).getData()));
                        boolean majorChange = self.processReconfig(qv, ByteBuffer.wrap(qp.getData()).getLong(), qp.getZxid(), true);
                        if (majorChange) {
                            throw new Exception("changes proposed in reconfig");
                        }
                    }
                    if (!writeToTxnLog) {
                        if (pif.hdr.getZxid() != qp.getZxid()) {
                            LOG.warn("Committing " + qp.getZxid() + ", but next proposal is " + pif.hdr.getZxid());
                        } else {
                            zk.processTxn(pif.hdr, pif.rec);
                            packetsNotCommitted.remove();
                        }
                    } else {
                        packetsCommitted.add(qp.getZxid());
                    }
                    break;
                case Leader.INFORM:
                case Leader.INFORMANDACTIVATE:
                    PacketInFlight packet = new PacketInFlight();
                    packet.hdr = new TxnHeader();
                    if (qp.getType() == Leader.INFORMANDACTIVATE) {
                        ByteBuffer buffer = ByteBuffer.wrap(qp.getData());
                        long suggestedLeaderId = buffer.getLong();
                        byte[] remainingdata = new byte[buffer.remaining()];
                        buffer.get(remainingdata);
                        packet.rec = SerializeUtils.deserializeTxn(remainingdata, packet.hdr);
                        QuorumVerifier qv = self.configFromString(new String(((SetDataTxn) packet.rec).getData()));
                        boolean majorChange = self.processReconfig(qv, suggestedLeaderId, qp.getZxid(), true);
                        if (majorChange) {
                            throw new Exception("changes proposed in reconfig");
                        }
                    } else {
                        packet.rec = SerializeUtils.deserializeTxn(qp.getData(), packet.hdr);
                        // Log warning message if txn comes out-of-order
                        if (packet.hdr.getZxid() != lastQueued + 1) {
                            LOG.warn("Got zxid 0x" + Long.toHexString(packet.hdr.getZxid()) + " expected 0x" + Long.toHexString(lastQueued + 1));
                        }
                        lastQueued = packet.hdr.getZxid();
                    }
                    if (!writeToTxnLog) {
                        // Apply to db directly if we haven't taken the snapshot
                        zk.processTxn(packet.hdr, packet.rec);
                    } else {
                        packetsNotCommitted.add(packet);
                        packetsCommitted.add(qp.getZxid());
                    }
                    break;
                case Leader.UPTODATE:
                    LOG.info("Learner received UPTODATE message");
                    if (newLeaderQV != null) {
                        boolean majorChange = self.processReconfig(newLeaderQV, null, null, true);
                        if (majorChange) {
                            throw new Exception("changes proposed in reconfig");
                        }
                    }
                    if (isPreZAB1_0) {
                        zk.takeSnapshot();
                        self.setCurrentEpoch(newEpoch);
                    }
                    self.setZooKeeperServer(zk);
                    self.adminServer.setZooKeeperServer(zk);
                    break outerLoop;
                case // Getting NEWLEADER here instead of in discovery 
                Leader.NEWLEADER:
                    // means this is Zab 1.0
                    LOG.info("Learner received NEWLEADER message");
                    if (qp.getData() != null && qp.getData().length > 1) {
                        try {
                            QuorumVerifier qv = self.configFromString(new String(qp.getData()));
                            self.setLastSeenQuorumVerifier(qv, true);
                            newLeaderQV = qv;
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    if (snapshotNeeded) {
                        zk.takeSnapshot();
                    }
                    self.setCurrentEpoch(newEpoch);
                    //Anything after this needs to go to the transaction log, not applied directly in memory
                    writeToTxnLog = true;
                    isPreZAB1_0 = false;
                    writePacket(new QuorumPacket(Leader.ACK, newLeaderZxid, null, null), true);
                    break;
            }
        }
    }
    ack.setZxid(ZxidUtils.makeZxid(newEpoch, 0));
    writePacket(ack, true);
    sock.setSoTimeout(self.tickTime * self.syncLimit);
    zk.startup();
    /*
         * Update the election vote here to ensure that all members of the
         * ensemble report the same vote to new servers that start up and
         * send leader election notifications to the ensemble.
         * 
         * @see https://issues.apache.org/jira/browse/ZOOKEEPER-1732
         */
    self.updateElectionVote(newEpoch);
    // We need to log the stuff that came in between the snapshot and the uptodate
    if (zk instanceof FollowerZooKeeperServer) {
        FollowerZooKeeperServer fzk = (FollowerZooKeeperServer) zk;
        for (PacketInFlight p : packetsNotCommitted) {
            fzk.logRequest(p.hdr, p.rec);
        }
        for (Long zxid : packetsCommitted) {
            fzk.commit(zxid);
        }
    } else if (zk instanceof ObserverZooKeeperServer) {
        // Similar to follower, we need to log requests between the snapshot
        // and UPTODATE
        ObserverZooKeeperServer ozk = (ObserverZooKeeperServer) zk;
        for (PacketInFlight p : packetsNotCommitted) {
            Long zxid = packetsCommitted.peekFirst();
            if (p.hdr.getZxid() != zxid) {
                // log warning message if there is no matching commit
                // old leader send outstanding proposal to observer
                LOG.warn("Committing " + Long.toHexString(zxid) + ", but next proposal is " + Long.toHexString(p.hdr.getZxid()));
                continue;
            }
            packetsCommitted.remove();
            Request request = new Request(null, p.hdr.getClientId(), p.hdr.getCxid(), p.hdr.getType(), null, null);
            request.setTxn(p.rec);
            request.setHdr(p.hdr);
            ozk.commitRequest(request);
        }
    } else {
        // New server type need to handle in-flight packets
        throw new UnsupportedOperationException("Unknown server type");
    }
}
Also used : Request(org.apache.zookeeper.server.Request) IOException(java.io.IOException) SetDataTxn(org.apache.zookeeper.txn.SetDataTxn) ByteBuffer(java.nio.ByteBuffer) QuorumVerifier(org.apache.zookeeper.server.quorum.flexible.QuorumVerifier) LinkedList(java.util.LinkedList) ConnectException(java.net.ConnectException) IOException(java.io.IOException) TxnHeader(org.apache.zookeeper.txn.TxnHeader)

Example 12 with QuorumVerifier

use of org.apache.zookeeper.server.quorum.flexible.QuorumVerifier in project zookeeper by apache.

the class QuorumPeer method setQuorumVerifier.

public QuorumVerifier setQuorumVerifier(QuorumVerifier qv, boolean writeToDisk) {
    synchronized (QV_LOCK) {
        if ((quorumVerifier != null) && (quorumVerifier.getVersion() >= qv.getVersion())) {
            // this is normal. For example - server found out about new config through FastLeaderElection gossiping
            // and then got the same config in UPTODATE message so its already known
            LOG.debug(getId() + " setQuorumVerifier called with known or old config " + qv.getVersion() + ". Current version: " + quorumVerifier.getVersion());
            return quorumVerifier;
        }
        QuorumVerifier prevQV = quorumVerifier;
        quorumVerifier = qv;
        if (lastSeenQuorumVerifier == null || (qv.getVersion() > lastSeenQuorumVerifier.getVersion()))
            lastSeenQuorumVerifier = qv;
        if (writeToDisk) {
            // some tests initialize QuorumPeer without a static config file
            if (configFilename != null) {
                try {
                    String dynamicConfigFilename = makeDynamicConfigFilename(qv.getVersion());
                    QuorumPeerConfig.writeDynamicConfig(dynamicConfigFilename, qv, false);
                    QuorumPeerConfig.editStaticConfig(configFilename, dynamicConfigFilename, needEraseClientInfoFromStaticConfig());
                } catch (IOException e) {
                    LOG.error("Error closing file: ", e.getMessage());
                }
            } else {
                LOG.info("writeToDisk == true but configFilename == null");
            }
        }
        if (qv.getVersion() == lastSeenQuorumVerifier.getVersion()) {
            QuorumPeerConfig.deleteFile(getNextDynamicConfigFilename());
        }
        QuorumServer qs = qv.getAllMembers().get(getId());
        if (qs != null) {
            setQuorumAddress(qs.addr);
            setElectionAddress(qs.electionAddr);
            setClientAddress(qs.clientAddr);
        }
        return prevQV;
    }
}
Also used : IOException(java.io.IOException) QuorumVerifier(org.apache.zookeeper.server.quorum.flexible.QuorumVerifier)

Example 13 with QuorumVerifier

use of org.apache.zookeeper.server.quorum.flexible.QuorumVerifier in project zookeeper by apache.

the class QuorumPeerConfig method parseDynamicConfig.

/**
     * Parse dynamic configuration file and return
     * quorumVerifier for new configuration.
     * @param dynamicConfigProp Properties to parse from.
     * @throws IOException
     * @throws ConfigException
     */
public static QuorumVerifier parseDynamicConfig(Properties dynamicConfigProp, int eAlg, boolean warnings, boolean configBackwardCompatibilityMode) throws IOException, ConfigException {
    boolean isHierarchical = false;
    for (Entry<Object, Object> entry : dynamicConfigProp.entrySet()) {
        String key = entry.getKey().toString().trim();
        if (key.startsWith("group") || key.startsWith("weight")) {
            isHierarchical = true;
        } else if (!configBackwardCompatibilityMode && !key.startsWith("server.") && !key.equals("version")) {
            LOG.info(dynamicConfigProp.toString());
            throw new ConfigException("Unrecognised parameter: " + key);
        }
    }
    QuorumVerifier qv = createQuorumVerifier(dynamicConfigProp, isHierarchical);
    int numParticipators = qv.getVotingMembers().size();
    int numObservers = qv.getObservingMembers().size();
    if (numParticipators == 0) {
        if (!standaloneEnabled) {
            throw new IllegalArgumentException("standaloneEnabled = false then " + "number of participants should be >0");
        }
        if (numObservers > 0) {
            throw new IllegalArgumentException("Observers w/o participants is an invalid configuration");
        }
    } else if (numParticipators == 1 && standaloneEnabled) {
        // HBase currently adds a single server line to the config, for
        // b/w compatibility reasons we need to keep this here. If standaloneEnabled
        // is true, the QuorumPeerMain script will create a standalone server instead
        // of a quorum configuration
        LOG.error("Invalid configuration, only one server specified (ignoring)");
        if (numObservers > 0) {
            throw new IllegalArgumentException("Observers w/o quorum is an invalid configuration");
        }
    } else {
        if (warnings) {
            if (numParticipators <= 2) {
                LOG.warn("No server failure will be tolerated. " + "You need at least 3 servers.");
            } else if (numParticipators % 2 == 0) {
                LOG.warn("Non-optimial configuration, consider an odd number of servers.");
            }
        }
        /*
             * If using FLE, then every server requires a separate election
             * port.
             */
        if (eAlg != 0) {
            for (QuorumServer s : qv.getVotingMembers().values()) {
                if (s.electionAddr == null)
                    throw new IllegalArgumentException("Missing election port for server: " + s.id);
            }
        }
    }
    return qv;
}
Also used : QuorumServer(org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer) QuorumVerifier(org.apache.zookeeper.server.quorum.flexible.QuorumVerifier)

Example 14 with QuorumVerifier

use of org.apache.zookeeper.server.quorum.flexible.QuorumVerifier in project zookeeper by apache.

the class Follower method processPacket.

/**
     * Examine the packet received in qp and dispatch based on its contents.
     * @param qp
     * @throws IOException
     */
protected void processPacket(QuorumPacket qp) throws Exception {
    switch(qp.getType()) {
        case Leader.PING:
            ping(qp);
            break;
        case Leader.PROPOSAL:
            TxnHeader hdr = new TxnHeader();
            Record txn = SerializeUtils.deserializeTxn(qp.getData(), hdr);
            if (hdr.getZxid() != lastQueued + 1) {
                LOG.warn("Got zxid 0x" + Long.toHexString(hdr.getZxid()) + " expected 0x" + Long.toHexString(lastQueued + 1));
            }
            lastQueued = hdr.getZxid();
            if (hdr.getType() == OpCode.reconfig) {
                SetDataTxn setDataTxn = (SetDataTxn) txn;
                QuorumVerifier qv = self.configFromString(new String(setDataTxn.getData()));
                self.setLastSeenQuorumVerifier(qv, true);
            }
            fzk.logRequest(hdr, txn);
            break;
        case Leader.COMMIT:
            fzk.commit(qp.getZxid());
            break;
        case Leader.COMMITANDACTIVATE:
            // get the new configuration from the request
            Request request = fzk.pendingTxns.element();
            SetDataTxn setDataTxn = (SetDataTxn) request.getTxn();
            QuorumVerifier qv = self.configFromString(new String(setDataTxn.getData()));
            // get new designated leader from (current) leader's message
            ByteBuffer buffer = ByteBuffer.wrap(qp.getData());
            long suggestedLeaderId = buffer.getLong();
            boolean majorChange = self.processReconfig(qv, suggestedLeaderId, qp.getZxid(), true);
            // commit (writes the new config to ZK tree (/zookeeper/config)                     
            fzk.commit(qp.getZxid());
            if (majorChange) {
                throw new Exception("changes proposed in reconfig");
            }
            break;
        case Leader.UPTODATE:
            LOG.error("Received an UPTODATE message after Follower started");
            break;
        case Leader.REVALIDATE:
            revalidate(qp);
            break;
        case Leader.SYNC:
            fzk.sync();
            break;
        default:
            LOG.warn("Unknown packet type: {}", LearnerHandler.packetToString(qp));
            break;
    }
}
Also used : Request(org.apache.zookeeper.server.Request) Record(org.apache.jute.Record) SetDataTxn(org.apache.zookeeper.txn.SetDataTxn) ByteBuffer(java.nio.ByteBuffer) QuorumVerifier(org.apache.zookeeper.server.quorum.flexible.QuorumVerifier) IOException(java.io.IOException) TxnHeader(org.apache.zookeeper.txn.TxnHeader)

Example 15 with QuorumVerifier

use of org.apache.zookeeper.server.quorum.flexible.QuorumVerifier in project zookeeper by apache.

the class QuorumPeer method processReconfig.

public boolean processReconfig(QuorumVerifier qv, Long suggestedLeaderId, Long zxid, boolean restartLE) {
    InetSocketAddress oldClientAddr = getClientAddress();
    // update last committed quorum verifier, write the new config to disk
    // and restart leader election if config changed
    QuorumVerifier prevQV = setQuorumVerifier(qv, true);
    // There is no log record for the initial config, thus after syncing
    // with leader
    // /zookeeper/config is empty! it is also possible that last committed
    // config is propagated during leader election
    // without the propagation the corresponding log records.
    // so we should explicitly do this (this is not necessary when we're
    // already a Follower/Observer, only
    // for Learner):
    initConfigInZKDatabase();
    if (prevQV.getVersion() < qv.getVersion() && !prevQV.equals(qv)) {
        Map<Long, QuorumServer> newMembers = qv.getAllMembers();
        updateRemotePeerMXBeans(newMembers);
        if (restartLE)
            restartLeaderElection(prevQV, qv);
        QuorumServer myNewQS = newMembers.get(getId());
        if (myNewQS != null && myNewQS.clientAddr != null && !myNewQS.clientAddr.equals(oldClientAddr)) {
            cnxnFactory.reconfigure(myNewQS.clientAddr);
            updateThreadName();
        }
        boolean roleChange = updateLearnerType(qv);
        boolean leaderChange = false;
        if (suggestedLeaderId != null) {
            // zxid should be non-null too
            leaderChange = updateVote(suggestedLeaderId, zxid);
        } else {
            long currentLeaderId = getCurrentVote().getId();
            QuorumServer myleaderInCurQV = prevQV.getVotingMembers().get(currentLeaderId);
            QuorumServer myleaderInNewQV = qv.getVotingMembers().get(currentLeaderId);
            leaderChange = (myleaderInCurQV == null || myleaderInCurQV.addr == null || myleaderInNewQV == null || !myleaderInCurQV.addr.equals(myleaderInNewQV.addr));
            // we don't have a designated leader - need to go into leader
            // election
            reconfigFlagClear();
        }
        if (roleChange || leaderChange) {
            return true;
        }
    }
    return false;
}
Also used : InetSocketAddress(java.net.InetSocketAddress) QuorumVerifier(org.apache.zookeeper.server.quorum.flexible.QuorumVerifier)

Aggregations

QuorumVerifier (org.apache.zookeeper.server.quorum.flexible.QuorumVerifier)16 IOException (java.io.IOException)7 SetDataTxn (org.apache.zookeeper.txn.SetDataTxn)4 TxnHeader (org.apache.zookeeper.txn.TxnHeader)4 ByteBuffer (java.nio.ByteBuffer)3 Request (org.apache.zookeeper.server.Request)3 AtomicLong (java.util.concurrent.atomic.AtomicLong)2 Record (org.apache.jute.Record)2 KeeperException (org.apache.zookeeper.KeeperException)2 ZooKeeper (org.apache.zookeeper.ZooKeeper)2 QuorumServer (org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer)2 Test (org.junit.Test)2 StringReader (java.io.StringReader)1 BindException (java.net.BindException)1 ConnectException (java.net.ConnectException)1 InetSocketAddress (java.net.InetSocketAddress)1 SocketException (java.net.SocketException)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1