View Javadoc

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   * Implementation that backed on to Atlassian Cache.
29   *
30   * @param <V> the value type
31   * @since 1.0.0
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             // Need to build a new context, which involves getting the current cache version, or setting it if it does
119             // not exist.
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 }