1 package org.apache.directmemory.guava;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.List;
23 import java.util.Map;
24 import java.util.concurrent.Callable;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.TimeUnit;
27
28 import org.apache.directmemory.cache.CacheService;
29
30 import com.google.common.base.Stopwatch;
31 import com.google.common.cache.Cache;
32 import com.google.common.cache.CacheStats;
33 import com.google.common.cache.ForwardingCache;
34 import com.google.common.cache.RemovalCause;
35 import com.google.common.cache.RemovalListener;
36 import com.google.common.cache.RemovalNotification;
37 import com.google.common.collect.ImmutableMap;
38 import com.google.common.collect.Lists;
39 import com.google.common.collect.Maps;
40
41 import static com.google.common.cache.AbstractCache.SimpleStatsCounter;
42 import static com.google.common.cache.AbstractCache.StatsCounter;
43
44
45
46
47 public class OffHeapCache<K, V>
48 extends ForwardingCache.SimpleForwardingCache<K, V>
49 implements RemovalListener<K, V>
50 {
51 private final CacheService<K, V> cacheService;
52
53 private final StatsCounter statsCounter = new SimpleStatsCounter();
54
55
56 public OffHeapCache( CacheService<K, V> cacheService, Cache<K, V> primaryCache, ForwardingListener<K, V> listener )
57 {
58 super( primaryCache );
59 this.cacheService = cacheService;
60 listener.setDelegate( this );
61 }
62
63 @Override
64 public V getIfPresent( Object key )
65 {
66 V result = super.getIfPresent( key );
67 if ( result == null )
68 {
69 result = retrieve( key );
70 }
71 return result;
72 }
73
74
75 @Override
76 public V get( final K key, final Callable<? extends V> valueLoader )
77 throws ExecutionException
78 {
79 return super.get( key, new Callable<V>()
80 {
81 @Override
82 public V call()
83 throws Exception
84 {
85
86 V result = retrieve( key );
87
88
89 if ( result == null )
90 {
91 result = valueLoader.call();
92 }
93 return result;
94 }
95 } );
96 }
97
98 @Override
99 public ImmutableMap<K, V> getAllPresent( Iterable<?> keys )
100 {
101 List<?> list = Lists.newArrayList( keys );
102 ImmutableMap<K, V> result = super.getAllPresent( list );
103
104
105
106 if ( result.size() == list.size() )
107 {
108 return result;
109 }
110
111
112 Map<K, V> r2 = Maps.newHashMap( result );
113 for ( Object key : list )
114 {
115 if ( !result.containsKey( key ) )
116 {
117 V val = retrieve( key );
118 if ( val != null )
119 {
120
121
122
123 r2.put( (K) key, val );
124 }
125 }
126 }
127 return ImmutableMap.copyOf( r2 );
128 }
129
130 @Override
131 public void invalidate( Object key )
132 {
133 super.invalidate( key );
134 cacheService.free( (K) key );
135 }
136
137 @Override
138 public void invalidateAll( Iterable<?> keys )
139 {
140 super.invalidateAll( keys );
141 for ( Object key : keys )
142 {
143 cacheService.free( (K) key );
144 }
145 }
146
147 @Override
148 public void invalidateAll()
149 {
150 super.invalidateAll();
151
152 for ( K key : cacheService.getMap().keySet() )
153 {
154 cacheService.free( key );
155 }
156 }
157
158 @Override
159 public void onRemoval( RemovalNotification<K, V> notification )
160 {
161 if ( notification.getCause() == RemovalCause.SIZE )
162 {
163 cacheService.put( notification.getKey(), notification.getValue() );
164 }
165 }
166
167 public CacheStats offHeapStats()
168 {
169 return statsCounter.snapshot();
170 }
171
172 protected V retrieve( Object key )
173 {
174 Stopwatch watch = new Stopwatch().start();
175
176 V value = cacheService.retrieve( (K) key );
177
178 if ( value != null )
179 {
180 statsCounter.recordLoadSuccess( watch.elapsed( TimeUnit.NANOSECONDS ) );
181 }
182 else
183 {
184 statsCounter.recordMisses( 1 );
185 }
186
187 return value;
188 }
189
190 }