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(), 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             // Need to build a new context, which involves getting the current cache version, or setting it if it does
115             // not exist.
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 }