Search in sources :

Example 36 with Request

use of org.apache.zookeeper.server.Request in project zookeeper by apache.

the class CommitProcessorConcurrencyTest method processAsMuchUncommittedRequestsAsPossibleTest.

/**
 * Here we create the following requests queue structure: R1_1, W1_2, R1_3,
 * R2_1, R2_2, W2_3, R2_4, R3_1, R3_2, R3_3, W3_4, R3_5, ... , W5_6, R5_7
 * i.e., 5 sessions, each has different amount or read requests, followed by
 * single write and afterwards single read. The idea is to check that all of
 * the reads that can be processed concurrently do so, and that none of the
 * uncommited requests, followed by the reads are processed.
 */
@Test
public void processAsMuchUncommittedRequestsAsPossibleTest() throws Exception {
    final String path = "/testAsMuchAsPossible";
    List<Request> shouldBeProcessed = new LinkedList<Request>();
    Set<Request> shouldNotBeProcessed = new HashSet<Request>();
    for (int sessionId = 1; sessionId <= 5; ++sessionId) {
        for (int readReqId = 1; readReqId <= sessionId; ++readReqId) {
            Request readReq = newRequest(new GetDataRequest(path, false), OpCode.getData, sessionId, readReqId);
            shouldBeProcessed.add(readReq);
            processor.queuedRequests.add(readReq);
        }
        Request writeReq = newRequest(new CreateRequest(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL.toFlag()), OpCode.create, sessionId, sessionId + 1);
        Request readReq = newRequest(new GetDataRequest(path, false), OpCode.getData, sessionId, sessionId + 2);
        processor.queuedRequests.add(writeReq);
        processor.queuedWriteRequests.add(writeReq);
        processor.queuedRequests.add(readReq);
        shouldNotBeProcessed.add(writeReq);
        shouldNotBeProcessed.add(readReq);
    }
    processor.initThreads(defaultSizeOfThreadPool);
    processor.stoppedMainLoop = true;
    processor.run();
    Thread.sleep(1000);
    shouldBeProcessed.removeAll(processedRequests);
    for (Request r : shouldBeProcessed) {
        LOG.error("Did not process {}", r);
    }
    assertTrue(shouldBeProcessed.isEmpty(), "Not all requests were processed");
    assertFalse(shouldNotBeProcessed.removeAll(processedRequests), "Processed a wrong request");
}
Also used : CreateRequest(org.apache.zookeeper.proto.CreateRequest) GetDataRequest(org.apache.zookeeper.proto.GetDataRequest) CreateRequest(org.apache.zookeeper.proto.CreateRequest) SetDataRequest(org.apache.zookeeper.proto.SetDataRequest) Request(org.apache.zookeeper.server.Request) GetDataRequest(org.apache.zookeeper.proto.GetDataRequest) LinkedList(java.util.LinkedList) HashSet(java.util.HashSet) Test(org.junit.jupiter.api.Test)

Example 37 with Request

use of org.apache.zookeeper.server.Request in project zookeeper by apache.

the class CommitProcessorConcurrencyTest method noStarvationOfNonLocalCommittedRequestsTest.

/**
 * In the following test, we verify that committed requests are processed
 * even when queuedRequests never gets empty. We add 10 committed request
 * and use infinite queuedRequests. We verify that the committed request was
 * processed.
 */
@Test
@Timeout(value = 1)
public void noStarvationOfNonLocalCommittedRequestsTest() throws Exception {
    final String path = "/noStarvationOfCommittedRequests";
    processor.queuedRequests = new MockRequestsQueue();
    Set<Request> nonLocalCommits = new HashSet<Request>();
    for (int i = 0; i < 10; i++) {
        Request nonLocalCommitReq = newRequest(new CreateRequest(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL.toFlag()), OpCode.create, 51, i + 1);
        processor.committedRequests.add(nonLocalCommitReq);
        nonLocalCommits.add(nonLocalCommitReq);
    }
    for (int i = 0; i < 10; i++) {
        processor.initThreads(defaultSizeOfThreadPool);
        processor.stoppedMainLoop = true;
        processor.run();
    }
    assertTrue(processedRequests.containsAll(nonLocalCommits), "commit request was not processed");
}
Also used : CreateRequest(org.apache.zookeeper.proto.CreateRequest) GetDataRequest(org.apache.zookeeper.proto.GetDataRequest) CreateRequest(org.apache.zookeeper.proto.CreateRequest) SetDataRequest(org.apache.zookeeper.proto.SetDataRequest) Request(org.apache.zookeeper.server.Request) HashSet(java.util.HashSet) Test(org.junit.jupiter.api.Test) Timeout(org.junit.jupiter.api.Timeout)

Example 38 with Request

use of org.apache.zookeeper.server.Request in project zookeeper by apache.

the class CommitProcessorConcurrencyTest method newRequest.

private Request newRequest(Record rec, int type, int sessionId, int xid) throws IOException {
    ByteArrayOutputStream boas = new ByteArrayOutputStream();
    BinaryOutputArchive boa = BinaryOutputArchive.getArchive(boas);
    rec.serialize(boa, "request");
    ByteBuffer bb = ByteBuffer.wrap(boas.toByteArray());
    return new Request(null, sessionId, xid, type, bb, new ArrayList<Id>());
}
Also used : BinaryOutputArchive(org.apache.jute.BinaryOutputArchive) GetDataRequest(org.apache.zookeeper.proto.GetDataRequest) CreateRequest(org.apache.zookeeper.proto.CreateRequest) SetDataRequest(org.apache.zookeeper.proto.SetDataRequest) Request(org.apache.zookeeper.server.Request) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Id(org.apache.zookeeper.data.Id) ByteBuffer(java.nio.ByteBuffer)

Example 39 with Request

use of org.apache.zookeeper.server.Request in project zookeeper by apache.

the class CommitProcessorConcurrencyTest method processAllFollowingUncommittedAfterFirstCommitTest.

/**
 * In the following test, we add a write request followed by several read
 * requests of the same session, and we verify several things - 1. The write
 * is not processed until commit arrives. 2. Once the write is processed,
 * all the read requests are processed as well. 3. All read requests are
 * executed after the write, before any other write, along with new reads.
 */
@Test
public void processAllFollowingUncommittedAfterFirstCommitTest() throws Exception {
    final String path = "/testUncommittedFollowingCommited";
    Set<Request> shouldBeInPending = new HashSet<Request>();
    Set<Request> shouldBeProcessedAfterPending = new HashSet<Request>();
    Request writeReq = newRequest(new CreateRequest(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL.toFlag()), OpCode.create, 0x1, 1);
    processor.queuedRequests.add(writeReq);
    processor.queuedWriteRequests.add(writeReq);
    shouldBeInPending.add(writeReq);
    for (int readReqId = 2; readReqId <= 5; ++readReqId) {
        Request readReq = newRequest(new GetDataRequest(path, false), OpCode.getData, 0x1, readReqId);
        processor.queuedRequests.add(readReq);
        shouldBeInPending.add(readReq);
        shouldBeProcessedAfterPending.add(readReq);
    }
    processor.initThreads(defaultSizeOfThreadPool);
    processor.stoppedMainLoop = true;
    processor.run();
    assertTrue(processedRequests.isEmpty(), "Processed without waiting for commit");
    assertTrue(processor.queuedRequests.isEmpty(), "Did not handled all of queuedRequests' requests");
    assertTrue(!processor.queuedWriteRequests.isEmpty(), "Removed from blockedQueuedRequests before commit");
    shouldBeInPending.removeAll(processor.pendingRequests.get(writeReq.sessionId));
    for (Request r : shouldBeInPending) {
        LOG.error("Should be in pending {}", r);
    }
    assertTrue(shouldBeInPending.isEmpty(), "Not all requests moved to pending from queuedRequests");
    processor.committedRequests.add(writeReq);
    processor.stoppedMainLoop = true;
    processor.run();
    processor.initThreads(defaultSizeOfThreadPool);
    Thread.sleep(500);
    assertTrue(processedRequests.peek() == writeReq, "Did not process committed request");
    assertTrue(processedRequests.containsAll(shouldBeProcessedAfterPending), "Did not process following read request");
    assertTrue(processor.committedRequests.isEmpty(), "Did not process committed request");
    assertTrue(processor.pendingRequests.isEmpty(), "Did not process committed request");
    assertTrue(processor.queuedWriteRequests.isEmpty(), "Did not remove from blockedQueuedRequests");
}
Also used : CreateRequest(org.apache.zookeeper.proto.CreateRequest) GetDataRequest(org.apache.zookeeper.proto.GetDataRequest) CreateRequest(org.apache.zookeeper.proto.CreateRequest) SetDataRequest(org.apache.zookeeper.proto.SetDataRequest) Request(org.apache.zookeeper.server.Request) GetDataRequest(org.apache.zookeeper.proto.GetDataRequest) HashSet(java.util.HashSet) Test(org.junit.jupiter.api.Test)

Example 40 with Request

use of org.apache.zookeeper.server.Request in project zookeeper by apache.

the class Learner method syncWithLeader.

/**
 * Finally, synchronize our history with the Leader (if Follower)
 * or the LearnerMaster (if Observer).
 * @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;
    boolean syncSnapshot = false;
    readPacket(qp);
    Deque<Long> packetsCommitted = new ArrayDeque<>();
    Deque<PacketInFlight> packetsNotCommitted = new ArrayDeque<>();
    synchronized (zk) {
        if (qp.getType() == Leader.DIFF) {
            LOG.info("Getting a diff from the leader 0x{}", Long.toHexString(qp.getZxid()));
            self.setSyncMode(QuorumPeer.SyncMode.DIFF);
            if (zk.shouldForceWriteInitialSnapshotAfterLeaderElection()) {
                LOG.info("Forcing a snapshot write as part of upgrading from an older Zookeeper. This should only happen while upgrading.");
                snapshotNeeded = true;
                syncSnapshot = true;
            } else {
                snapshotNeeded = false;
            }
        } else if (qp.getType() == Leader.SNAP) {
            self.setSyncMode(QuorumPeer.SyncMode.SNAP);
            LOG.info("Getting a snapshot from leader 0x{}", Long.toHexString(qp.getZxid()));
            // The leader is going to dump the database
            // db is clear as part of deserializeSnapshot()
            zk.getZKDatabase().deserializeSnapshot(leaderIs);
            // inconsistency of config node content during rolling restart.
            if (!self.isReconfigEnabled()) {
                LOG.debug("Reset config node content from local config after deserialization of snapshot.");
                zk.getZKDatabase().initConfigInZKDatabase(self.getQuorumVerifier());
            }
            String signature = leaderIs.readString("signature");
            if (!signature.equals("BenWasHere")) {
                LOG.error("Missing signature. Got {}", signature);
                throw new IOException("Missing signature");
            }
            zk.getZKDatabase().setlastProcessedZxid(qp.getZxid());
            // immediately persist the latest snapshot when there is txn log gap
            syncSnapshot = true;
        } else if (qp.getType() == Leader.TRUNC) {
            // we need to truncate the log to the lastzxid of the leader
            self.setSyncMode(QuorumPeer.SyncMode.TRUNC);
            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 0x{}", Long.toHexString(qp.getZxid()));
                ServiceUtils.requestSystemExit(ExitCode.QUORUM_PACKET_ERROR.getValue());
            }
            zk.getZKDatabase().setlastProcessedZxid(qp.getZxid());
        } else {
            LOG.error("Got unexpected packet from leader: {}, exiting ... ", LearnerHandler.packetToString(qp));
            ServiceUtils.requestSystemExit(ExitCode.QUORUM_PACKET_ERROR.getValue());
        }
        zk.getZKDatabase().initConfigInZKDatabase(self.getQuorumVerifier());
        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;
        TxnLogEntry logEntry;
        // 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();
                    logEntry = SerializeUtils.deserializeTxn(qp.getData());
                    pif.hdr = logEntry.getHeader();
                    pif.rec = logEntry.getTxn();
                    pif.digest = logEntry.getDigest();
                    if (pif.hdr.getZxid() != lastQueued + 1) {
                        LOG.warn("Got zxid 0x{} expected 0x{}", Long.toHexString(pif.hdr.getZxid()), 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(), UTF_8));
                        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(), UTF_8));
                        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 0x{}, but next proposal is 0x{}", Long.toHexString(qp.getZxid()), Long.toHexString(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();
                    if (qp.getType() == Leader.INFORMANDACTIVATE) {
                        ByteBuffer buffer = ByteBuffer.wrap(qp.getData());
                        long suggestedLeaderId = buffer.getLong();
                        byte[] remainingdata = new byte[buffer.remaining()];
                        buffer.get(remainingdata);
                        logEntry = SerializeUtils.deserializeTxn(remainingdata);
                        packet.hdr = logEntry.getHeader();
                        packet.rec = logEntry.getTxn();
                        packet.digest = logEntry.getDigest();
                        QuorumVerifier qv = self.configFromString(new String(((SetDataTxn) packet.rec).getData(), UTF_8));
                        boolean majorChange = self.processReconfig(qv, suggestedLeaderId, qp.getZxid(), true);
                        if (majorChange) {
                            throw new Exception("changes proposed in reconfig");
                        }
                    } else {
                        logEntry = SerializeUtils.deserializeTxn(qp.getData());
                        packet.rec = logEntry.getTxn();
                        packet.hdr = logEntry.getHeader();
                        packet.digest = logEntry.getDigest();
                        // Log warning message if txn comes out-of-order
                        if (packet.hdr.getZxid() != lastQueued + 1) {
                            LOG.warn("Got zxid 0x{} expected 0x{}", Long.toHexString(packet.hdr.getZxid()), 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(syncSnapshot);
                        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(), UTF_8));
                            self.setLastSeenQuorumVerifier(qv, true);
                            newLeaderQV = qv;
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    if (snapshotNeeded) {
                        zk.takeSnapshot(syncSnapshot);
                    }
                    self.setCurrentEpoch(newEpoch);
                    writeToTxnLog = true;
                    // Anything after this needs to go to the transaction log, not applied directly in memory
                    isPreZAB1_0 = false;
                    // ZOOKEEPER-3911: make sure sync the uncommitted logs before commit them (ACK NEWLEADER).
                    sock.setSoTimeout(self.tickTime * self.syncLimit);
                    self.setSyncMode(QuorumPeer.SyncMode.NONE);
                    zk.startupWithoutServing();
                    if (zk instanceof FollowerZooKeeperServer) {
                        FollowerZooKeeperServer fzk = (FollowerZooKeeperServer) zk;
                        for (PacketInFlight p : packetsNotCommitted) {
                            fzk.logRequest(p.hdr, p.rec, p.digest);
                        }
                        packetsNotCommitted.clear();
                    }
                    writePacket(new QuorumPacket(Leader.ACK, newLeaderZxid, null, null), true);
                    break;
            }
        }
    }
    ack.setZxid(ZxidUtils.makeZxid(newEpoch, 0));
    writePacket(ack, true);
    zk.startServing();
    /*
         * 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, p.digest);
        }
        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 0x{}, but next proposal is 0x{}", Long.toHexString(zxid), 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);
            request.setTxnDigest(p.digest);
            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) ArrayDeque(java.util.ArrayDeque) X509Exception(org.apache.zookeeper.common.X509Exception) IOException(java.io.IOException) TxnLogEntry(org.apache.zookeeper.server.TxnLogEntry)

Aggregations

Request (org.apache.zookeeper.server.Request)51 Test (org.junit.jupiter.api.Test)25 CreateRequest (org.apache.zookeeper.proto.CreateRequest)15 IOException (java.io.IOException)9 ByteBuffer (java.nio.ByteBuffer)9 GetDataRequest (org.apache.zookeeper.proto.GetDataRequest)9 SetDataRequest (org.apache.zookeeper.proto.SetDataRequest)9 TxnHeader (org.apache.zookeeper.txn.TxnHeader)9 HashSet (java.util.HashSet)8 ByteArrayOutputStream (java.io.ByteArrayOutputStream)6 BinaryOutputArchive (org.apache.jute.BinaryOutputArchive)6 Record (org.apache.jute.Record)6 KeeperException (org.apache.zookeeper.KeeperException)5 SetDataTxn (org.apache.zookeeper.txn.SetDataTxn)5 Id (org.apache.zookeeper.data.Id)4 ErrorTxn (org.apache.zookeeper.txn.ErrorTxn)4 OutputArchive (org.apache.jute.OutputArchive)3 ZooKeeper (org.apache.zookeeper.ZooKeeper)3 TxnLogEntry (org.apache.zookeeper.server.TxnLogEntry)3 QuorumVerifier (org.apache.zookeeper.server.quorum.flexible.QuorumVerifier)3