1 package com.atlassian.vcache.internal.memcached;
2
3 import com.atlassian.marshalling.api.MarshallingPair;
4 import com.atlassian.vcache.CasIdentifier;
5 import com.atlassian.vcache.ExternalCacheException;
6 import com.atlassian.vcache.IdentifiedValue;
7 import com.atlassian.vcache.PutPolicy;
8 import com.atlassian.vcache.internal.core.DefaultIdentifiedValue;
9 import com.atlassian.vcache.internal.core.VCacheCoreUtils;
10 import net.spy.memcached.CASValue;
11 import net.spy.memcached.MemcachedClientIF;
12 import net.spy.memcached.OperationTimeoutException;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.Set;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
21 import java.util.function.Supplier;
22 import java.util.stream.Collectors;
23
24 import static com.atlassian.vcache.ExternalCacheException.Reason.UNCLASSIFIED_FAILURE;
25 import static com.atlassian.vcache.internal.core.VCacheCoreUtils.unmarshall;
26
27
28
29
30
31
32 class MemcachedUtils {
33 private static final Logger log = LoggerFactory.getLogger(MemcachedUtils.class);
34
35
36
37
38 private static final int MAX_SECONDS_OFFSET = 60 * 60 * 24 * 30;
39
40 static long safeExtractId(CasIdentifier casId) {
41 if (casId instanceof MemcachedCasIdentifier) {
42 return ((MemcachedCasIdentifier) casId).getId();
43 }
44
45 log.warn("Passed an unknown CasIdentifier instance of class {}.", casId.getClass().getName());
46 throw new ExternalCacheException(UNCLASSIFIED_FAILURE);
47 }
48
49 static <V> Optional<IdentifiedValue<V>> identifiedValueFrom(Future<CASValue<Object>> op, MarshallingPair<V> valueMarshalling) {
50 final CASValue<Object> casValue;
51 try {
52 casValue = op.get();
53 } catch (ExecutionException | InterruptedException ex) {
54 throw new ExternalCacheException(UNCLASSIFIED_FAILURE, ex);
55 }
56
57 if (casValue == null) {
58 return Optional.empty();
59 }
60
61 final CasIdentifier identifier = new MemcachedCasIdentifier(casValue.getCas());
62 final IdentifiedValue<V> iv = new DefaultIdentifiedValue<>(
63 identifier, VCacheCoreUtils.unmarshall((byte[]) casValue.getValue(), valueMarshalling).get());
64 return Optional.of(iv);
65 }
66
67 static Future<Boolean> putOperationForPolicy(
68 PutPolicy policy, MemcachedClientIF client, String externalKey, int defaultTtl, byte[] valueBytes) {
69 final Future<Boolean> putOp;
70 if (policy == PutPolicy.ADD_ONLY) {
71 putOp = client.add(externalKey, defaultTtl, valueBytes);
72 } else if (policy == PutPolicy.PUT_ALWAYS) {
73 putOp = client.set(externalKey, defaultTtl, valueBytes);
74 } else if (policy == PutPolicy.REPLACE_ONLY) {
75 putOp = client.replace(externalKey, defaultTtl, valueBytes);
76 } else {
77 throw new IllegalArgumentException("Unknown put policy: " + policy);
78 }
79
80 return putOp;
81 }
82
83 static ExternalCacheException mapException(Exception ex) {
84 if (ex instanceof OperationTimeoutException) {
85 return new ExternalCacheException(ExternalCacheException.Reason.TIMEOUT, ex);
86 }
87 return new ExternalCacheException(ExternalCacheException.Reason.UNCLASSIFIED_FAILURE, ex);
88 }
89
90 static <V> Map<String, Optional<V>> directGetBulk(
91 Set<String> externalKeys, Supplier<MemcachedClientIF> clientSupplier, MarshallingPair<V> valueMarshalling) {
92
93 final Map<String, Object> haveValues = clientSupplier.get().getBulk(externalKeys);
94
95 return externalKeys.stream().collect(Collectors.toMap(
96 k -> k,
97 k -> unmarshall((byte[]) haveValues.get(k), valueMarshalling)));
98 }
99
100 static long obtainCacheVersion(Supplier<MemcachedClientIF> clientSupplier, String externalCacheVersionKey) {
101
102 return clientSupplier.get().incr(externalCacheVersionKey, 0, 1);
103 }
104
105 static long incrementCacheVersion(Supplier<MemcachedClientIF> clientSupplier, String externalCacheVersionKey) {
106 return clientSupplier.get().incr(externalCacheVersionKey, 1, 1);
107 }
108
109
110
111
112
113
114
115
116 static int expiryTime(int seconds) {
117 if (seconds < MAX_SECONDS_OFFSET) {
118 return seconds;
119 }
120
121 final int currentTime = (int) (System.currentTimeMillis() / 1_000);
122 return currentTime + seconds;
123 }
124 }