View Javadoc
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 }