001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Nuxeo - initial API and implementation 011 * 012 * $Id$ 013 * 014 */ 015package org.nuxeo.ecm.core.convert.cache; 016 017import java.util.ArrayList; 018import java.util.Collections; 019import java.util.Date; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027import org.nuxeo.ecm.core.convert.service.ConversionServiceImpl; 028 029/** 030 * Manages GC processing to clean up disk cache. 031 * 032 * @author tiry 033 */ 034public class ConversionCacheGCManager { 035 036 public static final String MAX_DISK_SPACE_USAGE_KEY = "MaxDiskSpaceUsageForCache"; 037 038 public static final long MAX_DISK_SPACE_USAGE_KB = 1000; 039 040 private static final Log log = LogFactory.getLog(ConversionCacheGCManager.class); 041 042 private static int gcRuns = 0; 043 044 private static int gcCalls = 0; 045 046 // Utility class. 047 private ConversionCacheGCManager() { 048 } 049 050 protected static int getMaxDiskSpaceUsageKB() { 051 return ConversionServiceImpl.getMaxCacheSizeInKB(); 052 } 053 054 public static int getGCRuns() { 055 return gcRuns; 056 } 057 058 public static int getGCCalls() { 059 return gcCalls; 060 } 061 062 public static long getCacheSizeInKB() { 063 long totalSize = 0; 064 Set<String> cacheKeys = ConversionCacheHolder.getCacheKeys(); 065 066 for (String key : cacheKeys) { 067 ConversionCacheEntry cacheEntry = ConversionCacheHolder.getCacheEntry(key); 068 if (cacheEntry != null) { 069 totalSize += cacheEntry.getDiskSpaceUsageInKB(); 070 } 071 } 072 return totalSize; 073 } 074 075 public static boolean gcIfNeeded() { 076 log.debug("GC Thread awake, see if there is some work to be done"); 077 078 long totalSize = getCacheSizeInKB(); 079 long limit = getMaxDiskSpaceUsageKB(); 080 081 if (totalSize < limit) { 082 gcCalls += 1; 083 log.debug("No GC needed, go back to sleep for now"); 084 return false; 085 } 086 087 // do the GC 088 long deltaInKB = totalSize - limit; 089 if (limit < 0) { 090 // mainly for testing : negative limit means cleanup everything 091 deltaInKB = totalSize; 092 } 093 log.debug("GC needed to free " + deltaInKB + " KB of data"); 094 doGC(deltaInKB); 095 log.debug("GC terminated"); 096 gcCalls += 1; 097 return true; 098 } 099 100 public static void doGC(long deltaInKB) { 101 102 Set<String> cacheKeys = ConversionCacheHolder.getCacheKeys(); 103 104 Map<Date, String> sortingMap = new HashMap<Date, String>(); 105 106 for (String key : cacheKeys) { 107 ConversionCacheEntry cacheEntry = ConversionCacheHolder.getCacheEntry(key); 108 if (key != null) { 109 sortingMap.put(cacheEntry.getLastAccessedTime(), key); 110 } 111 } 112 113 List<Date> accessTimeList = new ArrayList<Date>(); 114 accessTimeList.addAll(sortingMap.keySet()); 115 Collections.sort(accessTimeList); 116 117 long deletedVolume = 0; 118 for (Date accessDate : accessTimeList) { 119 ConversionCacheEntry cacheEntry = ConversionCacheHolder.getCacheEntry(sortingMap.get(accessDate)); 120 121 long deletePotential = cacheEntry.getDiskSpaceUsageInKB(); 122 123 deletedVolume += deletePotential; 124 ConversionCacheHolder.removeFromCache(sortingMap.get(accessDate)); 125 126 if (deletedVolume > deltaInKB) { 127 break; 128 } 129 } 130 gcRuns += 1; 131 } 132 133}