// Path: core/src/main/java/com/bazaarvoice/ostrich/pool/ServiceCacheBuilder.java
// public static ScheduledExecutorService buildDefaultExecutor() {
//     return Executors.newScheduledThreadPool(1,
//             new ThreadFactoryBuilder().setNameFormat("ServiceCache-CleanupThread-%d").setDaemon(true).build());
// }


import com.bazaarvoice.ostrich.MultiThreadedServiceFactory;
import com.bazaarvoice.ostrich.ServiceEndPoint;
import com.bazaarvoice.ostrich.ServiceFactory;
import com.bazaarvoice.ostrich.metrics.Metrics;
import com.codahale.metrics.Counter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static com.bazaarvoice.ostrich.pool.ServiceCacheBuilder.buildDefaultExecutor;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
        }

        public boolean isOld() {
            return System.currentTimeMillis() > _sellByDate;
        }

        public boolean hasBeenFlaggedForEviction() {
            return _expireAfterDate != Long.MAX_VALUE;
        }

        public boolean timeToEvict() {
            return _expireAfterDate != Long.MAX_VALUE && System.currentTimeMillis() > _expireAfterDate;
        }

        public void flagAsEvicted() {
            if (_expireAfterDate == Long.MAX_VALUE) {
                // Not synchronized - evictionDelay is long enough that thread contention here shouldn't matter
                _expireAfterDate = System.currentTimeMillis() + _evictionDelayInMilliSeconds;
            }
        }
    }

    /**
     * Builds a {@code MultiThreadedClientServiceCache} with a default executor and cleanup delay.
     * Used by the builder.
     *
     * @param serviceFactory The service factory for creating service handles
     * @param metricRegistry The metric registry for reporting metrics
     */
    MultiThreadedClientServiceCache(MultiThreadedServiceFactory<S> serviceFactory, MetricRegistry metricRegistry) {
// Path: core/src/main/java/com/bazaarvoice/ostrich/pool/ServiceCacheBuilder.java
// public static ScheduledExecutorService buildDefaultExecutor() {
//     return Executors.newScheduledThreadPool(1,
//             new ThreadFactoryBuilder().setNameFormat("ServiceCache-CleanupThread-%d").setDaemon(true).build());
// }


// Path: core/src/main/java/com/bazaarvoice/ostrich/pool/MultiThreadedClientServiceCache.java
import com.bazaarvoice.ostrich.MultiThreadedServiceFactory;
import com.bazaarvoice.ostrich.ServiceEndPoint;
import com.bazaarvoice.ostrich.ServiceFactory;
import com.bazaarvoice.ostrich.metrics.Metrics;
import com.codahale.metrics.Counter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static com.bazaarvoice.ostrich.pool.ServiceCacheBuilder.buildDefaultExecutor;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;

        }

        public boolean isOld() {
            return System.currentTimeMillis() > _sellByDate;
        }

        public boolean hasBeenFlaggedForEviction() {
            return _expireAfterDate != Long.MAX_VALUE;
        }

        public boolean timeToEvict() {
            return _expireAfterDate != Long.MAX_VALUE && System.currentTimeMillis() > _expireAfterDate;
        }

        public void flagAsEvicted() {
            if (_expireAfterDate == Long.MAX_VALUE) {
                // Not synchronized - evictionDelay is long enough that thread contention here shouldn't matter
                _expireAfterDate = System.currentTimeMillis() + _evictionDelayInMilliSeconds;
            }
        }
    }

    /**
     * Builds a {@code MultiThreadedClientServiceCache} with a default executor and cleanup delay.
     * Used by the builder.
     *
     * @param serviceFactory The service factory for creating service handles
     * @param metricRegistry The metric registry for reporting metrics
     */
    MultiThreadedClientServiceCache(MultiThreadedServiceFactory<S> serviceFactory, MetricRegistry metricRegistry) {
        this(serviceFactory, buildDefaultExecutor(), DEFAULT_EVICTION_DELAY_SECONDS, DEFAULT_CLEANUP_DELAY_SECONDS, metricRegistry);