Search in sources :

Example 1 with CloseSessionTxn

use of org.apache.zookeeper.txn.CloseSessionTxn in project zookeeper by apache.

the class PrepRequestProcessor method pRequest2Txn.

/**
 * This method will be called inside the ProcessRequestThread, which is a
 * singleton, so there will be a single thread calling this code.
 *
 * @param type
 * @param zxid
 * @param request
 * @param record
 */
protected void pRequest2Txn(int type, long zxid, Request request, Record record, boolean deserialize) throws KeeperException, IOException, RequestProcessorException {
    if (request.getHdr() == null) {
        request.setHdr(new TxnHeader(request.sessionId, request.cxid, zxid, Time.currentWallTime(), type));
    }
    switch(type) {
        case OpCode.create:
        case OpCode.create2:
        case OpCode.createTTL:
        case OpCode.createContainer:
            {
                pRequest2TxnCreate(type, request, record, deserialize);
                break;
            }
        case OpCode.deleteContainer:
            {
                String path = new String(request.request.array(), UTF_8);
                String parentPath = getParentPathAndValidate(path);
                ChangeRecord nodeRecord = getRecordForPath(path);
                if (nodeRecord.childCount > 0) {
                    throw new KeeperException.NotEmptyException(path);
                }
                if (EphemeralType.get(nodeRecord.stat.getEphemeralOwner()) == EphemeralType.NORMAL) {
                    throw new KeeperException.BadVersionException(path);
                }
                ChangeRecord parentRecord = getRecordForPath(parentPath);
                request.setTxn(new DeleteTxn(path));
                parentRecord = parentRecord.duplicate(request.getHdr().getZxid());
                parentRecord.childCount--;
                parentRecord.stat.setPzxid(request.getHdr().getZxid());
                parentRecord.precalculatedDigest = precalculateDigest(DigestOpCode.UPDATE, parentPath, parentRecord.data, parentRecord.stat);
                addChangeRecord(parentRecord);
                nodeRecord = new ChangeRecord(request.getHdr().getZxid(), path, null, -1, null);
                nodeRecord.precalculatedDigest = precalculateDigest(DigestOpCode.REMOVE, path);
                setTxnDigest(request, nodeRecord.precalculatedDigest);
                addChangeRecord(nodeRecord);
                break;
            }
        case OpCode.delete:
            zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
            DeleteRequest deleteRequest = (DeleteRequest) record;
            if (deserialize) {
                ByteBufferInputStream.byteBuffer2Record(request.request, deleteRequest);
            }
            String path = deleteRequest.getPath();
            String parentPath = getParentPathAndValidate(path);
            ChangeRecord parentRecord = getRecordForPath(parentPath);
            zks.checkACL(request.cnxn, parentRecord.acl, ZooDefs.Perms.DELETE, request.authInfo, path, null);
            ChangeRecord nodeRecord = getRecordForPath(path);
            checkAndIncVersion(nodeRecord.stat.getVersion(), deleteRequest.getVersion(), path);
            if (nodeRecord.childCount > 0) {
                throw new KeeperException.NotEmptyException(path);
            }
            request.setTxn(new DeleteTxn(path));
            parentRecord = parentRecord.duplicate(request.getHdr().getZxid());
            parentRecord.childCount--;
            parentRecord.stat.setPzxid(request.getHdr().getZxid());
            parentRecord.precalculatedDigest = precalculateDigest(DigestOpCode.UPDATE, parentPath, parentRecord.data, parentRecord.stat);
            addChangeRecord(parentRecord);
            nodeRecord = new ChangeRecord(request.getHdr().getZxid(), path, null, -1, null);
            nodeRecord.precalculatedDigest = precalculateDigest(DigestOpCode.REMOVE, path);
            setTxnDigest(request, nodeRecord.precalculatedDigest);
            addChangeRecord(nodeRecord);
            break;
        case OpCode.setData:
            zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
            SetDataRequest setDataRequest = (SetDataRequest) record;
            if (deserialize) {
                ByteBufferInputStream.byteBuffer2Record(request.request, setDataRequest);
            }
            path = setDataRequest.getPath();
            validatePath(path, request.sessionId);
            nodeRecord = getRecordForPath(path);
            zks.checkACL(request.cnxn, nodeRecord.acl, ZooDefs.Perms.WRITE, request.authInfo, path, null);
            zks.checkQuota(path, nodeRecord.data, setDataRequest.getData(), OpCode.setData);
            int newVersion = checkAndIncVersion(nodeRecord.stat.getVersion(), setDataRequest.getVersion(), path);
            request.setTxn(new SetDataTxn(path, setDataRequest.getData(), newVersion));
            nodeRecord = nodeRecord.duplicate(request.getHdr().getZxid());
            nodeRecord.stat.setVersion(newVersion);
            nodeRecord.stat.setMtime(request.getHdr().getTime());
            nodeRecord.stat.setMzxid(zxid);
            nodeRecord.data = setDataRequest.getData();
            nodeRecord.precalculatedDigest = precalculateDigest(DigestOpCode.UPDATE, path, nodeRecord.data, nodeRecord.stat);
            setTxnDigest(request, nodeRecord.precalculatedDigest);
            addChangeRecord(nodeRecord);
            break;
        case OpCode.reconfig:
            if (!zks.isReconfigEnabled()) {
                LOG.error("Reconfig operation requested but reconfig feature is disabled.");
                throw new KeeperException.ReconfigDisabledException();
            }
            if (ZooKeeperServer.skipACL) {
                LOG.warn("skipACL is set, reconfig operation will skip ACL checks!");
            }
            zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
            LeaderZooKeeperServer lzks;
            try {
                lzks = (LeaderZooKeeperServer) zks;
            } catch (ClassCastException e) {
                // standalone mode - reconfiguration currently not supported
                throw new KeeperException.UnimplementedException();
            }
            QuorumVerifier lastSeenQV = lzks.self.getLastSeenQuorumVerifier();
            // check that there's no reconfig in progress
            if (lastSeenQV.getVersion() != lzks.self.getQuorumVerifier().getVersion()) {
                throw new KeeperException.ReconfigInProgress();
            }
            ReconfigRequest reconfigRequest = (ReconfigRequest) record;
            long configId = reconfigRequest.getCurConfigId();
            if (configId != -1 && configId != lzks.self.getLastSeenQuorumVerifier().getVersion()) {
                String msg = "Reconfiguration from version " + configId + " failed -- last seen version is " + lzks.self.getLastSeenQuorumVerifier().getVersion();
                throw new KeeperException.BadVersionException(msg);
            }
            String newMembers = reconfigRequest.getNewMembers();
            if (newMembers != null) {
                // non-incremental membership change
                LOG.info("Non-incremental reconfig");
                // Input may be delimited by either commas or newlines so convert to common newline separated format
                newMembers = newMembers.replaceAll(",", "\n");
                try {
                    Properties props = new Properties();
                    props.load(new StringReader(newMembers));
                    request.qv = QuorumPeerConfig.parseDynamicConfig(props, lzks.self.getElectionType(), true, false, lastSeenQV.getOraclePath());
                    request.qv.setVersion(request.getHdr().getZxid());
                } catch (IOException | ConfigException e) {
                    throw new KeeperException.BadArgumentsException(e.getMessage());
                }
            } else {
                // incremental change - must be a majority quorum system
                LOG.info("Incremental reconfig");
                List<String> joiningServers = null;
                String joiningServersString = reconfigRequest.getJoiningServers();
                if (joiningServersString != null) {
                    joiningServers = StringUtils.split(joiningServersString, ",");
                }
                List<String> leavingServers = null;
                String leavingServersString = reconfigRequest.getLeavingServers();
                if (leavingServersString != null) {
                    leavingServers = StringUtils.split(leavingServersString, ",");
                }
                if (!(lastSeenQV instanceof QuorumMaj) && !(lastSeenQV instanceof QuorumOracleMaj)) {
                    String msg = "Incremental reconfiguration requested but last configuration seen has a non-majority quorum system";
                    LOG.warn(msg);
                    throw new KeeperException.BadArgumentsException(msg);
                }
                Map<Long, QuorumServer> nextServers = new HashMap<Long, QuorumServer>(lastSeenQV.getAllMembers());
                try {
                    if (leavingServers != null) {
                        for (String leaving : leavingServers) {
                            long sid = Long.parseLong(leaving);
                            nextServers.remove(sid);
                        }
                    }
                    if (joiningServers != null) {
                        for (String joiner : joiningServers) {
                            // joiner should have the following format: server.x = server_spec;client_spec
                            String[] parts = StringUtils.split(joiner, "=").toArray(new String[0]);
                            if (parts.length != 2) {
                                throw new KeeperException.BadArgumentsException("Wrong format of server string");
                            }
                            // extract server id x from first part of joiner: server.x
                            Long sid = Long.parseLong(parts[0].substring(parts[0].lastIndexOf('.') + 1));
                            QuorumServer qs = new QuorumServer(sid, parts[1]);
                            if (qs.clientAddr == null || qs.electionAddr == null || qs.addr == null) {
                                throw new KeeperException.BadArgumentsException("Wrong format of server string - each server should have 3 ports specified");
                            }
                            // check duplication of addresses and ports
                            for (QuorumServer nqs : nextServers.values()) {
                                if (qs.id == nqs.id) {
                                    continue;
                                }
                                qs.checkAddressDuplicate(nqs);
                            }
                            nextServers.remove(qs.id);
                            nextServers.put(qs.id, qs);
                        }
                    }
                } catch (ConfigException e) {
                    throw new KeeperException.BadArgumentsException("Reconfiguration failed");
                }
                if (lastSeenQV instanceof QuorumMaj) {
                    request.qv = new QuorumMaj(nextServers);
                } else {
                    request.qv = new QuorumOracleMaj(nextServers, lastSeenQV.getOraclePath());
                }
                request.qv.setVersion(request.getHdr().getZxid());
            }
            if (QuorumPeerConfig.isStandaloneEnabled() && request.qv.getVotingMembers().size() < 2) {
                String msg = "Reconfig failed - new configuration must include at least 2 followers";
                LOG.warn(msg);
                throw new KeeperException.BadArgumentsException(msg);
            } else if (request.qv.getVotingMembers().size() < 1) {
                String msg = "Reconfig failed - new configuration must include at least 1 follower";
                LOG.warn(msg);
                throw new KeeperException.BadArgumentsException(msg);
            }
            if (!lzks.getLeader().isQuorumSynced(request.qv)) {
                String msg2 = "Reconfig failed - there must be a connected and synced quorum in new configuration";
                LOG.warn(msg2);
                throw new KeeperException.NewConfigNoQuorum();
            }
            nodeRecord = getRecordForPath(ZooDefs.CONFIG_NODE);
            zks.checkACL(request.cnxn, nodeRecord.acl, ZooDefs.Perms.WRITE, request.authInfo, null, null);
            SetDataTxn setDataTxn = new SetDataTxn(ZooDefs.CONFIG_NODE, request.qv.toString().getBytes(), -1);
            request.setTxn(setDataTxn);
            nodeRecord = nodeRecord.duplicate(request.getHdr().getZxid());
            nodeRecord.stat.setVersion(-1);
            nodeRecord.stat.setMtime(request.getHdr().getTime());
            nodeRecord.stat.setMzxid(zxid);
            nodeRecord.data = setDataTxn.getData();
            // Reconfig is currently a noop from digest computation
            // perspective since config node is not covered by the digests.
            nodeRecord.precalculatedDigest = precalculateDigest(DigestOpCode.NOOP, ZooDefs.CONFIG_NODE, nodeRecord.data, nodeRecord.stat);
            setTxnDigest(request, nodeRecord.precalculatedDigest);
            addChangeRecord(nodeRecord);
            break;
        case OpCode.setACL:
            zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
            SetACLRequest setAclRequest = (SetACLRequest) record;
            if (deserialize) {
                ByteBufferInputStream.byteBuffer2Record(request.request, setAclRequest);
            }
            path = setAclRequest.getPath();
            validatePath(path, request.sessionId);
            List<ACL> listACL = fixupACL(path, request.authInfo, setAclRequest.getAcl());
            nodeRecord = getRecordForPath(path);
            zks.checkACL(request.cnxn, nodeRecord.acl, ZooDefs.Perms.ADMIN, request.authInfo, path, listACL);
            newVersion = checkAndIncVersion(nodeRecord.stat.getAversion(), setAclRequest.getVersion(), path);
            request.setTxn(new SetACLTxn(path, listACL, newVersion));
            nodeRecord = nodeRecord.duplicate(request.getHdr().getZxid());
            nodeRecord.stat.setAversion(newVersion);
            nodeRecord.precalculatedDigest = precalculateDigest(DigestOpCode.UPDATE, path, nodeRecord.data, nodeRecord.stat);
            setTxnDigest(request, nodeRecord.precalculatedDigest);
            addChangeRecord(nodeRecord);
            break;
        case OpCode.createSession:
            request.request.rewind();
            int to = request.request.getInt();
            request.setTxn(new CreateSessionTxn(to));
            request.request.rewind();
            // only add the global session tracker but not to ZKDb
            zks.sessionTracker.trackSession(request.sessionId, to);
            zks.setOwner(request.sessionId, request.getOwner());
            break;
        case OpCode.closeSession:
            // We don't want to do this check since the session expiration thread
            // queues up this operation without being the session owner.
            // this request is the last of the session so it should be ok
            // zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
            long startTime = Time.currentElapsedTime();
            synchronized (zks.outstandingChanges) {
                // need to move getEphemerals into zks.outstandingChanges
                // synchronized block, otherwise there will be a race
                // condition with the on flying deleteNode txn, and we'll
                // delete the node again here, which is not correct
                Set<String> es = zks.getZKDatabase().getEphemerals(request.sessionId);
                for (ChangeRecord c : zks.outstandingChanges) {
                    if (c.stat == null) {
                        // Doing a delete
                        es.remove(c.path);
                    } else if (c.stat.getEphemeralOwner() == request.sessionId) {
                        es.add(c.path);
                    }
                }
                for (String path2Delete : es) {
                    if (digestEnabled) {
                        parentPath = getParentPathAndValidate(path2Delete);
                        parentRecord = getRecordForPath(parentPath);
                        parentRecord = parentRecord.duplicate(request.getHdr().getZxid());
                        parentRecord.stat.setPzxid(request.getHdr().getZxid());
                        parentRecord.precalculatedDigest = precalculateDigest(DigestOpCode.UPDATE, parentPath, parentRecord.data, parentRecord.stat);
                        addChangeRecord(parentRecord);
                    }
                    nodeRecord = new ChangeRecord(request.getHdr().getZxid(), path2Delete, null, 0, null);
                    nodeRecord.precalculatedDigest = precalculateDigest(DigestOpCode.REMOVE, path2Delete);
                    addChangeRecord(nodeRecord);
                }
                if (ZooKeeperServer.isCloseSessionTxnEnabled()) {
                    request.setTxn(new CloseSessionTxn(new ArrayList<String>(es)));
                }
                zks.sessionTracker.setSessionClosing(request.sessionId);
            }
            ServerMetrics.getMetrics().CLOSE_SESSION_PREP_TIME.add(Time.currentElapsedTime() - startTime);
            break;
        case OpCode.check:
            zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
            CheckVersionRequest checkVersionRequest = (CheckVersionRequest) record;
            if (deserialize) {
                ByteBufferInputStream.byteBuffer2Record(request.request, checkVersionRequest);
            }
            path = checkVersionRequest.getPath();
            validatePath(path, request.sessionId);
            nodeRecord = getRecordForPath(path);
            zks.checkACL(request.cnxn, nodeRecord.acl, ZooDefs.Perms.READ, request.authInfo, path, null);
            request.setTxn(new CheckVersionTxn(path, checkAndIncVersion(nodeRecord.stat.getVersion(), checkVersionRequest.getVersion(), path)));
            break;
        default:
            LOG.warn("unknown type {}", type);
            break;
    }
    // we just set the current tree digest in it
    if (request.getTxnDigest() == null && digestEnabled) {
        setTxnDigest(request);
    }
}
Also used : CheckVersionRequest(org.apache.zookeeper.proto.CheckVersionRequest) HashMap(java.util.HashMap) QuorumServer(org.apache.zookeeper.server.quorum.QuorumPeer.QuorumServer) QuorumMaj(org.apache.zookeeper.server.quorum.flexible.QuorumMaj) QuorumOracleMaj(org.apache.zookeeper.server.quorum.flexible.QuorumOracleMaj) ArrayList(java.util.ArrayList) ConfigException(org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException) Properties(java.util.Properties) ReconfigRequest(org.apache.zookeeper.proto.ReconfigRequest) DeleteTxn(org.apache.zookeeper.txn.DeleteTxn) CreateSessionTxn(org.apache.zookeeper.txn.CreateSessionTxn) BadArgumentsException(org.apache.zookeeper.KeeperException.BadArgumentsException) StringReader(java.io.StringReader) CloseSessionTxn(org.apache.zookeeper.txn.CloseSessionTxn) SetACLRequest(org.apache.zookeeper.proto.SetACLRequest) CheckVersionTxn(org.apache.zookeeper.txn.CheckVersionTxn) ACL(org.apache.zookeeper.data.ACL) SetDataRequest(org.apache.zookeeper.proto.SetDataRequest) SetDataTxn(org.apache.zookeeper.txn.SetDataTxn) IOException(java.io.IOException) QuorumVerifier(org.apache.zookeeper.server.quorum.flexible.QuorumVerifier) BadArgumentsException(org.apache.zookeeper.KeeperException.BadArgumentsException) SetACLTxn(org.apache.zookeeper.txn.SetACLTxn) ChangeRecord(org.apache.zookeeper.server.ZooKeeperServer.ChangeRecord) DeleteRequest(org.apache.zookeeper.proto.DeleteRequest) KeeperException(org.apache.zookeeper.KeeperException) TxnHeader(org.apache.zookeeper.txn.TxnHeader) LeaderZooKeeperServer(org.apache.zookeeper.server.quorum.LeaderZooKeeperServer)

Example 2 with CloseSessionTxn

use of org.apache.zookeeper.txn.CloseSessionTxn in project zookeeper by apache.

the class DataTree method processTxn.

public ProcessTxnResult processTxn(TxnHeader header, Record txn, boolean isSubTxn) {
    ProcessTxnResult rc = new ProcessTxnResult();
    try {
        rc.clientId = header.getClientId();
        rc.cxid = header.getCxid();
        rc.zxid = header.getZxid();
        rc.type = header.getType();
        rc.err = 0;
        rc.multiResult = null;
        switch(header.getType()) {
            case OpCode.create:
                CreateTxn createTxn = (CreateTxn) txn;
                rc.path = createTxn.getPath();
                createNode(createTxn.getPath(), createTxn.getData(), createTxn.getAcl(), createTxn.getEphemeral() ? header.getClientId() : 0, createTxn.getParentCVersion(), header.getZxid(), header.getTime(), null);
                break;
            case OpCode.create2:
                CreateTxn create2Txn = (CreateTxn) txn;
                rc.path = create2Txn.getPath();
                Stat stat = new Stat();
                createNode(create2Txn.getPath(), create2Txn.getData(), create2Txn.getAcl(), create2Txn.getEphemeral() ? header.getClientId() : 0, create2Txn.getParentCVersion(), header.getZxid(), header.getTime(), stat);
                rc.stat = stat;
                break;
            case OpCode.createTTL:
                CreateTTLTxn createTtlTxn = (CreateTTLTxn) txn;
                rc.path = createTtlTxn.getPath();
                stat = new Stat();
                createNode(createTtlTxn.getPath(), createTtlTxn.getData(), createTtlTxn.getAcl(), EphemeralType.TTL.toEphemeralOwner(createTtlTxn.getTtl()), createTtlTxn.getParentCVersion(), header.getZxid(), header.getTime(), stat);
                rc.stat = stat;
                break;
            case OpCode.createContainer:
                CreateContainerTxn createContainerTxn = (CreateContainerTxn) txn;
                rc.path = createContainerTxn.getPath();
                stat = new Stat();
                createNode(createContainerTxn.getPath(), createContainerTxn.getData(), createContainerTxn.getAcl(), EphemeralType.CONTAINER_EPHEMERAL_OWNER, createContainerTxn.getParentCVersion(), header.getZxid(), header.getTime(), stat);
                rc.stat = stat;
                break;
            case OpCode.delete:
            case OpCode.deleteContainer:
                DeleteTxn deleteTxn = (DeleteTxn) txn;
                rc.path = deleteTxn.getPath();
                deleteNode(deleteTxn.getPath(), header.getZxid());
                break;
            case OpCode.reconfig:
            case OpCode.setData:
                SetDataTxn setDataTxn = (SetDataTxn) txn;
                rc.path = setDataTxn.getPath();
                rc.stat = setData(setDataTxn.getPath(), setDataTxn.getData(), setDataTxn.getVersion(), header.getZxid(), header.getTime());
                break;
            case OpCode.setACL:
                SetACLTxn setACLTxn = (SetACLTxn) txn;
                rc.path = setACLTxn.getPath();
                rc.stat = setACL(setACLTxn.getPath(), setACLTxn.getAcl(), setACLTxn.getVersion());
                break;
            case OpCode.closeSession:
                long sessionId = header.getClientId();
                if (txn != null) {
                    killSession(sessionId, header.getZxid(), ephemerals.remove(sessionId), ((CloseSessionTxn) txn).getPaths2Delete());
                } else {
                    killSession(sessionId, header.getZxid());
                }
                break;
            case OpCode.error:
                ErrorTxn errTxn = (ErrorTxn) txn;
                rc.err = errTxn.getErr();
                break;
            case OpCode.check:
                CheckVersionTxn checkTxn = (CheckVersionTxn) txn;
                rc.path = checkTxn.getPath();
                break;
            case OpCode.multi:
                MultiTxn multiTxn = (MultiTxn) txn;
                List<Txn> txns = multiTxn.getTxns();
                rc.multiResult = new ArrayList<ProcessTxnResult>();
                boolean failed = false;
                for (Txn subtxn : txns) {
                    if (subtxn.getType() == OpCode.error) {
                        failed = true;
                        break;
                    }
                }
                boolean post_failed = false;
                for (Txn subtxn : txns) {
                    ByteBuffer bb = ByteBuffer.wrap(subtxn.getData());
                    Record record = null;
                    switch(subtxn.getType()) {
                        case OpCode.create:
                            record = new CreateTxn();
                            break;
                        case OpCode.createTTL:
                            record = new CreateTTLTxn();
                            break;
                        case OpCode.createContainer:
                            record = new CreateContainerTxn();
                            break;
                        case OpCode.delete:
                        case OpCode.deleteContainer:
                            record = new DeleteTxn();
                            break;
                        case OpCode.setData:
                            record = new SetDataTxn();
                            break;
                        case OpCode.error:
                            record = new ErrorTxn();
                            post_failed = true;
                            break;
                        case OpCode.check:
                            record = new CheckVersionTxn();
                            break;
                        default:
                            throw new IOException("Invalid type of op: " + subtxn.getType());
                    }
                    assert (record != null);
                    ByteBufferInputStream.byteBuffer2Record(bb, record);
                    if (failed && subtxn.getType() != OpCode.error) {
                        int ec = post_failed ? Code.RUNTIMEINCONSISTENCY.intValue() : Code.OK.intValue();
                        subtxn.setType(OpCode.error);
                        record = new ErrorTxn(ec);
                    }
                    assert !failed || (subtxn.getType() == OpCode.error);
                    TxnHeader subHdr = new TxnHeader(header.getClientId(), header.getCxid(), header.getZxid(), header.getTime(), subtxn.getType());
                    ProcessTxnResult subRc = processTxn(subHdr, record, true);
                    rc.multiResult.add(subRc);
                    if (subRc.err != 0 && rc.err == 0) {
                        rc.err = subRc.err;
                    }
                }
                break;
        }
    } catch (KeeperException e) {
        LOG.debug("Failed: {}:{}", header, txn, e);
        rc.err = e.code().intValue();
    } catch (IOException e) {
        LOG.debug("Failed: {}:{}", header, txn, e);
    }
    /*
         * Snapshots are taken lazily. When serializing a node, it's data
         * and children copied in a synchronization block on that node,
         * which means newly created node won't be in the snapshot, so
         * we won't have mismatched cversion and pzxid when replaying the
         * createNode txn.
         *
         * But there is a tricky scenario that if the child is deleted due
         * to session close and re-created in a different global session
         * after that the parent is serialized, then when replay the txn
         * because the node is belonging to a different session, replay the
         * closeSession txn won't delete it anymore, and we'll get NODEEXISTS
         * error when replay the createNode txn. In this case, we need to
         * update the cversion and pzxid to the new value.
         *
         * Note, such failures on DT should be seen only during
         * restore.
         */
    if (header.getType() == OpCode.create && rc.err == Code.NODEEXISTS.intValue()) {
        LOG.debug("Adjusting parent cversion for Txn: {} path: {} err: {}", header.getType(), rc.path, rc.err);
        int lastSlash = rc.path.lastIndexOf('/');
        String parentName = rc.path.substring(0, lastSlash);
        CreateTxn cTxn = (CreateTxn) txn;
        try {
            setCversionPzxid(parentName, cTxn.getParentCVersion(), header.getZxid());
        } catch (KeeperException.NoNodeException e) {
            LOG.error("Failed to set parent cversion for: {}", parentName, e);
            rc.err = e.code().intValue();
        }
    } else if (rc.err != Code.OK.intValue()) {
        LOG.debug("Ignoring processTxn failure hdr: {} : error: {}", header.getType(), rc.err);
    }
    /*
         * Things we can only update after the whole txn is applied to data
         * tree.
         *
         * If we update the lastProcessedZxid with the first sub txn in multi
         * and there is a snapshot in progress, it's possible that the zxid
         * associated with the snapshot only include partial of the multi op.
         *
         * When loading snapshot, it will only load the txns after the zxid
         * associated with snapshot file, which could cause data inconsistency
         * due to missing sub txns.
         *
         * To avoid this, we only update the lastProcessedZxid when the whole
         * multi-op txn is applied to DataTree.
         */
    if (!isSubTxn) {
        /*
             * A snapshot might be in progress while we are modifying the data
             * tree. If we set lastProcessedZxid prior to making corresponding
             * change to the tree, then the zxid associated with the snapshot
             * file will be ahead of its contents. Thus, while restoring from
             * the snapshot, the restore method will not apply the transaction
             * for zxid associated with the snapshot file, since the restore
             * method assumes that transaction to be present in the snapshot.
             *
             * To avoid this, we first apply the transaction and then modify
             * lastProcessedZxid.  During restore, we correctly handle the
             * case where the snapshot contains data ahead of the zxid associated
             * with the file.
             */
        if (rc.zxid > lastProcessedZxid) {
            lastProcessedZxid = rc.zxid;
        }
        if (digestFromLoadedSnapshot != null) {
            compareSnapshotDigests(rc.zxid);
        } else {
            // only start recording digest when we're not in fuzzy state
            logZxidDigest(rc.zxid, getTreeDigest());
        }
    }
    return rc;
}
Also used : CreateContainerTxn(org.apache.zookeeper.txn.CreateContainerTxn) MultiTxn(org.apache.zookeeper.txn.MultiTxn) CheckVersionTxn(org.apache.zookeeper.txn.CheckVersionTxn) NoNodeException(org.apache.zookeeper.KeeperException.NoNodeException) SetDataTxn(org.apache.zookeeper.txn.SetDataTxn) SetDataTxn(org.apache.zookeeper.txn.SetDataTxn) CreateTxn(org.apache.zookeeper.txn.CreateTxn) CreateTTLTxn(org.apache.zookeeper.txn.CreateTTLTxn) DeleteTxn(org.apache.zookeeper.txn.DeleteTxn) CreateContainerTxn(org.apache.zookeeper.txn.CreateContainerTxn) SetACLTxn(org.apache.zookeeper.txn.SetACLTxn) CheckVersionTxn(org.apache.zookeeper.txn.CheckVersionTxn) Txn(org.apache.zookeeper.txn.Txn) MultiTxn(org.apache.zookeeper.txn.MultiTxn) ErrorTxn(org.apache.zookeeper.txn.ErrorTxn) CloseSessionTxn(org.apache.zookeeper.txn.CloseSessionTxn) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) CreateTTLTxn(org.apache.zookeeper.txn.CreateTTLTxn) DeleteTxn(org.apache.zookeeper.txn.DeleteTxn) CreateTxn(org.apache.zookeeper.txn.CreateTxn) Stat(org.apache.zookeeper.data.Stat) ErrorTxn(org.apache.zookeeper.txn.ErrorTxn) SetACLTxn(org.apache.zookeeper.txn.SetACLTxn) Record(org.apache.jute.Record) KeeperException(org.apache.zookeeper.KeeperException) TxnHeader(org.apache.zookeeper.txn.TxnHeader)

Example 3 with CloseSessionTxn

use of org.apache.zookeeper.txn.CloseSessionTxn in project zookeeper by apache.

the class SerializeUtils method deserializeTxn.

public static TxnLogEntry deserializeTxn(byte[] txnBytes) throws IOException {
    TxnHeader hdr = new TxnHeader();
    final ByteArrayInputStream bais = new ByteArrayInputStream(txnBytes);
    InputArchive ia = BinaryInputArchive.getArchive(bais);
    hdr.deserialize(ia, "hdr");
    bais.mark(bais.available());
    Record txn = null;
    switch(hdr.getType()) {
        case OpCode.createSession:
            // This isn't really an error txn; it just has the same
            // format. The error represents the timeout
            txn = new CreateSessionTxn();
            break;
        case OpCode.closeSession:
            txn = ZooKeeperServer.isCloseSessionTxnEnabled() ? new CloseSessionTxn() : null;
            break;
        case OpCode.create:
        case OpCode.create2:
            txn = new CreateTxn();
            break;
        case OpCode.createTTL:
            txn = new CreateTTLTxn();
            break;
        case OpCode.createContainer:
            txn = new CreateContainerTxn();
            break;
        case OpCode.delete:
        case OpCode.deleteContainer:
            txn = new DeleteTxn();
            break;
        case OpCode.reconfig:
        case OpCode.setData:
            txn = new SetDataTxn();
            break;
        case OpCode.setACL:
            txn = new SetACLTxn();
            break;
        case OpCode.error:
            txn = new ErrorTxn();
            break;
        case OpCode.multi:
            txn = new MultiTxn();
            break;
        default:
            throw new IOException("Unsupported Txn with type=%d" + hdr.getType());
    }
    if (txn != null) {
        try {
            txn.deserialize(ia, "txn");
        } catch (EOFException e) {
            // perhaps this is a V0 Create
            if (hdr.getType() == OpCode.create) {
                CreateTxn create = (CreateTxn) txn;
                bais.reset();
                CreateTxnV0 createv0 = new CreateTxnV0();
                createv0.deserialize(ia, "txn");
                // cool now make it V1. a -1 parentCVersion will
                // trigger fixup processing in processTxn
                create.setPath(createv0.getPath());
                create.setData(createv0.getData());
                create.setAcl(createv0.getAcl());
                create.setEphemeral(createv0.getEphemeral());
                create.setParentCVersion(-1);
            } else if (hdr.getType() == OpCode.closeSession) {
                // perhaps this is before CloseSessionTxn was added,
                // ignore it and reset txn to null
                txn = null;
            } else {
                throw e;
            }
        }
    }
    TxnDigest digest = null;
    if (ZooKeeperServer.isDigestEnabled()) {
        digest = new TxnDigest();
        try {
            digest.deserialize(ia, "digest");
        } catch (EOFException exception) {
            // may not have digest in the txn
            digest = null;
        }
    }
    return new TxnLogEntry(txn, hdr, digest);
}
Also used : CreateContainerTxn(org.apache.zookeeper.txn.CreateContainerTxn) MultiTxn(org.apache.zookeeper.txn.MultiTxn) InputArchive(org.apache.jute.InputArchive) BinaryInputArchive(org.apache.jute.BinaryInputArchive) SetDataTxn(org.apache.zookeeper.txn.SetDataTxn) IOException(java.io.IOException) CreateTxnV0(org.apache.zookeeper.txn.CreateTxnV0) CreateTTLTxn(org.apache.zookeeper.txn.CreateTTLTxn) DeleteTxn(org.apache.zookeeper.txn.DeleteTxn) CreateSessionTxn(org.apache.zookeeper.txn.CreateSessionTxn) CreateTxn(org.apache.zookeeper.txn.CreateTxn) ErrorTxn(org.apache.zookeeper.txn.ErrorTxn) ByteArrayInputStream(java.io.ByteArrayInputStream) TxnLogEntry(org.apache.zookeeper.server.TxnLogEntry) EOFException(java.io.EOFException) CloseSessionTxn(org.apache.zookeeper.txn.CloseSessionTxn) Record(org.apache.jute.Record) SetACLTxn(org.apache.zookeeper.txn.SetACLTxn) TxnDigest(org.apache.zookeeper.txn.TxnDigest) TxnHeader(org.apache.zookeeper.txn.TxnHeader)

Aggregations

IOException (java.io.IOException)3 CloseSessionTxn (org.apache.zookeeper.txn.CloseSessionTxn)3 DeleteTxn (org.apache.zookeeper.txn.DeleteTxn)3 SetACLTxn (org.apache.zookeeper.txn.SetACLTxn)3 SetDataTxn (org.apache.zookeeper.txn.SetDataTxn)3 TxnHeader (org.apache.zookeeper.txn.TxnHeader)3 Record (org.apache.jute.Record)2 KeeperException (org.apache.zookeeper.KeeperException)2 CheckVersionTxn (org.apache.zookeeper.txn.CheckVersionTxn)2 CreateContainerTxn (org.apache.zookeeper.txn.CreateContainerTxn)2 CreateSessionTxn (org.apache.zookeeper.txn.CreateSessionTxn)2 CreateTTLTxn (org.apache.zookeeper.txn.CreateTTLTxn)2 CreateTxn (org.apache.zookeeper.txn.CreateTxn)2 ErrorTxn (org.apache.zookeeper.txn.ErrorTxn)2 MultiTxn (org.apache.zookeeper.txn.MultiTxn)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 EOFException (java.io.EOFException)1 StringReader (java.io.StringReader)1 ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1