1 package org.apache.commons.jcs3.engine.memory.lru;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.IOException;
23 import java.util.Collections;
24 import java.util.Map;
25
26 import org.apache.commons.jcs3.engine.behavior.ICacheElement;
27 import org.apache.commons.jcs3.engine.control.CompositeCache;
28 import org.apache.commons.jcs3.engine.memory.AbstractMemoryCache;
29 import org.apache.commons.jcs3.engine.memory.util.MemoryElementDescriptor;
30 import org.apache.commons.jcs3.engine.stats.behavior.IStats;
31 import org.apache.commons.jcs3.log.Log;
32 import org.apache.commons.jcs3.log.LogManager;
33
34 /**
35 * This is a test memory manager using the jdk1.4 LinkedHashMap.
36 */
37 public class LHMLRUMemoryCache<K, V>
38 extends AbstractMemoryCache<K, V>
39 {
40 /** The Logger. */
41 private static final Log log = LogManager.getLog( LRUMemoryCache.class );
42
43 /**
44 * For post reflection creation initialization
45 * <p>
46 * @param hub
47 */
48 @Override
49 public void initialize( final CompositeCache<K, V> hub )
50 {
51 super.initialize( hub );
52 log.info( "initialized LHMLRUMemoryCache for {0}", this::getCacheName );
53 }
54
55 /**
56 * Returns a synchronized LHMSpooler
57 * <p>
58 * @return Collections.synchronizedMap( new LHMSpooler() )
59 */
60 @Override
61 public Map<K, MemoryElementDescriptor<K, V>> createMap()
62 {
63 return Collections.synchronizedMap( new LHMSpooler() );
64 }
65
66 /**
67 * Puts an item to the cache.
68 * <p>
69 * @param ce Description of the Parameter
70 * @throws IOException
71 */
72 @Override
73 public void update( final ICacheElement<K, V> ce )
74 throws IOException
75 {
76 putCnt.incrementAndGet();
77 map.put( ce.getKey(), new MemoryElementDescriptor<>(ce) );
78 }
79
80 /**
81 * Update control structures after get
82 * (guarded by the lock)
83 *
84 * @param me the memory element descriptor
85 */
86 @Override
87 protected void lockedGetElement(final MemoryElementDescriptor<K, V> me)
88 {
89 // empty
90 }
91
92 /**
93 * Remove element from control structure
94 * (guarded by the lock)
95 *
96 * @param me the memory element descriptor
97 */
98 @Override
99 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 }