001/* 002 * (C) Copyright 2006-2011 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.core.convert.cache; 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; 030import java.util.Set; 031 032import org.apache.commons.logging.Log; 033import org.apache.commons.logging.LogFactory; 034import org.nuxeo.ecm.core.convert.service.ConversionServiceImpl; 035 036/** 037 * Manages GC processing to clean up disk cache. 038 * 039 * @author tiry 040 */ 041public class ConversionCacheGCManager { 042 043 public static final String MAX_DISK_SPACE_USAGE_KEY = "MaxDiskSpaceUsageForCache"; 044 045 public static final long MAX_DISK_SPACE_USAGE_KB = 1000; 046 047 private static final Log log = LogFactory.getLog(ConversionCacheGCManager.class); 048 049 private static int gcRuns = 0; 050 051 private static int gcCalls = 0; 052 053 // Utility class. 054 private ConversionCacheGCManager() { 055 } 056 057 protected static int getMaxDiskSpaceUsageKB() { 058 return ConversionServiceImpl.getMaxCacheSizeInKB(); 059 } 060 061 public static int getGCRuns() { 062 return gcRuns; 063 } 064 065 public static int getGCCalls() { 066 return gcCalls; 067 } 068 069 public static long getCacheSizeInKB() { 070 long totalSize = 0; 071 Set<String> cacheKeys = ConversionCacheHolder.getCacheKeys(); 072 073 for (String key : cacheKeys) { 074 ConversionCacheEntry cacheEntry = ConversionCacheHolder.getCacheEntry(key); 075 if (cacheEntry != null) { 076 totalSize += cacheEntry.getDiskSpaceUsageInKB(); 077 } 078 } 079 return totalSize; 080 } 081 082 public static boolean gcIfNeeded() { 083 log.debug("GC Thread awake, see if there is some work to be done"); 084 085 long totalSize = getCacheSizeInKB(); 086 long limit = getMaxDiskSpaceUsageKB(); 087 088 if (totalSize < limit) { 089 gcCalls += 1; 090 log.debug("No GC needed, go back to sleep for now"); 091 return false; 092 } 093 094 // do the GC 095 long deltaInKB = totalSize - limit; 096 if (limit < 0) { 097 // mainly for testing : negative limit means cleanup everything 098 deltaInKB = totalSize; 099 } 100 log.debug("GC needed to free " + deltaInKB + " KB of data"); 101 doGC(deltaInKB); 102 log.debug("GC terminated"); 103 gcCalls += 1; 104 return true; 105 } 106 107 public static void doGC(long deltaInKB) { 108 109 Set<String> cacheKeys = ConversionCacheHolder.getCacheKeys(); 110 111 Map<Date, String> sortingMap = new HashMap<Date, String>(); 112 113 for (String key : cacheKeys) { 114 ConversionCacheEntry cacheEntry = ConversionCacheHolder.getCacheEntry(key); 115 if (key != null) { 116 sortingMap.put(cacheEntry.getLastAccessedTime(), key); 117 } 118 } 119 120 List<Date> accessTimeList = new ArrayList<Date>(); 121 accessTimeList.addAll(sortingMap.keySet()); 122 Collections.sort(accessTimeList); 123 124 long deletedVolume = 0; 125 for (Date accessDate : accessTimeList) { 126 ConversionCacheEntry cacheEntry = ConversionCacheHolder.getCacheEntry(sortingMap.get(accessDate)); 127 128 long deletePotential = cacheEntry.getDiskSpaceUsageInKB(); 129 130 deletedVolume += deletePotential; 131 ConversionCacheHolder.removeFromCache(sortingMap.get(accessDate)); 132 133 if (deletedVolume > deltaInKB) { 134 break; 135 } 136 } 137 gcRuns += 1; 138 } 139 140}