public static Builder from(final RequestMessage msg) { final Builder builder = build(msg.op) .overrideRequestId(msg.requestId) .processor(msg.processor); msg.args.forEach(builder::addArg); return builder; }
@Override public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final RequestMessage requestMessage) { kryo.writeObject(output, requestMessage.getRequestId()); output.writeString(requestMessage.getProcessor()); output.writeString(requestMessage.getOp()); kryo.writeObject(output, requestMessage.getArgs()); }
/** * Uses a {@link LoadBalancingStrategy} to choose the best {@link Host} and then selects the best connection * from that host's connection pool. */ @Override protected Connection chooseConnection(final RequestMessage msg) throws TimeoutException, ConnectionException { final Iterator<Host> possibleHosts; if (msg.optionalArgs(Tokens.ARGS_HOST).isPresent()) { // TODO: not sure what should be done if unavailable - select new host and re-submit traversal? final Host host = (Host) msg.getArgs().get(Tokens.ARGS_HOST); msg.getArgs().remove(Tokens.ARGS_HOST); possibleHosts = IteratorUtils.of(host); } else { possibleHosts = this.cluster.loadBalancingStrategy().select(msg); } // you can get no possible hosts in more than a few situations. perhaps the servers are just all down. // or perhaps the client is not configured properly (disables ssl when ssl is enabled on the server). if (!possibleHosts.hasNext()) throw new TimeoutException("Timed out while waiting for an available host - check the client configuration and connectivity to the server if this message persists"); final Host bestHost = possibleHosts.next(); final ConnectionPool pool = hostConnectionPools.get(bestHost); return pool.borrowConnection(cluster.connectionPoolSettings().maxWaitForConnection, TimeUnit.MILLISECONDS); }
/** * Used to decrease the size of a Gremlin script that triggered a "method too large" exception so that it * doesn't log a massive text string nor return a large error message. */ private RequestMessage trimMessage(final RequestMessage msg) { final RequestMessage trimmedMsg = RequestMessage.from(msg).create(); if (trimmedMsg.getArgs().containsKey(Tokens.ARGS_GREMLIN)) trimmedMsg.getArgs().put(Tokens.ARGS_GREMLIN, trimmedMsg.getArgs().get(Tokens.ARGS_GREMLIN).toString().substring(0, 1021) + "..."); return trimmedMsg; }
/** * Examines the {@link RequestMessage} and extracts the session token. The session is then either found or a new * one is created. */ protected static Session getSession(final Context context, final RequestMessage msg) { final String sessionId = (String) msg.getArgs().get(Tokens.ARGS_SESSION); logger.debug("In-session request {} for eval for session {} in thread {}", msg.getRequestId(), sessionId, Thread.currentThread().getName()); final Session session = sessions.computeIfAbsent(sessionId, k -> new Session(k, context, sessions)); session.touch(); return session; }
/** * Session based requests accept a "close" operator in addition to "eval". A close will trigger the session to be * killed and any uncommitted transaction to be rolled-back. */ @Override public Optional<ThrowingConsumer<Context>> selectOther(final RequestMessage requestMessage) throws OpProcessorException { if (requestMessage.getOp().equals(Tokens.OPS_CLOSE)) { // this must be an in-session request if (!requestMessage.optionalArgs(Tokens.ARGS_SESSION).isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument", Tokens.OPS_CLOSE, Tokens.ARGS_SESSION); throw new OpProcessorException(msg, ResponseMessage.build(requestMessage).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create()); } final boolean force = requestMessage.<Boolean>optionalArgs(Tokens.ARGS_FORCE).orElse(false); return Optional.of(ctx -> { // validate the session is present and then remove it if it is. final Session sessionToClose = sessions.get(requestMessage.getArgs().get(Tokens.ARGS_SESSION).toString()); if (null == sessionToClose) { final String msg = String.format("There was no session named %s to close", requestMessage.getArgs().get(Tokens.ARGS_SESSION).toString()); throw new OpProcessorException(msg, ResponseMessage.build(requestMessage).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create()); } sessionToClose.manualKill(force); // send back a confirmation of the close ctx.getChannelHandlerContext().writeAndFlush(ResponseMessage.build(requestMessage) .code(ResponseStatusCode.NO_CONTENT) .create()); }); } else { return Optional.empty(); } }
private void iterateBytecodeTraversal(final Context context) throws Exception { final RequestMessage msg = context.getRequestMessage(); logger.debug("Traversal request {} for in thread {}", msg.getRequestId(), Thread.currentThread().getName()); final Object bytecodeObj = msg.getArgs().get(Tokens.ARGS_GREMLIN); final Bytecode bytecode = bytecodeObj instanceof Bytecode ? (Bytecode) bytecodeObj : mapper.readValue(bytecodeObj.toString(), Bytecode.class); final Map<String, String> aliases = (Map<String, String>) msg.optionalArgs(Tokens.ARGS_ALIASES).get(); final long seto = msg.getArgs().containsKey(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT) ? ((Number) msg.getArgs().get(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT)).longValue() : context.getSettings().scriptEvaluationTimeout; onError(graph, context); } else { logger.warn(String.format("Exception processing a Traversal on iteration for request [%s].", msg.getRequestId()), ex); ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR) .statusMessage(ex.getMessage()) logger.warn(String.format("Exception processing a Traversal on request [%s].", msg.getRequestId()), ex); ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR) .statusMessage(ex.getMessage())
private void gatherSideEffect(final Context context) throws OpProcessorException { final RequestMessage msg = context.getRequestMessage(); logger.debug("Side-effect request {} for in thread {}", msg.getRequestId(), Thread.currentThread().getName()); final Optional<UUID> sideEffect = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT); final Optional<String> sideEffectKey = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT_KEY); final Map<String, String> aliases = (Map<String, String>) msg.optionalArgs(Tokens.ARGS_ALIASES).get(); logger.warn(String.format("Exception processing a side-effect on iteration for request [%s].", msg.getRequestId()), ex); ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR) .statusMessage(ex.getMessage()) logger.warn(String.format("Exception processing a side-effect on request [%s].", msg.getRequestId()), ex); ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR) .statusMessage(ex.getMessage())
switch (message.getOp()) { case Tokens.OPS_BYTECODE: validateTraversalSourceAlias(ctx, message, validateTraversalRequest(message)); break; case Tokens.OPS_GATHER: final Optional<String> sideEffectForGather = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT); if (!sideEffectForGather.isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_GATHER, Tokens.ARGS_SIDE_EFFECT); final Optional<String> sideEffectKey = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT_KEY); if (!sideEffectKey.isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_GATHER, Tokens.ARGS_SIDE_EFFECT_KEY); final Optional<String> sideEffectForKeys = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT); if (!sideEffectForKeys.isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_GATHER, Tokens.ARGS_SIDE_EFFECT); final Optional<UUID> sideEffect = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT); final TraversalSideEffects sideEffects = cache.getIfPresent(sideEffect.get()); final Optional<String> sideEffectForClose = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT); if (!sideEffectForClose.isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_CLOSE, Tokens.ARGS_SIDE_EFFECT); logger.debug("Close request {} for in thread {}", msg.getRequestId(), Thread.currentThread().getName()); final Optional<UUID> sideEffect = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT); cache.invalidate(sideEffect.get());
protected static void attemptCommit(final RequestMessage msg, final GraphManager graphManager, final boolean strict) { if (strict) { if (msg.getArgs().containsKey(Tokens.ARGS_ALIASES)) { final Map<String, String> aliases = (Map<String, String>) msg.getArgs().get(Tokens.ARGS_ALIASES); graphManager.commit(new HashSet<>(aliases.values())); } else { graphManager.commitAll(); } } else { graphManager.commitAll(); } }
@Override protected Optional<ThrowingConsumer<Context>> validateEvalMessage(final RequestMessage message) throws OpProcessorException { super.validateEvalMessage(message); if (!message.optionalArgs(Tokens.ARGS_SESSION).isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument", Tokens.OPS_EVAL, Tokens.ARGS_SESSION); throw new OpProcessorException(msg, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create()); } return Optional.empty(); }
private Builder(final RequestMessage requestMessage) { this.requestId = requestMessage.getRequestId(); }
@Override public ThrowingConsumer<Context> select(final Context ctx) throws OpProcessorException { final RequestMessage message = ctx.getRequestMessage(); logger.debug("Selecting processor for RequestMessage {}", message); final ThrowingConsumer<Context> op; switch (message.getOp()) { case Tokens.OPS_EVAL: op = validateEvalMessage(message).orElse(getEvalOp()); break; case Tokens.OPS_INVALID: final String msgInvalid = String.format("Message could not be parsed. Check the format of the request. [%s]", message); throw new OpProcessorException(msgInvalid, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_MALFORMED_REQUEST).statusMessage(msgInvalid).create()); default: op = selectOther(message).orElseThrow(() -> { final String msgDefault = String.format("Message with op code [%s] is not recognized.", message.getOp()); return new OpProcessorException(msgDefault, ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_MALFORMED_REQUEST).statusMessage(msgDefault).create()); }); } return op; }
@Override protected void decode(final ChannelHandlerContext ctx, final RequestMessage msg, final List<Object> objects) throws Exception { final Context gremlinServerContext = new Context(msg, ctx, settings, graphManager, gremlinExecutor, this.scheduledExecutorService); try { // choose a processor to do the work based on the request message. final Optional<OpProcessor> processor = OpLoader.getProcessor(msg.getProcessor()); if (processor.isPresent()) // the processor is known so use it to evaluate the message objects.add(Pair.with(msg, processor.get().select(gremlinServerContext))); else { // invalid op processor selected so write back an error by way of OpProcessorException. final String errorMessage = String.format("Invalid OpProcessor requested [%s]", msg.getProcessor()); throw new OpProcessorException(errorMessage, ResponseMessage.build(msg) .code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS) .statusMessage(errorMessage).create()); } } catch (OpProcessorException ope) { logger.warn(ope.getMessage(), ope); ctx.writeAndFlush(ope.getResponseMessage()); } }
/** * Session based requests accept a "close" operator in addition to "eval". A close will trigger the session to be * killed and any uncommitted transaction to be rolled-back. */ @Override public Optional<ThrowingConsumer<Context>> selectOther(final RequestMessage requestMessage) throws OpProcessorException { if (requestMessage.getOp().equals(Tokens.OPS_CLOSE)) { // this must be an in-session request if (!requestMessage.optionalArgs(Tokens.ARGS_SESSION).isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument", Tokens.OPS_CLOSE, Tokens.ARGS_SESSION); throw new OpProcessorException(msg, ResponseMessage.build(requestMessage).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create()); } final boolean force = requestMessage.<Boolean>optionalArgs(Tokens.ARGS_FORCE).orElse(false); return Optional.of(ctx -> { // validate the session is present and then remove it if it is. final Session sessionToClose = sessions.get(requestMessage.getArgs().get(Tokens.ARGS_SESSION).toString()); if (null == sessionToClose) { final String msg = String.format("There was no session named %s to close", requestMessage.getArgs().get(Tokens.ARGS_SESSION).toString()); throw new OpProcessorException(msg, ResponseMessage.build(requestMessage).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create()); } sessionToClose.manualKill(force); // send back a confirmation of the close ctx.getChannelHandlerContext().writeAndFlush(ResponseMessage.build(requestMessage) .code(ResponseStatusCode.NO_CONTENT) .create()); }); } else { return Optional.empty(); } }
private void iterateBytecodeTraversal(final Context context) throws Exception { final RequestMessage msg = context.getRequestMessage(); logger.debug("Traversal request {} for in thread {}", msg.getRequestId(), Thread.currentThread().getName()); final Object bytecodeObj = msg.getArgs().get(Tokens.ARGS_GREMLIN); final Bytecode bytecode = bytecodeObj instanceof Bytecode ? (Bytecode) bytecodeObj : mapper.readValue(bytecodeObj.toString(), Bytecode.class); final Map<String, String> aliases = (Map<String, String>) msg.optionalArgs(Tokens.ARGS_ALIASES).get(); final long seto = msg.getArgs().containsKey(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT) ? ((Number) msg.getArgs().get(Tokens.ARGS_SCRIPT_EVAL_TIMEOUT)).longValue() : context.getSettings().scriptEvaluationTimeout; onError(graph, context); } else { logger.warn(String.format("Exception processing a Traversal on iteration for request [%s].", msg.getRequestId()), ex); ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR) .statusMessage(ex.getMessage()) logger.warn(String.format("Exception processing a Traversal on request [%s].", msg.getRequestId()), ex); ctx.writeAndFlush(ResponseMessage.build(msg).code(ResponseStatusCode.SERVER_ERROR) .statusMessage(ex.getMessage())
@Override public CompletableFuture<ResultSet> submitAsync(final RequestMessage msg) { final RequestMessage.Builder builder = RequestMessage.from(msg); // only add aliases which aren't already present. if they are present then they represent request level // overrides which should be mucked with if (!aliases.isEmpty()) { final Map original = (Map) msg.getArgs().getOrDefault(Tokens.ARGS_ALIASES, Collections.emptyMap()); aliases.forEach((k,v) -> { if (!original.containsKey(k)) builder.addArg(Tokens.ARGS_ALIASES, aliases); }); } return super.submitAsync(builder.create()); }
cache.put(msg.getRequestId(), ((TraverserIterator)itty).getTraversal().getSideEffects()); final int resultIterationBatchSize = (Integer) msg.optionalArgs(Tokens.ARGS_BATCH_SIZE) .orElse(settings.resultIterationBatchSize); List<Object> aggregate = new ArrayList<>(resultIterationBatchSize);
switch (message.getOp()) { case Tokens.OPS_BYTECODE: validateTraversalSourceAlias(ctx, message, validateTraversalRequest(message)); break; case Tokens.OPS_GATHER: final Optional<String> sideEffectForGather = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT); if (!sideEffectForGather.isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_GATHER, Tokens.ARGS_SIDE_EFFECT); final Optional<String> sideEffectKey = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT_KEY); if (!sideEffectKey.isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_GATHER, Tokens.ARGS_SIDE_EFFECT_KEY); final Optional<String> sideEffectForKeys = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT); if (!sideEffectForKeys.isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_GATHER, Tokens.ARGS_SIDE_EFFECT); final Optional<UUID> sideEffect = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT); final TraversalSideEffects sideEffects = cache.getIfPresent(sideEffect.get()); final Optional<String> sideEffectForClose = message.optionalArgs(Tokens.ARGS_SIDE_EFFECT); if (!sideEffectForClose.isPresent()) { final String msg = String.format("A message with an [%s] op code requires a [%s] argument.", Tokens.OPS_CLOSE, Tokens.ARGS_SIDE_EFFECT); logger.debug("Close request {} for in thread {}", msg.getRequestId(), Thread.currentThread().getName()); final Optional<UUID> sideEffect = msg.optionalArgs(Tokens.ARGS_SIDE_EFFECT); cache.invalidate(sideEffect.get());