001package org.apache.commons.jcs3.engine.memory.lru; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.IOException; 023import java.util.Collections; 024import java.util.Map; 025 026import org.apache.commons.jcs3.engine.behavior.ICacheElement; 027import org.apache.commons.jcs3.engine.control.CompositeCache; 028import org.apache.commons.jcs3.engine.memory.AbstractMemoryCache; 029import org.apache.commons.jcs3.engine.memory.util.MemoryElementDescriptor; 030import org.apache.commons.jcs3.engine.stats.behavior.IStats; 031import org.apache.commons.jcs3.log.Log; 032import org.apache.commons.jcs3.log.LogManager; 033 034/** 035 * This is a test memory manager using the jdk1.4 LinkedHashMap. 036 */ 037public class LHMLRUMemoryCache<K, V> 038 extends AbstractMemoryCache<K, V> 039{ 040 /** The Logger. */ 041 private static final Log log = LogManager.getLog( LRUMemoryCache.class ); 042 043 /** 044 * For post reflection creation initialization 045 * <p> 046 * @param hub 047 */ 048 @Override 049 public void initialize( final CompositeCache<K, V> hub ) 050 { 051 super.initialize( hub ); 052 log.info( "initialized LHMLRUMemoryCache for {0}", this::getCacheName ); 053 } 054 055 /** 056 * Returns a synchronized LHMSpooler 057 * <p> 058 * @return Collections.synchronizedMap( new LHMSpooler() ) 059 */ 060 @Override 061 public Map<K, MemoryElementDescriptor<K, V>> createMap() 062 { 063 return Collections.synchronizedMap( new LHMSpooler() ); 064 } 065 066 /** 067 * Puts an item to the cache. 068 * <p> 069 * @param ce Description of the Parameter 070 * @throws IOException 071 */ 072 @Override 073 public void update( final ICacheElement<K, V> ce ) 074 throws IOException 075 { 076 putCnt.incrementAndGet(); 077 map.put( ce.getKey(), new MemoryElementDescriptor<>(ce) ); 078 } 079 080 /** 081 * Update control structures after get 082 * (guarded by the lock) 083 * 084 * @param me the memory element descriptor 085 */ 086 @Override 087 protected void lockedGetElement(final MemoryElementDescriptor<K, V> me) 088 { 089 // empty 090 } 091 092 /** 093 * Remove element from control structure 094 * (guarded by the lock) 095 * 096 * @param me the memory element descriptor 097 */ 098 @Override 099 protected void lockedRemoveElement(final MemoryElementDescriptor<K, V> me) 100 { 101 // empty 102 } 103 104 /** 105 * Removes all cached items from the cache control structures. 106 * (guarded by the lock) 107 */ 108 @Override 109 protected void lockedRemoveAll() 110 { 111 // empty 112 } 113 114 /** 115 * This returns semi-structured information on the memory cache, such as the size, put count, 116 * hit count, and miss count. 117 * <p> 118 * @return IStats 119 */ 120 @Override 121 public IStats getStatistics() 122 { 123 final IStats stats = super.getStatistics(); 124 stats.setTypeName( "LHMLRU Memory Cache" ); 125 126 return stats; 127 } 128 129 // ---------------------------------------------------------- debug methods 130 131 /** 132 * Dump the cache entries from first to last for debugging. 133 */ 134 public void dumpCacheEntries() 135 { 136 dumpMap(); 137 } 138 139 /** 140 * This can't be implemented. 141 * <p> 142 * @param numberToFree 143 * @return 0 144 * @throws IOException 145 */ 146 @Override 147 public int freeElements( final int numberToFree ) 148 throws IOException 149 { 150 // can't be implemented using the LHM 151 return 0; 152 } 153 154 // ---------------------------------------------------------- extended map 155 156 /** 157 * Implementation of removeEldestEntry in LinkedHashMap 158 */ 159 protected class LHMSpooler 160 extends java.util.LinkedHashMap<K, MemoryElementDescriptor<K, V>> 161 { 162 /** Don't change. */ 163 private static final long serialVersionUID = -1255907868906762484L; 164 165 /** 166 * Initialize to a small size--for now, 1/2 of max 3rd variable "true" indicates that it 167 * should be access and not time governed. This could be configurable. 168 */ 169 public LHMSpooler() 170 { 171 super( (int) ( getCacheAttributes().getMaxObjects() * .5 ), .75F, true ); 172 } 173 174 /** 175 * Remove eldest. Automatically called by LinkedHashMap. 176 * <p> 177 * @param eldest 178 * @return true if removed 179 */ 180 @SuppressWarnings("synthetic-access") 181 @Override 182 protected boolean removeEldestEntry( final Map.Entry<K, MemoryElementDescriptor<K, V>> eldest ) 183 { 184 final ICacheElement<K, V> element = eldest.getValue().getCacheElement(); 185 186 if ( size() <= getCacheAttributes().getMaxObjects() ) 187 { 188 return false; 189 } 190 log.debug( "LHMLRU max size: {0}. Spooling element, key: {1}", 191 () -> getCacheAttributes().getMaxObjects(), element::getKey); 192 193 waterfal( element ); 194 195 log.debug( "LHMLRU size: {0}", () -> map.size() ); 196 return true; 197 } 198 } 199}