<commit_before>/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
*    http://www.geo-solutions.it/
*    Copyright 2014 GeoSolutions


* 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 it.geosolutions.concurrent;

import java.awt.Point;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Observable;
import java.util.Vector;

import javax.media.jai.TileCache;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.google.common.cache.Weigher;
import com.sun.media.jai.util.CacheDiagnostics;

public class ConcurrentTileCache extends Observable implements TileCache, CacheDiagnostics {

    /** The default memory threshold of the cache. */
    public static final float DEFAULT_MEMORY_THRESHOLD = 0.75F;

    /** The default memory capacity of the cache (16 MB). */
    public static final long DEFAULT_MEMORY_CACHE = 16L * 1024L * 1024L;

    /** The default diagnostic settings */
    public static final boolean DEFAULT_DIAGNOSTIC = false;

    /** The default concurrency settings */
    public static final int DEFAULT_CONCURRENCY_LEVEL = 4;

    /**
     * The tile cache. A Guava Cache is used to cache the tiles. The "key" is a <code>Object</code>. The "value" is a CachedTileImpl.
     */
    private Cache<Object, CachedTileImpl> cacheObject;

    /** The memory capacity of the cache. */
    private long memoryCacheCapacity;

    /** The concurrency level of the cache. */
    private int concurrencyLevel;

    /** The amount of memory to keep after memory control */
    private float memoryCacheThreshold = DEFAULT_MEMORY_THRESHOLD;

    /** diagnosticEnabled enable/disable */
    private volatile boolean diagnosticEnabled = DEFAULT_DIAGNOSTIC;

    /**
     * The listener is used for receiving notification about the removal of a tile for size constraints
     */
    private final RemovalListener<Object, CachedTileImpl> listener = new RemovalListener<Object, CachedTileImpl>() {
        public void onRemoval(RemovalNotification<Object, CachedTileImpl> n) {
            // if a tile is manually removed, the diagnosticEnabled already consider
            // it in
            // the remove() method

            if (diagnosticEnabled) {
                synchronized (this) {
                    if (n.wasEvicted() && n.getCause() == RemovalCause.SIZE) {
                        CachedTileImpl cti = n.getValue();
                        cti.setAction(Actions.REMOVAL_FROM_EVICTION);
                        setChanged();
                        notifyObservers(cti);
                    }
                }

            }
        }
    };

    // diagnostic actions
    /** A list of all the possible diagnostic actions */
    public enum Actions {
        ADDITION(0), MANUAL_REMOVAL(1), REMOVAL_FROM_FLUSH(2), REMOVAL_FROM_EVICTION(
                3), SUBSTITUTION_FROM_ADD(4), UPDATING_TILE_FROM_GETTILE(5), ABOUT_TO_REMOVAL(6);

        private final int action;

        Actions(int value) {
            this.action = value;
        }

        public int valueAction() {
            return action;
        }

    };

    /** Private cache creation method */
    private Cache<Object, CachedTileImpl> buildCache() {
        CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
        builder.maximumWeight((long) (memoryCacheCapacity * memoryCacheThreshold))
                .concurrencyLevel(concurrencyLevel).weigher(new Weigher<Object, CachedTileImpl>() {
                    public int weigh(Object o, CachedTileImpl cti) {
                        return (int) cti.getTileSize();
                    }
                });

        return builder.build();

    }

    public ConcurrentTileCache() {
        this(DEFAULT_MEMORY_CACHE, DEFAULT_DIAGNOSTIC, DEFAULT_MEMORY_THRESHOLD,
                DEFAULT_CONCURRENCY_LEVEL);
    }

    public ConcurrentTileCache(long memoryCacheCapacity, boolean diagnostic, float mem_threshold,
            int concurrencyLevel) {
        if (memoryCacheCapacity < 0) {
            throw new IllegalArgumentException("Memory capacity too small");
        }
        this.memoryCacheThreshold = mem_threshold;
        this.diagnosticEnabled = diagnostic;
        this.memoryCacheCapacity = memoryCacheCapacity;
        this.concurrencyLevel = concurrencyLevel;

        // cache creation
        cacheObject = buildCache();
    }

    /** Add a new tile to the cache */
    public void add(RenderedImage owner, int tileX, int tileY, Raster data) {
        add(owner, tileX, tileY, data, null);
    }

    /** Add a new tile to the cache */
    public void add(RenderedImage owner, int tileX, int tileY, Raster data,
            Object tileCacheMetric) {
        // This tile is not in the cache; create a new CachedTileImpl.
        // else just update.
        Object key = CachedTileImpl.hashKey(owner, tileX, tileY);
        // old tile
        CachedTileImpl cti;
        // create a new tile
        CachedTileImpl cti_new = new CachedTileImpl(owner, tileX, tileY, data, tileCacheMetric);

        // if the tile is already cached<commit_msg>Don't report a NPE every time a tile fails to compute (the ts will return null)<commit_after>/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
*    http://www.geo-solutions.it/
*    Copyright 2014 GeoSolutions


* 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 it.geosolutions.concurrent;

import java.awt.Point;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Observable;
import java.util.Vector;

import javax.media.jai.TileCache;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.google.common.cache.Weigher;
import com.sun.media.jai.util.CacheDiagnostics;

public class ConcurrentTileCache extends Observable implements TileCache, CacheDiagnostics {

    /** The default memory threshold of the cache. */
    public static final float DEFAULT_MEMORY_THRESHOLD = 0.75F;

    /** The default memory capacity of the cache (16 MB). */
    public static final long DEFAULT_MEMORY_CACHE = 16L * 1024L * 1024L;

    /** The default diagnostic settings */
    public static final boolean DEFAULT_DIAGNOSTIC = false;

    /** The default concurrency settings */
    public static final int DEFAULT_CONCURRENCY_LEVEL = 4;

    /**
     * The tile cache. A Guava Cache is used to cache the tiles. The "key" is a <code>Object</code>. The "value" is a CachedTileImpl.
     */
    private Cache<Object, CachedTileImpl> cacheObject;

    /** The memory capacity of the cache. */
    private long memoryCacheCapacity;

    /** The concurrency level of the cache. */
    private int concurrencyLevel;

    /** The amount of memory to keep after memory control */
    private float memoryCacheThreshold = DEFAULT_MEMORY_THRESHOLD;

    /** diagnosticEnabled enable/disable */
    private volatile boolean diagnosticEnabled = DEFAULT_DIAGNOSTIC;

    /**
     * The listener is used for receiving notification about the removal of a tile for size constraints
     */
    private final RemovalListener<Object, CachedTileImpl> listener = new RemovalListener<Object, CachedTileImpl>() {
        public void onRemoval(RemovalNotification<Object, CachedTileImpl> n) {
            // if a tile is manually removed, the diagnosticEnabled already consider
            // it in
            // the remove() method

            if (diagnosticEnabled) {
                synchronized (this) {
                    if (n.wasEvicted() && n.getCause() == RemovalCause.SIZE) {
                        CachedTileImpl cti = n.getValue();
                        cti.setAction(Actions.REMOVAL_FROM_EVICTION);
                        setChanged();
                        notifyObservers(cti);
                    }
                }

            }
        }
    };

    // diagnostic actions
    /** A list of all the possible diagnostic actions */
    public enum Actions {
        ADDITION(0), MANUAL_REMOVAL(1), REMOVAL_FROM_FLUSH(2), REMOVAL_FROM_EVICTION(
                3), SUBSTITUTION_FROM_ADD(4), UPDATING_TILE_FROM_GETTILE(5), ABOUT_TO_REMOVAL(6);

        private final int action;

        Actions(int value) {
            this.action = value;
        }

        public int valueAction() {
            return action;
        }

    };

    /** Private cache creation method */
    private Cache<Object, CachedTileImpl> buildCache() {
        CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
        builder.maximumWeight((long) (memoryCacheCapacity * memoryCacheThreshold))
                .concurrencyLevel(concurrencyLevel).weigher(new Weigher<Object, CachedTileImpl>() {
                    public int weigh(Object o, CachedTileImpl cti) {
                        return (int) cti.getTileSize();
                    }
                });

        return builder.build();

    }

    public ConcurrentTileCache() {
        this(DEFAULT_MEMORY_CACHE, DEFAULT_DIAGNOSTIC, DEFAULT_MEMORY_THRESHOLD,
                DEFAULT_CONCURRENCY_LEVEL);
    }

    public ConcurrentTileCache(long memoryCacheCapacity, boolean diagnostic, float mem_threshold,
            int concurrencyLevel) {
        if (memoryCacheCapacity < 0) {
            throw new IllegalArgumentException("Memory capacity too small");
        }
        this.memoryCacheThreshold = mem_threshold;
        this.diagnosticEnabled = diagnostic;
        this.memoryCacheCapacity = memoryCacheCapacity;
        this.concurrencyLevel = concurrencyLevel;

        // cache creation
        cacheObject = buildCache();
    }

    /** Add a new tile to the cache */
    public void add(RenderedImage owner, int tileX, int tileY, Raster data) {
        add(owner, tileX, tileY, data, null);
    }

    /** Add a new tile to the cache */
    public void add(RenderedImage owner, int tileX, int tileY, Raster data,
            Object tileCacheMetric) {
        // when computation fails this method is called with a null raster,
        // avoid logging an extra NPE
        if(data == null) {
            return;
        }
        
        // This tile is not in the cache; create a new CachedTileImpl.
        // else just update.
        Object key = CachedTileImpl.hashKey(owner, tileX, tileY);
        // old tile
        CachedTileImpl cti;
        // create a new tile
        CachedTileImpl cti_new = new CachedTileImpl(owner, tileX, tileY, data, tileCacheMetric);

        // if the tile is already cached
{'fraction_non_alphanumeric': 0.08303827347833417, 'fraction_numerical': 0.00539538020569887, 'mean_word_length': 2.604679428745062, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, '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': '4944901', 'n_tokens_mistral': 3236, 'n_tokens_neox': 3099, 'n_words': 999}