1 package com.atlassian.vcache.internal.test;
2
3 import com.atlassian.marshalling.api.MarshallingPair;
4 import com.atlassian.marshalling.jdk.StringMarshalling;
5 import com.atlassian.vcache.ChangeRate;
6 import com.atlassian.vcache.DirectExternalCache;
7 import com.atlassian.vcache.ExternalCacheException;
8 import com.atlassian.vcache.ExternalCacheSettings;
9 import com.atlassian.vcache.ExternalCacheSettingsBuilder;
10 import com.atlassian.vcache.JvmCache;
11 import com.atlassian.vcache.JvmCacheSettings;
12 import com.atlassian.vcache.JvmCacheSettingsBuilder;
13 import com.atlassian.vcache.RequestCache;
14 import com.atlassian.vcache.StableReadExternalCache;
15 import com.atlassian.vcache.TransactionalExternalCache;
16 import com.atlassian.vcache.VCacheFactory;
17 import com.atlassian.vcache.VCacheUtils;
18 import com.atlassian.vcache.internal.BegunTransactionalActivityHandler;
19 import com.atlassian.vcache.internal.ExternalCacheDetails;
20 import com.atlassian.vcache.internal.JvmCacheDetails;
21 import com.atlassian.vcache.internal.LongMetric;
22 import com.atlassian.vcache.internal.MetricLabel;
23 import com.atlassian.vcache.internal.RequestCacheDetails;
24 import com.atlassian.vcache.internal.RequestContext;
25 import com.atlassian.vcache.internal.RequestMetrics;
26 import com.atlassian.vcache.internal.VCacheLifecycleManager;
27 import com.atlassian.vcache.internal.VCacheManagement;
28 import com.atlassian.vcache.marshallers.MarshallerFactory;
29 import org.junit.Rule;
30 import org.junit.Test;
31 import org.junit.rules.ExpectedException;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 import java.time.Duration;
36 import java.util.Map;
37 import java.util.Optional;
38 import java.util.concurrent.CompletionStage;
39
40 import static com.atlassian.vcache.PutPolicy.PUT_ALWAYS;
41 import static com.atlassian.vcache.VCacheUtils.unsafeJoin;
42 import static com.atlassian.vcache.internal.test.CompletionStageSuccessful.successful;
43 import static com.atlassian.vcache.internal.test.CompletionStageSuccessful.successfulWith;
44 import static org.hamcrest.Matchers.containsInAnyOrder;
45 import static org.hamcrest.Matchers.greaterThan;
46 import static org.hamcrest.Matchers.is;
47 import static org.hamcrest.Matchers.notNullValue;
48 import static org.junit.Assert.assertThat;
49
50
51
52
53 @SuppressWarnings("OptionalGetWithoutIsPresent")
54 public abstract class AbstractVCacheServiceIT {
55 protected static final int MAX_ENTRIES = 100;
56 protected static final Duration MAX_TTL = Duration.ofSeconds(60);
57
58 private static final Logger log = LoggerFactory.getLogger(AbstractVCacheServiceIT.class);
59
60 @Rule
61 public ExpectedException thrown = ExpectedException.none();
62
63 @Rule
64 public LoggingTestWatcher watcher = new LoggingTestWatcher(log);
65
66 @SuppressWarnings("WeakerAccess")
67 protected int invocationsOfBegunTxns;
68 protected final BegunTransactionalActivityHandler begunTxnActivityHandler = c -> invocationsOfBegunTxns++;
69
70 protected abstract VCacheFactory vCacheFactory();
71
72 protected abstract VCacheManagement vCacheManagement();
73
74 protected abstract VCacheLifecycleManager vCacheLifecycleManager();
75
76 protected abstract RequestContext currentRequestContext();
77
78 protected abstract void forceNewRequestContext();
79
80 @Test
81 public void jvmCache_normal() {
82 final JvmCacheSettings settings = new JvmCacheSettingsBuilder()
83 .defaultTtl(MAX_TTL.plusSeconds(1))
84 .maxEntries(MAX_ENTRIES + 1)
85 .build();
86
87 final JvmCache<String, Long> cache = vCacheFactory().getJvmCache("my-jvm-cache", settings);
88
89 assertThat(cache, notNullValue());
90 assertThat(cache.getName(), is("my-jvm-cache"));
91
92 cache.put("key", 666L);
93
94 final RequestMetrics metrics = vCacheLifecycleManager().metrics(currentRequestContext());
95
96 assertThat(metrics, notNullValue());
97 assertThat(metrics.allJvmCacheLongMetrics(), notNullValue());
98
99 final Map<MetricLabel, ? extends LongMetric> myCacheMetrics =
100 metrics.allJvmCacheLongMetrics().get("my-jvm-cache");
101
102 assertThat(myCacheMetrics, notNullValue());
103 final LongMetric timedPuts = myCacheMetrics.get(MetricLabel.TIMED_PUT_CALL);
104 assertThat(timedPuts, notNullValue());
105 assertThat(timedPuts.getSampleCount(), is(1L));
106 assertThat(timedPuts.getSamplesTotal(), greaterThan(0L));
107 assertThat(vCacheManagement().allExternalCacheDetails().size(), is(0));
108 assertThat(vCacheManagement().allRequestCacheDetails().size(), is(0));
109
110 final Map<String, JvmCacheDetails> allCacheDetails = vCacheManagement().allJvmCacheDetails();
111
112 assertThat(allCacheDetails, notNullValue());
113 assertThat(allCacheDetails.keySet(), containsInAnyOrder("my-jvm-cache"));
114
115 final JvmCacheDetails cacheDetails = allCacheDetails.get("my-jvm-cache");
116
117 assertThat(cacheDetails.getName(), is("my-jvm-cache"));
118 assertThat(cacheDetails.getSettings().getDefaultTtl(), is(Optional.of(MAX_TTL)));
119 assertThat(cacheDetails.getSettings().getMaxEntries(), is(Optional.of(MAX_ENTRIES)));
120
121 assertThat(invocationsOfBegunTxns, is(0));
122 }
123
124 @Test
125 public void requestCache_normal() {
126 final RequestCache<String, String> cache = vCacheFactory().getRequestCache("my-request-cache");
127
128 assertThat(cache, notNullValue());
129 assertThat(cache.getName(), is("my-request-cache"));
130
131 cache.removeAll();
132 cache.put("one", "eine");
133
134 final Optional<String> get1 = cache.get("one");
135
136 assertThat(get1, is(Optional.of("eine")));
137 assertThat(vCacheManagement().allJvmCacheDetails().size(), is(0));
138 assertThat(vCacheManagement().allExternalCacheDetails().size(), is(0));
139
140 final Map<String, RequestCacheDetails> allCacheDetails = vCacheManagement().allRequestCacheDetails();
141
142 assertThat(allCacheDetails, notNullValue());
143 assertThat(allCacheDetails.keySet(), containsInAnyOrder("my-request-cache"));
144
145 final RequestCacheDetails cacheDetails = allCacheDetails.get("my-request-cache");
146
147 assertThat(cacheDetails.getName(), is("my-request-cache"));
148 assertThat(invocationsOfBegunTxns, is(0));
149 }
150
151 @Test
152 public void directExternalCache_normal_marshalling() {
153 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
154 .defaultTtl(Duration.ofSeconds(60))
155 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
156 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
157 .entryCountHint(100)
158 .build();
159
160 final DirectExternalCache<String> cache = vCacheFactory().getDirectExternalCache(
161 "my-direct-cache", StringMarshalling.pair(), settings);
162
163 assertThat(cache, notNullValue());
164 assertThat(cache.getName(), is("my-direct-cache"));
165
166 final CompletionStage<Void> rmall = cache.removeAll();
167
168 assertThat(rmall, successful());
169
170 final CompletionStage<Boolean> put1 = cache.put("one", "eine", PUT_ALWAYS);
171
172 assertThat(put1, successfulWith(is(true)));
173
174 final CompletionStage<Optional<String>> get1 = cache.get("one");
175
176 assertThat(get1, successfulWith(is(Optional.of("eine"))));
177 assertThat(vCacheManagement().allJvmCacheDetails().size(), is(0));
178 assertThat(vCacheManagement().allRequestCacheDetails().size(), is(0));
179
180 final Map<String, ExternalCacheDetails> allCacheDetails = vCacheManagement().allExternalCacheDetails();
181
182 assertThat(allCacheDetails, notNullValue());
183 assertThat(allCacheDetails.keySet(), containsInAnyOrder("my-direct-cache"));
184
185 final ExternalCacheDetails cacheDetails = allCacheDetails.get("my-direct-cache");
186
187 assertThat(cacheDetails.getName(), is("my-direct-cache"));
188 assertThat(cacheDetails.getSettings().getDefaultTtl(), is(Optional.of(MAX_TTL)));
189 assertThat(cacheDetails.getSettings().getEntryCountHint(), is(Optional.of(MAX_ENTRIES)));
190 assertThat(invocationsOfBegunTxns, is(0));
191 }
192
193 @Test
194 public void directExternalCache_normal_marshaller() {
195 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
196 .defaultTtl(Duration.ofSeconds(60))
197 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
198 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
199 .entryCountHint(100)
200 .build();
201
202 @SuppressWarnings("deprecation")
203 final DirectExternalCache<String> cache = vCacheFactory().getDirectExternalCache(
204 "my-direct-cache", MarshallerFactory.stringMarshaller(), settings);
205
206 assertThat(cache, notNullValue());
207 assertThat(cache.getName(), is("my-direct-cache"));
208
209 final CompletionStage<Void> rmall = cache.removeAll();
210
211 assertThat(rmall, successful());
212
213 final CompletionStage<Boolean> put1 = cache.put("one1", "eine", PUT_ALWAYS);
214
215 assertThat(put1, successfulWith(is(true)));
216
217 final CompletionStage<Optional<String>> get1 = cache.get("one1");
218
219 assertThat(get1, successfulWith(is(Optional.of("eine"))));
220 assertThat(vCacheManagement().allJvmCacheDetails().size(), is(0));
221 assertThat(vCacheManagement().allRequestCacheDetails().size(), is(0));
222 }
223
224 @Test
225 public void stableReadExternalCache_normal_marshalling() {
226 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
227 .defaultTtl(Duration.ofSeconds(60))
228 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
229 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
230 .entryCountHint(100)
231 .build();
232
233 final StableReadExternalCache<String> cache = vCacheFactory().getStableReadExternalCache(
234 "my-stable-read-cache", StringMarshalling.pair(), settings);
235
236 assertThat(cache, notNullValue());
237 assertThat(cache.getName(), is("my-stable-read-cache"));
238
239 final CompletionStage<Void> rmall = cache.removeAll();
240
241 assertThat(rmall, successful());
242
243 final CompletionStage<Boolean> put1 = cache.put("three", "drei", PUT_ALWAYS);
244
245 assertThat(put1, successfulWith(is(true)));
246
247 final CompletionStage<Optional<String>> get1 = cache.get("three");
248
249 assertThat(get1, successfulWith(is(Optional.of("drei"))));
250 assertThat(invocationsOfBegunTxns, is(0));
251 }
252
253 @Test
254 public void stableReadExternalCache_normal_marshaller() {
255 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
256 .defaultTtl(Duration.ofSeconds(60))
257 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
258 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
259 .entryCountHint(100)
260 .build();
261
262 @SuppressWarnings("deprecation")
263 final StableReadExternalCache<String> cache = vCacheFactory().getStableReadExternalCache(
264 "my-stable-read-cache", MarshallerFactory.stringMarshaller(), settings);
265
266 assertThat(cache, notNullValue());
267 assertThat(cache.getName(), is("my-stable-read-cache"));
268
269 final CompletionStage<Void> rmall = cache.removeAll();
270
271 assertThat(rmall, successful());
272
273 final CompletionStage<Boolean> put1 = cache.put("three", "drei", PUT_ALWAYS);
274
275 assertThat(put1, successfulWith(is(true)));
276
277 final CompletionStage<Optional<String>> get1 = cache.get("three");
278
279 assertThat(get1, successfulWith(is(Optional.of("drei"))));
280 assertThat(invocationsOfBegunTxns, is(0));
281 }
282
283 @Test
284 public void transactionalExternalCache_normal_marshalling() {
285 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
286 .defaultTtl(Duration.ofSeconds(60))
287 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
288 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
289 .entryCountHint(100)
290 .build();
291
292 final TransactionalExternalCache<String> cache = vCacheFactory().getTransactionalExternalCache(
293 "my-txn-cache", StringMarshalling.pair(), settings);
294
295 assertThat(cache, notNullValue());
296 assertThat(cache.getName(), is("my-txn-cache"));
297 assertThat(invocationsOfBegunTxns, is(0));
298
299 cache.removeAll();
300 assertThat(invocationsOfBegunTxns, is(1));
301
302 cache.put("three", "drei", PUT_ALWAYS);
303
304 final CompletionStage<Optional<String>> get1 = cache.get("three");
305
306 assertThat(get1, successfulWith(is(Optional.of("drei"))));
307
308 vCacheLifecycleManager().transactionSync(currentRequestContext());
309 assertThat(invocationsOfBegunTxns, is(1));
310
311 forceNewRequestContext();
312 final CompletionStage<Optional<String>> get2 = cache.get("three");
313 assertThat(invocationsOfBegunTxns, is(2));
314 unsafeJoin(get2.toCompletableFuture()).get();
315 assertThat(get2, successfulWith(is(Optional.of("drei"))));
316 assertThat(invocationsOfBegunTxns, is(2));
317 }
318
319 @Test
320 public void transactionalExternalCache_normal_marshaller() {
321 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
322 .defaultTtl(Duration.ofSeconds(60))
323 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
324 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
325 .entryCountHint(100)
326 .build();
327
328 @SuppressWarnings("deprecation")
329 final TransactionalExternalCache<String> cache = vCacheFactory().getTransactionalExternalCache(
330 "my-txn-cache", MarshallerFactory.stringMarshaller(), settings);
331
332 assertThat(cache, notNullValue());
333 assertThat(cache.getName(), is("my-txn-cache"));
334 assertThat(invocationsOfBegunTxns, is(0));
335
336 cache.removeAll();
337 assertThat(invocationsOfBegunTxns, is(1));
338
339 cache.put("three", "drei", PUT_ALWAYS);
340
341 final CompletionStage<Optional<String>> get1 = cache.get("three");
342
343 assertThat(get1, successfulWith(is(Optional.of("drei"))));
344
345 vCacheLifecycleManager().transactionSync(currentRequestContext());
346 assertThat(invocationsOfBegunTxns, is(1));
347
348 forceNewRequestContext();
349 final CompletionStage<Optional<String>> get2 = cache.get("three");
350 assertThat(invocationsOfBegunTxns, is(2));
351 unsafeJoin(get2.toCompletableFuture()).get();
352 assertThat(get2, successfulWith(is(Optional.of("drei"))));
353 assertThat(invocationsOfBegunTxns, is(2));
354 }
355
356 @Test
357 public void verify_txns_sync_sync_sync() {
358 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
359 .defaultTtl(Duration.ofSeconds(60))
360 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
361 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
362 .entryCountHint(100)
363 .build();
364
365 final TransactionalExternalCache<String> cache1 = vCacheFactory().getTransactionalExternalCache(
366 "sync_sync_sync-1", StringMarshalling.pair(), settings);
367 assertThat(invocationsOfBegunTxns, is(0));
368
369 cache1.put("updated-key", "first1", PUT_ALWAYS);
370 assertThat(invocationsOfBegunTxns, is(1));
371
372 cache1.put("phase-1", "first", PUT_ALWAYS);
373 vCacheLifecycleManager().transactionSync(currentRequestContext());
374 assertThat(invocationsOfBegunTxns, is(1));
375
376 final TransactionalExternalCache<String> cache2 = vCacheFactory().getTransactionalExternalCache(
377 "sync_sync_sync-2", StringMarshalling.pair(), settings);
378
379 cache1.put("updated-key", "second1", PUT_ALWAYS);
380 assertThat(invocationsOfBegunTxns, is(2));
381
382 cache2.put("updated-key", "second2", PUT_ALWAYS);
383 cache1.put("phase-2", "second", PUT_ALWAYS);
384 cache2.put("phase-2", "second", PUT_ALWAYS);
385
386 vCacheLifecycleManager().transactionSync(currentRequestContext());
387 assertThat(invocationsOfBegunTxns, is(2));
388
389 final TransactionalExternalCache<String> cache3 = vCacheFactory().getTransactionalExternalCache(
390 "sync_sync_sync-3", StringMarshalling.pair(), settings);
391
392 cache1.put("updated-key", "third1", PUT_ALWAYS);
393 assertThat(invocationsOfBegunTxns, is(3));
394 cache2.put("updated-key", "third2", PUT_ALWAYS);
395 cache1.put("phase-3", "third", PUT_ALWAYS);
396 cache2.put("phase-3", "third", PUT_ALWAYS);
397 cache3.put("phase-3", "third", PUT_ALWAYS);
398
399 vCacheLifecycleManager().transactionSync(currentRequestContext());
400 assertThat(invocationsOfBegunTxns, is(3));
401
402 forceNewRequestContext();
403
404 assertThat(cache1.get("updated-key"), successfulWith(is(Optional.of("third1"))));
405 assertThat(invocationsOfBegunTxns, is(4));
406 assertThat(unsafeJoin(cache1.get("updated-key")), is(Optional.of("third1")));
407 assertThat(unsafeJoin(cache1.get("phase-1")), is(Optional.of("first")));
408 assertThat(unsafeJoin(cache1.get("phase-2")), is(Optional.of("second")));
409 assertThat(unsafeJoin(cache1.get("phase-3")), is(Optional.of("third")));
410
411 assertThat(unsafeJoin(cache2.get("updated-key")), is(Optional.of("third2")));
412 assertThat(unsafeJoin(cache2.get("phase-2")), is(Optional.of("second")));
413 assertThat(unsafeJoin(cache2.get("phase-3")), is(Optional.of("third")));
414
415 assertThat(unsafeJoin(cache3.get("phase-3")), is(Optional.of("third")));
416 assertThat(invocationsOfBegunTxns, is(4));
417 }
418
419 @Test
420 public void verify_txns_sync_discard_sync() {
421 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
422 .defaultTtl(Duration.ofSeconds(60))
423 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
424 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
425 .entryCountHint(100)
426 .build();
427
428 final TransactionalExternalCache<String> cache1 = vCacheFactory().getTransactionalExternalCache(
429 "sync_discard_sync-1", StringMarshalling.pair(), settings);
430 assertThat(invocationsOfBegunTxns, is(0));
431
432 cache1.put("updated-key", "first1", PUT_ALWAYS);
433 assertThat(invocationsOfBegunTxns, is(1));
434 cache1.put("phase-1", "first", PUT_ALWAYS);
435
436 vCacheLifecycleManager().transactionSync(currentRequestContext());
437
438 final TransactionalExternalCache<String> cache2 = vCacheFactory().getTransactionalExternalCache(
439 "sync_discard_sync-2", StringMarshalling.pair(), settings);
440
441 assertThat(invocationsOfBegunTxns, is(1));
442 cache1.put("updated-key", "second1", PUT_ALWAYS);
443 assertThat(invocationsOfBegunTxns, is(2));
444 cache2.put("updated-key", "second2", PUT_ALWAYS);
445 cache1.put("phase-2", "second", PUT_ALWAYS);
446 cache2.put("phase-2", "second", PUT_ALWAYS);
447
448 vCacheLifecycleManager().transactionDiscard(currentRequestContext());
449
450 final TransactionalExternalCache<String> cache3 = vCacheFactory().getTransactionalExternalCache(
451 "sync_discard_sync-3", StringMarshalling.pair(), settings);
452
453 assertThat(invocationsOfBegunTxns, is(2));
454 cache1.put("updated-key", "third1", PUT_ALWAYS);
455 assertThat(invocationsOfBegunTxns, is(3));
456 cache2.put("updated-key", "third2", PUT_ALWAYS);
457 cache1.put("phase-3", "third", PUT_ALWAYS);
458 cache2.put("phase-3", "third", PUT_ALWAYS);
459 cache3.put("phase-3", "third", PUT_ALWAYS);
460
461 vCacheLifecycleManager().transactionSync(currentRequestContext());
462
463 forceNewRequestContext();
464
465 assertThat(invocationsOfBegunTxns, is(3));
466 assertThat(unsafeJoin(cache1.get("updated-key")), is(Optional.of("third1")));
467 assertThat(invocationsOfBegunTxns, is(4));
468 assertThat(unsafeJoin(cache1.get("phase-1")), is(Optional.of("first")));
469 assertThat(unsafeJoin(cache1.get("phase-2")), is(Optional.empty()));
470 assertThat(unsafeJoin(cache1.get("phase-3")), is(Optional.of("third")));
471
472 assertThat(unsafeJoin(cache2.get("updated-key")), is(Optional.of("third2")));
473 assertThat(unsafeJoin(cache2.get("phase-2")), is(Optional.empty()));
474 assertThat(unsafeJoin(cache2.get("phase-3")), is(Optional.of("third")));
475
476 assertThat(unsafeJoin(cache3.get("phase-3")), is(Optional.of("third")));
477 assertThat(invocationsOfBegunTxns, is(4));
478 }
479
480 @Test
481 public void verify_txns_discard_sync_discard() {
482 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
483 .defaultTtl(Duration.ofSeconds(60))
484 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
485 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
486 .entryCountHint(100)
487 .build();
488
489 final TransactionalExternalCache<String> cache1 = vCacheFactory().getTransactionalExternalCache(
490 "discard_sync_discard-1", StringMarshalling.pair(), settings);
491
492 cache1.put("updated-key", "first1", PUT_ALWAYS);
493 cache1.put("phase-1", "first", PUT_ALWAYS);
494
495 vCacheLifecycleManager().transactionDiscard(currentRequestContext());
496
497 final TransactionalExternalCache<String> cache2 = vCacheFactory().getTransactionalExternalCache(
498 "discard_sync_discard-2", StringMarshalling.pair(), settings);
499
500 cache1.put("updated-key", "second1", PUT_ALWAYS);
501 cache2.put("updated-key", "second2", PUT_ALWAYS);
502 cache1.put("phase-2", "second", PUT_ALWAYS);
503 cache2.put("phase-2", "second", PUT_ALWAYS);
504
505 vCacheLifecycleManager().transactionSync(currentRequestContext());
506
507 final TransactionalExternalCache<String> cache3 = vCacheFactory().getTransactionalExternalCache(
508 "discard_sync_discard-3", StringMarshalling.pair(), settings);
509
510 cache1.put("updated-key", "third1", PUT_ALWAYS);
511 cache2.put("updated-key", "third2", PUT_ALWAYS);
512 cache1.put("phase-3", "third", PUT_ALWAYS);
513 cache2.put("phase-3", "third", PUT_ALWAYS);
514 cache3.put("phase-3", "third", PUT_ALWAYS);
515
516
517 vCacheLifecycleManager().transactionDiscard(currentRequestContext());
518
519 forceNewRequestContext();
520
521 assertThat(unsafeJoin(cache1.get("updated-key")), is(Optional.of("second1")));
522 assertThat(unsafeJoin(cache1.get("phase-1")), is(Optional.empty()));
523 assertThat(unsafeJoin(cache1.get("phase-2")), is(Optional.of("second")));
524 assertThat(unsafeJoin(cache1.get("phase-3")), is(Optional.empty()));
525
526 assertThat(unsafeJoin(cache2.get("updated-key")), is(Optional.of("second2")));
527 assertThat(unsafeJoin(cache2.get("phase-2")), is(Optional.of("second")));
528 assertThat(unsafeJoin(cache2.get("phase-3")), is(Optional.empty()));
529
530 assertThat(unsafeJoin(cache3.get("phase-3")), is(Optional.empty()));
531 assertThat(invocationsOfBegunTxns, is(4));
532 }
533
534 @Test
535 public void verify_txns_discard_discard_discard() {
536 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
537 .defaultTtl(Duration.ofSeconds(60))
538 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
539 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
540 .entryCountHint(100)
541 .build();
542
543 final TransactionalExternalCache<String> cache1 = vCacheFactory().getTransactionalExternalCache(
544 "discard_discard_discard-1", StringMarshalling.pair(), settings);
545
546 cache1.put("updated-key", "first1", PUT_ALWAYS);
547 cache1.put("phase-1", "first", PUT_ALWAYS);
548
549 vCacheLifecycleManager().transactionDiscard(currentRequestContext());
550
551 final TransactionalExternalCache<String> cache2 = vCacheFactory().getTransactionalExternalCache(
552 "discard_discard_discard-2", StringMarshalling.pair(), settings);
553
554 cache1.put("updated-key", "second1", PUT_ALWAYS);
555 cache2.put("updated-key", "second2", PUT_ALWAYS);
556 cache1.put("phase-2", "second", PUT_ALWAYS);
557 cache2.put("phase-2", "second", PUT_ALWAYS);
558
559 vCacheLifecycleManager().transactionDiscard(currentRequestContext());
560
561 final TransactionalExternalCache<String> cache3 = vCacheFactory().getTransactionalExternalCache(
562 "discard_discard_discard-3", StringMarshalling.pair(), settings);
563
564 cache1.put("updated-key", "third1", PUT_ALWAYS);
565 cache2.put("updated-key", "third2", PUT_ALWAYS);
566 cache1.put("phase-3", "third", PUT_ALWAYS);
567 cache2.put("phase-3", "third", PUT_ALWAYS);
568 cache3.put("phase-3", "third", PUT_ALWAYS);
569
570 vCacheLifecycleManager().transactionDiscard(currentRequestContext());
571
572 forceNewRequestContext();
573
574 assertThat(unsafeJoin(cache1.get("updated-key")), is(Optional.empty()));
575 assertThat(unsafeJoin(cache1.get("phase-1")), is(Optional.empty()));
576 assertThat(unsafeJoin(cache1.get("phase-2")), is(Optional.empty()));
577 assertThat(unsafeJoin(cache1.get("phase-3")), is(Optional.empty()));
578
579 assertThat(unsafeJoin(cache2.get("updated-key")), is(Optional.empty()));
580 assertThat(unsafeJoin(cache2.get("phase-2")), is(Optional.empty()));
581 assertThat(unsafeJoin(cache2.get("phase-3")), is(Optional.empty()));
582
583 assertThat(unsafeJoin(cache3.get("phase-3")), is(Optional.empty()));
584 assertThat(invocationsOfBegunTxns, is(4));
585 }
586
587 @Test
588 public void duplicate_names_different_policys() {
589 final DirectExternalCache<String> directCache =
590 vCacheFactory().getDirectExternalCache(
591 "duplicate", StringMarshalling.pair(), new ExternalCacheSettingsBuilder().build());
592
593 thrown.expect(ExternalCacheException.class);
594 thrown.expectMessage("Failed due to CREATION_FAILURE");
595
596 final StableReadExternalCache<String> stableCache =
597 vCacheFactory().getStableReadExternalCache(
598 "duplicate", StringMarshalling.pair(), new ExternalCacheSettingsBuilder().build());
599 }
600
601 @Test
602 public void directexternalcache_duplicate_obtain() {
603 final DirectExternalCache<String> firstTime =
604 vCacheFactory().getDirectExternalCache(
605 "duplicate", dodgyPair("first"), new ExternalCacheSettingsBuilder().build());
606
607 final CompletionStage<Boolean> put1 = firstTime.put("key", "ignored", PUT_ALWAYS);
608 assertThat(VCacheUtils.unsafeJoin(put1), is(true));
609
610 final CompletionStage<Optional<String>> get1 = firstTime.get("key");
611 assertThat(VCacheUtils.unsafeJoin(get1), is(Optional.of("first")));
612
613 final DirectExternalCache<String> secondTime =
614 vCacheFactory().getDirectExternalCache(
615 "duplicate", dodgyPair("second"), new ExternalCacheSettingsBuilder().build());
616
617 final CompletionStage<Optional<String>> get2 = secondTime.get("key");
618 assertThat(VCacheUtils.unsafeJoin(get2), is(Optional.of("second")));
619 }
620
621 @Test
622 public void stablereadexternalcache_duplicate_obtain() {
623 final StableReadExternalCache<String> firstTime =
624 vCacheFactory().getStableReadExternalCache(
625 "duplicate", dodgyPair("first"), new ExternalCacheSettingsBuilder().build());
626
627 final CompletionStage<Boolean> put1 = firstTime.put("key", "ignored", PUT_ALWAYS);
628 assertThat(VCacheUtils.unsafeJoin(put1), is(true));
629
630 forceNewRequestContext();
631 final CompletionStage<Optional<String>> get1 = firstTime.get("key");
632 assertThat(VCacheUtils.unsafeJoin(get1), is(Optional.of("first")));
633
634 final StableReadExternalCache<String> secondTime =
635 vCacheFactory().getStableReadExternalCache(
636 "duplicate", dodgyPair("second"), new ExternalCacheSettingsBuilder().build());
637 forceNewRequestContext();
638
639 final CompletionStage<Optional<String>> get2 = secondTime.get("key");
640 assertThat(VCacheUtils.unsafeJoin(get2), is(Optional.of("second")));
641 }
642
643 @Test
644 public void txnexternalcache_duplicate_obtain() {
645 final TransactionalExternalCache<String> firstTime =
646 vCacheFactory().getTransactionalExternalCache(
647 "duplicate", dodgyPair("first"), new ExternalCacheSettingsBuilder().build());
648
649 firstTime.put("key", "ignored", PUT_ALWAYS);
650 vCacheLifecycleManager().transactionSync(currentRequestContext());
651
652 forceNewRequestContext();
653 final CompletionStage<Optional<String>> get1 = firstTime.get("key");
654 assertThat(VCacheUtils.unsafeJoin(get1), is(Optional.of("first")));
655
656 final TransactionalExternalCache<String> secondTime =
657 vCacheFactory().getTransactionalExternalCache(
658 "duplicate", dodgyPair("second"), new ExternalCacheSettingsBuilder().build());
659
660 forceNewRequestContext();
661 final CompletionStage<Optional<String>> get2 = secondTime.get("key");
662 assertThat(VCacheUtils.unsafeJoin(get2), is(Optional.of("second")));
663 }
664
665 private static MarshallingPair<String> dodgyPair(String returning) {
666 return new MarshallingPair<>(String::getBytes, b -> returning);
667 }
668
669 @Test
670 public void handle_legal_recursive_get_supplier() {
671 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
672 .defaultTtl(Duration.ofSeconds(60))
673 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
674 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
675 .entryCountHint(100)
676 .build();
677
678 final StableReadExternalCache<String> cache = vCacheFactory().getStableReadExternalCache(
679 "my-stable-read-cache", StringMarshalling.pair(), settings);
680
681 final CompletionStage<String> get1 = cache.get("recursive", () ->
682 "ignored-" + unsafeJoin(cache.get("recursive", () -> "2")));
683 assertThat(get1, successfulWith(is("2")));
684 }
685
686 @Test
687 public void handle_legal_recursive_get_supplier2() {
688 final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder()
689 .defaultTtl(Duration.ofSeconds(60))
690 .entryGrowthRateHint(ChangeRate.LOW_CHANGE)
691 .dataChangeRateHint(ChangeRate.LOW_CHANGE)
692 .entryCountHint(100)
693 .build();
694
695 final StableReadExternalCache<String> cache = vCacheFactory().getStableReadExternalCache(
696 "my-stable-read-cache", StringMarshalling.pair(), settings);
697
698 final CompletionStage<String> get1 = cache.get("recursive", () ->
699 unsafeJoin(cache.get("recursive2", () -> "pass")));
700 assertThat(get1, successfulWith(is("pass")));
701 }
702 }