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
31
32
33
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(), (n, ex) -> {});
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
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
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 }