1 package com.atlassian.cache.vcache;
2
3 import java.util.Optional;
4 import javax.annotation.Nonnull;
5
6 import com.atlassian.cache.CacheSettings;
7 import com.atlassian.cache.CachedReference;
8 import com.atlassian.cache.CachedReferenceListener;
9 import com.atlassian.cache.Supplier;
10 import com.atlassian.vcache.JvmCache;
11 import com.atlassian.vcache.PutPolicy;
12 import com.atlassian.vcache.StableReadExternalCache;
13
14 import static com.atlassian.vcache.VCacheUtils.join;
15 import static java.util.Objects.requireNonNull;
16
17 class HybridCachedReference<V>
18 extends ManagedCacheSupport
19 implements CachedReference<V>
20 {
21 private static final String REFERENCE_KEY = "ReferenceKey";
22
23 private final JvmCache<String, Versioned<V>> localVersioned;
24 private final StableReadExternalCache<String> globalVersions;
25 private final Supplier<V> supplier;
26
27 HybridCachedReference(String name,
28 JvmCache<String, Versioned<V>> localVersioned,
29 StableReadExternalCache<String> globalVersions,
30 Supplier<V> supplier,
31 CacheSettings settings)
32 {
33 super(name, settings);
34 this.localVersioned = requireNonNull(localVersioned);
35 this.globalVersions = requireNonNull(globalVersions);
36 this.supplier = requireNonNull(supplier);
37 }
38
39 @Nonnull
40 @Override
41 public V get()
42 {
43 final Optional<Versioned<V>> localVersion = localVersioned.get(REFERENCE_KEY);
44 final Optional<String> globalVersion = join(globalVersions.get(REFERENCE_KEY));
45
46 if (!localVersion.isPresent()
47 || !globalVersion.isPresent()
48 || !globalVersion.get().equals(localVersion.get().getVersion()))
49 {
50
51 localVersioned.removeAll();
52 final Versioned<V> newVersioned =
53 localVersioned.get(REFERENCE_KEY, () -> new Versioned<>(Utils.uniqueId(), supplier.get()));
54 join(globalVersions.put(REFERENCE_KEY, newVersioned.getVersion(), PutPolicy.PUT_ALWAYS));
55
56 return newVersioned.getValue();
57 }
58
59 return localVersion.get().getValue();
60 }
61
62 @Override
63 public void reset()
64 {
65 join(globalVersions.put(REFERENCE_KEY, Utils.uniqueId(), PutPolicy.PUT_ALWAYS));
66 localVersioned.removeAll();
67 }
68
69 @Override
70 public void addListener(@Nonnull CachedReferenceListener<V> listener, boolean includeValues)
71 {
72 throw new UnsupportedOperationException("Unsupported when using the VCache implementation");
73 }
74
75 @Override
76 public void removeListener(@Nonnull CachedReferenceListener<V> listener)
77 {
78 throw new UnsupportedOperationException("Unsupported when using the VCache implementation");
79 }
80
81 @Override
82 public void clear()
83 {
84 if (isFlushable())
85 {
86 reset();
87 }
88 }
89
90 @Override
91 public boolean isLocal()
92 {
93 return false;
94 }
95 }