/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2014, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.image.io.large; import org.apache.sis.util.Static; import org.apache.sis.util.logging.Logging; import java.util.Arrays; import java.util.IllegalFormatException; import java.util.logging.Logger; /** * Class that control {@link org.geotoolkit.image.io.large.LargeCache LargeCache} configuration * * @author Quentin Boileau (Geomatys) */ public final class ImageCacheConfiguration extends Static { private static final Logger LOGGER = Logging.getLogger("org.geotoolkit.image.io.large"); /** * List of supported memory units. */ private static final char[] VALID_UNIT = new char[]{'G', 'K', 'M', 'g', 'k', 'm'}; /** * The {@linkplain System#getProperties() system properties} key which control * the LargeCache memory size. * Format <size>[g|G|m|M|k|K] */ public static final String KEY_CACHE_MEMORY_SIZE = "geotk.image.cache.size"; /** * The {@linkplain System#getProperties() system properties} key which control * the LargeCache swap on filesystem. * Valid values : "true", "false" * If true LargeCache will use a QuadTreeDirectory to write tiles on filesystem, otherwise * cache will only use memory to store tiles. */ public static final String KEY_CACHE_SWAP = "geotk.image.cache.swap"; /** * Default memory size used if {@linkplain System#getProperties() system properties} {@linkplain #KEY_CACHE_MEMORY_SIZE} * property is not defined. * * This value is equivalent to 64MB. Decomposed version : 1024l * 1024 * 1 * 1 * 64 * (tile width(px) * tile height(px) * band number * component type size (byte) * number of images.) */ private static final long DEFAULT_MEMORY_SIZE = 67108864l; /** * Check in {@linkplain System#getProperties() system properties} for cache memory size configuration * or use {@link #DEFAULT_MEMORY_SIZE} value is not found or doesn't respect <size>[g|G|m|M|k|K] format. * * @return cache memory size in bytes. */ public static long getCacheMemorySize() { final String memoryProp = System.getProperty(KEY_CACHE_MEMORY_SIZE); if (memoryProp == null) { return DEFAULT_MEMORY_SIZE; } //TODO compare cache size to -xmx runtime configuration to inform possible memory error. return parseToByte(memoryProp); } /** * Set cache memory size in {@linkplain System#getProperties() system properties}. * It is not assured that LargeCache will use given value if it was already instantiated. * <b>This memory size should be set during application startup not during his life-cycle.</b> * * @param candidate memory property value String formatted as <size>[g|G|m|M|k|K] * @throws IllegalArgumentException if candidate String doesn't respect <size>[g|G|m|M|k|K] format. */ public static void setCacheMemorySize(String candidate) throws IllegalArgumentException{ try { Long.valueOf(candidate.substring(0, candidate.length() - 1)); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid cache memory format : '"+candidate+"' should be formatted as <size>[g|G|m|M|k|K]"); } //test unit char unit = candidate.charAt(candidate.length()-1); if (Arrays.binarySearch(VALID_UNIT, unit) < 0) { throw new IllegalArgumentException("Invalid cache memory format : '"+candidate+"' should be formatted as <size>[g|G|m|M|k|K]"); } System.setProperty(KEY_CACHE_MEMORY_SIZE, candidate); } /** * Convert memory property value String formatted as <size>[g|G|m|M|k|K] to byte. * e.g. * 1g -> 1073741824l * 256m -> 268435456l * 900k -> 921600l * * If input String format is invalid, {@linkplain #DEFAULT_MEMORY_SIZE} value will be returned. * * @param memoryProp String formatted as <size>[g|G|m|M|k|K] * @return string input converted in byte number. */ private static long parseToByte(String memoryProp) throws IllegalFormatException{ long value; try { value = Long.valueOf(memoryProp.substring(0, memoryProp.length() - 1)); } catch (NumberFormatException e) { LOGGER.warning("Invalid property -Dgeotk.image.cache.size value "+memoryProp+". Default value (64m) will be used."); return DEFAULT_MEMORY_SIZE; } char unit = memoryProp.charAt(memoryProp.length()-1); switch (unit) { case 'g' : case 'G' : return (long) (value * Math.pow(1024, 3)); case 'm' : case 'M' : return (long) (value * Math.pow(1024, 2)); case 'k' : case 'K' : return value * 1024; default: LOGGER.warning("Invalid property -Dgeotk.image.cache.size value "+memoryProp+". Default value (64m) will be used."); return DEFAULT_MEMORY_SIZE; } } /** * Check in {@linkplain System#getProperties() system properties} for cache swap configuration. * * @return return property value or {@code true} if property not found. */ public static boolean isCacheSwapEnable() { final String swap = System.getProperty(KEY_CACHE_SWAP); return swap == null || Boolean.parseBoolean(swap); } /** * Set cache swap in {@linkplain System#getProperties() system properties}. * It is not assured that LargeCache will use given value if it was already instantiated. * <b>This flag should be set during application startup not during his life-cycle.</b> * * @param allowSwap flag that enable memory swapping on filesystem. */ public static void setCacheSwapEnable(boolean allowSwap) { System.setProperty(KEY_CACHE_SWAP, String.valueOf(allowSwap)); } }