1 package com.atlassian.cache.vcache;
2
3 import java.io.Serializable;
4 import java.time.Duration;
5 import javax.annotation.Nonnull;
6 import javax.annotation.Nullable;
7
8 import com.atlassian.cache.Cache;
9 import com.atlassian.cache.CacheLoader;
10 import com.atlassian.cache.CacheSettings;
11 import com.atlassian.cache.CacheSettingsDefaultsProvider;
12 import com.atlassian.cache.CachedReference;
13 import com.atlassian.cache.ManagedCache;
14 import com.atlassian.cache.Supplier;
15 import com.atlassian.cache.impl.AbstractCacheManager;
16 import com.atlassian.cache.impl.StrongSupplier;
17 import com.atlassian.cache.impl.WeakSupplier;
18 import com.atlassian.vcache.DirectExternalCache;
19 import com.atlassian.vcache.ExternalCacheSettings;
20 import com.atlassian.vcache.ExternalCacheSettingsBuilder;
21 import com.atlassian.vcache.JvmCache;
22 import com.atlassian.vcache.JvmCacheSettings;
23 import com.atlassian.vcache.JvmCacheSettingsBuilder;
24 import com.atlassian.vcache.StableReadExternalCache;
25 import com.atlassian.vcache.VCacheFactory;
26 import com.atlassian.vcache.marshallers.MarshallerFactory;
27
28 import static java.util.Objects.requireNonNull;
29
30
31
32
33
34
35 public class VCacheCacheManager extends AbstractCacheManager
36 {
37 private static final String PREFIX = "atlassian-cache.";
38 private static final String PREFIX_CACHE = PREFIX + "Cache.";
39 private static final String PREFIX_HYBRID_LOCAL_CACHE = PREFIX + "Hybrid.Local.";
40 private static final String PREFIX_HYBRID_GLOBAL_CACHE = PREFIX + "Hybrid.Global.";
41 private static final String PREFIX_CACHE_REFERENCE = PREFIX + "CacheReference.";
42
43 private final VCacheFactory vCacheFactory;
44
45 public VCacheCacheManager(VCacheFactory vCacheFactory,
46 CacheSettingsDefaultsProvider cacheSettingsDefaultsProvider)
47 {
48 super(cacheSettingsDefaultsProvider);
49 this.vCacheFactory = requireNonNull(vCacheFactory);
50 }
51
52 @Override
53 protected <K, V> ManagedCache createComputingCache(final String name, final CacheSettings settings, @Nullable final CacheLoader<K, V> loader)
54 {
55
56
57 return cacheCreationLocks.apply(name).withLock((java.util.function.Supplier<ManagedCache>) () -> {
58 if (!caches.containsKey(name) || loader != null)
59 {
60 caches.put(name, new WeakSupplier<>((ManagedCache) doCreateCache(name, loader, settings)));
61 }
62 return caches.get(name).get();
63 });
64 }
65
66 @Override
67 protected ManagedCache createSimpleCache(@Nonnull final String name, @Nonnull final CacheSettings settings)
68 {
69 ManagedCache existing = getManagedCache(name);
70 if (existing != null)
71 {
72 return existing;
73 }
74
75 return cacheCreationLocks.apply(name).withLock((java.util.function.Supplier<ManagedCache>) () -> {
76 if (!caches.containsKey(name))
77 {
78 caches.put(name, new StrongSupplier<>((ManagedCache) doCreateCache(name, null, settings)));
79 }
80 return caches.get(name).get();
81 });
82 }
83
84
85 @Nonnull
86 @Override
87 public <V> CachedReference<V> getCachedReference(@Nonnull final String name, @Nonnull final Supplier<V> supplier,
88 @Nonnull final CacheSettings settings)
89 {
90 return cacheCreationLocks.apply(name).withLock((java.util.function.Supplier<CachedReference<V>>) () -> {
91 caches.put(name, new WeakSupplier<>((ManagedCache) doCreateCachedReference(name, supplier, settings)));
92
93 return (CachedReference<V>) caches.get(name).get();
94 });
95 }
96
97 private <K, V> Cache<K, V> createLocalCache(String name, @Nullable CacheLoader<K, V> loader, CacheSettings settings)
98 {
99 final String mapName = PREFIX_CACHE + name;
100 final JvmCacheSettings vSettings = buildJvmSettings(settings);
101 final JvmCache<K, V> vcache = vCacheFactory.getJvmCache(mapName, vSettings);
102
103 return new JvmCacheDelegate<>(name, vcache, loader, settings);
104 }
105
106 private Cache<String, Serializable> createDistributedCache(String name, @Nullable CacheLoader<String, Serializable> loader, CacheSettings settings)
107 {
108 final ExternalCacheSettings vSettings = buildExternalCacheSettings(settings);
109
110 final String mapName = PREFIX_CACHE + name;
111 final DirectExternalCache<Serializable> vcache =
112 vCacheFactory.getDirectExternalCache(
113 mapName, MarshallerFactory.serializableMarshaller(Serializable.class), vSettings);
114
115
116 return new ExternalCacheDelegate(name, vcache, loader, settings);
117 }
118
119 private <K, V> Cache createHybridCache(String name, @Nullable CacheLoader<K, V> loader, CacheSettings settings)
120 {
121 final JvmCacheSettings localSettings = buildJvmSettings(settings);
122 final ExternalCacheSettings externalSettings = buildExternalCacheSettings(settings);
123
124 final JvmCache<K, Versioned<V>> localVersioned =
125 vCacheFactory.getJvmCache(PREFIX_HYBRID_LOCAL_CACHE + name, localSettings);
126 final StableReadExternalCache<String> globalVersions =
127 vCacheFactory.getStableReadExternalCache(
128 PREFIX_HYBRID_GLOBAL_CACHE + name, MarshallerFactory.stringMarshaller(), externalSettings);
129
130 return new HybridCache<>(name, localVersioned, globalVersions, loader, settings);
131 }
132
133 private <K, V> Cache<K, V> doCreateCache(String name, @Nullable CacheLoader<K, V> loader, CacheSettings settings)
134 {
135 if (settings.getLocal(false))
136 {
137 return createLocalCache(name, loader, settings);
138 }
139
140 if (settings.getReplicateViaCopy(true))
141 {
142
143
144
145 return (Cache<K, V>) createDistributedCache(name, (CacheLoader<String, Serializable>) loader, settings);
146 }
147
148
149 return (Cache<K, V>) createHybridCache(name, loader, settings);
150 }
151
152 private <V> CachedReference<V> createLocalCachedReference(String name, Supplier<V> supplier, CacheSettings settings)
153 {
154 final String mapName = PREFIX_CACHE_REFERENCE + name;
155 final JvmCacheSettings vSettings = buildJvmSettings(settings);
156 final JvmCache<String, V> vCache = vCacheFactory.getJvmCache(mapName, vSettings);
157
158 return new JvmCachedReference<>(name, vCache, supplier, settings);
159 }
160
161 private <V> CachedReference<V> createDistributedCachedReference(String name, Supplier<V> supplier, CacheSettings settings)
162 {
163 final String mapName = PREFIX_CACHE_REFERENCE + name;
164 final ExternalCacheSettings vSettings = buildExternalCacheSettings(settings);
165
166 final StableReadExternalCache<Serializable> vCache =
167 vCacheFactory.getStableReadExternalCache(
168 mapName,
169 MarshallerFactory.serializableMarshaller(Serializable.class),
170 vSettings);
171
172 return new ExternalCachedReference<>(name, vCache, supplier, settings);
173 }
174
175 private <V> CachedReference<V> createHybridCachedReference(String name, Supplier<V> supplier, CacheSettings settings)
176 {
177 final JvmCacheSettings localSettings = buildJvmSettings(settings);
178 final ExternalCacheSettings externalSettings = buildExternalCacheSettings(settings);
179
180 final JvmCache<String, Versioned<V>> localVersioned =
181 vCacheFactory.getJvmCache(PREFIX_HYBRID_LOCAL_CACHE + name, localSettings);
182 final StableReadExternalCache<String> globalVersions =
183 vCacheFactory.getStableReadExternalCache(
184 PREFIX_HYBRID_GLOBAL_CACHE + name, MarshallerFactory.stringMarshaller(), externalSettings);
185
186 return new HybridCachedReference<>(name, localVersioned, globalVersions, supplier, settings);
187 }
188
189 private <V> CachedReference<V> doCreateCachedReference(String name, Supplier<V> supplier, CacheSettings settings)
190 {
191 if (settings.getLocal(false))
192 {
193 return createLocalCachedReference(name, supplier, settings);
194 }
195
196 if (settings.getReplicateViaCopy(true))
197 {
198 return createDistributedCachedReference(name, supplier, settings);
199 }
200
201 return createHybridCachedReference(name, supplier, settings);
202 }
203
204 private JvmCacheSettings buildJvmSettings(CacheSettings settings)
205 {
206 final JvmCacheSettingsBuilder bob = new JvmCacheSettingsBuilder();
207 if (settings.getExpireAfterWrite() != null)
208 {
209 bob.defaultTtl(Duration.ofMillis(settings.getExpireAfterWrite()));
210 }
211 if (settings.getExpireAfterAccess() != null)
212 {
213 bob.defaultTtl(Duration.ofMillis(settings.getExpireAfterAccess()));
214 }
215 if (settings.getMaxEntries() != null)
216 {
217 bob.maxEntries(settings.getMaxEntries());
218 }
219
220 return bob.build();
221 }
222
223 private ExternalCacheSettings buildExternalCacheSettings(CacheSettings settings)
224 {
225 final ExternalCacheSettingsBuilder bob = new ExternalCacheSettingsBuilder();
226 if (settings.getExpireAfterWrite() != null)
227 {
228 bob.defaultTtl(Duration.ofMillis(settings.getExpireAfterWrite()));
229 }
230 if (settings.getExpireAfterAccess() != null)
231 {
232 bob.defaultTtl(Duration.ofMillis(settings.getExpireAfterAccess()));
233 }
234 if (settings.getMaxEntries() != null)
235 {
236 bob.entryCountHint(settings.getMaxEntries());
237 }
238
239 return bob.build();
240 }
241 }