All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bazaarvoice.emodb.common.dropwizard.guava.MoreSuppliers Maven / Gradle / Ivy

There is a newer version: 6.5.190
Show newest version
package com.bazaarvoice.emodb.common.dropwizard.guava;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;

import java.security.SecureRandom;
import java.util.PrimitiveIterator;
import java.util.concurrent.TimeUnit;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;

/**
 * Extension of {@link Suppliers}.
 */
public final class MoreSuppliers {

    private MoreSuppliers() {
        // empty
    }

    /**
     * Memoization similar to {@link Suppliers#memoizeWithExpiration(Supplier, long, TimeUnit)} except the expiration
     * is randomly selected to be a value within provided bounds.  For example:
     *
     * 
     *     Supplier<Object&t; supplier = MoreSuppliers.memoizeWithRandomExpiration(delegate, 5, 10, TimeUnit.SECONDS);
     * 
     *
     * returns a Supplier that will memoize the delegate's response for a random number of nanoseconds between 5
     * (inclusive) to 10 (exclusive) seconds.
     *
     * This is useful when numerous memoized values are typically computed independently but used within the same operation.
     * If all values were computed and memoized together then each call that refreshes from delegate could take longer
     * than desirable.  Similarly, if each value were memomized independently using the same expiration then herding
     * behavior would result in the same long calls at expiration time.  A random expiration allows each value to be
     * cached but spread out the refresh cycle so that it is unlikely that any single call will refresh the entire value
     * set, so long as the call frequency is significantly below minDuration.
     */
    public static  Supplier memoizeWithRandomExpiration(Supplier delegate, long minDuration, long maxDuration, TimeUnit units) {
        if (minDuration == maxDuration) {
            // This case resolves to standard expiration
            return Suppliers.memoizeWithExpiration(delegate, minDuration, units);
        }
        return new RandomExpirationSupplier(delegate, minDuration, maxDuration, units);
    }

    /**
     * Class modeled off of {@link Suppliers.ExpiringMemoizingSupplier} except the expiration time is randomly
     * selected within the provided bounds for each iteration.
     */
    private final static class RandomExpirationSupplier implements Supplier {

        private final Supplier _delegate;
        private final PrimitiveIterator.OfLong _nanosDurations;
        private transient volatile T _value;
        private transient volatile long _expirationNanos = 0;

        RandomExpirationSupplier(Supplier delegate, long minDuration, long maxDuration, TimeUnit timeUnit) {
            checkArgument(minDuration >= 0, "minDuration cannot be negative");
            checkArgument(maxDuration > minDuration, "maxDuration must be greater than minDuration");
            requireNonNull(delegate, "delegate");
            requireNonNull(timeUnit, "timeUnit");

            long minDurationNanos = timeUnit.toNanos(minDuration);
            long maxDurationNanos = timeUnit.toNanos(maxDuration);

            _delegate = delegate;
            _nanosDurations = new SecureRandom().longs(minDurationNanos, maxDurationNanos).iterator();
        }

        @Override
        public T get() {
            long expirationNanos = _expirationNanos;
            long now = System.nanoTime();

            if (expirationNanos == 0 || now - expirationNanos >= 0) {
                synchronized(this) {
                    if (expirationNanos == _expirationNanos) {
                        _value = _delegate.get();
                        expirationNanos = now + _nanosDurations.nextLong();
                    }
                    _expirationNanos = expirationNanos == 0 ? 1 : expirationNanos;
                }
            }

            return _value;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy