View Javadoc
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              // Either missing a version, or a version mismatch
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  }