001/* 002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id$ 020 * 021 */ 022package org.nuxeo.ecm.platform.pictures.tiles.service; 023 024import java.util.ArrayList; 025import java.util.Collections; 026import java.util.Date; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033 034/** 035 * Manage GC processing to clean up disk cache 036 * 037 * @author tiry 038 */ 039public class PictureTilingCacheGCManager { 040 041 public static final String MAX_DISK_SPACE_USAGE_KEY = "MaxDiskSpaceUsageForCache"; 042 043 public static final long MAX_DISK_SPACE_USAGE_KB = 1000; 044 045 private static final Log log = LogFactory.getLog(PictureTilingCacheGCManager.class); 046 047 private static int gcRuns = 0; 048 049 private static int gcCalls = 0; 050 051 protected static long getMaxDiskSpaceUsageKB() { 052 String maxStr = PictureTilingComponent.getEnvValue(MAX_DISK_SPACE_USAGE_KEY, 053 Long.toString(MAX_DISK_SPACE_USAGE_KB)); 054 return Long.parseLong(maxStr); 055 } 056 057 public static int getGCRuns() { 058 return gcRuns; 059 } 060 061 public static int getGCCalls() { 062 return gcCalls; 063 } 064 065 public static long getCacheSizeInKBs() { 066 return getCacheSizeInBytes() / 1000; 067 } 068 069 public static long getCacheSizeInBytes() { 070 long totalSize = 0; 071 Map<String, PictureTilingCacheInfo> cache = PictureTilingComponent.getCache(); 072 073 for (String key : cache.keySet()) { 074 PictureTilingCacheInfo cacheEntry = cache.get(key); 075 totalSize += cacheEntry.getDiskSpaceUsageInBytes(); 076 } 077 078 return totalSize; 079 } 080 081 public static boolean gcIfNeeded() { 082 gcCalls += 1; 083 log.debug("GC Thread awake, see if there is some work to be done"); 084 085 long totalSize = getCacheSizeInKBs(); 086 long limit = getMaxDiskSpaceUsageKB(); 087 088 if (totalSize < limit) { 089 log.debug("No GC needed, go back to sleep for now"); 090 return false; 091 } 092 093 // do the GC 094 long deltaInKB = totalSize - limit; 095 log.debug("GC needed to free " + deltaInKB + " KB of data"); 096 doGC(deltaInKB); 097 log.debug("GC terminated"); 098 099 return true; 100 } 101 102 public static void doGC(long deltaInKB) { 103 gcRuns += 1; 104 Map<String, PictureTilingCacheInfo> cache = PictureTilingComponent.getCache(); 105 106 Map<Date, String> sortingMap = new HashMap<Date, String>(); 107 108 for (String key : cache.keySet()) { 109 PictureTilingCacheInfo cacheEntry = cache.get(key); 110 sortingMap.put(cacheEntry.getLastAccessedTime(), key); 111 } 112 113 List<Date> accesTimeList = new ArrayList<Date>(); 114 115 accesTimeList.addAll(sortingMap.keySet()); 116 117 Collections.sort(accesTimeList); 118 119 long deletedVolume = 0; 120 for (Date accessDate : accesTimeList) { 121 PictureTilingCacheInfo cacheEntry = cache.get(sortingMap.get(accessDate)); 122 123 long deletePotential = cacheEntry.getDiskSpaceUsageInBytes() / (1024); 124 125 if (deletePotential > deltaInKB - deletedVolume) { 126 cacheEntry.partialCleanUp(deltaInKB - deletedVolume + 1); 127 return; 128 } else { 129 deletedVolume += deletePotential; 130 cacheEntry.cleanUp(); 131 cache.remove(accessDate); 132 } 133 if (deletedVolume > deltaInKB) 134 break; 135 } 136 } 137 138}