ChangeRecord getRecordForPath(String path) throws KeeperException.NoNodeException {
   ChangeRecord lastChange = null;
   synchronized (zks.outstandingChanges) {
     lastChange = zks.outstandingChangesForPath.get(path);
     /*
     for (int i = 0; i < zks.outstandingChanges.size(); i++) {
         ChangeRecord c = zks.outstandingChanges.get(i);
         if (c.path.equals(path)) {
             lastChange = c;
         }
     }
     */
     if (lastChange == null) {
       DataNode n = zks.getZKDatabase().getNode(path);
       if (n != null) {
         Long acl;
         Set<String> children;
         synchronized (n) {
           acl = n.acl;
           children = n.getChildren();
         }
         lastChange =
             new ChangeRecord(
                 -1,
                 path,
                 n.stat,
                 children != null ? children.size() : 0,
                 zks.getZKDatabase().convertLong(acl));
       }
     }
   }
   if (lastChange == null || lastChange.stat == null) {
     throw new KeeperException.NoNodeException(path);
   }
   return lastChange;
 }
  /**
   * This method will be called inside the ProcessRequestThread, which is a singleton, so there will
   * be a single thread calling this code.
   *
   * @param request
   */
  @SuppressWarnings("unchecked")
  protected void pRequest(Request request) throws RequestProcessorException {
    // LOG.info("Prep>>> cxid = " + request.cxid + " type = " +
    // request.type + " id = 0x" + Long.toHexString(request.sessionId));
    TxnHeader txnHeader = null;
    Record txn = null;
    try {
      switch (request.type) {
        case OpCode.create:
          txnHeader =
              new TxnHeader(
                  request.sessionId, request.cxid, zks.getNextZxid(), zks.getTime(), OpCode.create);
          zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
          CreateRequest createRequest = new CreateRequest();
          ZooKeeperServer.byteBuffer2Record(request.request, createRequest);
          String path = createRequest.getPath();
          int lastSlash = path.lastIndexOf('/');
          if (lastSlash == -1 || path.indexOf('\0') != -1 || failCreate) {
            LOG.info(
                "Invalid path " + path + " with session 0x" + Long.toHexString(request.sessionId));
            throw new KeeperException.BadArgumentsException(path);
          }
          if (!fixupACL(request.authInfo, createRequest.getAcl())) {
            throw new KeeperException.InvalidACLException(path);
          }
          String parentPath = path.substring(0, lastSlash);
          ChangeRecord parentRecord = getRecordForPath(parentPath);

          checkACL(zks, parentRecord.acl, ZooDefs.Perms.CREATE, request.authInfo);
          int parentCVersion = parentRecord.stat.getCversion();
          CreateMode createMode = CreateMode.fromFlag(createRequest.getFlags());
          if (createMode.isSequential()) {
            path = path + String.format(Locale.ENGLISH, "%010d", parentCVersion);
          }
          try {
            PathUtils.validatePath(path);
          } catch (IllegalArgumentException ie) {
            LOG.info(
                "Invalid path " + path + " with session 0x" + Long.toHexString(request.sessionId));
            throw new KeeperException.BadArgumentsException(path);
          }
          try {
            if (getRecordForPath(path) != null) {
              throw new KeeperException.NodeExistsException(path);
            }
          } catch (KeeperException.NoNodeException e) {
            // ignore this one
          }
          boolean ephemeralParent = parentRecord.stat.getEphemeralOwner() != 0;
          if (ephemeralParent) {
            throw new KeeperException.NoChildrenForEphemeralsException(path);
          }
          txn =
              new CreateTxn(
                  path, createRequest.getData(), createRequest.getAcl(), createMode.isEphemeral());
          StatPersisted s = new StatPersisted();
          if (createMode.isEphemeral()) {
            s.setEphemeralOwner(request.sessionId);
          }
          parentRecord = parentRecord.duplicate(txnHeader.getZxid());
          parentRecord.childCount++;
          parentRecord.stat.setCversion(parentRecord.stat.getCversion() + 1);
          addChangeRecord(parentRecord);
          addChangeRecord(
              new ChangeRecord(txnHeader.getZxid(), path, s, 0, createRequest.getAcl()));

          break;
        case OpCode.delete:
          txnHeader =
              new TxnHeader(
                  request.sessionId, request.cxid, zks.getNextZxid(), zks.getTime(), OpCode.delete);
          zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
          DeleteRequest deleteRequest = new DeleteRequest();
          ZooKeeperServer.byteBuffer2Record(request.request, deleteRequest);
          path = deleteRequest.getPath();
          lastSlash = path.lastIndexOf('/');
          if (lastSlash == -1
              || path.indexOf('\0') != -1
              || zks.getZKDatabase().isSpecialPath(path)) {
            throw new KeeperException.BadArgumentsException(path);
          }
          parentPath = path.substring(0, lastSlash);
          parentRecord = getRecordForPath(parentPath);
          ChangeRecord nodeRecord = getRecordForPath(path);
          checkACL(zks, parentRecord.acl, ZooDefs.Perms.DELETE, request.authInfo);
          int version = deleteRequest.getVersion();
          if (version != -1 && nodeRecord.stat.getVersion() != version) {
            throw new KeeperException.BadVersionException(path);
          }
          if (nodeRecord.childCount > 0) {
            throw new KeeperException.NotEmptyException(path);
          }
          txn = new DeleteTxn(path);
          parentRecord = parentRecord.duplicate(txnHeader.getZxid());
          parentRecord.childCount--;
          parentRecord.stat.setCversion(parentRecord.stat.getCversion() + 1);
          addChangeRecord(parentRecord);
          addChangeRecord(new ChangeRecord(txnHeader.getZxid(), path, null, -1, null));
          break;
        case OpCode.setData:
          txnHeader =
              new TxnHeader(
                  request.sessionId,
                  request.cxid,
                  zks.getNextZxid(),
                  zks.getTime(),
                  OpCode.setData);
          zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
          SetDataRequest setDataRequest = new SetDataRequest();
          ZooKeeperServer.byteBuffer2Record(request.request, setDataRequest);
          path = setDataRequest.getPath();
          nodeRecord = getRecordForPath(path);
          checkACL(zks, nodeRecord.acl, ZooDefs.Perms.WRITE, request.authInfo);
          version = setDataRequest.getVersion();
          int currentVersion = nodeRecord.stat.getVersion();
          if (version != -1 && version != currentVersion) {
            throw new KeeperException.BadVersionException(path);
          }
          version = currentVersion + 1;
          txn = new SetDataTxn(path, setDataRequest.getData(), version);
          nodeRecord = nodeRecord.duplicate(txnHeader.getZxid());
          nodeRecord.stat.setVersion(version);
          addChangeRecord(nodeRecord);
          break;
        case OpCode.setACL:
          txnHeader =
              new TxnHeader(
                  request.sessionId, request.cxid, zks.getNextZxid(), zks.getTime(), OpCode.setACL);
          zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
          SetACLRequest setAclRequest = new SetACLRequest();
          ZooKeeperServer.byteBuffer2Record(request.request, setAclRequest);
          path = setAclRequest.getPath();
          if (!fixupACL(request.authInfo, setAclRequest.getAcl())) {
            throw new KeeperException.InvalidACLException(path);
          }
          nodeRecord = getRecordForPath(path);
          checkACL(zks, nodeRecord.acl, ZooDefs.Perms.ADMIN, request.authInfo);
          version = setAclRequest.getVersion();
          currentVersion = nodeRecord.stat.getAversion();
          if (version != -1 && version != currentVersion) {
            throw new KeeperException.BadVersionException(path);
          }
          version = currentVersion + 1;
          txn = new SetACLTxn(path, setAclRequest.getAcl(), version);
          nodeRecord = nodeRecord.duplicate(txnHeader.getZxid());
          nodeRecord.stat.setAversion(version);
          addChangeRecord(nodeRecord);
          break;
        case OpCode.createSession:
          txnHeader =
              new TxnHeader(
                  request.sessionId,
                  request.cxid,
                  zks.getNextZxid(),
                  zks.getTime(),
                  OpCode.createSession);
          request.request.rewind();
          int to = request.request.getInt();
          txn = new CreateSessionTxn(to);
          request.request.rewind();
          zks.sessionTracker.addSession(request.sessionId, to);
          zks.setOwner(request.sessionId, request.getOwner());
          break;
        case OpCode.closeSession:
          txnHeader =
              new TxnHeader(
                  request.sessionId,
                  request.cxid,
                  zks.getNextZxid(),
                  zks.getTime(),
                  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());
          HashSet<String> es = zks.getZKDatabase().getEphemerals(request.sessionId);
          synchronized (zks.outstandingChanges) {
            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) {
              addChangeRecord(new ChangeRecord(txnHeader.getZxid(), path2Delete, null, 0, null));
            }

            zks.sessionTracker.setSessionClosing(request.sessionId);
          }

          LOG.info(
              "Processed session termination for sessionid: 0x"
                  + Long.toHexString(request.sessionId));
          break;
        case OpCode.sync:
        case OpCode.exists:
        case OpCode.getData:
        case OpCode.getACL:
        case OpCode.getChildren:
        case OpCode.getChildren2:
        case OpCode.ping:
        case OpCode.setWatches:
          zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
          break;
      }
    } catch (KeeperException e) {
      if (txnHeader != null) {
        txnHeader.setType(OpCode.error);
        txn = new ErrorTxn(e.code().intValue());
      }
      LOG.info(
          "Got user-level KeeperException when processing "
              + request.toString()
              + " Error Path:"
              + e.getPath()
              + " Error:"
              + e.getMessage());
      request.setException(e);
    } catch (Exception e) {
      // log at error level as we are returning a marshalling
      // error to the user
      LOG.error("Failed to process " + request, e);

      StringBuilder sb = new StringBuilder();
      ByteBuffer bb = request.request;
      if (bb != null) {
        bb.rewind();
        while (bb.hasRemaining()) {
          sb.append(Integer.toHexString(bb.get() & 0xff));
        }
      } else {
        sb.append("request buffer is null");
      }

      LOG.error("Dumping request buffer: 0x" + sb.toString());
      if (txnHeader != null) {
        txnHeader.setType(OpCode.error);
        txn = new ErrorTxn(Code.MARSHALLINGERROR.intValue());
      }
    }
    request.hdr = txnHeader;
    request.txn = txn;
    request.zxid = zks.getZxid();
    nextProcessor.processRequest(request);
  }
Пример #3
0
  public void processRequest(Request request) {
    if (LOG.isDebugEnabled()) {
      LOG.debug("Processing request:: " + request);
    }
    // request.addRQRec(">final");
    long traceMask = ZooTrace.CLIENT_REQUEST_TRACE_MASK;
    if (request.type == OpCode.ping) {
      traceMask = ZooTrace.SERVER_PING_TRACE_MASK;
    }
    if (LOG.isTraceEnabled()) {
      ZooTrace.logRequest(LOG, traceMask, 'E', request, "");
    }
    ProcessTxnResult rc = null;
    synchronized (zks.outstandingChanges) {
      while (!zks.outstandingChanges.isEmpty()
          && zks.outstandingChanges.get(0).zxid <= request.zxid) {
        ChangeRecord cr = zks.outstandingChanges.remove(0);
        if (cr.zxid < request.zxid) {
          LOG.warn("Zxid outstanding " + cr.zxid + " is less than current " + request.zxid);
        }
        if (zks.outstandingChangesForPath.get(cr.path) == cr) {
          zks.outstandingChangesForPath.remove(cr.path);
        }
      }
      if (request.hdr != null) {
        TxnHeader hdr = request.hdr;
        Record txn = request.txn;

        rc = zks.processTxn(hdr, txn);
      }
      // do not add non quorum packets to the queue.
      if (Request.isQuorum(request.type)) {
        zks.getZKDatabase().addCommittedProposal(request);
      }
    }

    if (request.hdr != null && request.hdr.getType() == OpCode.closeSession) {
      ServerCnxnFactory scxn = zks.getServerCnxnFactory();
      // this might be possible since
      // we might just be playing diffs from the leader
      if (scxn != null && request.cnxn == null) {
        // calling this if we have the cnxn results in the client's
        // close session response being lost - we've already closed
        // the session/socket here before we can send the closeSession
        // in the switch block below
        scxn.closeSession(request.sessionId);
        return;
      }
    }

    if (request.cnxn == null) {
      return;
    }
    ServerCnxn cnxn = request.cnxn;

    String lastOp = "NA";
    zks.decInProcess();
    Code err = Code.OK;
    Record rsp = null;
    boolean closeSession = false;
    try {
      if (request.hdr != null && request.hdr.getType() == OpCode.error) {
        throw KeeperException.create(KeeperException.Code.get(((ErrorTxn) request.txn).getErr()));
      }

      KeeperException ke = request.getException();
      if (ke != null && request.type != OpCode.multi) {
        throw ke;
      }

      if (LOG.isDebugEnabled()) {
        LOG.debug("{}", request);
      }
      switch (request.type) {
        case OpCode.ping:
          {
            zks.serverStats().updateLatency(request.createTime);

            lastOp = "PING";
            cnxn.updateStatsForResponse(
                request.cxid, request.zxid, lastOp, request.createTime, System.currentTimeMillis());

            cnxn.sendResponse(
                new ReplyHeader(-2, zks.getZKDatabase().getDataTreeLastProcessedZxid(), 0),
                null,
                "response");
            return;
          }
        case OpCode.createSession:
          {
            zks.serverStats().updateLatency(request.createTime);

            lastOp = "SESS";
            cnxn.updateStatsForResponse(
                request.cxid, request.zxid, lastOp, request.createTime, System.currentTimeMillis());

            zks.finishSessionInit(request.cnxn, true);
            return;
          }
        case OpCode.multi:
          {
            lastOp = "MULT";
            rsp = new MultiResponse();

            for (ProcessTxnResult subTxnResult : rc.multiResult) {

              OpResult subResult;

              switch (subTxnResult.type) {
                case OpCode.check:
                  subResult = new CheckResult();
                  break;
                case OpCode.create:
                  subResult = new CreateResult(subTxnResult.path);
                  break;
                case OpCode.delete:
                  subResult = new DeleteResult();
                  break;
                case OpCode.setData:
                  subResult = new SetDataResult(subTxnResult.stat);
                  break;
                case OpCode.error:
                  subResult = new ErrorResult(subTxnResult.err);
                  break;
                default:
                  throw new IOException("Invalid type of op");
              }

              ((MultiResponse) rsp).add(subResult);
            }

            break;
          }
        case OpCode.create:
          {
            lastOp = "CREA";
            rsp = new CreateResponse(rc.path);
            err = Code.get(rc.err);
            break;
          }
        case OpCode.delete:
          {
            lastOp = "DELE";
            err = Code.get(rc.err);
            break;
          }
        case OpCode.setData:
          {
            lastOp = "SETD";
            rsp = new SetDataResponse(rc.stat);
            err = Code.get(rc.err);
            break;
          }
        case OpCode.setACL:
          {
            lastOp = "SETA";
            rsp = new SetACLResponse(rc.stat);
            err = Code.get(rc.err);
            break;
          }
        case OpCode.closeSession:
          {
            lastOp = "CLOS";
            closeSession = true;
            err = Code.get(rc.err);
            break;
          }
        case OpCode.sync:
          {
            lastOp = "SYNC";
            SyncRequest syncRequest = new SyncRequest();
            ByteBufferInputStream.byteBuffer2Record(request.request, syncRequest);
            rsp = new SyncResponse(syncRequest.getPath());
            break;
          }
        case OpCode.check:
          {
            lastOp = "CHEC";
            rsp = new SetDataResponse(rc.stat);
            err = Code.get(rc.err);
            break;
          }
        case OpCode.exists:
          {
            lastOp = "EXIS";
            // TODO we need to figure out the security requirement for this!
            ExistsRequest existsRequest = new ExistsRequest();
            ByteBufferInputStream.byteBuffer2Record(request.request, existsRequest);
            String path = existsRequest.getPath();
            if (path.indexOf('\0') != -1) {
              throw new KeeperException.BadArgumentsException();
            }
            Stat stat = zks.getZKDatabase().statNode(path, existsRequest.getWatch() ? cnxn : null);
            rsp = new ExistsResponse(stat);
            break;
          }
        case OpCode.getData:
          {
            lastOp = "GETD";
            GetDataRequest getDataRequest = new GetDataRequest();
            ByteBufferInputStream.byteBuffer2Record(request.request, getDataRequest);
            DataNode n = zks.getZKDatabase().getNode(getDataRequest.getPath());
            if (n == null) {
              throw new KeeperException.NoNodeException();
            }
            Long aclL;
            synchronized (n) {
              aclL = n.acl;
            }
            PrepRequestProcessor.checkACL(
                zks, zks.getZKDatabase().convertLong(aclL), ZooDefs.Perms.READ, request.authInfo);
            Stat stat = new Stat();
            byte b[] =
                zks.getZKDatabase()
                    .getData(
                        getDataRequest.getPath(), stat, getDataRequest.getWatch() ? cnxn : null);
            rsp = new GetDataResponse(b, stat);
            break;
          }
        case OpCode.setWatches:
          {
            lastOp = "SETW";
            SetWatches setWatches = new SetWatches();
            // XXX We really should NOT need this!!!!
            request.request.rewind();
            ByteBufferInputStream.byteBuffer2Record(request.request, setWatches);
            long relativeZxid = setWatches.getRelativeZxid();
            zks.getZKDatabase()
                .setWatches(
                    relativeZxid,
                    setWatches.getDataWatches(),
                    setWatches.getExistWatches(),
                    setWatches.getChildWatches(),
                    cnxn);
            break;
          }
        case OpCode.getACL:
          {
            lastOp = "GETA";
            GetACLRequest getACLRequest = new GetACLRequest();
            ByteBufferInputStream.byteBuffer2Record(request.request, getACLRequest);
            Stat stat = new Stat();
            List<ACL> acl = zks.getZKDatabase().getACL(getACLRequest.getPath(), stat);
            rsp = new GetACLResponse(acl, stat);
            break;
          }
        case OpCode.getChildren:
          {
            lastOp = "GETC";
            GetChildrenRequest getChildrenRequest = new GetChildrenRequest();
            ByteBufferInputStream.byteBuffer2Record(request.request, getChildrenRequest);
            DataNode n = zks.getZKDatabase().getNode(getChildrenRequest.getPath());
            if (n == null) {
              throw new KeeperException.NoNodeException();
            }
            Long aclG;
            synchronized (n) {
              aclG = n.acl;
            }
            PrepRequestProcessor.checkACL(
                zks, zks.getZKDatabase().convertLong(aclG), ZooDefs.Perms.READ, request.authInfo);
            List<String> children =
                zks.getZKDatabase()
                    .getChildren(
                        getChildrenRequest.getPath(),
                        null,
                        getChildrenRequest.getWatch() ? cnxn : null);
            rsp = new GetChildrenResponse(children);
            break;
          }
        case OpCode.getChildren2:
          {
            lastOp = "GETC";
            GetChildren2Request getChildren2Request = new GetChildren2Request();
            ByteBufferInputStream.byteBuffer2Record(request.request, getChildren2Request);
            Stat stat = new Stat();
            DataNode n = zks.getZKDatabase().getNode(getChildren2Request.getPath());
            if (n == null) {
              throw new KeeperException.NoNodeException();
            }
            Long aclG;
            synchronized (n) {
              aclG = n.acl;
            }
            PrepRequestProcessor.checkACL(
                zks, zks.getZKDatabase().convertLong(aclG), ZooDefs.Perms.READ, request.authInfo);
            List<String> children =
                zks.getZKDatabase()
                    .getChildren(
                        getChildren2Request.getPath(),
                        stat,
                        getChildren2Request.getWatch() ? cnxn : null);
            rsp = new GetChildren2Response(children, stat);
            break;
          }
      }
    } catch (SessionMovedException e) {
      // session moved is a connection level error, we need to tear
      // down the connection otw ZOOKEEPER-710 might happen
      // ie client on slow follower starts to renew session, fails
      // before this completes, then tries the fast follower (leader)
      // and is successful, however the initial renew is then
      // successfully fwd/processed by the leader and as a result
      // the client and leader disagree on where the client is most
      // recently attached (and therefore invalid SESSION MOVED generated)
      cnxn.sendCloseSession();
      return;
    } catch (KeeperException e) {
      err = e.code();
    } catch (Exception e) {
      // log at error level as we are returning a marshalling
      // error to the user
      LOG.error("Failed to process " + request, e);
      StringBuilder sb = new StringBuilder();
      ByteBuffer bb = request.request;
      bb.rewind();
      while (bb.hasRemaining()) {
        sb.append(Integer.toHexString(bb.get() & 0xff));
      }
      LOG.error("Dumping request buffer: 0x" + sb.toString());
      err = Code.MARSHALLINGERROR;
    }

    long lastZxid = zks.getZKDatabase().getDataTreeLastProcessedZxid();
    ReplyHeader hdr = new ReplyHeader(request.cxid, lastZxid, err.intValue());

    zks.serverStats().updateLatency(request.createTime);
    cnxn.updateStatsForResponse(
        request.cxid, lastZxid, lastOp, request.createTime, System.currentTimeMillis());

    try {
      cnxn.sendResponse(hdr, rsp, "response");
      if (closeSession) {
        cnxn.sendCloseSession();
      }
    } catch (IOException e) {
      LOG.error("FIXMSG", e);
    }
  }