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