1 package com.atlassian.cache.memory;
2
3 import java.util.SortedMap;
4
5 import javax.annotation.Nonnull;
6 import javax.annotation.Nullable;
7
8 import com.atlassian.cache.CacheException;
9 import com.atlassian.cache.CacheSettings;
10 import com.atlassian.cache.CacheStatisticsKey;
11 import com.atlassian.cache.CachedReference;
12 import com.atlassian.cache.CachedReferenceListener;
13 import com.atlassian.cache.impl.CachedReferenceListenerSupport;
14 import com.atlassian.cache.impl.DefaultCachedReferenceListenerSupport;
15 import com.atlassian.cache.impl.ReferenceKey;
16 import com.atlassian.instrumentation.caches.CacheCollector;
17
18 import com.google.common.cache.LoadingCache;
19 import com.google.common.cache.RemovalListener;
20 import com.google.common.cache.RemovalNotification;
21 import com.google.common.collect.ImmutableSortedMap;
22 import com.google.common.util.concurrent.UncheckedExecutionException;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import static com.atlassian.cache.memory.DelegatingCacheStatistics.toStatistics;
27
28
29
30
31
32
33 class DelegatingCachedReference<V> extends ManagedCacheSupport implements CachedReference<V>
34 {
35 static final CreateFunction DEFAULT_CREATE_FUNCTION = new DefaultCreateFunction();
36
37 private final Logger eventLogger;
38 private final Logger stacktraceLogger;
39
40 private final LoadingCache<ReferenceKey, V> internalCache;
41 private final CachedReferenceListenerSupport<V> listenerSupport;
42 private final CacheCollector collector;
43
44 protected DelegatingCachedReference(final LoadingCache<ReferenceKey, V> internalCache,
45 String name, CacheSettings settings, final CacheCollector collector)
46 {
47 super(name, settings);
48 this.internalCache = internalCache;
49
50 this.listenerSupport = new DefaultCachedReferenceListenerSupport<V>();
51 this.collector = collector;
52
53 this.eventLogger = LoggerFactory.getLogger("com.atlassian.cache.event." + name);
54 this.stacktraceLogger = LoggerFactory.getLogger("com.atlassian.cache.stacktrace." + name);
55 }
56
57 static <V> DelegatingCachedReference<V> create(final LoadingCache<ReferenceKey, V> internalCache,
58 String name, CacheSettings settings, CacheCollector collector)
59 {
60 return DEFAULT_CREATE_FUNCTION.create(internalCache, name, settings, collector);
61 }
62
63 @Override
64 public CacheCollector getCacheCollector()
65 {
66 return collector;
67 }
68
69 @Nonnull
70 @Override
71 public V get()
72 {
73 try
74 {
75 V value = internalCache.getIfPresent(ReferenceKey.KEY);
76 if (value != null)
77 {
78 if (isCollectorStatisticsEnabled())
79 {
80 collector.hit();
81 }
82 return value;
83 }
84 else
85 {
86 return getUnderLock();
87 }
88 }
89 catch (UncheckedExecutionException e)
90 {
91 throw new CacheException(e.getCause());
92 }
93 catch (Exception e)
94 {
95 throw new CacheException(e);
96 }
97 }
98
99 synchronized private V getUnderLock()
100 {
101 return internalCache.getUnchecked(ReferenceKey.KEY);
102 }
103
104 @Override
105 synchronized public void reset()
106 {
107 try
108 {
109 internalCache.invalidate(ReferenceKey.KEY);
110 if (isCollectorStatisticsEnabled())
111 {
112 collector.remove();
113 }
114 eventLogger.info("Cache {} was flushed", getName());
115 if (stacktraceLogger.isInfoEnabled()) {
116 stacktraceLogger.info("Cache {} was flushed. Stacktrace:", getName(), new Exception());
117 }
118 }
119 catch (Exception e)
120 {
121 throw new CacheException(e);
122 }
123 }
124
125 @Override
126 public void clear()
127 {
128 reset();
129 }
130
131 private boolean isCollectorStatisticsEnabled()
132 {
133 return collector.isEnabled();
134 }
135
136 @Override
137 public boolean isStatisticsEnabled() {
138 return settings.getStatisticsEnabled();
139 }
140
141 @Override
142 public boolean equals(@Nullable final Object other)
143 {
144 if (other instanceof DelegatingCachedReference)
145 {
146 DelegatingCachedReference<?> otherDelegatingReference = (DelegatingCachedReference<?>) other;
147 if (internalCache.equals(otherDelegatingReference.internalCache))
148 {
149 return true;
150 }
151 }
152 return false;
153 }
154
155 @Override
156 public int hashCode()
157 {
158 return 3 + internalCache.hashCode();
159 }
160
161 @Nonnull
162 @Override
163 public SortedMap<CacheStatisticsKey, java.util.function.Supplier<Long>> getStatistics()
164 {
165 if (isStatisticsEnabled())
166 {
167 return toStatistics(internalCache);
168 }
169 else
170 {
171 return ImmutableSortedMap.of();
172 }
173 }
174
175 @Override
176 public void addListener(@Nonnull CachedReferenceListener<V> listener, boolean includeValues)
177 {
178 listenerSupport.add(listener, includeValues);
179 }
180
181 @Override
182 public void removeListener(@Nonnull CachedReferenceListener<V> listener)
183 {
184 listenerSupport.remove(listener);
185 }
186
187 protected static class DelegatingReferenceRemovalListener<V> implements RemovalListener<ReferenceKey, V>
188 {
189 private DelegatingCachedReference<V> cachedReference;
190
191 protected void onSupply(V value)
192 {
193 cachedReference.listenerSupport.notifySet(value);
194 }
195
196 @Override
197 public void onRemoval(RemovalNotification<ReferenceKey, V> notification)
198 {
199 switch (notification.getCause())
200 {
201 case COLLECTED:
202 case EXPIRED:
203 cachedReference.listenerSupport.notifyEvict(notification.getValue());
204 break;
205 case EXPLICIT:
206 cachedReference.listenerSupport.notifyReset(notification.getValue());
207 break;
208 case REPLACED:
209 V value = cachedReference.internalCache.getIfPresent(ReferenceKey.KEY);
210 cachedReference.listenerSupport.notifySet(value);
211 break;
212 }
213 }
214
215 public void setCachedReference(DelegatingCachedReference<V> cachedReference)
216 {
217 this.cachedReference = cachedReference;
218 }
219 }
220
221 public interface CreateFunction
222 {
223 <V> DelegatingCachedReference<V> create(final LoadingCache<ReferenceKey, V> internalCache,
224 String name, CacheSettings settings, CacheCollector collector);
225 }
226
227 public static class DefaultCreateFunction implements CreateFunction
228 {
229
230 @Override
231 public <V> DelegatingCachedReference<V> create(final LoadingCache<ReferenceKey, V> internalCache,
232 String name, CacheSettings settings, CacheCollector collector) {
233 return new DelegatingCachedReference<>(internalCache, name, settings, collector);
234 }
235 }
236 }