public void processResult(int rc, String node, Object ctx, Stat statistics) { if (Code.NONODE.equals(Code.get(rc))) { if (configuration.shouldCreate()) { log.warn(format("Node '%s' did not exist, creating it...", node)); ProductionContext context = (ProductionContext) ctx; OperationResult<String> result = null; try { result = createNode(context); } catch (Exception e) { log.error(format("Error trying to create node '%s'", node), e); } if (result == null || !result.isOk()) { log.error(format("Error creating node '%s'", node), result.getException()); } } } else { logStoreComplete(node, statistics); } }
/** * async create * * <p>TODO: rename to create */ @Override public boolean[] createChildren(List<String> paths, List<T> records, int options) { boolean[] success = new boolean[paths.size()]; CreateMode mode = AccessOption.getMode(options); if (mode == null) { LOG.error("Invalid async create mode. options: " + options); return success; } boolean[] needCreate = new boolean[paths.size()]; Arrays.fill(needCreate, true); List<List<String>> pathsCreated = new ArrayList<List<String>>(Collections.<List<String>>nCopies(paths.size(), null)); long startT = System.nanoTime(); try { CreateCallbackHandler[] cbList = create(paths, records, needCreate, pathsCreated, options); for (int i = 0; i < cbList.length; i++) { CreateCallbackHandler cb = cbList[i]; success[i] = (Code.get(cb.getRc()) == Code.OK); } return success; } finally { long endT = System.nanoTime(); if (LOG.isDebugEnabled()) { LOG.debug( "create_async, size: " + paths.size() + ", paths: " + paths.get(0) + ",... time: " + (endT - startT) + " ns"); } } }
/** * async update * * <p>return: updatedData on success or null on fail */ List<T> update( List<String> paths, List<DataUpdater<T>> updaters, List<List<String>> pathsCreated, List<Stat> stats, int options) { if (paths == null || paths.size() == 0) { LOG.error("paths is null or empty"); return Collections.emptyList(); } if (updaters.size() != paths.size() || (pathsCreated != null && pathsCreated.size() != paths.size())) { throw new IllegalArgumentException( "paths, updaters, and pathsCreated should be of same size"); } List<Stat> setStats = new ArrayList<Stat>(Collections.<Stat>nCopies(paths.size(), null)); List<T> updateData = new ArrayList<T>(Collections.<T>nCopies(paths.size(), null)); CreateMode mode = AccessOption.getMode(options); if (mode == null) { LOG.error("Invalid update mode. options: " + options); return updateData; } SetDataCallbackHandler[] cbList = new SetDataCallbackHandler[paths.size()]; CreateCallbackHandler[] createCbList = null; boolean[] needUpdate = new boolean[paths.size()]; Arrays.fill(needUpdate, true); long startT = System.nanoTime(); try { boolean retry; do { retry = false; boolean[] needCreate = new boolean[paths.size()]; // init'ed with false boolean failOnNoNode = false; // asycn read all data List<Stat> curStats = new ArrayList<Stat>(); List<T> curDataList = get(paths, curStats, Arrays.copyOf(needUpdate, needUpdate.length)); // async update List<T> newDataList = new ArrayList<T>(); for (int i = 0; i < paths.size(); i++) { if (!needUpdate[i]) { newDataList.add(null); continue; } String path = paths.get(i); DataUpdater<T> updater = updaters.get(i); T newData = updater.update(curDataList.get(i)); newDataList.add(newData); Stat curStat = curStats.get(i); if (curStat == null) { // node not exists failOnNoNode = true; needCreate[i] = true; } else { cbList[i] = new SetDataCallbackHandler(); _zkClient.asyncSetData(path, newData, curStat.getVersion(), cbList[i]); } } // wait for completion boolean failOnBadVersion = false; for (int i = 0; i < paths.size(); i++) { SetDataCallbackHandler cb = cbList[i]; if (cb == null) continue; cb.waitForSuccess(); switch (Code.get(cb.getRc())) { case OK: updateData.set(i, newDataList.get(i)); setStats.set(i, cb.getStat()); needUpdate[i] = false; break; case NONODE: failOnNoNode = true; needCreate[i] = true; break; case BADVERSION: failOnBadVersion = true; break; default: // if fail on error other than NoNode or BadVersion // will not retry needUpdate[i] = false; break; } } // if failOnNoNode, try create if (failOnNoNode) { createCbList = create(paths, newDataList, needCreate, pathsCreated, options); for (int i = 0; i < paths.size(); i++) { CreateCallbackHandler createCb = createCbList[i]; if (createCb == null) { continue; } switch (Code.get(createCb.getRc())) { case OK: needUpdate[i] = false; updateData.set(i, newDataList.get(i)); setStats.set(i, ZNode.ZERO_STAT); break; case NODEEXISTS: retry = true; break; default: // if fail on error other than NodeExists // will not retry needUpdate[i] = false; break; } } } // if failOnBadVersion, retry if (failOnBadVersion) { retry = true; } } while (retry); if (stats != null) { stats.clear(); stats.addAll(setStats); } return updateData; } finally { long endT = System.nanoTime(); if (LOG.isDebugEnabled()) { LOG.debug( "setData_async, size: " + paths.size() + ", paths: " + paths.get(0) + ",... time: " + (endT - startT) + " ns"); } } }
/** async set, give up on error other than NoNode */ boolean[] set( List<String> paths, List<T> records, List<List<String>> pathsCreated, List<Stat> stats, int options) { if (paths == null || paths.size() == 0) { return new boolean[0]; } if ((records != null && records.size() != paths.size()) || (pathsCreated != null && pathsCreated.size() != paths.size())) { throw new IllegalArgumentException("paths, records, and pathsCreated should be of same size"); } boolean[] success = new boolean[paths.size()]; CreateMode mode = AccessOption.getMode(options); if (mode == null) { LOG.error("Invalid async set mode. options: " + options); return success; } List<Stat> setStats = new ArrayList<Stat>(Collections.<Stat>nCopies(paths.size(), null)); SetDataCallbackHandler[] cbList = new SetDataCallbackHandler[paths.size()]; CreateCallbackHandler[] createCbList = null; boolean[] needSet = new boolean[paths.size()]; Arrays.fill(needSet, true); long startT = System.nanoTime(); try { boolean retry; do { retry = false; for (int i = 0; i < paths.size(); i++) { if (!needSet[i]) continue; String path = paths.get(i); T record = records.get(i); cbList[i] = new SetDataCallbackHandler(); _zkClient.asyncSetData(path, record, -1, cbList[i]); } boolean failOnNoNode = false; for (int i = 0; i < cbList.length; i++) { SetDataCallbackHandler cb = cbList[i]; cb.waitForSuccess(); Code rc = Code.get(cb.getRc()); switch (rc) { case OK: setStats.set(i, cb.getStat()); needSet[i] = false; break; case NONODE: // if fail on NoNode, try create the node failOnNoNode = true; break; default: // if fail on error other than NoNode, give up needSet[i] = false; break; } } // if failOnNoNode, try create if (failOnNoNode) { boolean[] needCreate = Arrays.copyOf(needSet, needSet.length); createCbList = create(paths, records, needCreate, pathsCreated, options); for (int i = 0; i < createCbList.length; i++) { CreateCallbackHandler createCb = createCbList[i]; if (createCb == null) { continue; } Code rc = Code.get(createCb.getRc()); switch (rc) { case OK: setStats.set(i, ZNode.ZERO_STAT); needSet[i] = false; break; case NODEEXISTS: retry = true; break; default: // if creation fails on error other than NodeExists // no need to retry set needSet[i] = false; break; } } } } while (retry); // construct return results for (int i = 0; i < cbList.length; i++) { SetDataCallbackHandler cb = cbList[i]; Code rc = Code.get(cb.getRc()); if (rc == Code.OK) { success[i] = true; } else if (rc == Code.NONODE) { CreateCallbackHandler createCb = createCbList[i]; if (Code.get(createCb.getRc()) == Code.OK) { success[i] = true; } } } if (stats != null) { stats.clear(); stats.addAll(setStats); } return success; } finally { long endT = System.nanoTime(); if (LOG.isDebugEnabled()) { LOG.debug( "setData_async, size: " + paths.size() + ", paths: " + paths.get(0) + ",... time: " + (endT - startT) + " ns"); } } }
/** async create. give up on error other than NONODE */ CreateCallbackHandler[] create( List<String> paths, List<T> records, boolean[] needCreate, List<List<String>> pathsCreated, int options) { if ((records != null && records.size() != paths.size()) || needCreate.length != paths.size() || (pathsCreated != null && pathsCreated.size() != paths.size())) { throw new IllegalArgumentException( "paths, records, needCreate, and pathsCreated should be of same size"); } CreateCallbackHandler[] cbList = new CreateCallbackHandler[paths.size()]; CreateMode mode = AccessOption.getMode(options); if (mode == null) { LOG.error("Invalid async set mode. options: " + options); return cbList; } boolean retry; do { retry = false; for (int i = 0; i < paths.size(); i++) { if (!needCreate[i]) continue; String path = paths.get(i); T record = records == null ? null : records.get(i); cbList[i] = new CreateCallbackHandler(); _zkClient.asyncCreate(path, record, mode, cbList[i]); } List<String> parentPaths = new ArrayList<String>(Collections.<String>nCopies(paths.size(), null)); boolean failOnNoNode = false; for (int i = 0; i < paths.size(); i++) { if (!needCreate[i]) continue; CreateCallbackHandler cb = cbList[i]; cb.waitForSuccess(); String path = paths.get(i); if (Code.get(cb.getRc()) == Code.NONODE) { String parentPath = new File(path).getParent(); parentPaths.set(i, parentPath); failOnNoNode = true; } else { // if create succeed or fail on error other than NONODE, // give up needCreate[i] = false; // if succeeds, record what paths we've created if (Code.get(cb.getRc()) == Code.OK && pathsCreated != null) { if (pathsCreated.get(i) == null) { pathsCreated.set(i, new ArrayList<String>()); } pathsCreated.get(i).add(path); } } } if (failOnNoNode) { boolean[] needCreateParent = Arrays.copyOf(needCreate, needCreate.length); CreateCallbackHandler[] parentCbList = create(parentPaths, null, needCreateParent, pathsCreated, AccessOption.PERSISTENT); for (int i = 0; i < parentCbList.length; i++) { CreateCallbackHandler parentCb = parentCbList[i]; if (parentCb == null) continue; Code rc = Code.get(parentCb.getRc()); // if parent is created, retry create child if (rc == Code.OK || rc == Code.NODEEXISTS) { retry = true; break; } } } } while (retry); return cbList; }
/** async get */ List<T> get(List<String> paths, List<Stat> stats, boolean[] needRead) { if (paths == null || paths.size() == 0) { return Collections.emptyList(); } // init stats if (stats != null) { stats.clear(); stats.addAll(Collections.<Stat>nCopies(paths.size(), null)); } long startT = System.nanoTime(); try { // issue asyn get requests GetDataCallbackHandler[] cbList = new GetDataCallbackHandler[paths.size()]; for (int i = 0; i < paths.size(); i++) { if (!needRead[i]) continue; String path = paths.get(i); cbList[i] = new GetDataCallbackHandler(); _zkClient.asyncGetData(path, cbList[i]); } // wait for completion for (int i = 0; i < cbList.length; i++) { if (!needRead[i]) continue; GetDataCallbackHandler cb = cbList[i]; cb.waitForSuccess(); } // construct return results List<T> records = new ArrayList<T>(Collections.<T>nCopies(paths.size(), null)); for (int i = 0; i < paths.size(); i++) { if (!needRead[i]) continue; GetDataCallbackHandler cb = cbList[i]; if (Code.get(cb.getRc()) == Code.OK) { @SuppressWarnings("unchecked") T record = (T) _zkClient.deserialize(cb._data, paths.get(i)); records.set(i, record); if (stats != null) { stats.set(i, cb._stat); } } } return records; } finally { long endT = System.nanoTime(); if (LOG.isDebugEnabled()) { LOG.debug( "getData_async, size: " + paths.size() + ", paths: " + paths.get(0) + ",... time: " + (endT - startT) + " ns"); } } }
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); } }