1 package com.atlassian.cache.hazelcast;
2
3 import javax.annotation.Nonnull;
4
5 import com.atlassian.cache.Cache;
6 import com.atlassian.cache.CacheFactory;
7 import com.atlassian.cache.CacheLoader;
8 import com.atlassian.cache.CacheSettings;
9 import com.atlassian.cache.CacheSettingsBuilder;
10 import com.atlassian.cache.CacheSettingsDefaultsProvider;
11 import com.atlassian.cache.CachedReference;
12 import com.atlassian.cache.ManagedCache;
13 import com.atlassian.cache.Supplier;
14 import com.atlassian.cache.impl.AbstractCacheManager;
15 import com.atlassian.cache.impl.ReferenceKey;
16 import com.atlassian.cache.impl.StrongSupplier;
17 import com.atlassian.cache.impl.WeakSupplier;
18 import com.atlassian.hazelcast.serialization.OsgiSafe;
19
20 import com.hazelcast.config.Config;
21 import com.hazelcast.config.MapConfig;
22 import com.hazelcast.core.HazelcastInstance;
23 import com.hazelcast.core.IMap;
24
25 import static com.google.common.base.Preconditions.checkNotNull;
26
27
28
29
30 public class HazelcastCacheManager extends AbstractCacheManager
31 {
32
33 protected static final String PREFIX = "atlassian-cache.";
34 protected static final String PREFIX_CACHE = PREFIX + "Cache.";
35 protected static final String PREFIX_CACHE_REFERENCE = PREFIX + "CacheReference.";
36
37 private final HazelcastInstance hazelcast;
38 private final CacheFactory localCacheFactory;
39
40 public HazelcastCacheManager(HazelcastInstance hazelcast, CacheFactory localCacheFactory,
41 CacheSettingsDefaultsProvider cacheSettingsDefaultsProvider)
42 {
43 super(cacheSettingsDefaultsProvider);
44
45 this.hazelcast = hazelcast;
46 this.localCacheFactory = localCacheFactory;
47 }
48
49 @Override
50 protected <K, V> ManagedCache createComputingCache(@Nonnull final String name, @Nonnull final CacheSettings settings, final CacheLoader<K, V> loader)
51 {
52 checkSettingsAreCompatible(name, settings);
53
54
55
56 return cacheCreationLocks.get(name).withLock(new com.atlassian.util.concurrent.Supplier<ManagedCache>()
57 {
58 @Override
59 public ManagedCache get()
60 {
61 if (!caches.containsKey(name) || loader != null)
62 {
63 caches.put(name, new WeakSupplier<ManagedCache>((ManagedCache) doCreateCache(name, loader, settings)));
64 }
65 return caches.get(name).get();
66 }
67 });
68 }
69
70 @Override
71 protected ManagedCache createSimpleCache(@Nonnull final String name, @Nonnull final CacheSettings settings)
72 {
73 checkSettingsAreCompatible(name, settings);
74
75 ManagedCache existing = getManagedCache(name);
76 if (existing != null)
77 {
78 return existing;
79 }
80
81 return cacheCreationLocks.get(name).withLock(new com.atlassian.util.concurrent.Supplier<ManagedCache>()
82 {
83 @Override
84 public ManagedCache get()
85 {
86 if (!caches.containsKey(name))
87 {
88 caches.put(name, new StrongSupplier<ManagedCache>((ManagedCache) doCreateCache(name, null, settings)));
89 }
90 return caches.get(name).get();
91 }
92 });
93 }
94
95 @Nonnull
96 @Override
97 public <V> CachedReference<V> getCachedReference(@Nonnull final String name, @Nonnull final Supplier<V> supplier,
98 @Nonnull final CacheSettings settings)
99 {
100 checkSettingsAreCompatible(name, settings);
101
102 return cacheCreationLocks.get(name).withLock(new com.atlassian.util.concurrent.Supplier<CachedReference<V>>()
103 {
104 @Override
105 public CachedReference<V> get()
106 {
107 caches.put(name, new WeakSupplier<ManagedCache>((ManagedCache) doCreateCachedReference(name, supplier, settings)));
108
109 return (CachedReference<V>) caches.get(name).get();
110 }
111 });
112 }
113
114 protected void checkSettingsAreCompatible(String name, CacheSettings settings)
115 {
116 }
117
118 protected MapConfig configureMap(String mapName, CacheSettings settings)
119 {
120 Config config = hazelcast.getConfig();
121 MapConfig mapConfig = config.getMapConfig(mapName);
122 mapConfig.setStatisticsEnabled(true);
123
124 new HazelcastMapConfigConfigurator().configureMapConfig(settings, mapConfig);
125 config.addMapConfig(mapConfig);
126
127 return mapConfig;
128 }
129
130 protected <K, V> Cache<K, V> createDistributedCache(String name, CacheLoader<K, V> loader, CacheSettings settings)
131 {
132 String mapName = PREFIX_CACHE + name;
133 MapConfig config = configureMap(mapName, settings);
134 IMap<K, OsgiSafe<V>> map = hazelcast.getMap(mapName);
135
136 return new HazelcastCache<K, V>(name, map, config, loader, settings);
137 }
138
139 protected <V> CachedReference<V> createDistributedCachedReference(String name, Supplier<V> supplier, CacheSettings settings)
140 {
141
142
143 final CacheSettings overriddenSettings = checkNotNull(settings, "settings").override(
144 new CacheSettingsBuilder().flushable().maxEntries(1000).build());
145
146 String mapName = PREFIX_CACHE_REFERENCE + name;
147 MapConfig config = configureMap(mapName, overriddenSettings);
148 IMap<String, OsgiSafe<V>> map = hazelcast.getMap(mapName);
149
150 return new HazelcastCachedReference<V>(name, map, config, supplier, overriddenSettings);
151 }
152
153 protected <K, V> Cache<K, V> createHybridCache(String name, CacheLoader<K, V> loader, CacheSettings settings)
154 {
155 String mapName = PREFIX_CACHE + name;
156 MapConfig config = configureMap(mapName, settings);
157 IMap<K, Long> map = hazelcast.getMap(mapName);
158
159 return new HazelcastHybridCache<K, V>(name, localCacheFactory, map, config, loader, settings);
160 }
161
162 protected <V> CachedReference<V> createHybridCachedReference(String name, Supplier<V> supplier, CacheSettings settings)
163 {
164 String mapName = PREFIX_CACHE_REFERENCE + name;
165 MapConfig config = configureMap(mapName, settings);
166 IMap<ReferenceKey, Long> map = hazelcast.getMap(mapName);
167
168 return new HazelcastHybridCachedReference<V>(name, localCacheFactory, map, supplier, settings);
169 }
170
171 private <K, V> Cache<K, V> doCreateCache(String name, CacheLoader<K, V> loader, CacheSettings settings)
172 {
173 if (settings.getLocal(false))
174 {
175 return localCacheFactory.getCache(name, loader, settings);
176 }
177
178 if (settings.getReplicateViaCopy(true))
179 {
180 return createDistributedCache(name, loader, settings);
181 }
182
183 return createHybridCache(name, loader, settings);
184 }
185
186 protected <V> CachedReference<V> doCreateCachedReference(String name, Supplier<V> supplier, CacheSettings settings)
187 {
188 if (settings.getLocal(false))
189 {
190 return localCacheFactory.getCachedReference(name, supplier, settings);
191 }
192
193
194 if (settings.getReplicateViaCopy(true))
195 {
196 return createDistributedCachedReference(name, supplier, settings);
197 }
198
199 return createHybridCachedReference(name, supplier, settings);
200 }
201 }