Package com.hazelcast.cache.impl.record

Source Code of com.hazelcast.cache.impl.record.CacheRecordHashMap

/*
* Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.
*
* 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 com.hazelcast.cache.impl.record;

import com.hazelcast.cache.impl.CacheKeyIteratorResult;
import com.hazelcast.cache.impl.ICacheRecordStore;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.spi.Callback;
import com.hazelcast.util.Clock;
import com.hazelcast.util.ConcurrentReferenceHashMap;
import com.hazelcast.util.EmptyStatement;
import com.hazelcast.util.FetchableConcurrentHashMap;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;

public class CacheRecordHashMap<K, V>
        extends FetchableConcurrentHashMap<K, V>
        implements CacheRecordMap<K, V> {

    private static final int MIN_EVICTION_ELEMENT_COUNT = 100;

    private Callback<Data> evictionCallback;

    public CacheRecordHashMap(int initialCapacity) {
        super(initialCapacity);
    }

    public CacheRecordHashMap(int initialCapacity,
                              float loadFactor,
                              int concurrencyLevel,
                              ConcurrentReferenceHashMap.ReferenceType keyType,
                              ConcurrentReferenceHashMap.ReferenceType valueType,
                              EnumSet<Option> options) {
        this(initialCapacity, loadFactor, concurrencyLevel, keyType, valueType, options, null);
    }

    public CacheRecordHashMap(int initialCapacity,
                              float loadFactor,
                              int concurrencyLevel,
                              ConcurrentReferenceHashMap.ReferenceType keyType,
                              ConcurrentReferenceHashMap.ReferenceType valueType,
                              EnumSet<ConcurrentReferenceHashMap.Option> options,
                              Callback<Data> evictionCallback) {
        super(initialCapacity, loadFactor, concurrencyLevel, keyType, valueType, options);
        this.evictionCallback = evictionCallback;
    }

    @Override
    public CacheKeyIteratorResult fetchNext(int nextTableIndex, int size) {
        List<Data> keys = new ArrayList<Data>();
        int tableIndex = fetch(nextTableIndex, size, keys);
        return new CacheKeyIteratorResult(keys, tableIndex);
    }

    private void callbackEvictionListeners(Data data) {
        if (evictionCallback != null) {
            evictionCallback.notify(data);
        }
    }

    @Override
    public int evictExpiredRecords(int percentage) {
        long now = Clock.currentTimeMillis();
        int sizeLimitForEviction = (int) ((double) (size() * percentage)
                / (double) ICacheRecordStore.ONE_HUNDRED_PERCENT);

        if (sizeLimitForEviction < MIN_EVICTION_ELEMENT_COUNT) {
            return 0;
        }

        List<Map.Entry<K, Expirable>> expiredEntries =
                new ArrayList<Map.Entry<K, Expirable>>(sizeLimitForEviction);
        int expiredCount = 0;
        for (Map.Entry<K, V> entry : entrySet()) {
            K key = entry.getKey();
            V value = entry.getValue();
            final boolean isExpired =
                    (value instanceof Expirable)
                            && ((Expirable) value).isExpiredAt(now);
            if (isExpired) {
                expiredEntries.add((Map.Entry<K, Expirable>) entry);
                if (++expiredCount >= sizeLimitForEviction) {
                    break;
                }
            }
        }
        int actualExpiredCount = 0;
        for (Map.Entry<K, Expirable> entry : expiredEntries) {
            Expirable expirableValue = entry.getValue();
            if (expirableValue instanceof Data) {
                callbackEvictionListeners((Data) expirableValue);
            }
            if (remove(entry.getKey()) != null) {
                actualExpiredCount++;
            }
        }
        return actualExpiredCount;
    }

    @Override
    public int evictRecords(int percentage, EvictionPolicy policy) {
        switch (policy) {
            case RANDOM:
                try {
                    return evictRecordsRandom(percentage);
                } catch (Throwable e) {
                    EmptyStatement.ignore(e);
                    break;
                }

            case LRU:
                try {
                    return evictRecordsLRU(percentage);
                } catch (Throwable e) {
                    EmptyStatement.ignore(e);
                    break;
                }

            case LFU:
                try {
                    return evictRecordsLFU(percentage);
                } catch (Throwable e) {
                    EmptyStatement.ignore(e);
                    break;
                }

            default:
                throw new IllegalArgumentException();
        }

        return evictExpiredRecords(percentage);
    }

    private int evictRecordsLRU(int percentage) {
        throw new UnsupportedOperationException(
                "\"LRU\" eviction is not supported right now !");
    }

    private int evictRecordsLFU(int percentage) {
        throw new UnsupportedOperationException(
                "\"LFU\" eviction is not supported right now !");
    }

    private int evictRecordsRandom(int percentage) {
        int sizeLimitForEviction = (int) ((double) (size() * percentage)
                / (double) ICacheRecordStore.ONE_HUNDRED_PERCENT);

        if (sizeLimitForEviction < MIN_EVICTION_ELEMENT_COUNT) {
            return 0;
        }

        List<Map.Entry<K, V>> expiredEntries =
                new ArrayList<Map.Entry<K, V>>(sizeLimitForEviction);
        int expiredCount = 0;
        for (Map.Entry<K, V> entry : entrySet()) {
            expiredEntries.add(entry);
            if (++expiredCount >= sizeLimitForEviction) {
                break;
            }
        }
        int actualExpiredCount = 0;
        for (Map.Entry<K, V> entry : expiredEntries) {
            V value = entry.getValue();
            if (value instanceof Data) {
                callbackEvictionListeners((Data) value);
            }
            if (remove(entry.getKey()) != null) {
                actualExpiredCount++;
            }
        }
        return actualExpiredCount;
    }

}
TOP

Related Classes of com.hazelcast.cache.impl.record.CacheRecordHashMap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.