1 23 24 package org.apache.slide.util; 25 26 import java.util.HashMap ; 27 import java.util.HashSet ; 28 import java.util.Map ; 29 import java.util.Set ; 30 import java.util.Iterator ; 31 32 import org.apache.slide.util.logger.Logger; 33 34 import org.apache.commons.collections.LRUMap; 35 36 51 public class ByteSizeLimitedObjectCache extends TxLRUObjectCache { 52 53 protected static final int MAX_FREEING_TRIES = 10; 55 56 protected long globalByteSize; 57 protected int txCacheSize; 58 protected long txByteSize; 59 protected long maxByteSizePerEntry; 60 61 77 public ByteSizeLimitedObjectCache( 78 int globalCacheSize, 79 int txCacheSize, 80 long globalByteSize, 81 long txByteSize, 82 long maxByteSizePerEntry, 83 String name, 84 Logger logger, 85 boolean noGlobalCachingInsideTx) { 86 super(globalCacheSize, name, logger, noGlobalCachingInsideTx); 87 globalCache = new SizeCountingLRUMap(globalCacheSize, globalByteSize, maxByteSizePerEntry); 88 this.globalByteSize = globalByteSize; 89 this.txCacheSize = txCacheSize; 90 this.txByteSize = txByteSize; 91 this.maxByteSizePerEntry = maxByteSizePerEntry; 92 logChannel = "ByteSizeLimitedObjectCache"; 93 if (name != null) { 94 logChannel += "." + name; 95 } 96 97 } 98 99 public synchronized void clear() { 100 super.clear(); 101 } 102 103 public synchronized boolean canCache(Object txId, long byteSize) { 104 long maxSize; 105 if (txId != null) { 106 maxSize = globalByteSize; 107 } else { 108 maxSize = txByteSize; 109 } 110 return (maxSize >= byteSize && maxByteSizePerEntry >= byteSize); 111 } 112 113 public synchronized void put(Object txId, Object key, Object value, long byteSize) { 114 if (key == null) { 115 logger.log(txId + " adding null key with byte size " + byteSize, logChannel, Logger.WARNING); 116 } 117 118 if (txId != null) { 119 Set deleteCache = (Set ) txDeleteCaches.get(txId); 121 deleteCache.remove(key); 122 123 SizeCountingLRUMap changeCache = (SizeCountingLRUMap) txChangeCaches.get(txId); 124 changeCache.put(key, value, byteSize); 125 126 if (loggingEnabled) { 127 logger.log(txId + " added '" + key + "' with byte size " + byteSize, logChannel, Logger.DEBUG); 128 } 129 } else { 130 ((SizeCountingLRUMap) globalCache).put(key, value, byteSize); 131 if (loggingEnabled) { 132 logger.log("Added '" + key + "' with byte size " + byteSize, logChannel, Logger.DEBUG); 133 } 134 } 135 } 136 137 public synchronized void start(Object txId) { 138 if (txId != null) { 139 txChangeCaches.put(txId, new SizeCountingLRUMap(txCacheSize, txByteSize, maxByteSizePerEntry, txId)); 140 txDeleteCaches.put(txId, new HashSet ()); 141 } 142 } 143 144 public synchronized void commit(Object txId) { 145 if (txId != null) { 146 148 SizeCountingLRUMap changeCache = (SizeCountingLRUMap) txChangeCaches.get(txId); 149 for (Iterator it = changeCache.entrySet().iterator(); it.hasNext();) { 150 Map.Entry entry = (Map.Entry ) it.next(); 151 long byteSize = changeCache.getByteSize(entry.getKey()); 152 if (byteSize == -1L) { 153 globalCache.put(entry.getKey(), entry.getValue()); 154 } else { 155 ((SizeCountingLRUMap) globalCache).put(entry.getKey(), entry.getValue(), byteSize); 156 } 157 } 158 159 Set deleteCache = (Set ) txDeleteCaches.get(txId); 160 for (Iterator it = deleteCache.iterator(); it.hasNext();) { 161 Object key = it.next(); 162 globalCache.remove(key); 163 } 164 165 if (loggingEnabled) { 166 logger.log( 167 txId 168 + " committed " 169 + changeCache.size() 170 + " changes and " 171 + deleteCache.size() 172 + " scheduled deletes", 173 logChannel, 174 Logger.DEBUG); 175 } 176 177 forget(txId); 179 } 180 } 181 182 protected class SizeCountingLRUMap extends LRUMap { 183 184 private Map shadowSizes; 185 private long globalSize; 186 private long maxByteSize; 187 private long maxByteSizePerEntry; 188 private Object txId; 189 190 public SizeCountingLRUMap(int size, long maxByteSize, long maxByteSizePerEntry, Object txId) { 191 this(size, maxByteSize, maxByteSizePerEntry); 192 this.txId = txId; 193 } 194 195 public SizeCountingLRUMap(int size, long maxByteSize, long maxByteSizePerEntry) { 196 super(size); 197 this.shadowSizes = new HashMap(); 198 this.globalSize = 0; 199 this.maxByteSize = maxByteSize; 200 this.maxByteSizePerEntry = maxByteSizePerEntry; 201 } 202 203 public Object put(Object key, Object value, long byteSize) { 204 if (byteSize > maxByteSizePerEntry || byteSize > maxByteSize) { 206 if (loggingEnabled) { 207 logger.log(txId + " for '" + key + "' is too big to be cached", logChannel, Logger.DEBUG); 208 } 209 Object oldValue = get(key); 210 invalidate(key); 216 return oldValue; 217 } else { 218 freeBytes(key); 220 221 for (int i = 0; globalSize + byteSize > maxByteSize && i < MAX_FREEING_TRIES; i++) { 223 if (loggingEnabled) { 224 logger.log(txId + " for '" + key + "' needs " 225 + Long.toString(globalSize + byteSize - maxByteSize) 226 + " bytes more to be cached. Freeing bytes!", logChannel, Logger.DEBUG); 227 } 228 removeLRU(); 231 } 232 } 233 if (globalSize + byteSize <= maxByteSize) { 235 shadowSizes.put(key, new Long (byteSize)); 236 globalSize += byteSize; 237 return super.put(key, value); 238 } else { 239 Object oldValue = get(key); 240 invalidate(key); 241 return oldValue; 242 } 243 } 244 245 public long getByteSize(Object key) { 246 Long lSize = (Long ) shadowSizes.get(key); 247 if (lSize != null) { 248 return lSize.longValue(); 249 } else { 250 return -1L; 251 } 252 } 253 254 protected void freeBytes(Object key) { 255 Long lSize = (Long ) shadowSizes.remove(key); 256 if (lSize != null) { 257 long size = lSize.longValue(); 258 globalSize -= size; 259 } 260 } 261 262 protected void invalidate(Object key) { 263 freeBytes(key); 266 ByteSizeLimitedObjectCache.this.remove(txId, key); 267 if (loggingEnabled) { 268 logger.log(txId + " invalidated '" + key + "'", logChannel, Logger.DEBUG); 269 } 270 } 271 272 protected void processRemovedLRU(Object key, Object value) { 274 invalidate(key); 275 } 276 } 277 } 278 | Popular Tags |