/* * Copyright 2014-2017 Real Logic Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.aeron.driver; /** * Feedback delay used for NAKs as well as for some retransmission use cases. * * Generates delay based on Optimal Multicast Feedback * http://tools.ietf.org/html/rfc5401#page-13 * * {@code * maxBackoffT is max interval for delay * * C version: * * <code> * double RandomBackoff(double maxBackoffT, double groupSize) * { * double lambda = log(groupSize) + 1; * double x = UniformRand(lambda / maxBackoffT) + lambda / (maxBackoffT * (exp(lambda) - 1)); * return ((maxBackoffT / lambda) * log( x * (exp(lambda) - 1) * (maxBackoffT / lambda))); * } * </code> * * where UniformRand(x) is uniform distribution from 0..max * * In this implementations calculation: * - the groupSize is a constant (could be configurable as system property) * - maxBackoffT is a constant (could be configurable as system property) * - GRTT is a constant (could be configurable as a system property) * * N (the expected number of feedback messages per RTT) is * N = exp(1.2 * L / (2 * maxBackoffT/GRTT)) * * Assumptions: * maxBackoffT = K * GRTT (K >= 1) * * Recommended K: * - K = 4 for situations where responses come from multiple places (i.e. for NAKs, multiple retransmitters) * - K = 6 for situations where responses come from single places (i.e. for NAKs, source only retransmit) * } */ public class OptimalMulticastDelayGenerator implements FeedbackDelayGenerator { private final double calculatedN; private final double randMax; private final double baseX; private final double constantT; private final double factorT; /** * Create new feedback delay generator based on estimates. Pre-calculating some parameters upfront. * * {@code maxBackoffT} and {@code gRtt} must be expressed in the same units. * * @param maxBackoffT of the delay interval * @param groupSize estimate * @param gRtt estimate */ public OptimalMulticastDelayGenerator(final double maxBackoffT, final double groupSize, final double gRtt) { final double lambda = Math.log(groupSize) + 1; this.calculatedN = Math.exp(1.2 * lambda / (2 * maxBackoffT / gRtt)); // constant pieces of the calculation this.randMax = lambda / maxBackoffT; this.baseX = lambda / (maxBackoffT * (Math.exp(lambda) - 1)); this.constantT = maxBackoffT / lambda; this.factorT = (Math.exp(lambda) - 1) * (maxBackoffT / lambda); } /** * {@inheritDoc} */ public long generateDelay() { return (long)generateNewOptimalDelay(); } /** * Generate a new randomized delay value in the units of backoff and {@code gRtt}. * * @return delay in units of backoff and RTT */ public double generateNewOptimalDelay() { final double x = uniformRandom(randMax) + baseX; return constantT * Math.log(x * factorT); } /** * Return the estimated number of feedback messages per RTT. * * @return number of estimated feedback messages in units of backoff and RTT */ public double calculatedN() { return calculatedN; } /** * Return uniform random value in the range 0..max * * @param max of the random range * @return random value */ public static double uniformRandom(final double max) { return Math.random() * max; } }