1 package com.atlassian.vcache.internal.legacy;
2
3 import com.atlassian.cache.Cache;
4 import com.atlassian.cache.CacheException;
5 import com.atlassian.marshalling.api.MarshallingPair;
6 import com.atlassian.vcache.ExternalCacheException;
7 import com.atlassian.vcache.internal.RequestContext;
8 import com.atlassian.vcache.internal.core.ExternalCacheKeyGenerator;
9 import com.atlassian.vcache.internal.core.TransactionControlManager;
10 import com.atlassian.vcache.internal.core.cas.IdentifiedData;
11 import com.atlassian.vcache.internal.core.metrics.MetricsRecorder;
12 import com.atlassian.vcache.internal.core.service.AbstractExternalCacheRequestContext;
13 import com.atlassian.vcache.internal.core.service.AbstractTransactionalExternalCache;
14 import com.atlassian.vcache.internal.core.service.UnversionedExternalCacheRequestContext;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 import java.util.Map;
19 import java.util.Optional;
20 import java.util.Set;
21 import java.util.function.Supplier;
22
23 import static com.atlassian.vcache.internal.core.cas.IdentifiedUtils.marshall;
24 import static com.atlassian.vcache.internal.core.cas.IdentifiedUtils.unmarshall;
25 import static java.util.Objects.requireNonNull;
26
27
28
29
30
31
32
33 class LegacyTransactionalExternalCache<V>
34 extends AbstractTransactionalExternalCache<V> {
35 private static final Logger log = LoggerFactory.getLogger(LegacyTransactionalExternalCache.class);
36
37 private final Cache<String, IdentifiedData> delegate;
38 private final ExternalCacheKeyGenerator keyGenerator;
39 private final Optional<MarshallingPair<V>> valueMarshalling;
40 private final TransactionControlManager transactionControlManager;
41 private final LegacyServiceSettings serviceSettings;
42
43 LegacyTransactionalExternalCache(
44 Cache<String, IdentifiedData> delegate,
45 Supplier<RequestContext> contextSupplier,
46 ExternalCacheKeyGenerator keyGenerator,
47 Optional<MarshallingPair<V>> valueMarshalling,
48 TransactionControlManager transactionControlManager,
49 LegacyServiceSettings serviceSettings,
50 MetricsRecorder metricsRecorder) {
51 super(delegate.getName(), contextSupplier, metricsRecorder);
52 this.delegate = requireNonNull(delegate);
53 this.keyGenerator = requireNonNull(keyGenerator);
54 this.valueMarshalling = requireNonNull(valueMarshalling);
55 this.transactionControlManager = requireNonNull(transactionControlManager);
56 this.serviceSettings = requireNonNull(serviceSettings);
57 }
58
59 @Override
60 public void transactionSync() {
61 log.trace("Cache {}: synchronising operations", name);
62 final AbstractExternalCacheRequestContext<V> cacheContext = ensureCacheContext();
63
64 if (cacheContext.hasRemoveAll()) {
65 delegate.removeAll();
66 }
67
68 performKeyedOperations(cacheContext);
69 cacheContext.forgetAll();
70 }
71
72 private void performKeyedOperations(AbstractExternalCacheRequestContext<V> cacheContext) {
73 try {
74 for (Map.Entry<String, AbstractExternalCacheRequestContext.DeferredOperation<V>> entry
75 : cacheContext.getKeyedOperations()) {
76 final String externalKey = cacheContext.externalEntryKeyFor(entry.getKey());
77
78 if (entry.getValue().isRemove()) {
79 log.trace("Cache {}: performing remove on entry {}", name, entry.getKey());
80 delegate.remove(externalKey);
81 } else {
82 log.trace("Cache {}: performing {} on entry {}", name, entry.getValue().getPolicy(), entry.getKey());
83 final IdentifiedData identifiedData = marshall(entry.getValue().getValue(), valueMarshalling);
84
85 final boolean putOutcome =
86 LegacyUtils.directPut(
87 externalKey,
88 identifiedData,
89 entry.getValue().getPolicy(),
90 delegate,
91 serviceSettings.isAvoidCasOps());
92
93 if (!putOutcome) {
94 log.debug("Cache {}: Unable to perform put() operation {} on entry {}, clearing cache",
95 name, entry.getValue().getPolicy(), entry.getKey());
96 delegate.removeAll();
97 break;
98 }
99 }
100 }
101 } catch (ExternalCacheException | CacheException bugger) {
102 log.error("Cache {}: an operation failed in transaction sync, so clearing the cache", name, bugger);
103 delegate.removeAll();
104 }
105 }
106
107 @Override
108 protected AbstractExternalCacheRequestContext<V> ensureCacheContext() {
109 final RequestContext requestContext = contextSupplier.get();
110
111 transactionControlManager.registerTransactionalExternalCache(requestContext, name, this);
112
113 return requestContext.computeIfAbsent(this, () -> {
114
115
116 log.trace("Cache {}: Setting up a new context", name);
117 return new UnversionedExternalCacheRequestContext<>(
118 keyGenerator, delegate.getName(), requestContext::partitionIdentifier);
119 });
120 }
121
122 @Override
123 protected Logger getLogger() {
124 return log;
125 }
126
127 @Override
128 protected final ExternalCacheException mapException(Exception ex) {
129 return LegacyUtils.mapException(ex);
130 }
131
132 @Override
133 protected final Optional<V> directGet(String externalKey) {
134 return unmarshall(delegate.get(externalKey), valueMarshalling);
135 }
136
137 @Override
138 protected final Map<String, Optional<V>> directGetBulk(Set<String> externalKeys) {
139 return LegacyUtils.directGetBulk(externalKeys, delegate, valueMarshalling);
140 }
141 }