1 package com.atlassian.vcache.internal.core;
2
3 import com.atlassian.vcache.internal.BegunTransactionalActivityHandler;
4 import com.atlassian.vcache.internal.RequestContext;
5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.concurrent.atomic.AtomicBoolean;
13
14 import static java.util.Objects.requireNonNull;
15
16
17
18
19
20
21 public class DefaultTransactionControlManager implements TransactionControlManager {
22 private static final Logger log = LoggerFactory.getLogger(DefaultTransactionControlManager.class);
23
24 private final Object transactionControllersKey = new Object();
25 private final Object callbackKey = new Object();
26
27 private final Instrumentor instrumentor;
28 private final BegunTransactionalActivityHandler begunTransactionalActivityHandler;
29
30 public DefaultTransactionControlManager(Instrumentor instrumentor,
31 BegunTransactionalActivityHandler begunTransactionalActivityHandler) {
32 this.instrumentor = requireNonNull(instrumentor);
33 this.begunTransactionalActivityHandler = requireNonNull(begunTransactionalActivityHandler);
34 }
35
36 @Override
37 public void registerTransactionalExternalCache(RequestContext requestContext,
38 String cacheName,
39 TransactionControl control) {
40 requestContext
41 .computeIfAbsent(transactionControllersKey, HashMap::new)
42 .computeIfAbsent(cacheName, x -> {
43 log.trace("Registering {}", cacheName);
44 return instrumentor.wrap(control, cacheName);
45 });
46
47 invokeCallbackIfNecessary(requestContext);
48 }
49
50 @Override
51 public void syncAll(RequestContext requestContext) {
52 log.trace("Synchronising all caches");
53
54 requestContext.<Map<String, TransactionControl>>get(transactionControllersKey)
55 .ifPresent(txControls -> txControls.forEach((cacheName, transactionControl) -> {
56 log.trace("Syncing {}", cacheName);
57 transactionControl.transactionSync();
58 }));
59 resetShouldInvokeCallback(requestContext);
60 }
61
62 @Override
63 public Set<String> discardAll(RequestContext requestContext) {
64 log.trace("Discarding all caches");
65 final Set<String> discardedCacheNames = new HashSet<>();
66
67 requestContext.<Map<String, TransactionControl>>get(transactionControllersKey)
68 .ifPresent(txControls -> txControls.forEach((cacheName, transactionControl) -> {
69 log.trace("Discarding {}", cacheName);
70 if (transactionControl.transactionDiscard()) {
71 discardedCacheNames.add(cacheName);
72 }
73 }));
74 resetShouldInvokeCallback(requestContext);
75
76 return discardedCacheNames;
77 }
78
79 private void invokeCallbackIfNecessary(RequestContext requestContext) {
80 if (getCallbackInvokedFlag(requestContext).compareAndSet(false, true)) {
81 begunTransactionalActivityHandler.onRequest(requestContext);
82 }
83 }
84
85 private void resetShouldInvokeCallback(RequestContext requestContext) {
86 getCallbackInvokedFlag(requestContext).set(false);
87 }
88
89 private AtomicBoolean getCallbackInvokedFlag(RequestContext requestContext) {
90 return requestContext.computeIfAbsent(callbackKey, () -> new AtomicBoolean(false));
91 }
92 }