@Override public RetryDecision onUnavailable(Statement statement, ConsistencyLevel consistencyLevel, int requiredReplica, int aliveReplica, int retries) { if (retries >= 10) { return RetryDecision.rethrow(); } try { int jitter = ThreadLocalRandom.current().nextInt(100); int delay = (100 * (retries + 1)) + jitter; Thread.sleep(delay); return RetryDecision.retry(consistencyLevel); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return RetryDecision.rethrow(); } }
@Test(groups = "unit") public void should_expose_decision_properties() throws Throwable { RetryDecision retryAtOne = RetryDecision.retry(ONE); assertThat(retryAtOne.getType()).isEqualTo(RETRY); assertThat(retryAtOne.getRetryConsistencyLevel()).isEqualTo(ONE); assertThat(retryAtOne.isRetryCurrent()).isTrue(); assertThat(retryAtOne.toString()).isEqualTo("Retry at ONE on same host."); RetryDecision tryNextAtOne = RetryDecision.tryNextHost(ONE); assertThat(tryNextAtOne.getType()).isEqualTo(RETRY); assertThat(tryNextAtOne.getRetryConsistencyLevel()).isEqualTo(ONE); assertThat(tryNextAtOne.isRetryCurrent()).isFalse(); assertThat(tryNextAtOne.toString()).isEqualTo("Retry at ONE on next host."); RetryDecision rethrow = RetryDecision.rethrow(); assertThat(rethrow.getType()).isEqualTo(RETHROW); assertThat(rethrow.toString()).isEqualTo("Rethrow"); RetryDecision ignore = RetryDecision.ignore(); assertThat(ignore.getType()).isEqualTo(IGNORE); assertThat(ignore.toString()).isEqualTo("Ignore"); } }
@Test(groups = "short") public void retriesTest() { retryDecision = RetryDecision.retry(ConsistencyLevel.ONE); // We only have one node, this will throw an unavailable exception Statement statement = new SimpleStatement("SELECT v FROM test WHERE k = 1") .setConsistencyLevel(ConsistencyLevel.TWO); session().execute(statement); Errors errors = cluster().getMetrics().getErrorMetrics(); assertEquals(errors.getUnavailables().getCount(), 1); assertEquals(errors.getRetries().getCount(), 1); assertEquals(errors.getRetriesOnUnavailable().getCount(), 1); retryDecision = RetryDecision.ignore(); session().execute(statement); assertEquals(errors.getUnavailables().getCount(), 2); assertEquals(errors.getIgnores().getCount(), 1); assertEquals(errors.getIgnoresOnUnavailable().getCount(), 1); }
@Override public RetryDecision onUnavailable(Statement statement, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) { return RetryDecision.retry(ConsistencyLevel.ONE); }
@Override public RetryDecision onReadTimeout(Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) { return RetryDecision.retry(ConsistencyLevel.ONE); }
@Override public RetryDecision onReadTimeout( Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) { if (nbRetry != 0) return RetryDecision.rethrow(); return RetryDecision.retry(ConsistencyLevel.ONE); }
@Override public RetryDecision onWriteTimeout( Statement statement, ConsistencyLevel cl, WriteType writeType, int requiredAcks, int receivedAcks, int nbRetry) { return RetryDecision.retry(ConsistencyLevel.ONE); }
@Override public RetryDecision onReadTimeout( Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) { return RetryDecision.retry(ConsistencyLevel.ONE); }
@Override public RetryDecision onWriteTimeout(Statement statement, ConsistencyLevel cl, WriteType writeType, int requiredAcks, int receivedAcks, int nbRetry) { return RetryDecision.retry(cl); }
@Override public RetryDecision onRequestError(Statement statement, ConsistencyLevel cl, DriverException e, int nbRetry) { return RetryDecision.retry(cl); }
@Override public RetryDecision onReadTimeout(Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) { return RetryDecision.retry(cl); }
private RetryDecision maxLikelyToWorkCL(int knownOk) { if (knownOk >= 3) return RetryDecision.retry(ConsistencyLevel.THREE); else if (knownOk >= 2) return RetryDecision.retry(ConsistencyLevel.TWO); else if (knownOk >= 1) return RetryDecision.retry(ConsistencyLevel.ONE); else return RetryDecision.rethrow(); }
@Override public RetryDecision onUnavailable( Statement statement, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) { return (nbRetry == 0) ? RetryDecision.retry(cl) : RetryDecision.rethrow(); }
return RetryDecision.retry(cl);
return !dataRetrieved ? RetryDecision.retry(cl) : RetryDecision.rethrow();
/** * {@inheritDoc} * * <p>This implementation triggers a maximum of one retry, and only in the case of a {@code * WriteType.BATCH_LOG} write. The reasoning for the retry in that case is that write to the * distributed batch log is tried by the coordinator of the write against a small subset of all * the nodes alive in the local datacenter. Hence, a timeout usually means that none of the nodes * in that subset were alive but the coordinator hasn't detected them as dead. By the time we get * the timeout the dead nodes will likely have been detected as dead and the retry has thus a high * chance of success. * * @return {@code RetryDecision.retry(cl)} if no retry attempt has yet been tried and {@code * writeType == WriteType.BATCH_LOG}, {@code RetryDecision.rethrow()} otherwise. */ @Override public RetryDecision onWriteTimeout( Statement statement, ConsistencyLevel cl, WriteType writeType, int requiredAcks, int receivedAcks, int nbRetry) { if (nbRetry != 0) return RetryDecision.rethrow(); // If the batch log write failed, retry the operation as this might just be we were unlucky at // picking candidates // JAVA-764: testing the write type automatically filters out serial consistency levels as these // have always WriteType.CAS. return writeType == WriteType.BATCH_LOG ? RetryDecision.retry(cl) : RetryDecision.rethrow(); }
/** * {@inheritDoc} * * <p>This implementation triggers a maximum of one retry, and only if enough replicas had * responded to the read request but data was not retrieved amongst those. Indeed, that case * usually means that enough replica are alive to satisfy the consistency but the coordinator * picked a dead one for data retrieval, not having detected that replica as dead yet. The * reasoning for retrying then is that by the time we get the timeout the dead replica will likely * have been detected as dead and the retry has a high chance of success. * * @return {@code RetryDecision.retry(cl)} if no retry attempt has yet been tried and {@code * receivedResponses >= requiredResponses && !dataRetrieved}, {@code RetryDecision.rethrow()} * otherwise. */ @Override public RetryDecision onReadTimeout( Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) { if (nbRetry != 0) return RetryDecision.rethrow(); return receivedResponses >= requiredResponses && !dataRetrieved ? RetryDecision.retry(cl) : RetryDecision.rethrow(); }
private RetryDecision maxLikelyToWorkCL(int knownOk, ConsistencyLevel currentCL) { if (knownOk >= 3) return RetryDecision.retry(ConsistencyLevel.THREE); if (knownOk == 2) return RetryDecision.retry(ConsistencyLevel.TWO); // JAVA-1005: EACH_QUORUM does not report a global number of alive replicas // so even if we get 0 alive replicas, there might be // a node up in some other datacenter if (knownOk == 1 || currentCL == ConsistencyLevel.EACH_QUORUM) return RetryDecision.retry(ConsistencyLevel.ONE); return RetryDecision.rethrow(); }
@Override public RetryDecision onReadTimeout( Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) { if (nbRetry != 0) return RetryDecision.rethrow(); return RetryDecision.retry(ConsistencyLevel.ONE); }
@Override public RetryDecision onUnavailable( Statement statement, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) { return (nbRetry == 0) ? RetryDecision.retry(cl) : RetryDecision.rethrow(); }