commandDescriptionSupplier;
- @Nullable
- private Boolean writeRetryRequirementsMet;
- @Nullable
- private Integer maxWireVersion;
/**
- * @param descriptors A set of descriptors of the applicable specification retry policies.
- * @param effectiveRetrySetting See {@link MongoClientSettings#getRetryWrites()}, {@link MongoClientSettings#getRetryReads()}.
- * Note that for some commands, like {@code commitTransaction}/{@code abortTransaction},
- * retries are deemed to be enabled regardless of the settings; this argument must be {@code true} for them.
- * @param retryRequirementsMaybeMet {@code false} iff the retry requirements are known not to be met.
- * For example, if {@code effectiveRetrySetting} is {@code false}, then {@code retryRequirementsMaybeMet} must be {@code false}.
- *
- * For {@link Descriptor#READ}, this parameter specifies whether the read retry requirements are met;
- * for {@link Descriptor#WRITE}, see {@link #onWriteRetryRequirements(boolean, ConnectionDescription)}.
+ * @param descriptors Descriptors of the included specification retry policies.
*/
SpecRetryPolicy(
- final Set descriptors,
- final boolean effectiveRetrySetting,
- final boolean retryRequirementsMaybeMet,
+ final DescriptorSet descriptors,
final ExplicitMaxRetries explicitMaxRetries,
final ServerDeprioritization serverDeprioritization) {
- this.descriptors = assertNoConflicts(descriptors);
- assertTrue(effectiveRetrySetting || !retryRequirementsMaybeMet);
- this.effectiveRetrySetting = effectiveRetrySetting;
- this.retryRequirementsMaybeMet = retryRequirementsMaybeMet;
- if (!retryRequirementsMaybeMet) {
- assertTrue(explicitMaxRetries == NO_RETRIES);
- }
- this.explicitMaxRetries = explicitMaxRetries;
+ this.descriptors = descriptors.assertValid();
this.maxAttempts = explicitMaxRetries.maxAttempts(descriptors);
this.serverDeprioritization = serverDeprioritization;
commandDescriptionSupplier = () -> null;
- writeRetryRequirementsMet = null;
- maxWireVersion = null;
}
void onAttemptStart(final RetryContext retryContext, final OperationContext operationContext) {
@@ -130,9 +106,8 @@ SpecRetryPolicy onCommand(final Supplier commandDescriptionSupplier) {
/**
* The information gathered via this method is reset after each invocation of {@link #onAttemptFailure(RetryContext, Throwable)}.
*
- * @param remainingWriteRequirementsMet This argument, combined with
- * {@link SpecRetryPolicy#SpecRetryPolicy(Set, boolean, boolean, ExplicitMaxRetries, ServerDeprioritization) retryRequirementsMaybeMet},
- * specifies whether the write retry requirements are met.
+ * @param remainingWriteRequirementsMet This argument, combined with the information passed to
+ * {@link DescriptorSet#DescriptorSet(boolean)} and {@link DescriptorSet#includeWrite()}, specifies whether the write retry requirements are met.
*
* Specifying {@code false}, or not calling this method at all, does not completely prevent retrying,
* but affects logging and which failed results may be eligible for retry.
@@ -140,68 +115,68 @@ SpecRetryPolicy onCommand(final Supplier commandDescriptionSupplier) {
* @return {@code this}.
*/
SpecRetryPolicy onWriteRetryRequirements(final boolean remainingWriteRequirementsMet, final ConnectionDescription connectionDescription) {
- assertNull(writeRetryRequirementsMet);
- assertTrue(descriptors.contains(WRITE));
- writeRetryRequirementsMet = retryRequirementsMaybeMet && remainingWriteRequirementsMet;
- maxWireVersion = connectionDescription.getMaxWireVersion();
- return this;
- }
-
- private void resetWriteRetryRequirementsInfo() {
- maxWireVersion = null;
- writeRetryRequirementsMet = null;
+ return descriptors.write().map(state -> {
+ state.onRequirements(remainingWriteRequirementsMet, connectionDescription);
+ return this;
+ }).orElseThrow(() -> fail());
}
@Override
- public Decision onAttemptFailure(final RetryContext retryContext, final Throwable attemptFailedResult) {
+ public Decision onAttemptFailure(final RetryContext retryContext, final Throwable maybeInternalAttemptFailedResult) {
+ Throwable attemptFailedResult = stripResourceSupplierInternalException(maybeInternalAttemptFailedResult);
serverDeprioritization.onAttemptFailure(attemptFailedResult);
int attempt = retryContext.attempt();
assertTrue(attempt < INFINITE_ATTEMPTS);
assertTrue(attempt < maxAttempts);
- boolean retryableError;
- if (descriptors.contains(WRITE)) {
- retryableError = decideRetryableAndAddRetryableWriteErrorLabelIfNeeded(attemptFailedResult);
- } else if (descriptors.contains(READ)) {
- retryableError = isRetryableReadError(attemptFailedResult);
- } else {
- throw fail(descriptors.toString());
- }
- boolean maxAttemptsReached = attempt == maxAttempts - 1;
- if (retryRequirementsMaybeMet) {
- if (retryableError && maxAttemptsReached) {
- logUnableToRetryMaxAttemptsReached();
- } else if (!retryableError) {
- logUnableToRetryError(attemptFailedResult);
- }
+ boolean retryableError = false;
+ retryableError |= descriptors.write().map(state ->
+ decideRetryableAndAddRetryableWriteErrorLabelIfNeeded(state, attemptFailedResult)).orElse(false);
+ retryableError |= descriptors.read().map(state ->
+ decideRetryable(state, attemptFailedResult)).orElse(false);
+ retryableError |= descriptors.overload().map(state ->
+ decideRetryableAndUpdateMaxAttempts(state, attemptFailedResult)).orElse(false);
+ boolean maxAttemptsReached = attempt >= maxAttempts - 1;
+ if (descriptors.isRetrySettingEffectivelyEnabled() && !retryableError) {
+ logUnableToRetryError(attemptFailedResult);
}
boolean retry = retryableError && !maxAttemptsReached;
Decision decision = new Decision(
- decideProspectiveFailedResult(retryContext.getProspectiveFailedResult().orElse(null), attemptFailedResult),
- retry ? new RetryAttemptInfo(Duration.ZERO) : null);
- resetWriteRetryRequirementsInfo();
+ decideProspectiveFailedResult(retryContext.getProspectiveFailedResult().orElse(null), maybeInternalAttemptFailedResult),
+ retry ? new RetryAttemptInfo(calculateOverloadBackoff(attemptFailedResult, attempt + 1)) : null);
+ descriptors.write().ifPresent(DescriptorSet.State.Write::resetRequirementsInfo);
return decision;
}
+ private static Throwable stripResourceSupplierInternalException(final Throwable maybeInternal) {
+ Throwable external;
+ if (maybeInternal instanceof OperationHelper.ResourceSupplierInternalException) {
+ external = maybeInternal.getCause();
+ } else {
+ external = maybeInternal;
+ }
+ return external;
+ }
+
/**
- * Returns {@code true} iff another attempt must be executed;
+ * Returns {@code true} iff another attempt must be executed provided that {@link #maxAttempts} has not been reached;
* in this case, also adds the {@value CommandOperationHelper#RETRYABLE_WRITE_ERROR_LABEL} label if needed.
*/
- private boolean decideRetryableAndAddRetryableWriteErrorLabelIfNeeded(final Throwable maybeInternalException) {
- Throwable exception = stripResourceSupplierInternalException(maybeInternalException);
+ private boolean decideRetryableAndAddRetryableWriteErrorLabelIfNeeded(final DescriptorSet.State.Write state, final Throwable exception) {
+ assertFalse(exception instanceof OperationHelper.ResourceSupplierInternalException);
if (!(exception instanceof MongoException)) {
return false;
}
MongoException mongoException = (MongoException) exception;
boolean connectionPoolClearedException = mongoException instanceof MongoConnectionPoolClearedException;
- if (connectionPoolClearedException && effectiveRetrySetting) {
+ if (connectionPoolClearedException && descriptors.isRetrySettingEffectivelyEnabled()) {
// We would have retried regardless of the settings,
// but we add `RETRYABLE_WRITE_ERROR_LABEL` only if retries are enabled via settings.
mongoException.addLabel(RETRYABLE_WRITE_ERROR_LABEL);
}
boolean retryRegardlessOfRequirementsHavingBeenMet = connectionPoolClearedException || isRetryableMongoSecurityException(mongoException);
boolean retry;
- if (TRUE.equals(writeRetryRequirementsMet)) {
- addRetryableWriteErrorLabelIfNeeded(mongoException, assertNotNull(maxWireVersion));
+ if (state.isRequirementsMet()) {
+ addRetryableWriteErrorLabelIfNeeded(mongoException, state.getMaxWireVersion());
retry = mongoException.hasErrorLabel(RETRYABLE_WRITE_ERROR_LABEL);
} else {
retry = retryRegardlessOfRequirementsHavingBeenMet;
@@ -209,43 +184,46 @@ private boolean decideRetryableAndAddRetryableWriteErrorLabelIfNeeded(final Thro
return retry;
}
- private static Throwable stripResourceSupplierInternalException(final Throwable maybeInternal) {
- Throwable external;
- if (maybeInternal instanceof OperationHelper.ResourceSupplierInternalException) {
- external = maybeInternal.getCause();
- } else {
- external = maybeInternal;
- }
- return external;
- }
-
private static boolean isRetryableMongoSecurityException(final MongoException exception) {
return exception instanceof MongoSecurityException
&& exception.getCause() != null && isRetryableException(exception.getCause());
}
- private static boolean isRetryableReadError(final Throwable exception) {
+ /**
+ * Returns {@code true} iff another attempt must be executed provided that {@link #maxAttempts} has not been reached.
+ */
+ private static boolean decideRetryable(final DescriptorSet.State.Read state, final Throwable exception) {
assertFalse(exception instanceof OperationHelper.ResourceSupplierInternalException);
- if (!(exception instanceof MongoException)) {
+ if (!state.isRequirementsMet() || !(exception instanceof MongoException)) {
return false;
}
MongoException mongoException = (MongoException) exception;
return isRetryableMongoSecurityException(mongoException) || isRetryableException(mongoException);
}
- private void logUnableToRetryMaxAttemptsReached() {
- if (LOGGER.isDebugEnabled()) {
- String commandDescription = commandDescriptionSupplier.get();
- int maxRetries = ExplicitMaxRetries.maxRetries(maxAttempts);
- LOGGER.debug(commandDescription == null
- ? format("Unable to retry a command due to reaching the max retry attempts limit of %d", maxRetries)
- : format("Unable to retry the command '%s' due to reaching the max retry attempts limit of %d", commandDescription, maxRetries));
+ /**
+ * Returns {@code true} iff another attempt must be executed provided that {@link #maxAttempts} has not been reached.
+ */
+ private boolean decideRetryableAndUpdateMaxAttempts(final DescriptorSet.State.Overload state, final Throwable exception) {
+ boolean hasRetryableErrorLabel;
+ boolean hasSystemOverloadErrorLabel;
+ if (exception instanceof MongoException) {
+ MongoException mongoException = (MongoException) exception;
+ hasRetryableErrorLabel = mongoException.hasErrorLabel(RETRYABLE_ERROR_LABEL);
+ hasSystemOverloadErrorLabel = mongoException.hasErrorLabel(SYSTEM_OVERLOADED_ERROR_LABEL);
+ } else {
+ hasRetryableErrorLabel = false;
+ hasSystemOverloadErrorLabel = false;
}
+ if (hasSystemOverloadErrorLabel && descriptors.isRetrySettingEffectivelyEnabled()) {
+ maxAttempts = state.getMaxAttempts();
+ }
+ return state.isRequirementsMet() && hasRetryableErrorLabel && hasSystemOverloadErrorLabel;
}
- private void logUnableToRetryError(final Throwable maybeInternalException) {
+ private void logUnableToRetryError(final Throwable exception) {
+ assertFalse(exception instanceof OperationHelper.ResourceSupplierInternalException);
if (LOGGER.isDebugEnabled()) {
- Throwable exception = stripResourceSupplierInternalException(maybeInternalException);
String commandDescription = commandDescriptionSupplier.get();
LOGGER.debug(commandDescription == null
? format("Unable to retry a command due to the error \"%s\"", exception)
@@ -256,12 +234,12 @@ private void logUnableToRetryError(final Throwable maybeInternalException) {
private Throwable decideProspectiveFailedResult(
@Nullable final Throwable currentProspectiveFailedResult, final Throwable mostRecentAttemptFailedResult) {
Throwable newProspectiveFailedResult;
- if (descriptors.contains(WRITE)) {
+ if (descriptors.write().isPresent()) {
newProspectiveFailedResult = decideWriteProspectiveFailedResult(currentProspectiveFailedResult, mostRecentAttemptFailedResult);
- } else if (descriptors.contains(READ)) {
+ } else if (descriptors.read().isPresent()) {
newProspectiveFailedResult = decideReadProspectiveFailedResult(currentProspectiveFailedResult, mostRecentAttemptFailedResult);
} else {
- throw fail(descriptors.toString());
+ throw fail(toString());
}
if (mostRecentAttemptFailedResult instanceof MongoOperationTimeoutException) {
newProspectiveFailedResult = createMongoTimeoutException(newProspectiveFailedResult);
@@ -270,15 +248,15 @@ private Throwable decideProspectiveFailedResult(
}
private static Throwable decideWriteProspectiveFailedResult(
- @Nullable final Throwable currentProspectiveFailedResult, final Throwable mostRecentAttemptFailedResult) {
+ @Nullable final Throwable currentProspectiveFailedResult, final Throwable maybeInternalMostRecentAttemptFailedResult) {
if (currentProspectiveFailedResult == null) {
- return stripResourceSupplierInternalException(mostRecentAttemptFailedResult);
- } else if (mostRecentAttemptFailedResult instanceof OperationHelper.ResourceSupplierInternalException
- || (mostRecentAttemptFailedResult instanceof MongoException
- && ((MongoException) mostRecentAttemptFailedResult).hasErrorLabel(NO_WRITES_PERFORMED_ERROR_LABEL))) {
+ return stripResourceSupplierInternalException(maybeInternalMostRecentAttemptFailedResult);
+ } else if (maybeInternalMostRecentAttemptFailedResult instanceof OperationHelper.ResourceSupplierInternalException
+ || (maybeInternalMostRecentAttemptFailedResult instanceof MongoException
+ && ((MongoException) maybeInternalMostRecentAttemptFailedResult).hasErrorLabel(NO_WRITES_PERFORMED_ERROR_LABEL))) {
return currentProspectiveFailedResult;
} else {
- return mostRecentAttemptFailedResult;
+ return maybeInternalMostRecentAttemptFailedResult;
}
}
@@ -294,90 +272,298 @@ private static Throwable decideReadProspectiveFailedResult(
}
}
+ private static Duration calculateOverloadBackoff(final Throwable attemptFailedResult, final int immediateNextAttempt) {
+ assertFalse(attemptFailedResult instanceof OperationHelper.ResourceSupplierInternalException);
+ if (attemptFailedResult instanceof MongoException
+ && ((MongoException) attemptFailedResult).hasErrorLabel(SYSTEM_OVERLOADED_ERROR_LABEL)) {
+ return ExponentialBackoff.calculateOverloadBackoff(immediateNextAttempt);
+ }
+ return Duration.ZERO;
+ }
+
+ private static int maxAttempts(final int maxRetries) {
+ assertTrue(maxRetries < INFINITE_ATTEMPTS - 1);
+ return maxRetries + 1;
+ }
+
@Override
public String toString() {
return "SpecRetryPolicy{"
+ "descriptors=" + descriptors
- + ", effectiveRetrySetting=" + effectiveRetrySetting
- + ", retryRequirementsMaybeMet=" + retryRequirementsMaybeMet
- + ", explicitMaxRetries=" + explicitMaxRetries
+ ", maxAttempts=" + maxAttempts
+ ", serverDeprioritization=" + serverDeprioritization
+ ", commandDescription=" + commandDescriptionSupplier.get()
- + ", writeRetryRequirementsMet=" + writeRetryRequirementsMet
- + ", maxWireVersion=" + maxWireVersion
+ '}';
}
- enum Descriptor {
- /**
- * See Retryable Writes.
- */
- WRITE,
- /**
- * See Retryable Reads.
- */
- READ;
-
+ static final class DescriptorSet {
private static final EnumMap> CONFLICTS;
+ private final boolean effectiveRetrySetting;
+ private final EnumMap descriptors;
+
static {
CONFLICTS = new EnumMap<>(Descriptor.class);
- CONFLICTS.put(WRITE, EnumSet.of(READ));
- CONFLICTS.put(READ, EnumSet.of(WRITE));
+ CONFLICTS.put(Descriptor.WRITE, EnumSet.of(Descriptor.READ));
+ CONFLICTS.put(Descriptor.READ, EnumSet.of(Descriptor.WRITE));
+ }
+
+ /**
+ * @param effectiveRetrySetting See {@link MongoClientSettings#getRetryWrites()}, {@link MongoClientSettings#getRetryReads()}.
+ * Note that for some commands, like {@code commitTransaction}/{@code abortTransaction},
+ * retries are deemed to be enabled regardless of the settings; this argument must be {@code true} for them.
+ */
+ DescriptorSet(final boolean effectiveRetrySetting) {
+ this.effectiveRetrySetting = effectiveRetrySetting;
+ this.descriptors = new EnumMap<>(Descriptor.class);
+ }
+
+ private DescriptorSet assertValid() {
+ assertFalse(descriptors.isEmpty());
+ assertNoConflicts(descriptors.keySet());
+ return this;
}
- static Set assertNoConflicts(final Set descriptors) {
+ private static void assertNoConflicts(final Set descriptors) {
for (Descriptor descriptor : descriptors) {
- for (Descriptor conflictingDescriptor : CONFLICTS.get(descriptor)) {
- assertFalse(descriptors.contains(conflictingDescriptor));
+ Set conflictingDescriptors = CONFLICTS.get(descriptor);
+ if (conflictingDescriptors != null) {
+ for (Descriptor conflictingDescriptor : conflictingDescriptors) {
+ assertFalse(descriptors.contains(conflictingDescriptor));
+ }
+ }
+ }
+ }
+
+ private boolean isRetrySettingEffectivelyEnabled() {
+ return effectiveRetrySetting;
+ }
+
+ DescriptorSet includeWrite() {
+ include(Descriptor.WRITE, new State.Write(effectiveRetrySetting));
+ return this;
+ }
+
+ DescriptorSet includeRead(final OperationContext operationContext) {
+ include(Descriptor.READ, new State.Read(effectiveRetrySetting, operationContext));
+ return this;
+ }
+
+ DescriptorSet includeOverload(@Nullable final Integer maxAdaptiveRetriesSetting) {
+ include(Descriptor.OVERLOAD, new State.Overload(effectiveRetrySetting, maxAdaptiveRetriesSetting));
+ return this;
+ }
+
+ private void include(final Descriptor descriptor, final State state) {
+ State previous = descriptors.put(descriptor, state);
+ assertNull(previous);
+ }
+
+ private int getInitialMaxAttempts() {
+ int maxRetries;
+ if (descriptors.containsKey(Descriptor.WRITE)) {
+ maxRetries = Descriptor.WRITE.maxRetries;
+ } else if (descriptors.containsKey(Descriptor.READ)) {
+ maxRetries = Descriptor.READ.maxRetries;
+ } else if (descriptors.containsKey(Descriptor.OVERLOAD)) {
+ maxRetries = overload().map(state -> state.getMaxAttempts()).orElse(Descriptor.OVERLOAD.maxRetries);
+ } else {
+ throw fail(toString());
+ }
+ return maxAttempts(maxRetries);
+ }
+
+ private Optional write() {
+ return Optional.ofNullable((State.Write) descriptors.get(Descriptor.WRITE));
+ }
+
+ private Optional read() {
+ return Optional.ofNullable((State.Read) descriptors.get(Descriptor.READ));
+ }
+
+ private Optional overload() {
+ return Optional.ofNullable((State.Overload) descriptors.get(Descriptor.OVERLOAD));
+ }
+
+ @Override
+ public String toString() {
+ return "DescriptorSet{"
+ + "effectiveRetrySetting=" + effectiveRetrySetting
+ + ", descriptors=" + descriptors
+ + '}';
+ }
+
+ private enum Descriptor {
+ /**
+ * See
+ * Retryable Writes,
+ * which specifies the write retry policy.
+ */
+ WRITE(1),
+ /**
+ * See
+ * Retryable Reads,
+ * which specifies the read retry policy.
+ */
+ READ(1),
+ /**
+ * See
+ * Client Backpressure,
+ * which specifies the overload retry policy.
+ */
+ OVERLOAD(DEFAULT_MAX_ADAPTIVE_RETRIES);
+
+ private final int maxRetries;
+
+ Descriptor(final int maxRetries) {
+ this.maxRetries = maxRetries;
+ }
+ }
+
+ private abstract static class State {
+ private State() {
+ }
+
+ static final class Write extends State {
+ private final boolean requirementsMaybeMet;
+ @Nullable
+ private Boolean requirementsMet;
+ @Nullable
+ private Integer maxWireVersion;
+
+ Write(final boolean effectiveRetryWritesSetting) {
+ this.requirementsMaybeMet = effectiveRetryWritesSetting;
+ }
+
+ /**
+ * @see #isRequirementsMet()
+ * @see #resetRequirementsInfo()
+ * @see SpecRetryPolicy#onWriteRetryRequirements(boolean, ConnectionDescription)
+ */
+ void onRequirements(
+ final boolean remainingRequirementsMet,
+ final ConnectionDescription connectionDescription) {
+ assertNull(requirementsMet);
+ requirementsMet = requirementsMaybeMet && remainingRequirementsMet;
+ maxWireVersion = connectionDescription.getMaxWireVersion();
+ }
+
+ /**
+ * @see #onRequirements(boolean, ConnectionDescription)
+ * @see SpecRetryPolicy#onWriteRetryRequirements(boolean, ConnectionDescription)
+ */
+ void resetRequirementsInfo() {
+ maxWireVersion = null;
+ requirementsMet = null;
+ }
+
+ /**
+ * The requirements in question include settings requirements, server requirements, command requirements, etc.,
+ * but exclude error requirements (including operation timeout requirements), {@link #maxAttempts} requirements.
+ *
+ * @see #onRequirements(boolean, ConnectionDescription)
+ */
+ boolean isRequirementsMet() {
+ return TRUE.equals(requirementsMet);
+ }
+
+ /**
+ * May be called only if {@link #isRequirementsMet()}.
+ */
+ int getMaxWireVersion() {
+ return assertNotNull(maxWireVersion);
+ }
+
+ @Override
+ public String toString() {
+ return "Write{"
+ + "requirementsMaybeMet=" + requirementsMaybeMet
+ + ", requirementsMet=" + requirementsMet
+ + ", maxWireVersion=" + maxWireVersion
+ + '}';
+ }
+ }
+
+ static final class Read extends State {
+ private final boolean requirementsMet;
+
+ Read(final boolean effectiveRetryReadsSetting, final OperationContext operationContext) {
+ requirementsMet = isReadRetryRequirementsMet(effectiveRetryReadsSetting, operationContext);
+ }
+
+ /**
+ * The requirements in question include settings requirements, server requirements, command requirements, etc.,
+ * but exclude error requirements (including operation timeout requirements), {@link #maxAttempts} requirements.
+ */
+ boolean isRequirementsMet() {
+ return requirementsMet;
+ }
+
+ @Override
+ public String toString() {
+ return "Read{"
+ + "requirementsMet=" + requirementsMet
+ + '}';
+ }
+ }
+
+ static final class Overload extends State {
+ private final boolean requirementsMet;
+ @Nullable
+ private final Integer maxAdaptiveRetriesSetting;
+
+ Overload(
+ final boolean effectiveRetrySetting,
+ @Nullable
+ final Integer maxAdaptiveRetriesSetting) {
+ requirementsMet = effectiveRetrySetting;
+ this.maxAdaptiveRetriesSetting = maxAdaptiveRetriesSetting;
+ }
+
+ /**
+ * The requirements in question include settings requirements, server requirements, command requirements, etc.,
+ * but exclude error requirements (including operation timeout requirements), {@link #maxAttempts} requirements.
+ */
+ boolean isRequirementsMet() {
+ return requirementsMet;
+ }
+
+ int getMaxAttempts() {
+ return maxAttempts(maxAdaptiveRetriesSetting == null
+ ? DescriptorSet.Descriptor.OVERLOAD.maxRetries
+ : maxAdaptiveRetriesSetting);
+ }
+
+ @Override
+ public String toString() {
+ return "OverloadState{"
+ + "requirementsMet=" + requirementsMet
+ + ", maxAdaptiveRetriesSetting=" + maxAdaptiveRetriesSetting
+ + '}';
}
}
- return descriptors;
}
}
enum ExplicitMaxRetries {
NO_RETRIES_LIMIT,
/**
- * See {@link Descriptor}.
+ * See {@link DescriptorSet}.
*/
- RETRIES_LIMITED_BY_DESCRIPTORS,
- NO_RETRIES;
+ RETRIES_LIMITED_BY_DESCRIPTORS;
- private int maxAttempts(final Set descriptors) {
+ private int maxAttempts(final DescriptorSet descriptors) {
switch (this) {
case NO_RETRIES_LIMIT: {
return INFINITE_ATTEMPTS;
}
case RETRIES_LIMITED_BY_DESCRIPTORS: {
- return maxAttempts(maxRetries(descriptors));
- }
- case NO_RETRIES: {
- return maxAttempts(0);
+ return descriptors.getInitialMaxAttempts();
}
default: {
throw fail(this.toString());
}
}
}
-
- private static int maxRetries(final Set descriptors) {
- if (descriptors.contains(WRITE) || descriptors.contains(READ)) {
- return 1;
- } else {
- throw fail(descriptors.toString());
- }
- }
-
- private static int maxAttempts(final int maxRetries) {
- assertTrue(maxRetries < INFINITE_ATTEMPTS - 1);
- return maxRetries + 1;
- }
-
- static int maxRetries(final int maxAttempts) {
- assertTrue(maxAttempts > 0);
- return maxAttempts - 1;
- }
}
}
diff --git a/driver-core/src/main/com/mongodb/internal/operation/SyncOperationHelper.java b/driver-core/src/main/com/mongodb/internal/operation/SyncOperationHelper.java
index f41c286628e..0400092b4d4 100644
--- a/driver-core/src/main/com/mongodb/internal/operation/SyncOperationHelper.java
+++ b/driver-core/src/main/com/mongodb/internal/operation/SyncOperationHelper.java
@@ -31,6 +31,7 @@
import com.mongodb.internal.binding.WriteBinding;
import com.mongodb.internal.connection.Connection;
import com.mongodb.internal.connection.OperationContext;
+import com.mongodb.internal.operation.SpecRetryPolicy.DescriptorSet;
import com.mongodb.internal.session.SessionContext;
import com.mongodb.internal.validator.NoOpFieldNameValidator;
import com.mongodb.lang.Nullable;
@@ -40,7 +41,6 @@
import org.bson.codecs.BsonDocumentCodec;
import org.bson.codecs.Decoder;
-import java.util.EnumSet;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -54,10 +54,7 @@
import static com.mongodb.internal.operation.CommandOperationHelper.isWriteRetryRequirementsMet;
import static com.mongodb.internal.operation.CommandOperationHelper.transformWriteException;
import static com.mongodb.internal.operation.OperationHelper.ResourceSupplierInternalException;
-import static com.mongodb.internal.operation.OperationHelper.isReadRetryRequirementsMet;
import static com.mongodb.internal.operation.OperationHelper.isServerWriteRetryRequirementsMet;
-import static com.mongodb.internal.operation.SpecRetryPolicy.Descriptor.READ;
-import static com.mongodb.internal.operation.SpecRetryPolicy.Descriptor.WRITE;
import static com.mongodb.internal.operation.WriteConcernHelper.throwOnWriteConcernError;
final class SyncOperationHelper {
@@ -191,9 +188,10 @@ static T executeRetryableRead(
final CommandCreator commandCreator,
final Decoder decoder,
final CommandReadTransformer transformer,
- final boolean retryReadsSetting) {
+ final boolean retryReadsSetting,
+ @Nullable final Integer maxAdaptiveRetriesSetting) {
return executeRetryableRead(operationContext, binding::getReadConnectionSource, database, commandCreator,
- decoder, transformer, retryReadsSetting);
+ decoder, transformer, retryReadsSetting, maxAdaptiveRetriesSetting);
}
static