Map getBulkAndTouch()

in evcache-core/src/main/java/com/netflix/evcache/EVCache.java [867:1512]


    <T> Map<String, T> getBulkAndTouch(Collection<String> keys, Transcoder<T> tc, int timeToLive)
            throws EVCacheException;

    /**
     * Get the value for given key asynchronously and deserialize it with the
     * default transcoder.
     *
     * @param key
     *            the key for which we need the value. Ensure the key is
     *            properly encoded and does not contain whitespace or control
     *            characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @return the Futures containing the Value or null.
     * @throws EVCacheException
     *             in the circumstance where queue is too full to accept any
     *             more requests or issues during deserialization or timeout
     *             retrieving the value or any IO Related issues
     *
     * @deprecated This is a sub-optimal operation does not support Retries, Fast Failures, FIT, GC Detection, etc.
     *             Will be removed in a subsequent release
     */
    <T> Future<T> getAsynchronous(String key) throws EVCacheException;

    /**
     * Get the value for given key asynchronously and deserialize it with the
     * given transcoder.
     *
     * @param key
     *            the key for which we need the value. Ensure the key is
     *            properly encoded and does not contain whitespace or control
     *            characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param tc
     *            the transcoder to use for deserialization
     * @return the Futures containing the Value or null.
     * @throws EVCacheException
     *             in the circumstance where queue is too full to accept any
     *             more requests or issues during deserialization or timeout
     *             retrieving the value or any IO Related issues
     *
     * @deprecated This is a sub-optimal operation does not support Retries, Fast Failures, FIT, GC Detection, etc.
     *             Will be removed in a subsequent release
     */
    <T> Future<T> getAsynchronous(String key, Transcoder<T> tc) throws EVCacheException;

    /**
     * Increment the given counter, returning the new value.
     *
     * @param key
     *            the key. Ensure the key is
     *            properly encoded and does not contain whitespace or control
     *            characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param by
     *            the amount to increment
     * @param def
     *            the default value (if the counter does not exist)
     * @param exp
     *            the expiration of this object
     * @return the new value, or -1 if we were unable to increment or add
     * @throws EVCacheException
     *             in the circumstance where timeout is exceeded or queue is
     *             full
     *
     */
    public long incr(String key, long by, long def, int exp) throws EVCacheException;

    /**
     * Decrement the given counter, returning the new value.
     *
     * @param key
     *            the key. Ensure the key is
     *            properly encoded and does not contain whitespace or control
     *            characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param by
     *            the amount to decrement
     * @param def
     *            the default value (if the counter does not exist)
     * @param exp
     *            the expiration of this object
     * @return the new value, or -1 if we were unable to decrement or add
     * @throws EVCacheException
     *             in the circumstance where timeout is exceeded or queue is
     *             full
     *
     */
    public long decr(String key, long by, long def, int exp) throws EVCacheException;

    /**
     * Append the given value to the existing value in EVCache. You cannot
     * append if the key does not exist in EVCache. If the value has not changed
     * then false will be returned.
     *
     * @param key
     *            the key under which this object should be appended. Ensure the
     *            key is properly encoded and does not contain whitespace or
     *            control characters.  The max length of the key (including prefix)
     *            is 200 characters.
     * @param T
     *            the value to be appended
     * @param tc
     *            the transcoder the will be used for serialization
     * @param timeToLive
     *            the expiration of this object i.e. less than 30 days in
     *            seconds or the exact expiry time as UNIX time
     *
     * @return Array of futures representing the processing of this operation
     *         across all the replicas
     * @throws EVCacheException
     *             in the circumstance where queue is too full to accept any
     *             more requests or issues Serializing the value or any IO
     *             Related issues
     */
    <T> Future<Boolean>[] append(String key, T value, Transcoder<T> tc, int timeToLive) throws EVCacheException;

    /**
     * Append the given value to the existing value in EVCache. You cannot
     * append if the key does not exist in EVCache. If the value has not changed
     * or does not exist then false will be returned.
     *
     * @param key
     *            the key under which this object should be appended. Ensure the
     *            key is properly encoded and does not contain whitespace or
     *            control characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param T
     *            the value to be appended
     * @param timeToLive
     *            the expiration of this object i.e. less than 30 days in
     *            seconds or the exact expiry time as UNIX time
     *
     * @return Array of futures representing the processing of this operation
     *         across all the replicas
     * @throws EVCacheException
     *             in the circumstance where queue is too full to accept any
     *             more requests or issues Serializing the value or any IO
     *             Related issues
     */
    <T> Future<Boolean>[] append(String key, T value, int timeToLive) throws EVCacheException;

    /**
     * @deprecated Please use {@link #<T> EVCacheLatch add(String, T, Transcoder<T> , int, Policy) throws EVCacheException;}
     * 
     * Add the given value to EVCache. You cannot add if the key already exist in EVCache.
     *
     * @param key
     *            the key which this object should be added to. Ensure the
     *            key is properly encoded and does not contain whitespace or
     *            control characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param T
     *            the value to be added
     * @param tc
     *            the transcoder the will be used for serialization
     * @param timeToLive
     *            the expiration of this object i.e. less than 30 days in
     *            seconds or the exact expiry time as UNIX time
     *
     * @return boolean which indicates if the add was successful or not.
     * 			The operation will fail with a false response if the data already exists in EVCache.
     *
     * @throws EVCacheException
     *             in the rare circumstance where queue is too full to accept
     *             any more requests or issues Serializing the value or any IO
     *             Related issues
     */
    <T> boolean add(String key, T value, Transcoder<T> tc, int timeToLive) throws EVCacheException;



    /**
     * Add the given value to EVCache. You cannot add if the key already exist in EVCache.
     *
     * @param key
     *            the key which this object should be added to. Ensure the
     *            key is properly encoded and does not contain whitespace or
     *            control characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param T
     *            the value to be added
     * @param tc
     *            the transcoder the will be used for serialization
     * @param timeToLive
     *            the expiration of this object i.e. less than 30 days in
     *            seconds or the exact expiry time as UNIX time
     * @param policy
     *            The Latch will be returned based on the Policy. The Latch can then be used to await until the count down has reached to 0 or the specified time has elapsed.
     *
     *
     * @return EVCacheLatch which will encompasses the Operation. You can block
     *         on the Operation to ensure all adds are successful. If there are any partial success
     *         The client will try and fix the Data.
     *
     *
     * @throws EVCacheException
     *             in the rare circumstance where queue is too full to accept
     *             any more requests or issues Serializing the value or any IO
     *             Related issues
     */
    <T> EVCacheLatch add(String key, T value, Transcoder<T> tc, int timeToLive, Policy policy) throws EVCacheException;


    /**
     * Touch the given key and reset its expiration time.
     *
     * @param key
     *            the key to touch.  Ensure the
     *            key is properly encoded and does not contain whitespace or
     *            control characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param ttl
     *            the new expiration time in seconds
     *
     * @return Array of futures representing the processing of this operation
     *         across all the replicas
     * @throws EVCacheException
     *             in the rare circumstance where queue is too full to accept
     *             any more requests or issues Serializing the value or any IO
     *             Related issues
     */
    <T> Future<Boolean>[] touch(String key, int ttl) throws EVCacheException;


    /**
     * Touch the given key and reset its expiration time.
     *
     * @param key
     *            the key to touch.  Ensure the
     *            key is properly encoded and does not contain whitespace or
     *            control characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param ttl
     *            the new expiration time in seconds
     *
     * @param policy
     *            The Latch will be returned based on the Policy. The Latch can
     *            then be used to await until the count down has reached to 0 or
     *            the specified time has elapsed.
     *
     * @return EVCacheLatch which will encompasses the Operation. You can block
     *         on the Operation based on the policy to ensure the required
     *         criteria is met. The Latch can also be queried to get details on
     *         status of the operations
     *
     * @throws EVCacheException
     *             in the rare circumstance where queue is too full to accept
     *             any more requests or any IO Related issues
     */
    <T> EVCacheLatch touch(String key, int ttl, EVCacheLatch.Policy policy) throws EVCacheException;

    /**
     * Append the given value to the existing value in EVCache. If the Key does not exist the the key will added.
     *
     *
     * @param key
     *            the key under which this object should be appended or Added. Ensure the
     *            key is properly encoded and does not contain whitespace or
     *            control characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param T
     *            the value to be appended
     * @param tc
     *            the transcoder the will be used for serialization
     * @param timeToLive
     *            the expiration of this object i.e. less than 30 days in
     *            seconds or the exact expiry time as UNIX time
     *
     * @return Array of futures representing the processing of this operation
     *         across all the replicas
     * @throws EVCacheException
     *             in the circumstance where queue is too full to accept any
     *             more requests or issues Serializing the value or any IO
     *             Related issues
     */
    <T> Future<Boolean>[] appendOrAdd(String key, T value, Transcoder<T> tc, int timeToLive) throws EVCacheException;


    /**
     * Append the given value to the existing value in EVCache. If the Key does not exist the the key will added.
     *
     *
     * @param key
     *            the key under which this object should be appended or Added. Ensure the
     *            key is properly encoded and does not contain whitespace or
     *            control characters. The max length of the key (including prefix)
     *            is 200 characters.
     * @param T
     *            the value to be appended
     * @param tc
     *            the transcoder the will be used for serialization
     * @param timeToLive
     *            the expiration of this object i.e. less than 30 days in
     *            seconds or the exact expiry time as UNIX time
     *
     * @param policy
     *            The Latch will be returned based on the Policy. The Latch can then be used to await until the count down has reached to 0 or the specified time has elapsed.
     *
     * @return EVCacheLatch which will encompasses the Operation. You can block
     *         on the Operation based on the policy to ensure the required
     *         criteria is met. The Latch can also be queried to get details on
     *         status of the operations
     *
     * @throws EVCacheException
     *             in the circumstance where queue is too full to accept any
     *             more requests or issues Serializing the value or any IO
     *             Related issues
     */
    <T> EVCacheLatch appendOrAdd(String key, T value, Transcoder<T> tc, int timeToLive, Policy policy) throws EVCacheException;

    /**
     * The {@code appName} that will be used by this {@code EVCache}.
     *
     * @param The
     *            name of the EVCache App cluster.
     * @return this {@code Builder} object
     */
    String getAppName();


    /**
     * The {@code cachePrefix} that will be used by this {@code EVCache}.
     *
     * @param The
     *            name of the EVCache App cluster.
     * @return this {@code Builder} object
     */
    String getCachePrefix();

    /**
     * A Builder that builds an EVCache based on the specified App Name, cache
     * Name, TTl and Transcoder.
     *
     * @author smadappa
     */
    public class Builder {
        private static final Logger logger = LoggerFactory.getLogger(EVCacheImpl.class);

        private String _appName;
        private String _cachePrefix = null;
        private int _ttl = 900;
        private Transcoder<?> _transcoder = null;
        private boolean _serverGroupRetry = true;
        private boolean _enableExceptionThrowing = false;
        private List<Customizer> _customizers = new ArrayList<>();

        @Inject
        private EVCacheClientPoolManager _poolManager;

        /**
         * Customizers allow post-processing of the Builder. This affords a way for libraries to
         * perform customization.
         */
        @FunctionalInterface
        public interface Customizer {
            void customize(final String cacheName, final Builder builder);
        }

        public static class Factory {
            public Builder createInstance(String appName) {
                return Builder.forApp(appName);
            }
        }

        public static Builder forApp(final String appName) {
            return new Builder().setAppName(appName);
        }

        public Builder() {
        }

        public Builder withConfigurationProperties(
                final EVCacheClientPoolConfigurationProperties configurationProperties) {
            return this
                    .setCachePrefix(configurationProperties.getKeyPrefix())
                    .setDefaultTTL(configurationProperties.getTimeToLive())
                    .setRetry(configurationProperties.getRetryEnabled())
                    .setExceptionThrowing(configurationProperties.getExceptionThrowingEnabled());
        }

        /**
         * The {@code appName} that will be used by this {@code EVCache}.
         *
         * @param The
         *            name of the EVCache App cluster.
         * @return this {@code Builder} object
         */
        public Builder setAppName(String appName) {
            if (appName == null) throw new IllegalArgumentException("param appName cannot be null.");
            this._appName = appName.toUpperCase(Locale.US);
            if (!_appName.startsWith("EVCACHE")) logger.warn("Make sure the app you are connecting to is EVCache App");
            return this;
        }

        /**
         * Adds {@code cachePrefix} to the key. This ensures there are no cache
         * collisions if the same EVCache app is used across multiple use cases.
         * If the cache is not shared we recommend to set this to
         * <code>null</code>. Default is <code>null</code>.
         *
         * @param cacheName.
         *            The cache prefix cannot contain colon (':') in it.
         * @return this {@code Builder} object
         */
        public Builder setCachePrefix(String cachePrefix) {
            if (_cachePrefix != null && _cachePrefix.indexOf(':') != -1) throw new IllegalArgumentException(
                    "param cacheName cannot contain ':' character.");
            this._cachePrefix = cachePrefix;
            return this;
        }

        /**
         * @deprecated Please use {@link #setCachePrefix(String)}
         * @see #setCachePrefix(String)
         *
         *      Adds {@code cacheName} to the key. This ensures there are no
         *      cache collisions if the same EVCache app is used for across
         *      multiple use cases.
         *
         * @param cacheName
         * @return this {@code Builder} object
         */
        public Builder setCacheName(String cacheName) {
            return setCachePrefix(cacheName);
        }

        /**
         * The default Time To Live (TTL) for items in {@link EVCache} in
         * seconds. You can override the value by passing the desired TTL with
         * {@link EVCache#set(String, Object, int)} operations.
         *
         * @param ttl. Default is 900 seconds.
         * @return this {@code Builder} object
         */
        public Builder setDefaultTTL(int ttl) {
            if (ttl < 0) throw new IllegalArgumentException("Time to Live cannot be less than 0.");
            this._ttl = ttl;
            return this;
        }

        /**
         * The default Time To Live (TTL) for items in {@link EVCache} in
         * seconds. You can override the value by passing the desired TTL with
         * {@link EVCache#set(String, Object, int)} operations.
         *
         * @param ttl. Default is 900 seconds.
         * @return this {@code Builder} object
         */
        public Builder setDefaultTTL(@Nullable final Duration ttl) {
            if (ttl == null) {
                return this;
            }

            return setDefaultTTL((int) ttl.getSeconds());
        }

        @VisibleForTesting
        Transcoder<?> getTranscoder() {
            return this._transcoder;
        }

        /**
         * The default {@link Transcoder} to be used for serializing and
         * de-serializing items in {@link EVCache}.
         *
         * @param transcoder
         * @return this {@code Builder} object
         */
        public <T> Builder setTranscoder(Transcoder<T> transcoder) {
            this._transcoder = transcoder;
            return this;
        }

        /**
         * @deprecated Please use {@link #enableRetry()}
         *
         *             Will enable retries across Zone (Server Group).
         *
         * @return this {@code Builder} object
         */
        public <T> Builder enableZoneFallback() {
            this._serverGroupRetry = true;
            return this;
        }

        /**
         * Will enable or disable retry across Server Group for cache misses and exceptions
         * if there are multiple Server Groups for the given EVCache App and
         * data is replicated across them. This ensures the Hit Rate continues
         * to be unaffected whenever a server group loses instances.
         *
         * By Default retry is enabled.
         *
         * @param enableRetry whether retries are to be enabled
         * @return this {@code Builder} object
         */
        public Builder setRetry(boolean enableRetry) {
            this._serverGroupRetry = enableRetry;

            return this;
        }

        /**
         * Will enable retry across Server Group for cache misses and exceptions
         * if there are multiple Server Groups for the given EVCache App and
         * data is replicated across them. This ensures the Hit Rate continues
         * to be unaffected whenever a server group loses instances.
         *
         * By Default retry is enabled.
         *
         * @return this {@code Builder} object
         */
        public <T> Builder enableRetry() {
            this._serverGroupRetry = true;
            return this;
        }

        /**
         * Will disable retry across Server Groups. This means if the data is
         * not found in one server group null is returned.
         *
         * @return this {@code Builder} object
         */
        public <T> Builder disableRetry() {
            this._serverGroupRetry = false;
            return this;
        }

        /**
         * @deprecated Please use {@link #disableRetry()}
         *
         *             Will disable retry across Zone (Server Group).
         *
         * @return this {@code Builder} object
         */
        public <T> Builder disableZoneFallback() {
            this._serverGroupRetry = false;
            return this;
        }

        /**
         * By Default exceptions are not propagated and null values are
         * returned. By enabling exception propagation we return the
         * {@link EVCacheException} whenever the operations experience them.
         *
         * @param enableExceptionThrowing whether exception throwing is to be enabled
         * @return this {@code Builder} object
         */
        public Builder setExceptionThrowing(boolean enableExceptionThrowing) {
            this._enableExceptionThrowing = enableExceptionThrowing;

            return this;
        }

        /**
         * By Default exceptions are not propagated and null values are
         * returned. By enabling exception propagation we return the
         * {@link EVCacheException} whenever the operations experience them.
         *
         * @return this {@code Builder} object
         */
        public <T> Builder enableExceptionPropagation() {
            this._enableExceptionThrowing = true;
            return this;
        }

        /**
         * Adds customizers to be applied by {@code customize}.
         *
         * @param customizers List of {@code Customizer}s
         * @return this {@code Builder} object
         */
        public Builder addCustomizers(@Nullable final List<Customizer> customizers) {
            this._customizers.addAll(customizers);

            return this;
        }


        /**
         * Applies {@code Customizer}s added through {@code addCustomizers} to {@this}.
         *
         * @return this {@code Builder} object
         */
        public Builder customize() {
            _customizers.forEach(customizer -> {
                customizeWith(customizer);
            });

            return this;
        }

        /**
         * Customizes {@this} with the {@code customizer}.
         *
         * @param customizer {@code Customizer} or {@code Consumer<String, Builder>} to be applied to {@code this}.
         * @return this {@code Builder} object
         */
        public Builder customizeWith(final Customizer customizer) {
            customizer.customize(this._appName, this);

            return this;
        }

        /**
         * The EVCache pool manager that will be used by this {@code EVCache}.
         * @param poolManager
         * @return this {@code Builder} object
         */
        public Builder setPoolManager(EVCacheClientPoolManager poolManager) {
            _poolManager = poolManager;
            return this;
        }

        protected EVCache newImpl(String appName, String cachePrefix, int ttl, Transcoder<?> transcoder, boolean serverGroupRetry, boolean enableExceptionThrowing, EVCacheClientPoolManager poolManager) {
            return new EVCacheImpl(appName, cachePrefix, ttl, transcoder, serverGroupRetry, enableExceptionThrowing, poolManager);
        }

        /**
         * Returns a newly created {@code EVCache} based on the contents of the
         * {@code Builder}.
         */
        @SuppressWarnings("deprecation")
        public EVCache build() {
            if (_poolManager == null) {
                _poolManager = EVCacheClientPoolManager.getInstance();
                if (logger.isDebugEnabled()) logger.debug("_poolManager - " + _poolManager + " through getInstance");
            }

            if (_appName == null) {
                throw new IllegalArgumentException("param appName cannot be null.");
            }

            if(_cachePrefix != null) {
                for(int i = 0; i < _cachePrefix.length(); i++) {
                    if(Character.isWhitespace(_cachePrefix.charAt(i))){
                        throw new IllegalArgumentException("Cache Prefix ``" + _cachePrefix  + "`` contains invalid character at position " + i );
                    }
                }
            }

            customize();

            return newImpl(_appName, _cachePrefix, _ttl, _transcoder, _serverGroupRetry, _enableExceptionThrowing, _poolManager);
        }
    }