/** * Execute the provided query asynchronously. * * <p>This method does not block. It returns as soon as the query has been successfully sent to a * Cassandra node. In particular, returning from this method does not guarantee that the query is * valid. Any exception pertaining to the failure of the query will be thrown by the first access * to the {@link ResultSet}. * * <p>Note that for queries that doesn't return a result (INSERT, UPDATE and DELETE), you will * need to access the ResultSet (i.e. call any of its method) to make sure the query was * successful. * * @param query the CQL query to execute (that can be either a {@code Statement} or a {@code * BoundStatement}). If it is a {@code BoundStatement}, all variables must have been bound * (the statement must be ready). * @return a future on the result of the query. * @throws IllegalStateException if {@code query} is a {@code BoundStatement} but {@code * !query.isReady()}. */ public ResultSetFuture executeAsync(Query query) { if (query instanceof Statement) { return manager.executeQuery( new QueryMessage( ((Statement) query).getQueryString(), ConsistencyLevel.toCassandraCL(query.getConsistencyLevel())), query); } else { assert query instanceof BoundStatement : query; BoundStatement bs = (BoundStatement) query; if (!bs.isReady()) throw new IllegalStateException( "Some bind variables haven't been bound in the provided statement"); return manager.executeQuery( new ExecuteMessage( bs.statement.id, Arrays.asList(bs.values), ConsistencyLevel.toCassandraCL(query.getConsistencyLevel())), query); } }
/** Loops collecting cql binded variable values from the queue and sending to Cassandra */ public void run() { outer: while (run || !queue.isEmpty()) { List<ByteBuffer> bindVariables; try { bindVariables = queue.take(); } catch (InterruptedException e) { // re-check loop condition after interrupt continue; } ListIterator<InetAddress> iter = endpoints.listIterator(); while (true) { // send the mutation to the last-used endpoint. first time through, this will NPE // harmlessly. try { int i = 0; PreparedStatement statement = preparedStatement(client); while (bindVariables != null) { BoundStatement boundStatement = new BoundStatement(statement); for (int columnPosition = 0; columnPosition < bindVariables.size(); columnPosition++) { boundStatement.setBytesUnsafe(columnPosition, bindVariables.get(columnPosition)); } client.execute(boundStatement); i++; if (i >= batchThreshold) break; bindVariables = queue.poll(); } break; } catch (Exception e) { closeInternal(); if (!iter.hasNext()) { lastException = new IOException(e); break outer; } } // attempt to connect to a different endpoint try { InetAddress address = iter.next(); String host = address.getHostName(); client = CqlConfigHelper.getOutputCluster(host, conf).connect(); } catch (Exception e) { // If connection died due to Interrupt, just try connecting to the endpoint again. // There are too many ways for the Thread.interrupted() state to be cleared, so // we can't rely on that here. Until the java driver gives us a better way of knowing // that this exception came from an InterruptedException, this is the best solution. if (canRetryDriverConnection(e)) { iter.previous(); } closeInternal(); // Most exceptions mean something unexpected went wrong to that endpoint, so // we should try again to another. Other exceptions (auth or invalid request) are // fatal. if ((e instanceof AuthenticationException || e instanceof InvalidQueryException) || !iter.hasNext()) { lastException = new IOException(e); break outer; } } } } // close all our connections once we are done. closeInternal(); }