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(),
52 contextSupplier,
53 metricsRecorder,
54 serviceSettings.getLockTimeout(),
55 (n, e) -> {});
56 this.delegate = requireNonNull(delegate);
57 this.keyGenerator = requireNonNull(keyGenerator);
58 this.valueMarshalling = requireNonNull(valueMarshalling);
59 this.transactionControlManager = requireNonNull(transactionControlManager);
60 this.serviceSettings = requireNonNull(serviceSettings);
61 }
62
63 @Override
64 public void transactionSync() {
65 log.trace("Cache {}: synchronising operations", name);
66 final AbstractExternalCacheRequestContext<V> cacheContext = ensureCacheContext();
67
68 if (cacheContext.hasRemoveAll()) {
69 delegate.removeAll();
70 }
71
72 performKeyedOperations(cacheContext);
73 cacheContext.forgetAll();
74 }
75
76 private void performKeyedOperations(AbstractExternalCacheRequestContext<V> cacheContext) {
77 try {
78 for (Map.Entry<String, AbstractExternalCacheRequestContext.DeferredOperation<V>> entry
79 : cacheContext.getKeyedOperations()) {
80 final String externalKey = cacheContext.externalEntryKeyFor(entry.getKey());
81
82 if (entry.getValue().isRemove()) {
83 log.trace("Cache {}: performing remove on entry {}", name, entry.getKey());
84 delegate.remove(externalKey);
85 } else {
86 log.trace("Cache {}: performing {} on entry {}", name, entry.getValue().getPolicy(), entry.getKey());
87 final IdentifiedData identifiedData = marshall(entry.getValue().getValue(), valueMarshalling);
88
89 final boolean putOutcome =
90 LegacyUtils.directPut(
91 externalKey,
92 identifiedData,
93 entry.getValue().getPolicy(),
94 delegate,
95 serviceSettings.isAvoidCasOps());
96
97 if (!putOutcome) {
98 log.debug("Cache {}: Unable to perform put() operation {} on entry {}, clearing cache",
99 name, entry.getValue().getPolicy(), entry.getKey());
100 delegate.removeAll();
101 break;
102 }
103 }
104 }
105 } catch (ExternalCacheException | CacheException bugger) {
106 log.error("Cache {}: an operation failed in transaction sync, so clearing the cache", name, bugger);
107 delegate.removeAll();
108 }
109 }
110
111 @Override
112 protected AbstractExternalCacheRequestContext<V> ensureCacheContext() {
113 final RequestContext requestContext = contextSupplier.get();
114
115 transactionControlManager.registerTransactionalExternalCache(requestContext, name, this);
116
117 return requestContext.computeIfAbsent(this, () -> {
118
119
120 log.trace("Cache {}: Setting up a new context", name);
121 return new UnversionedExternalCacheRequestContext<>(
122 keyGenerator,
123 delegate.getName(),
124 requestContext::partitionIdentifier,
125 serviceSettings.getLockTimeout());
126 });
127 }
128
129 @Override
130 protected Logger getLogger() {
131 return log;
132 }
133
134 @Override
135 protected final ExternalCacheException mapException(Exception ex) {
136 return LegacyUtils.mapException(ex);
137 }
138
139 @Override
140 protected final Optional<V> directGet(String externalKey) {
141 return unmarshall(delegate.get(externalKey), valueMarshalling);
142 }
143
144 @Override
145 protected final Map<String, Optional<V>> directGetBulk(Set<String> externalKeys) {
146 return LegacyUtils.directGetBulk(externalKeys, delegate, valueMarshalling);
147 }
148 }