001/* 002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 * $Id$ 018 * 019 */ 020package org.nuxeo.ecm.platform.pictures.tiles.service; 021 022import java.util.ArrayList; 023import java.util.Collections; 024import java.util.Date; 025import java.util.HashMap; 026import java.util.List; 027import java.util.Map; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031 032/** 033 * Manage GC processing to clean up disk cache 034 * 035 * @author tiry 036 */ 037public class PictureTilingCacheGCManager { 038 039 public static final String MAX_DISK_SPACE_USAGE_KEY = "MaxDiskSpaceUsageForCache"; 040 041 public static final long MAX_DISK_SPACE_USAGE_KB = 1000; 042 043 private static final Log log = LogFactory.getLog(PictureTilingCacheGCManager.class); 044 045 private static int gcRuns = 0; 046 047 private static int gcCalls = 0; 048 049 protected static long getMaxDiskSpaceUsageKB() { 050 String maxStr = PictureTilingComponent.getEnvValue(MAX_DISK_SPACE_USAGE_KEY, 051 Long.toString(MAX_DISK_SPACE_USAGE_KB)); 052 return Long.parseLong(maxStr); 053 } 054 055 public static int getGCRuns() { 056 return gcRuns; 057 } 058 059 public static int getGCCalls() { 060 return gcCalls; 061 } 062 063 public static long getCacheSizeInKBs() { 064 return getCacheSizeInBytes() / 1000; 065 } 066 067 public static long getCacheSizeInBytes() { 068 long totalSize = 0; 069 Map<String, PictureTilingCacheInfo> cache = PictureTilingComponent.getCache(); 070 071 for (String key : cache.keySet()) { 072 PictureTilingCacheInfo cacheEntry = cache.get(key); 073 totalSize += cacheEntry.getDiskSpaceUsageInBytes(); 074 } 075 076 return totalSize; 077 } 078 079 public static boolean gcIfNeeded() { 080 gcCalls += 1; 081 log.debug("GC Thread awake, see if there is some work to be done"); 082 083 long totalSize = getCacheSizeInKBs(); 084 long limit = getMaxDiskSpaceUsageKB(); 085 086 if (totalSize < limit) { 087 log.debug("No GC needed, go back to sleep for now"); 088 return false; 089 } 090 091 // do the GC 092 long deltaInKB = totalSize - limit; 093 log.debug("GC needed to free " + deltaInKB + " KB of data"); 094 doGC(deltaInKB); 095 log.debug("GC terminated"); 096 097 return true; 098 } 099 100 public static void doGC(long deltaInKB) { 101 gcRuns += 1; 102 Map<String, PictureTilingCacheInfo> cache = PictureTilingComponent.getCache(); 103 104 Map<Date, String> sortingMap = new HashMap<Date, String>(); 105 106 for (String key : cache.keySet()) { 107 PictureTilingCacheInfo cacheEntry = cache.get(key); 108 sortingMap.put(cacheEntry.getLastAccessedTime(), key); 109 } 110 111 List<Date> accesTimeList = new ArrayList<Date>(); 112 113 accesTimeList.addAll(sortingMap.keySet()); 114 115 Collections.sort(accesTimeList); 116 117 long deletedVolume = 0; 118 for (Date accessDate : accesTimeList) { 119 PictureTilingCacheInfo cacheEntry = cache.get(sortingMap.get(accessDate)); 120 121 long deletePotential = cacheEntry.getDiskSpaceUsageInBytes() / (1024); 122 123 if (deletePotential > deltaInKB - deletedVolume) { 124 cacheEntry.partialCleanUp(deltaInKB - deletedVolume + 1); 125 return; 126 } else { 127 deletedVolume += deletePotential; 128 cacheEntry.cleanUp(); 129 cache.remove(accessDate); 130 } 131 if (deletedVolume > deltaInKB) 132 break; 133 } 134 } 135 136}