<commit_before>/*
 * Copyright 2012 <NAME>
 *
 * 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 net.tomp2p.utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A map with expiration and more or less LRU. Since the maps are separated in segments, the LRU is done for each
 * segment. A segment is chosen based on the hash of the key. If one segments is more loaded than another, then an entry
 * of the loaded segment may get evicted before an entry used least recently from an other segment. The expiration is
 * done best effort. There is no thread checking for timed out entries since the cache has a fixed size. Once an entry
 * times out, it remains in the map until it either is accessed or evicted. A test showed that for the default entry
 * size of 1024, this map has a size of 967 if 1024 items are inserted. This is due to the segmentation and hashing.
 * 
 * @author <NAME>
 * @param <K>
 *            the type of the key
 * @param <V>
 *            the type of the value
 */
public class ConcurrentCacheMap<K, V> implements ConcurrentMap<K, V> {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConcurrentCacheMap.class);

    /**
     * Number of segments that can be accessed concurrently.
     */
    public static final int SEGMENT_NR = 16;

    /**
     * Max. number of entries that the map can hold until the least recently used gets replaced
     */
    public static final int MAX_ENTRIES = 1024;

    /**
     * Time to live for a value. The value may stay longer in the map, but it is considered invalid.
     */
    public static final int DEFAULT_TIME_TO_LIVE = 60;

    private final CacheMap<K, ExpiringObject>[] segments;

    private final int timeToLiveSeconds;

    private final boolean refreshTimeout;

    private final AtomicInteger removedCounter = new AtomicInteger();

    /**
     * Creates a new instance of ConcurrentCacheMap using the supplied values and a {@link CacheMap} for the internal
     * data structure.
     */
    public ConcurrentCacheMap() {
        this(DEFAULT_TIME_TO_LIVE, MAX_ENTRIES, true);
    }

    /**
     * Creates a new instance of ConcurrentCacheMap using the supplied values and a {@link CacheMap} for the internal
     * data structure.
     * 
     * @param timeToLive
     *            The time-to-live value (seconds)
     * @param maxEntries
     *            Set the maximum number of entries until items gets replaced with LRU
     */
    public ConcurrentCacheMap(final int timeToLiveSeconds, final int maxEntries) {
        this(timeToLiveSeconds, maxEntries, true);
    }

    /**
     * Creates a new instance of ConcurrentCacheMap using the supplied values and a {@link CacheMap} for the internal
     * data structure.
     * 
     * @param timeToLiveSeconds
     *            The time-to-live value (seconds)
     * @param maxEntries
     *            The maximum entries to keep in cache, default is 1024
     * @param refreshTimeout
     *            If set to true, timeout will be reset in case of {@link #putIfAbsent(Object, Object)}
     */
    @SuppressWarnings("unchecked")
    public ConcurrentCacheMap(final int timeToLiveSeconds, final int maxEntries, final boolean refreshTimeout) {
        this.segments = new CacheMap[SEGMENT_NR];
        final int maxEntriesPerSegment = maxEntries / SEGMENT_NR;
        for (int i = 0; i < SEGMENT_NR; i++) {<commit_msg>ConcurrentCacheMap: updated c'tor docu<commit_after>/*
 * Copyright 2012 <NAME>
 *
 * 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 net.tomp2p.utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A map with expiration and more or less LRU. Since the maps are separated in segments, the LRU is done for each
 * segment. A segment is chosen based on the hash of the key. If one segments is more loaded than another, then an entry
 * of the loaded segment may get evicted before an entry used least recently from an other segment. The expiration is
 * done best effort. There is no thread checking for timed out entries since the cache has a fixed size. Once an entry
 * times out, it remains in the map until it either is accessed or evicted. A test showed that for the default entry
 * size of 1024, this map has a size of 967 if 1024 items are inserted. This is due to the segmentation and hashing.
 * 
 * @author <NAME>
 * @param <K>
 *            the type of the key
 * @param <V>
 *            the type of the value
 */
public class ConcurrentCacheMap<K, V> implements ConcurrentMap<K, V> {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConcurrentCacheMap.class);

    /**
     * Number of segments that can be accessed concurrently.
     */
    public static final int SEGMENT_NR = 16;

    /**
     * Max. number of entries that the map can hold until the least recently used gets replaced
     */
    public static final int MAX_ENTRIES = 1024;

    /**
     * Time to live for a value. The value may stay longer in the map, but it is considered invalid.
     */
    public static final int DEFAULT_TIME_TO_LIVE = 60;

    private final CacheMap<K, ExpiringObject>[] segments;

    private final int timeToLiveSeconds;

    private final boolean refreshTimeout;

    private final AtomicInteger removedCounter = new AtomicInteger();

    /**
     * Creates a new instance of ConcurrentCacheMap using the default values and a {@link CacheMap} for the internal
     * data structure.
     */
    public ConcurrentCacheMap() {
        this(DEFAULT_TIME_TO_LIVE, MAX_ENTRIES, true);
    }

    /**
     * Creates a new instance of ConcurrentCacheMap using the supplied values and a {@link CacheMap} for the internal
     * data structure.
     * 
     * @param timeToLive
     *            The time-to-live value (seconds)
     * @param maxEntries
     *            The maximum number of entries until items gets replaced with LRU
     */
    public ConcurrentCacheMap(final int timeToLiveSeconds, final int maxEntries) {
        this(timeToLiveSeconds, maxEntries, true);
    }

    /**
     * Creates a new instance of ConcurrentCacheMap using the supplied values and a {@link CacheMap} for the internal
     * data structure.
     * 
     * @param timeToLiveSeconds
     *            The time-to-live value (seconds)
     * @param maxEntries
     *            The maximum number of entries until items gets replaced with LRU
     * @param refreshTimeout
     *            If set to true, timeout will be reset in case of {@link #putIfAbsent(Object, Object)}
     */
    @SuppressWarnings("unchecked")
    public ConcurrentCacheMap(final int timeToLiveSeconds, final int maxEntries, final boolean refreshTimeout) {
        this.segments = new CacheMap[SEGMENT_NR];
        final int maxEntriesPerSegment = maxEntries / SEGMENT_NR;
        for (int i = 0; i < SEGMENT_NR; i++) {
{'fraction_non_alphanumeric': 0.06956831965750981, 'fraction_numerical': 0.00784873349982162, 'mean_word_length': 3.0706679574056146, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '254776', 'n_tokens_mistral': 2302, 'n_tokens_neox': 2206, 'n_words': 1001}