View Javadoc

1   package com.atlassian.vcache.internal.legacy;
2   
3   import com.atlassian.cache.Cache;
4   import com.atlassian.marshalling.api.MarshallingPair;
5   import com.atlassian.vcache.ExternalCacheException;
6   import com.atlassian.vcache.PutPolicy;
7   import com.atlassian.vcache.internal.MetricLabel;
8   import com.atlassian.vcache.internal.RequestContext;
9   import com.atlassian.vcache.internal.core.ExternalCacheKeyGenerator;
10  import com.atlassian.vcache.internal.core.cas.IdentifiedData;
11  import com.atlassian.vcache.internal.core.metrics.CacheType;
12  import com.atlassian.vcache.internal.core.metrics.MetricsRecorder;
13  import com.atlassian.vcache.internal.core.service.AbstractExternalCacheRequestContext;
14  import com.atlassian.vcache.internal.core.service.AbstractStableReadExternalCache;
15  import com.atlassian.vcache.internal.core.service.UnversionedExternalCacheRequestContext;
16  import org.slf4j.Logger;
17  import org.slf4j.LoggerFactory;
18  
19  import java.util.Map;
20  import java.util.Optional;
21  import java.util.Set;
22  import java.util.concurrent.ExecutionException;
23  import java.util.function.Supplier;
24  
25  import static com.atlassian.vcache.internal.core.cas.IdentifiedUtils.marshall;
26  import static com.atlassian.vcache.internal.core.cas.IdentifiedUtils.unmarshall;
27  import static java.util.Objects.requireNonNull;
28  
29  /**
30   * Implementation that backs onto Atlassian Cache.
31   *
32   * @param <V> the value type
33   * @since 1.0.0
34   */
35  class LegacyStableReadExternalCache<V>
36          extends AbstractStableReadExternalCache<V> {
37      private static final Logger log = LoggerFactory.getLogger(LegacyStableReadExternalCache.class);
38  
39      private final Cache<String, IdentifiedData> delegate;
40      private final Supplier<RequestContext> contextSupplier;
41      private final ExternalCacheKeyGenerator keyGenerator;
42      private final Optional<MarshallingPair<V>> valueMarshalling;
43      private final LegacyServiceSettings serviceSettings;
44  
45      LegacyStableReadExternalCache(
46              Cache<String, IdentifiedData> delegate,
47              Supplier<RequestContext> contextSupplier,
48              ExternalCacheKeyGenerator keyGenerator,
49              Optional<MarshallingPair<V>> valueMarshalling,
50              LegacyServiceSettings serviceSettings,
51              MetricsRecorder metricsRecorder) {
52          super(delegate.getName(), metricsRecorder, serviceSettings.getLockTimeout());
53          this.delegate = requireNonNull(delegate);
54          this.contextSupplier = requireNonNull(contextSupplier);
55          this.keyGenerator = requireNonNull(keyGenerator);
56          this.valueMarshalling = requireNonNull(valueMarshalling);
57          this.serviceSettings = requireNonNull(serviceSettings);
58      }
59  
60      @Override
61      public boolean internalPut(String internalKey, V value, PutPolicy policy) {
62          final String externalKey = ensureCacheContext().externalEntryKeyFor(internalKey);
63          final IdentifiedData identifiedData = marshall(value, valueMarshalling);
64          return LegacyUtils.directPut(
65                  externalKey, identifiedData, policy, delegate, serviceSettings.isAvoidCasOps());
66      }
67  
68      @Override
69      protected void internalRemove(Iterable<String> internalKeys) {
70          // There is no bulk delete in the api, so need to remove each one
71          final AbstractExternalCacheRequestContext<V> cacheContext = ensureCacheContext();
72          for (String key : internalKeys) {
73              delegate.remove(cacheContext.externalEntryKeyFor(key));
74              cacheContext.recordValue(key, Optional.empty());
75          }
76      }
77  
78      @Override
79      protected void internalRemoveAll() {
80          delegate.removeAll();
81      }
82  
83      @Override
84      protected Logger getLogger() {
85          return log;
86      }
87  
88      @Override
89      protected AbstractExternalCacheRequestContext<V> ensureCacheContext() {
90          final RequestContext requestContext = contextSupplier.get();
91  
92          return requestContext.computeIfAbsent(this, () -> {
93              log.trace("Cache {}: Setting up a new context", delegate.getName());
94              return new UnversionedExternalCacheRequestContext<>(
95                      keyGenerator, delegate.getName(), requestContext::partitionIdentifier, lockTimeout);
96          });
97      }
98  
99      @Override
100     protected V handleCreation(String internalKey, V candidateValue)
101             throws ExecutionException, InterruptedException {
102         final AbstractExternalCacheRequestContext<V> cacheContext = ensureCacheContext();
103         final IdentifiedData candidateIdentifiedData = marshall(candidateValue, valueMarshalling);
104         final String externalKey = cacheContext.externalEntryKeyFor(internalKey);
105 
106         metricsRecorder.record(name, CacheType.EXTERNAL, MetricLabel.NUMBER_OF_REMOTE_GET, 1);
107         if (serviceSettings.isAvoidCasOps()) {
108             delegate.put(externalKey, candidateIdentifiedData);
109         } else {
110             final Optional<V> otherAddedValue =
111                     unmarshall(delegate.putIfAbsent(externalKey, candidateIdentifiedData), valueMarshalling);
112 
113             if (otherAddedValue.isPresent()) {
114                 getLogger().info("Cache {}, unable to add candidate for key {}, use what was added", name, internalKey);
115                 // Record as if doing another remote call
116                 metricsRecorder.record(name, CacheType.EXTERNAL, MetricLabel.NUMBER_OF_REMOTE_GET, 1);
117                 return otherAddedValue.get();
118             }
119         }
120         return candidateValue;
121     }
122 
123     @Override
124     protected final ExternalCacheException mapException(Exception ex) {
125         return LegacyUtils.mapException(ex);
126     }
127 
128     @Override
129     protected final Optional<V> directGet(String externalKey) {
130         return unmarshall(delegate.get(externalKey), valueMarshalling);
131     }
132 
133     @Override
134     protected final Map<String, Optional<V>> directGetBulk(Set<String> externalKeys) {
135         return LegacyUtils.directGetBulk(externalKeys, delegate, valueMarshalling);
136     }
137 }